Skip to content

Backend & Frontend Test Coverage - #84

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

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

Conversation

@SagiEv

@SagiEvSagiEv 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)

PrincipleHow
AAAEvery it() block has clearly-commented // Arrange, // Act, // Assert sections
IsolationEvery dependency is jest.mock()'d — no real DB, no real HTTP, no real file IO
FactoriesShared tests/helpers/factories.js builds reusable test data objects via builder functions
Descriptive namesdescribe('serviceName.methodName')it('should X when Y')
Single responsibilityEach it() tests one behavior
Flexible assertionsexpect.objectContaining() over exact object matching — tests survive schema additions
No test interdependencebeforeEach(() => jest.clearAllMocks()) in every suite
Coverage of error pathsHappy 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 CaseCategory
Returns 401 when no Authorization headerError
Returns 401 when header doesn't start with "Bearer "Error
Returns 401 when supabase returns errorError
Returns 401 when user is nullError
Returns 500 on unexpected exceptionError
Sets req.user and req.token and calls next() on valid tokenHappy

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

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

Test CaseCategory
Calls next() when body passes schema validationHappy
Returns 400 with formatted issues on invalid bodyError
Returns 400 with "unknown" field when error has no pathEdge

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

Tests for authorize(allowedRoles) middleware.

Test CaseCategory
Returns 401 when req.user is missingError
Returns 403 when user role is not in allowed listError
Reads role from user_metadata.roleHappy
Falls back to app_metadata.roleEdge
Defaults to "user" when no role metadata existsEdge
Calls next() when role is authorizedHappy

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

Tests for errorHandler middleware.

Test CaseCategory
Returns error status from err.statusHappy
Defaults to 500 when no err.statusEdge
Returns 409 for Supabase unique constraint (code: '23505')Happy
Includes stack trace in development modeHappy
Excludes stack trace in production modeHappy

Schema Tests (1 file)

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

Tests for signupSchema and loginSchema Zod schemas.

Test CaseCategory
signupSchema accepts valid email + password ≥ 8 charsHappy
signupSchema rejects invalid emailError
signupSchema rejects password < 8 charsError
signupSchema accepts optional username (3-15 chars)Happy
signupSchema rejects username < 3 charsError
loginSchema accepts valid email + passwordHappy
loginSchema rejects empty passwordError

Utility Tests (3 files)

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

Test CaseCategory
encryptdecrypt round-trips correctlyHappy
encrypt(null) returns nullEdge
encrypt('') returns null (falsy)Edge
decrypt(null) returns nullEdge
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 CaseCategory
Returns invalid for empty tokenError
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 responseError
Returns invalid with message on network timeoutError
Returns invalid for unknown providerError
Claude: treats non-401 errors as valid (API quirk)Edge

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

Test CaseCategory
Renders full HTML with all personalInfo fieldsHappy
Uses fallback "Curriculum Vitae" when no name providedEdge
Omits sections when cvData fields are falsyEdge
Includes each section heading when data is presentHappy

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 CaseCategory
getHistoryByApplicationId returns data on successHappy
getHistoryByApplicationId throws on repo errorError
addHistory creates a history recordHappy
updateHistory updates by idHappy
logChange skips logging when nothing changed and eventType is not Note/InterviewEdge
logChange logs when eventType is "Note" even if status unchangedHappy
logChange includes event_date when providedHappy
logChange omits event_date when nullEdge

