Skip to content

Backend & Frontend Test Coverage - #84

Open
SagiEv wants to merge 21 commits into
mainfrom
chore/test-coverage
Open

Backend & Frontend Test Coverage#84
SagiEv wants to merge 21 commits into
mainfrom
chore/test-coverage

Conversation

@SagiEv

@SagiEv SagiEv commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Backend Unit Test Coverage — Full Plan

Add comprehensive unit tests to every testable layer of the Node.js backend using AAA (Arrange-Act-Assert) with Jest, following best practices for maintainability, flexibility, and isolation.

User Review Required

Important

Test scope: This plan covers the Node.js backend only (not the Python FastAPI AI service). The AI service has its own stack and should be tested separately with pytest.

Important

Heavy-IO services (mail-poller.service, rssPoller, cv.service, cv.jsonresume.service) that heavily couple to Puppeteer/IMAP/external APIs are tested at the service level with all IO mocked — not skipped. If you want true integration tests for those later, we can add them as a separate phase.

Important

Existing tests (applications.status.test.js and email-classifier.test.js) will be kept as-is. New tests fill in all the gaps.

Open Questions

Note

Coverage target: This plan targets line/branch coverage for all business logic. Do you want a minimum coverage threshold enforced (e.g., --coverage --coverageThreshold in Jest)?

Note

Notifications route: notifications.routes.js has no controller file — it appears to have inline handlers. Should I extract them into a controller for testability, or test the route handler inline?


Design Principles (Applied Everywhere)

Principle How
AAA Every it() block has clearly-commented // Arrange, // Act, // Assert sections
Isolation Every dependency is jest.mock()'d — no real DB, no real HTTP, no real file IO
Factories Shared tests/helpers/factories.js builds reusable test data objects via builder functions
Descriptive names describe('serviceName.methodName')it('should X when Y')
Single responsibility Each it() tests one behavior
Flexible assertions expect.objectContaining() over exact object matching — tests survive schema additions
No test interdependence beforeEach(() => jest.clearAllMocks()) in every suite
Coverage of error paths Happy path + error/edge cases for every function

Proposed Changes

Infrastructure & Tooling

[NEW] jest.config.js

Jest configuration file with:

  • testMatch pointing to tests/**/*.test.js
  • setupFilesAfterSetup pointing to tests/setup.js
  • Coverage collection enabled on controllers/, services/, middleware/, utils/, schemas/
  • modulePathIgnorePatterns for node_modules, ai_service

[NEW] tests/setup.js

Global test setup:

  • Stubs process.env vars (SUPABASE_URL, SUPABASE_ANON_KEY, ENCRYPTION_KEY)
  • Silences console.log / console.warn / console.error during test runs to keep output clean

[NEW] tests/helpers/factories.js

Builder functions for reusable test data:

  • buildUser(overrides) — returns a mock req.user object
  • buildApplication(overrides) — returns a mock application row
  • buildContact(overrides), buildInterview(overrides), buildEvent(overrides)
  • buildReqRes(overrides) — returns mock Express { req, res } with jest spies on res.json, res.status, res.end, etc.
  • buildHistoryEntry(overrides) — mock application_history row
  • buildSettings(overrides) — mock settings row with encrypted tokens

[NEW] tests/helpers/mockSupabase.js

A centralized mock for ../supabaseClient that returns chainable query builder stubs (.from().select().eq().single() etc.) — configurable per test via a helper function.

[MODIFY] package.json

  • Add test:coverage script: "jest --coverage --forceExit"
  • Keep existing test script

Middleware Tests (4 files)

[NEW] tests/middleware/auth.test.js

Tests for authenticate middleware. Mocks ../supabaseClient.

Test Case Category
Returns 401 when no Authorization header Error
Returns 401 when header doesn't start with "Bearer " Error
Returns 401 when supabase returns error Error
Returns 401 when user is null Error
Returns 500 on unexpected exception Error
Sets req.user and req.token and calls next() on valid token Happy

[NEW] tests/middleware/validate.test.js

