Skip to content

test(jef-121): add component tests for untested apps/web pages - #304

Merged
mankatcheung merged 1 commit into
mainfrom
feat/jef-121-web-component-tests
Aug 9, 2026
Merged

mankatcheung merged 1 commit into
mainfrom
feat/jef-121-web-component-tests

Conversation

@mankatcheung

@mankatcheung mankatcheung commented Aug 9, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Adds component tests for the previously-untested surfaces identified in JEF-121's audit: all application-detail tabs (Contacts, Interviews, Documents, Activity, CoverLetter, CompanyBriefing, ResumeMatch), OfferForm, HealthScorePanel, DocumentDraftEditor, the Board/Calendar/Analytics pages, the Offers index/compare routes, Settings > Experience, the email/backup-email confirmation pages, the useStepUpReauth hook, and StatusBadge.
  • Follows the existing apps/web testing conventions: Vitest + @testing-library/react, gqlClient mocked via vi.mock + vi.hoisted, @tanstack/react-router mocked per-component, QueryClientProvider wrapper with retry: false.
  • 20 new test files, 344/344 tests passing (up from 297 before this PR), typecheck and lint clean.

Test plan

  • pnpm --filter @job-finder/web typecheck — clean
  • pnpm --filter @job-finder/web lint — clean (only pre-existing warnings in unrelated files)
  • pnpm --filter @job-finder/web test — 344/344 passing across 50 files

🤖 Generated with Claude Code

https://claude.ai/code/session_01FioLhY9DMwRYGVW5H9D3Lu

Summary by CodeRabbit

  • Tests
    • Expanded automated coverage across activity tracking, analytics, boards, calendars, offers, documents, contacts, interviews, settings and authentication flows.
    • Added validation for empty states, loading and error handling, retries, navigation, form interactions, data updates and deletion workflows.
    • Added coverage for AI-assisted features, resume matching, document editing, health scores and reauthentication scenarios.

Covers the application-detail tabs (Contacts, Interviews, Documents,
Activity, CoverLetter, CompanyBriefing, ResumeMatch), OfferForm,
HealthScorePanel, DocumentDraftEditor, the Board/Calendar/Analytics
pages, the Offers index/compare routes, Settings > Experience, the
email/backup-email confirmation pages, the useStepUpReauth hook, and
StatusBadge — closing the testing gap identified in JEF-121.
@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Added comprehensive frontend tests for application pages, application tabs, account flows, settings, authentication, forms, editors, and shared UI components. The tests cover rendering, GraphQL requests, mutations, error states, navigation, validation, and retry behaviour.

Changes

Frontend test coverage

Layer / File(s) Summary
Shared component and form behaviour
apps/web/src/__tests__/components/DocumentDraftEditor.test.tsx, HealthScorePanel.test.tsx, OfferForm.test.tsx, StatusBadge.test.tsx
Tests cover editor readiness and updates, score panel interactions, offer form validation, and status styling fallbacks.
Page queries and interactions
apps/web/src/__tests__/components/AnalyticsPage.test.tsx, BoardPage.test.tsx, CalendarPage.test.tsx, CompareOffersPage.test.tsx, OffersIndexPage.test.tsx
Tests cover query errors, empty states, metrics, calendar navigation, application placement, offer comparison, offer mutations, and page navigation.
Application detail tabs
apps/web/src/__tests__/components/ActivityTab.test.tsx, CompanyBriefingTab.test.tsx, ContactsTab.test.tsx, CoverLetterTab.test.tsx, DocumentsTab.test.tsx, InterviewsTab.test.tsx, ResumeMatchTab.test.tsx
Tests cover tab rendering, GraphQL queries and mutations, AI configuration errors, clipboard actions, uploads, deletions, and generated results.
Account and settings flows
apps/web/src/__tests__/components/ConfirmBackupEmailPage.test.tsx, ConfirmEmailChangePage.test.tsx, settings/SettingsExperiencePage.test.tsx, useStepUpReauth.test.tsx
Tests cover email confirmation, settings mutations and editing, reauthentication retries, TOTP prompts, cancellation, and failure states.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related issues

Possibly related PRs

Poem

A rabbit checks each page with care,
And finds the empty states laid bare.
GraphQL paths now hop in line,
Errors retry, and charts align.
“Good tests,” says Bun, “this burrow’s fine!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the addition of component tests for previously untested apps/web pages.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/jef-121-web-component-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
apps/web/src/__tests__/components/BoardPage.test.tsx (1)