[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 CaseCategory
getAllApplications: returns data with last_activity_date enrichmentHappy
getAllApplications: falls back to app.date when no history existsEdge
getAllApplications: throws on repo errorError
createApplication: creates app + logs "Application Added" historyHappy
createApplication: throws on repo errorError
updateApplication: conflict detection — throws CONFLICTING_EVENT when conflict exists and no resolutionError
updateApplication: conflict resolution keep_both — logs both eventsHappy
updateApplication: conflict resolution overwrite — updates existing historyHappy
updateApplication: skips duplicate exact event on same dateEdge
deleteApplication: returns { success: true }Happy
deleteApplication: throws on repo errorError
bulkCreateApplications: returns success countHappy
bulkCreateApplications: throws on repo errorError
getAnalyticsMetrics: returns zero metrics for empty appsEdge
getAnalyticsMetrics: calculates correct averages for transitionsHappy

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

Standard CRUD tests. Mocks contacts.repository.

Test CaseCategory
getAllContacts returns dataHappy
getAllContacts throws on errorError
createContact returns new recordHappy
updateContact returns updated recordHappy
deleteContact returns { success: true }Happy
bulkCreateContacts returns success countHappy
Each method throws on repo errorError

[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 CaseCategory
getAllProjects returns dataHappy
createProject returns new projectHappy
createProject throws raw error (not wrapped) for detail loggingEdge
updateProject returns updated projectHappy
deleteProject returns { success: true }Happy
getExperienceText returns data or { text: '' } fallbackHappy + Edge
getExperienceText ignores PGRST116 (not found) errorEdge
saveExperienceText returns saved dataHappy

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

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

Test CaseCategory
getAllInterviews returns dataHappy
createInterview logs history when application_id presentHappy
createInterview skips history logging when no application_idEdge
updateInterview returns updated recordHappy
deleteInterview returns successHappy
getAiReports returns reportsHappy
generateAiReport throws on no interview dataError
generateAiReport throws on missing AI configError
generateAiReport calls AI service and saves resultHappy
generateAiReport wraps AI service errorsError

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

Test CaseCategory
getProfile transforms cv_datacvDataHappy
getProfile maps websitegithubHappy
getProfile returns {} when no profile found (PGRST116)Edge
upsertProfile maps cvDatacv_data and githubwebsiteHappy
upsertProfile calls createProfile when no idHappy
upsertProfile calls updateProfile when id presentHappy

[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 CaseCategory
getSettings returns masked tokens (first 6 chars + mask)Happy
getSettings returns null previews when no token setEdge
getSettings decrypts encrypted tokens; falls back to plain groq_tokenEdge
getSettings returns SMTP fields and defaultsHappy
saveSettings encrypts new AI tokens after validationHappy
saveSettings throws when AI token validation failsError
saveSettings clears token when empty string providedHappy
saveSettings clears legacy groq_token fieldHappy
saveSettings encrypts SMTP passwordHappy
saveSettings saves ai_routing and timezoneHappy
getAllAiConfigs returns decrypted tokens (internal use)Happy
getAllAiConfigs returns null on repo errorError

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

Mocks user.repository.

Test CaseCategory
registerUser returns data on successHappy
registerUser throws on errorError
loginUser returns { access_token, refresh_token, user }Happy
loginUser throws on errorError
refreshUserSession returns sessionHappy
refreshUserSession throws on errorError

[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 CaseCategory
createJob returns job IDHappy
createJob throws on errorError
completeJob updates status to completed with result_dataHappy
failJob handles string errorHappy
failJob handles object error with suggested_modelEdge
failJob handles object error with messageEdge
getJob returns job dataHappy
getJob throws on not foundError

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

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

Test CaseCategory
mapToJsonResume produces valid JSON Resume structureHappy
Skills: parses paragraph-based Category: item, item formatHappy
Skills: parses single-blob fallback formatEdge
Skills: returns flat list when no category headersEdge
Education: extracts degree, area, institution, dates, GPAHappy
Education: handles missing GPA and extra paragraphsEdge
Projects: extracts name, tech stack, GitHub URL, highlightsHappy
Work: extracts position, company, dates, highlightsHappy
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 formatHappy
LinkedIn/GitHub profiles are constructed correctlyHappy
Empty/null sections produce empty arraysEdge

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

Pure function — no mocks needed. Tests reorderSections.

Test CaseCategory
Returns HTML unchanged for stackoverflow themeHappy
Reorders claude theme sections into canonical orderHappy
Reorders architects-portfolio sectionsHappy
Returns HTML unchanged when no </header> foundEdge
Returns HTML unchanged when less than 2 sectionsEdge
Unknown theme returns HTML unchangedEdge

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 CaseCategory
getAll returns 401 when req.user is missingError
getAll calls service and returns data via res.jsonHappy
getAll returns 400 on service errorError
create returns 401 when req.user is missingError
create calls service and returns dataHappy
update returns 409 with CONFLICTING_EVENT codeError
update returns 400 on other errorsError
remove calls service and returns resultHappy
bulkCreate returns dataHappy
getAnalyticsMetrics returns metricsHappy

[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

LayerNew FilesEstimated Tests
Infrastructure4 (jest.config.js, setup.js, factories.js, mockSupabase.js)
Middleware4~20
Schemas1~7
Utils3~20
Services15~130
Controllers15~100
Total42 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!

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

vercelBot commented Sep 1, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated
job-pilotReadyReadyPreviewSep 4, 2026 10:21am UTC

@SagiEv

Copy link
Copy Markdown
OwnerAuthor

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

@SagiEvSagiEv changed the title Backend Unit Test CoverageBackend & Frontend Test CoverageSep 1, 2026
@SagiEv

Copy link
Copy Markdown
OwnerAuthor

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!

Sign up for freeto 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

@SagiEv