Tests for validate(schema) middleware. Uses real Zod schemas.

Test Case Category
Calls next() when body passes schema validation Happy
Returns 400 with formatted issues on invalid body Error
Returns 400 with "unknown" field when error has no path Edge

[NEW] tests/middleware/roleCheck.test.js

Tests for authorize(allowedRoles) middleware.

Test Case Category
Returns 401 when req.user is missing Error
Returns 403 when user role is not in allowed list Error
Reads role from user_metadata.role Happy
Falls back to app_metadata.role Edge
Defaults to "user" when no role metadata exists Edge
Calls next() when role is authorized Happy

[NEW] tests/middleware/error.test.js

Tests for errorHandler middleware.

Test Case Category
Returns error status from err.status Happy
Defaults to 500 when no err.status Edge
Returns 409 for Supabase unique constraint (code: '23505') Happy
Includes stack trace in development mode Happy
Excludes stack trace in production mode Happy

Schema Tests (1 file)

[NEW] tests/schemas/userSchemas.test.js

Tests for signupSchema and loginSchema Zod schemas.

Test Case Category
signupSchema accepts valid email + password ≥ 8 chars Happy
signupSchema rejects invalid email Error
signupSchema rejects password < 8 chars Error
signupSchema accepts optional username (3-15 chars) Happy
signupSchema rejects username < 3 chars Error
loginSchema accepts valid email + password Happy
loginSchema rejects empty password Error

Utility Tests (3 files)

[NEW] tests/utils/encryption.test.js

Test Case Category
encryptdecrypt round-trips correctly Happy
encrypt(null) returns null Edge
encrypt('') returns null (falsy) Edge
decrypt(null) returns null Edge
Encrypted output contains IV and ciphertext separated by : Happy
Different calls produce different ciphertexts (random IV) Happy

[NEW] tests/utils/ai_validator.test.js

Mocks axios. Tests validateAiToken and STRUCTURAL_RULES.

Test Case Category
Returns invalid for empty token Error
Returns invalid when token fails structural regex (groq, openai, claude, gemini) Error
Returns valid when API call succeeds (per provider) Happy
Returns invalid on 401/403 response Error
Returns invalid with message on network timeout Error
Returns invalid for unknown provider Error
Claude: treats non-401 errors as valid (API quirk) Edge

[NEW] tests/utils/cvTemplate.test.js

Test Case Category
Renders full HTML with all personalInfo fields Happy
Uses fallback "Curriculum Vitae" when no name provided Edge
Omits sections when cvData fields are falsy Edge
Includes each section heading when data is present Happy

Service Tests (15 files — the core of the coverage)

Each service test mocks its repository dependency. Services are where the business logic lives.

[NEW] tests/services/applicationHistory.service.test.js

Test Case Category
getHistoryByApplicationId returns data on success Happy
getHistoryByApplicationId throws on repo error Error
addHistory creates a history record Happy
updateHistory updates by id Happy
logChange skips logging when nothing changed and eventType is not Note/Interview Edge
logChange logs when eventType is "Note" even if status unchanged Happy
logChange includes event_date when provided Happy
logChange omits event_date when null Edge

[NEW] tests/services/applications.service.test.js

Extends the existing applications.status.test.js to cover the full service. Mocks applications.repository, applicationHistory.service, and ../supabaseClient.

Test Case Category
getAllApplications: returns data with last_activity_date enrichment Happy
getAllApplications: falls back to app.date when no history exists Edge
getAllApplications: throws on repo error Error
createApplication: creates app + logs "Application Added" history Happy
createApplication: throws on repo error Error
updateApplication: conflict detection — throws CONFLICTING_EVENT when conflict exists and no resolution Error
updateApplication: conflict resolution keep_both — logs both events Happy
updateApplication: conflict resolution overwrite — updates existing history Happy
updateApplication: skips duplicate exact event on same date Edge
deleteApplication: returns { success: true } Happy
deleteApplication: throws on repo error Error
bulkCreateApplications: returns success count Happy
bulkCreateApplications: throws on repo error Error
getAnalyticsMetrics: returns zero metrics for empty apps Edge
getAnalyticsMetrics: calculates correct averages for transitions Happy