84-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the status-column placement.

Scope each card assertion to its expected status column. The current assertions pass if both cards render in the same column.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/__tests__/components/BoardPage.test.tsx` around lines 84 - 97,
Update the test “places each application card into its matching status column”
to locate each status column and assert Acme is rendered within the applied
column while Globex is rendered within the interviewing column. Keep the
existing card presence checks, but scope them to their expected column
containers rather than querying the document globally.
apps/web/src/__tests__/components/OffersIndexPage.test.tsx (1)

70-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Verify the post-create refetch result.

Assert that the refetched offer is displayed after the mutation completes. The current test only verifies CreateOffer, so it passes if the list refresh is removed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/__tests__/components/OffersIndexPage.test.tsx` around lines 70 -
104, Extend the test case “creates a new offer and refetches the list” to wait
for and assert that the refetched offer with the created ID or salary is
displayed after saving. Keep the existing CreateOffer request assertion, but
ensure the test fails if the post-create list refresh is removed.
apps/web/src/__tests__/components/HealthScorePanel.test.tsx (1)

18-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test the score-band boundaries.

Add assertions for scores 91, 71, and 41. The current values only test the middle of each band. A threshold regression can pass this test suite.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/__tests__/components/HealthScorePanel.test.tsx` around lines 18
- 25, Add boundary assertions to the scoreColor test so scores 91, 71, and 41
verify the expected color bucket transitions. Keep the existing midpoint
assertions and use the established band mapping to determine each expected
result.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/__tests__/components/DocumentsTab.test.tsx`:
- Around line 9-19: Update the mocked Link component and its usage in
DocumentsTab tests so route parameters are resolved into the href using the
concrete application and draft IDs, rather than joining unresolved
route-template values. Replace the assertion around the draft navigation with an
exact concrete href check that would fail if either parameter is missing or
incorrect.

In `@apps/web/src/__tests__/components/OffersIndexPage.test.tsx`:
- Around line 122-149: In
apps/web/src/__tests__/components/OffersIndexPage.test.tsx:122-149 and 151-173,
remove the local vi.unstubAllGlobals() calls from both tests, and add a
suite-level afterEach(() => vi.unstubAllGlobals()) so global stubs are restored
even when assertions fail.

---

Nitpick comments:
In `@apps/web/src/__tests__/components/BoardPage.test.tsx`:
- Around line 84-97: Update the test “places each application card into its
matching status column” to locate each status column and assert Acme is rendered
within the applied column while Globex is rendered within the interviewing
column. Keep the existing card presence checks, but scope them to their expected
column containers rather than querying the document globally.

In `@apps/web/src/__tests__/components/HealthScorePanel.test.tsx`:
- Around line 18-25: Add boundary assertions to the scoreColor test so scores
91, 71, and 41 verify the expected color bucket transitions. Keep the existing
midpoint assertions and use the established band mapping to determine each
expected result.

In `@apps/web/src/__tests__/components/OffersIndexPage.test.tsx`:
- Around line 70-104: Extend the test case “creates a new offer and refetches
the list” to wait for and assert that the refetched offer with the created ID or
salary is displayed after saving. Keep the existing CreateOffer request
assertion, but ensure the test fails if the post-create list refresh is removed.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a619e4b9-2e7f-4194-9254-73d4eb030bc9

📥 Commits

Reviewing files that changed from the base of the PR and between ce02717 and b2a52dc.

📒 Files selected for processing (20)
  • apps/web/src/__tests__/components/ActivityTab.test.tsx
  • apps/web/src/__tests__/components/AnalyticsPage.test.tsx
  • apps/web/src/__tests__/components/BoardPage.test.tsx
  • apps/web/src/__tests__/components/CalendarPage.test.tsx
  • apps/web/src/__tests__/components/CompanyBriefingTab.test.tsx
  • apps/web/src/__tests__/components/CompareOffersPage.test.tsx
  • apps/web/src/__tests__/components/ConfirmBackupEmailPage.test.tsx
  • apps/web/src/__tests__/components/ConfirmEmailChangePage.test.tsx
  • apps/web/src/__tests__/components/ContactsTab.test.tsx
  • apps/web/src/__tests__/components/CoverLetterTab.test.tsx
  • apps/web/src/__tests__/components/DocumentDraftEditor.test.tsx
  • apps/web/src/__tests__/components/DocumentsTab.test.tsx
  • apps/web/src/__tests__/components/HealthScorePanel.test.tsx
  • apps/web/src/__tests__/components/InterviewsTab.test.tsx
  • apps/web/src/__tests__/components/OfferForm.test.tsx
  • apps/web/src/__tests__/components/OffersIndexPage.test.tsx
  • apps/web/src/__tests__/components/ResumeMatchTab.test.tsx
  • apps/web/src/__tests__/components/StatusBadge.test.tsx
  • apps/web/src/__tests__/components/settings/SettingsExperiencePage.test.tsx
  • apps/web/src/__tests__/components/useStepUpReauth.test.tsx

