test(jef-121): add component tests for untested apps/web pages - #304
Conversation
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.
WalkthroughAdded 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. ChangesFrontend test coverage
Estimated code review effort: 3 (Moderate) | ~30 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
apps/web/src/__tests__/components/BoardPage.test.tsx (1)
84-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert 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 winVerify 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 winTest the score-band boundaries.
Add assertions for scores
91,71, and41. 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
📒 Files selected for processing (20)
apps/web/src/__tests__/components/ActivityTab.test.tsxapps/web/src/__tests__/components/AnalyticsPage.test.tsxapps/web/src/__tests__/components/BoardPage.test.tsxapps/web/src/__tests__/components/CalendarPage.test.tsxapps/web/src/__tests__/components/CompanyBriefingTab.test.tsxapps/web/src/__tests__/components/CompareOffersPage.test.tsxapps/web/src/__tests__/components/ConfirmBackupEmailPage.test.tsxapps/web/src/__tests__/components/ConfirmEmailChangePage.test.tsxapps/web/src/__tests__/components/ContactsTab.test.tsxapps/web/src/__tests__/components/CoverLetterTab.test.tsxapps/web/src/__tests__/components/DocumentDraftEditor.test.tsxapps/web/src/__tests__/components/DocumentsTab.test.tsxapps/web/src/__tests__/components/HealthScorePanel.test.tsxapps/web/src/__tests__/components/InterviewsTab.test.tsxapps/web/src/__tests__/components/OfferForm.test.tsxapps/web/src/__tests__/components/OffersIndexPage.test.tsxapps/web/src/__tests__/components/ResumeMatchTab.test.tsxapps/web/src/__tests__/components/StatusBadge.test.tsxapps/web/src/__tests__/components/settings/SettingsExperiencePage.test.tsxapps/web/src/__tests__/components/useStepUpReauth.test.tsx
| 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>, | ||
| })); |
There was a problem hiding this comment.
🎯 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.
| 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(); | ||
| }); |
There was a problem hiding this comment.
🩺 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 localvi.unstubAllGlobals()call.apps/web/src/__tests__/components/OffersIndexPage.test.tsx#L151-L173: remove the localvi.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.
Summary
OfferForm,HealthScorePanel,DocumentDraftEditor, the Board/Calendar/Analytics pages, the Offers index/compare routes, Settings > Experience, the email/backup-email confirmation pages, theuseStepUpReauthhook, andStatusBadge.apps/webtesting conventions: Vitest +@testing-library/react,gqlClientmocked viavi.mock+vi.hoisted,@tanstack/react-routermocked per-component,QueryClientProviderwrapper withretry: false.Test plan
pnpm --filter @job-finder/web typecheck— cleanpnpm --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