[NEW] tests/services/contacts.service.test.js

Standard CRUD tests. Mocks contacts.repository.

Test Case Category
getAllContacts returns data Happy
getAllContacts throws on error Error
createContact returns new record Happy
updateContact returns updated record Happy
deleteContact returns { success: true } Happy
bulkCreateContacts returns success count Happy
Each method throws on repo error Error

[NEW] tests/services/events.service.test.js

Same pattern as contacts. Mocks events.repository.

[NEW] tests/services/experience.service.test.js

Mocks experience.repository. Tests both project CRUD + experience text operations.

Test Case Category
getAllProjects returns data Happy
createProject returns new project Happy
createProject throws raw error (not wrapped) for detail logging Edge
updateProject returns updated project Happy
deleteProject returns { success: true } Happy
getExperienceText returns data or { text: '' } fallback Happy + Edge
getExperienceText ignores PGRST116 (not found) error Edge
saveExperienceText returns saved data Happy

[NEW] tests/services/interviews.service.test.js

Mocks interviews.repository, applicationHistory.service, settings.service, axios.

Test Case Category
getAllInterviews returns data Happy
createInterview logs history when application_id present Happy
createInterview skips history logging when no application_id Edge
updateInterview returns updated record Happy
deleteInterview returns success Happy
getAiReports returns reports Happy
generateAiReport throws on no interview data Error
generateAiReport throws on missing AI config Error
generateAiReport calls AI service and saves result Happy
generateAiReport wraps AI service errors Error

[NEW] tests/services/profile.service.test.js

Test Case Category
getProfile transforms cv_datacvData Happy
getProfile maps websitegithub Happy
getProfile returns {} when no profile found (PGRST116) Edge
upsertProfile maps cvDatacv_data and githubwebsite Happy
upsertProfile calls createProfile when no id Happy
upsertProfile calls updateProfile when id present Happy

[NEW] tests/services/skills.service.test.js

Standard CRUD pattern. 4 methods × (happy + error) = 8 tests.

[NEW] tests/services/settings.service.test.js

Mocks settings.repository, ../utils/encryption, ../utils/ai_validator.

Test Case Category
getSettings returns masked tokens (first 6 chars + mask) Happy
getSettings returns null previews when no token set Edge
getSettings decrypts encrypted tokens; falls back to plain groq_token Edge
getSettings returns SMTP fields and defaults Happy
saveSettings encrypts new AI tokens after validation Happy
saveSettings throws when AI token validation fails Error
saveSettings clears token when empty string provided Happy
saveSettings clears legacy groq_token field Happy
saveSettings encrypts SMTP password Happy
saveSettings saves ai_routing and timezone Happy
getAllAiConfigs returns decrypted tokens (internal use) Happy
getAllAiConfigs returns null on repo error Error

[NEW] tests/services/user.service.test.js

Mocks user.repository.

Test Case Category
registerUser returns data on success Happy
registerUser throws on error Error
loginUser returns { access_token, refresh_token, user } Happy
loginUser throws on error Error
refreshUserSession returns session Happy
refreshUserSession throws on error Error

[NEW] tests/services/searchSettings.service.test.js

Mocks searchSettings.repository. Standard CRUD + sites sub-resource.

[NEW] tests/services/rss.service.test.js

Mocks rss.repository. Tests getFeeds, addFeed, updateFeed (sets updated_at), deleteFeed, getJobs.

[NEW] tests/services/job.service.test.js

Mocks ../supabaseClient (uses adminSupabase).

Test Case Category
createJob returns job ID Happy
createJob throws on error Error
completeJob updates status to completed with result_data Happy
failJob handles string error Happy
failJob handles object error with suggested_model Edge
failJob handles object error with message Edge
getJob returns job data Happy
getJob throws on not found Error

[NEW] tests/services/jsonresume-mapper.test.js

Pure function — no mocks needed. Tests mapToJsonResume and internal parsers.