Comment on lines +9 to +19
vi.mock('@tanstack/react-router', () => ({
Link: ({
children,
to,
params,
}: {
children: React.ReactNode;
to: string;
params?: Record<string, string>;
}) => <a href={`${to}${params ? '/' + Object.values(params).join('/') : ''}`}>{children}</a>,
}));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Resolve route parameters in the Link mock and assert the concrete href.

The mock at Lines 9-19 produces an href with unresolved $applicationId and $draftId segments. The assertion at Lines 106-110 accepts that invalid href. This test will not detect broken draft navigation.

Proposed fix
 vi.mock('`@tanstack/react-router`', () => ({
   Link: ({
     children,
     to,
     params,
   }: {
     children: React.ReactNode;
     to: string;
     params?: Record<string, string>;
-  }) => <a href={`${to}${params ? '/' + Object.values(params).join('/') : ''}`}>{children}</a>,
+  }) => (
+    <a href={to.replace(/\$([^/]+)/g, (_match, key) => params?.[key] ?? `$${key}`)}>
+      {children}
+    </a>
+  ),
 }));
@@
-    expect(link).toHaveAttribute(
-      'href',
-      expect.stringContaining('/applications/$applicationId/documents/$draftId'),
-    );
+    expect(link).toHaveAttribute('href', '/applications/app-1/documents/draft-1');

Also applies to: 99-111

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/__tests__/components/DocumentsTab.test.tsx` around lines 9 - 19,
Update the mocked Link component and its usage in DocumentsTab tests so route
parameters are resolved into the href using the concrete application and draft
IDs, rather than joining unresolved route-template values. Replace the assertion
around the draft navigation with an exact concrete href check that would fail if
either parameter is missing or incorrect.

Comment on lines +122 to +149
it('deletes an offer after confirming', async () => {
mockGqlRequest.mockImplementation((query: string) => {
if (query.includes('query Offers')) return Promise.resolve({ offers: [offer()] });
if (query.includes('DeleteOffer')) return Promise.resolve({ deleteOffer: true });
return Promise.resolve({});
});
vi.stubGlobal(
'confirm',
vi.fn(() => true),
);

render(<OffersPage />);
await waitFor(() => {
expect(screen.getByText('$150,000/yr')).toBeInTheDocument();
});

const card = cardFor('$150,000/yr');
const buttons = within(card).getAllByRole('button');
fireEvent.click(buttons[1]);

await waitFor(() => {
expect(mockGqlRequest).toHaveBeenCalledWith(expect.stringContaining('DeleteOffer'), {
id: 'offer-1',
});
});

vi.unstubAllGlobals();
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Restore global stubs in afterEach.

Both tests restore confirm only at their normal end. If an assertion fails first, the stub can affect later tests.

  • apps/web/src/__tests__/components/OffersIndexPage.test.tsx#L122-L149: remove the local vi.unstubAllGlobals() call.
  • apps/web/src/__tests__/components/OffersIndexPage.test.tsx#L151-L173: remove the local vi.unstubAllGlobals() call.
  • Add one afterEach(() => vi.unstubAllGlobals()) for the suite.
📍 Affects 1 file
  • apps/web/src/__tests__/components/OffersIndexPage.test.tsx#L122-L149 (this comment)
  • apps/web/src/__tests__/components/OffersIndexPage.test.tsx#L151-L173
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/__tests__/components/OffersIndexPage.test.tsx` around lines 122
- 149, In apps/web/src/__tests__/components/OffersIndexPage.test.tsx:122-149 and
151-173, remove the local vi.unstubAllGlobals() calls from both tests, and add a
suite-level afterEach(() => vi.unstubAllGlobals()) so global stubs are restored
even when assertions fail.

@mankatcheung
mankatcheung merged commit 0f1b55f into main Aug 9, 2026
11 checks passed
@mankatcheung
mankatcheung deleted the feat/jef-121-web-component-tests branch August 18, 2026 13:16
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.

1 participant