Test Case Category
mapToJsonResume produces valid JSON Resume structure Happy
Skills: parses paragraph-based Category: item, item format Happy
Skills: parses single-blob fallback format Edge
Skills: returns flat list when no category headers Edge
Education: extracts degree, area, institution, dates, GPA Happy
Education: handles missing GPA and extra paragraphs Edge
Projects: extracts name, tech stack, GitHub URL, highlights Happy
Work: extracts position, company, dates, highlights Happy
Work: handles various dash separators (en-dash, em-dash, hyphen) Edge
Date normalization: "October 2021""2021-10" Happy
Date normalization: "07/2017""2017-07" Happy
Date normalization: "Present""" Edge
Interests: parses Category: value, value format Happy
LinkedIn/GitHub profiles are constructed correctly Happy
Empty/null sections produce empty arrays Edge

[NEW] tests/services/jsonresume-section-order.test.js

Pure function — no mocks needed. Tests reorderSections.

Test Case Category
Returns HTML unchanged for stackoverflow theme Happy
Reorders claude theme sections into canonical order Happy
Reorders architects-portfolio sections Happy
Returns HTML unchanged when no </header> found Edge
Returns HTML unchanged when less than 2 sections Edge
Unknown theme returns HTML unchanged Edge

Controller Tests (15 files)

Controllers are thin wrappers (delegate to service, catch errors). Tests verify:

  1. Correct service method is called with correct args
  2. res.json() / res.status() is called correctly
  3. Error paths return proper HTTP status codes

[NEW] tests/controllers/applications.controller.test.js

Test Case Category
getAll returns 401 when req.user is missing Error
getAll calls service and returns data via res.json Happy
getAll returns 400 on service error Error
create returns 401 when req.user is missing Error
create calls service and returns data Happy
update returns 409 with CONFLICTING_EVENT code Error
update returns 400 on other errors Error
remove calls service and returns result Happy
bulkCreate returns data Happy
getAnalyticsMetrics returns metrics Happy

[NEW] tests/controllers/contacts.controller.test.js

[NEW] tests/controllers/events.controller.test.js

[NEW] tests/controllers/experience.controller.test.js

[NEW] tests/controllers/interviews.controller.test.js

[NEW] tests/controllers/profile.controller.test.js

[NEW] tests/controllers/skills.controller.test.js

[NEW] tests/controllers/user.controller.test.js

[NEW] tests/controllers/settings.controller.test.js

[NEW] tests/controllers/searchSettings.controller.test.js

[NEW] tests/controllers/rss.controller.test.js

[NEW] tests/controllers/applicationHistory.controller.test.js

[NEW] tests/controllers/tailor.controller.test.js

[NEW] tests/controllers/csv.controller.test.js

[NEW] tests/controllers/messages.controller.test.js

Each controller test file follows the same pattern:

  • Mock the underlying service(s)
  • Use buildReqRes() factory
  • Test happy path + error path per handler
  • Special cases for controllers with unique logic (e.g., csv.controller has CSV parsing strategies, settings.controller has SMTP test / AI token test)

File Summary

Layer New Files Estimated Tests
Infrastructure 4 (jest.config.js, setup.js, factories.js, mockSupabase.js)
Middleware 4 ~20
Schemas 1 ~7
Utils 3 ~20
Services 15 ~130
Controllers 15 ~100
Total 42 new files ~277 tests

Verification Plan

Automated Tests

cd backend
npm test                     # Run all tests
npm run test:coverage        # Run with coverage report

Manual Verification

  • Confirm all tests pass with zero failures
  • Review coverage report — aim for >85% line coverage on services/utils/middleware
  • Verify no real network calls or DB connections are made during tests (all mocked)

Frontend Testing Implementation Plan

We will add a comprehensive unit and integration testing suite for the React frontend, focusing on flexibility, ease of maintenance, and testing best practices (testing behavior over implementation details).

Testing Stack

  • Vitest: For fast and compatible test running (works seamlessly with Vite).
  • React Testing Library (@testing-library/react): For component testing focusing on user interactions.
  • @testing-library/jest-dom: For custom DOM element matchers.
  • @testing-library/user-event: For simulating realistic user interactions.
  • jsdom: As the test environment for simulating a browser.
  • MSW (Mock Service Worker): Optional but recommended for mocking API calls cleanly during integration tests without mocking axios or fetch directly.

User Review Required

Important

The current setup doesn't have a dedicated frontend testing framework. We propose installing vitest and @testing-library/react. Do you approve this stack, and should we also add msw (Mock Service Worker) for API mocking, or do you prefer mocking the API client/Axios directly?

Proposed Changes

Setup and Configuration

[MODIFY] package.json

  • Add devDependencies for testing tools: vitest, jsdom, @testing-library/react, @testing-library/jest-dom, @testing-library/user-event, msw.
  • Add test scripts: "test": "vitest", "test:ui": "vitest --ui", "coverage": "vitest run --coverage".

[MODIFY] vite.config.js

  • Configure test environment (environment: 'jsdom') and test setup file (setupFiles: './src/setupTests.js').

[NEW] setupTests.js

  • Import @testing-library/jest-dom.
  • Setup global mocks if necessary (e.g., ResizeObserver for graphs, MSW server setup).

UI Components Tests

Focus: Rendering correctly given props, basic accessibility.

[NEW] ProviderBadge.test.jsx

[NEW] PageLoader.test.jsx


Notifications & Dialogs Tests

Focus: Context providers functionality, trigger mechanism, visibility, and unmounting.

[NEW] ToastProvider.test.jsx

[NEW] ConfirmProvider.test.jsx

  • Test invoking a toast and ensuring it appears/disappears.
  • Test native UI alert confirmation behavior (accept/cancel flows).

Application List/Detail Loading & Forms

Focus: Integration tests. Mocking API/React Query to simulate loading, success, error states, and form submissions.

[NEW] ApplicationsPage.test.jsx

  • Test skeleton/loading state rendering.
  • Test data population after loading.

[NEW] ApplicationDetailPage.test.jsx

  • Test loading data.
  • Status update UI: Test changing status (select/buttons) and verifying the optimistic update/API call.

[NEW] SettingsPage.test.jsx

  • Form tests: verifying inputs, validation, and submission of the settings form.

Analytics Rendering Tests

Focus: Testing that chart containers render and process data correctly. (Note: testing D3 svgs deeply can be brittle; we will test the wrapper components and data passing).

[NEW] AnalyticsPage.test.jsx

[NEW] NetworkGraph.test.jsx


CV Rendering Tests

Focus: Ensure CV themes parse user data correctly into HTML structure.

[NEW] TailorPage.test.jsx

Verification Plan

Automated Tests

  • Run npm run test inside the /frontend directory to ensure all tests pass.
  • Generate coverage report npm run coverage to ensure all critical paths (components, contexts, hooks) are covered.

Manual Verification

  • N/A for adding automated tests, unless we discover UI discrepancies while writing the tests.

Frontend Testing Implementation Complete

I have successfully added a robust testing foundation for the React frontend and created tests for the key components and features you specified. The setup prioritizes behavior-driven testing and maintains flexibility for future changes.

Testing Setup

  • Vitest: Installed and configured for fast execution alongside Vite.
  • React Testing Library & Jest-DOM: Set up to test components based on user interaction (e.g. clicking buttons, inputting text, asserting visibility) instead of relying on brittle internal implementation details.
  • Global Mocks: Configured setupTests.js to automatically handle DOM APIs like ResizeObserver which aren't fully supported in jsdom (needed for D3 charts/Recharts).

Tests Added

1. UI Components (ProviderBadge, PageLoader)

  • Tested the ProviderBadge for correctly showing the configured API provider and reacting to user interactions when clicking the dropdown.
  • Ensured PageLoader displays the correct accessibility labels and custom loading texts.

2. Notifications & Dialogs (ToastProvider, ConfirmProvider)

  • Verified the context providers allow consuming components to trigger toasts and confirm dialogs.
  • Ensured auto-dismiss behavior for regular toasts, while persistent toasts (e.g., "processing") remain until explicitly removed.
  • Validated that the ConfirmProvider correctly resolves promises with true or false based on user interactions with the dialog.

3. Application List/Detail & Forms (ApplicationsPage, ApplicationDetailPage, SettingsPage)

  • Tested the rendering, searching, and opening of the "New Application" modal in ApplicationsPage.
  • Validated the ApplicationDetailPage, including the inline status-updating UI and adding notes to the application history.
  • Tested SettingsPage to ensure tab switching and complex settings forms (like changing passwords or API keys) render and behave as expected.

4. Analytics Rendering (AnalyticsPage, NetworkGraph)

  • Handled mocking D3 and container dimensions inside NetworkGraph to test view-mode switching (Contacts vs. Companies).
  • Ensured AnalyticsPage handles empty states gracefully and displays the charts when sufficient data is available.

5. CV Rendering (TailorPage)

  • Verified that the TailorPage correctly handles URL inputs and interacts with the AI services logic.
  • Ensured proper messaging is shown when the user's API key is missing.

Tip

You can run the tests locally at any time by executing npm run test inside the /frontend directory. For a UI dashboard showing test results, use npm run test:ui.

Robust Testing & Bug Prevention Strategy

To permanently eliminate bugs like the "Invalid Hook Call" and ensure the codebase is resilient against similar runtime logical errors, we need to shift away from shallow mocking towards a more robust, multi-layered testing strategy.

This generalized solution prevents bugs at three distinct levels: Build-time (Static Analysis), Test-time (Integration), and Runtime (E2E).

Proposed Changes


1. Static Analysis (ESLint + React Rules)

Currently, the project lacks an active ESLint configuration. ESLint can catch "Invalid hook calls" and other React-specific violations statically, without writing a single test.

[NEW] frontend/.eslintrc.cjs

  • Implement ESLint with the eslint-plugin-react-hooks plugin.
  • Configure react-hooks/rules-of-hooks to "error" instead of "warn". This will explicitly fail the build if a hook is used inside a regular helper function.

[MODIFY] frontend/package.json

  • Add an npm run lint script that runs across the /src directory.

2. Mock Service Worker (MSW) & Test Utils

Right now, tests use vi.mock('../../hooks/useApplications') to completely bypass business logic. We should test the actual logic by rendering components fully and mocking the network layer instead.

[NEW] frontend/src/tests/setup-msw.js

  • Install msw and set up a mock server that intercepts axios requests (e.g., apiClient.post('/api/applications')) and returns mock JSON data.

[NEW] frontend/src/tests/test-utils.jsx

  • Create a custom render function for @testing-library/react.
  • This utility will automatically wrap all tested components with a real QueryClientProvider, ToastProvider, and BrowserRouter, completely eliminating the need to mock them in individual test files.

[MODIFY] frontend/src/pages/__tests__/ApplicationsPage.test.jsx

  • Refactor the test to use the new render utility.
  • Remove the vi.mock('../../hooks/useApplications') block so the test executes the real useApplications logic, which would have caught the invalid hook call.

3. End-to-End Smoke Testing (Playwright)

E2E tests guarantee that user interactions don't crash the browser. They test the entire stack from the button click down to the DOM update.

[NEW] frontend/playwright.config.js

  • Install @playwright/test.
  • Configure it to start the Vite dev server and backend API before running tests.

[NEW] frontend/tests/e2e/smoke.spec.js

  • Write a core "Smoke Test" that mimics user behavior:
    1. Loads the Applications Dashboard.
    2. Clicks "+ New Application".
    3. Fills out the company and role fields.
    4. Submits the form.
    5. Asserts the new application appears in the table.

Open Questions

Important

Feedback Required:
Do you want to implement all three layers of this strategy (ESLint, MSW Integration Tests, and Playwright E2E)? If you prefer to start smaller, we can prioritize just ESLint and MSW for now. Let me know your preference and I will execute the changes!

@SagiEv SagiEv linked an issue Sep 1, 2026 that may be closed by this pull request
@vercel

vercel Bot commented Sep 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
job-pilot Ready Ready Preview Sep 5, 2026 10:34pm UTC

@SagiEv

SagiEv commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

Unit Tests Implementation Walkthrough

The backend has been successfully outfitted with a comprehensive unit test suite following the AAA (Arrange-Act-Assert) pattern.

What was accomplished

  • Test Infrastructure Setup: Configured jest.config.js and set up a global environment in tests/setup.js. This ensures environmental variables are managed properly and sets up a robust global mock for supabaseClient to prevent actual database calls and avoid "chaining" errors in testing.
  • Factory Helpers (tests/helpers/factories.js): Developed reusable mock functions like buildReqRes() to easily spin up standardized HTTP request/response objects for controllers.
  • Middleware & Utils Coverage: Added full test suites for authorization (auth.js, roleCheck.js), validation logic (validate.js), error handling, and utilities (e.g. encryption.js).
  • Service Layer Mocking: Tested business logic in backend/services/ by isolating it from the data layer. Repositories (like user.repository.js) were mocked to cleanly inject dependencies.
  • Controller Layer Verification: Built test suites for HTTP routers in backend/controllers/ to assert route handling, request validation, and correct error responses. Services were completely mocked out here to limit tests to routing and formatting logic.

Validation Results

The full suite runs and passes successfully!

> npm run test:coverage

Test Suites: 40 passed, 40 total
Tests:       345 passed, 345 total
Snapshots:   0 total
Time:        18.596 s

Coverage statistics achieved:

  • Statements: ~65%
  • Functions: ~73%

Note

The core CRUD controllers and services (like Profile, Events, ApplicationHistory, Skills, RSS) are largely at 100% coverage. The remaining 35% of uncovered codebase mostly lies in heavy integration-based tasks like cv.jsonresume.service.js, email-classifier.service.js, and external polling features (mail-poller).

Running The Tests Yourself

You can run the full test suite manually from the backend directory:

cd backend
npm run test:coverage

@SagiEv SagiEv changed the title Backend Unit Test Coverage Backend & Frontend Test Coverage Sep 1, 2026
@SagiEv

SagiEv commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

Generalization Testing Infrastructure Installed

We successfully resolved the disk space issues and I have fully implemented the three-pillar strategy to prevent "invalid hook calls" and other frontend logic bugs.

What Was Done

1. Static Analysis (ESLint)

  • Created .eslintrc.cjs configured with eslint-plugin-react-hooks.
  • Enabled the 'react-hooks/rules-of-hooks': 'error' rule.
  • Added an npm run lint script to your frontend package.json.
  • Impact: If a developer accidentally adds a hook inside a non-component function again, npm run lint will immediately flag it and prevent the build.

2. Mock Service Worker & Integration Setup

  • Installed msw and created tests/setup.js.
  • Created a test-utils.jsx wrapper that automatically injects QueryClientProvider, ToastProvider, ConfirmProvider, and BrowserRouter.
  • Impact: You can now write tests that render components exactly as they run in the browser without having to mock the internal hook business logic.

3. Playwright E2E Setup

  • Installed @playwright/test and added npm run e2e to package.json.
  • Created playwright.config.js to automatically spin up the Vite dev server (http://localhost:3000) before running tests.
  • Created tests/e2e/smoke.spec.js which simulates a user navigating to the app, opening the "New Application" modal, and submitting it.
  • Impact: This test runs in a real Chromium browser. If there is a crash (like the invalid hook call), the modal won't close, and the test will fail.

Tip

Try it out!
Run npm run lint to check for hook violations.
Run npx vitest run to see the integration test run.
Run npm run e2e to watch Playwright execute the smoke test against the live dev server!

@SagiEv

SagiEv commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Backend Integration Tests Walkthrough

We've successfully built a robust integration testing suite for the JobPilot backend.
A total of 9 test suites and 48 tests now thoroughly validate the APIs, database interactions, background chron jobs, state machines, and integrations with the AI python service.

What Was Accomplished

  1. Test Infrastructure (tests/integration/setup.integration.js)

    • Created a robust Jest test environment that automatically intercepts global require statements to mock out cron jobs and third-party ESM dependencies (like puppeteer and googleapis).
    • Added a supabaseSandbox tool (tests/integration/helpers/supabaseSandbox.js) that allows each integration test to define stateful, per-test overrides and spy on database queries safely without needing a live Postgres instance for every CI run.
  2. API & Database Tests

    • Applications API: Tested CRUD operations, including bulk imports and conflict resolution (e.g. duplicate dates).
    • Contacts & Interviews APIs: Verified that associated entities are successfully linked to applications and the correct users.
    • Application Lifecycle: Tested the applications.service.js state machine to ensure events trigger valid recalculations, and that invalid (or terminal) status transitions are correctly guarded against.
  3. Background Pipelines & AI Integrations

    • Email Processing: Tested the entire flow of IMAP -> Classification -> Application Status Update -> Notification creation. Handled transition guards where silent statuses (like applied) are ignored and backward transitions are blocked.
    • CSV Export/Import: Handled Multer file parsing edge-cases, date format normalization (e.g. DD/MM/YYYY handling), and bulk database ingestion.
    • AI Proxies (Tailor & RSS): Mocks axios internally to test node-to-python interactions.

How to Run Tests

The Jest configuration (jest.config.js) has been restructured as a multi-project setup to safely separate unit tests from integration tests.

To run the unit tests:

npm run test:unit

To run the integration tests (in mocked mode):

npm run test:integration

Live Testing the AI Service

For the tailor-proxy and rss-ai-pipeline tests, you can skip the Node-level axios mock to send real requests over the network to your FastAPI microservice:

npm run test:integration:live

This is achieved by checking process.env.LIVE_AI_SERVICE within the test factory and using jest.requireActual('axios') when true.

Results

All 48 integration tests, alongside the 345 unit tests, are now passing gracefully with no leaky async handles.

@SagiEv

SagiEv commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

E2E Testing Implementation Walkthrough

I have implemented the Playwright end-to-end tests covering the critical user journeys as outlined in our plan and incorporating your feedback.

What Was Done

  1. Test Setup & API Authentication:

    • [NEW] frontend/tests/e2e/auth.setup.js
      Added a setup project that first creates a dynamic test user via API POST /auth/signup and logs them in via POST /auth/login. It then injects the auth tokens into local storage and saves the Playwright storageState to playwright/.auth/user.json.
    • [MODIFY] frontend/playwright.config.js
      Configured Playwright to run the setup project first and make the chromium project depend on it and use the saved storageState.
  2. Smoke Test (Real UI Login):

    • [MODIFY] frontend/tests/e2e/smoke.spec.js
      Overrode the global storageState for this suite to verify the real UI login flow. It creates a test user via API setup, fills in the login form in the UI, and verifies successful login and basic application creation.
  3. Application Management Journeys:

    • [NEW] frontend/tests/e2e/applications.spec.js
      Implemented tests covering:
      • Creating an application.
      • Opening application details.
      • Updating application status (and stage, if Interviewing).
      • Adding a historical event (Activity Log note).
      • Scheduling an interview from the Dashboard.
  4. CV Tailoring & Export (Mocked AI Responses):

    • [NEW] frontend/tests/e2e/cv.spec.js
      Implemented tests for tailoring the CV and exporting it. Used page.route to mock the backend AI tailoring responses (/api/tailor & polling) to allow reliable frontend testing without spending real Groq API tokens.
  5. Analytics:

    • [NEW] frontend/tests/e2e/analytics.spec.js
      Implemented a test to verify the Analytics page loads correctly and renders the charts (SVG elements).

Verification

You can now run these E2E tests locally using:

cd frontend
npm run e2e

Ensure that your local backend (Node.js) and database (Supabase) are running on http://localhost:5000 before starting the tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add comprehensive automated test coverage

1 participant