Skip to content

refactor(tests): split DiscoveryProgress tests into focused files - #256

Merged
frankbria merged 2 commits into
mainfrom
refactor/split-discovery-progress-tests
Jan 13, 2026
Merged

refactor(tests): split DiscoveryProgress tests into focused files#256
frankbria merged 2 commits into
mainfrom
refactor/split-discovery-progress-tests

Conversation

@frankbria

@frankbria frankbria commented Jan 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • Split monolithic DiscoveryProgress.test.tsx (2992 lines, 95 tests) into 7 focused test files
  • Extracted shared utilities to testutils.tsx with mock factories and helpers
  • Improved test maintainability by organizing tests by feature area

Test Files Created

File Tests Coverage Area
core.test.tsx 24 Data fetching, loading states, phases, discovery states
answer.test.tsx 13 Answer UI - textarea, submit, validation, keyboard shortcuts
progress.test.tsx 7 Progress bar updates, question counter, completion flow
prd.test.tsx 6 PRD generation, View PRD button, minimize functionality
websocket.test.tsx 8 WebSocket message handlers for all event types
error.test.tsx 7 Stuck state detection (30s timeout), restart/retry flows
advanced.test.tsx 30 Minimized view, task generation, auto-minimize behavior

Shared Utilities (testutils.tsx)

  • Mock factories: mockStartProject, mockRestartDiscovery, mockAuthFetch, etc.
  • Test fixtures: createIdleDiscovery(), createCompletedDiscovery(), etc.
  • Setup/teardown: setupMocks(), cleanupMocks()
  • WebSocket simulation: simulateWsMessage()

Test plan

  • All 95 tests pass (verified: npm test -- --testPathPatterns="DiscoveryProgress")
  • Test count parity with original file verified
  • Each test file runs independently
  • Original DiscoveryProgress.test.tsx can be removed after merge verification

Summary by CodeRabbit

  • Tests
    • Added extensive DiscoveryProgress test coverage for core flows, answer UI, progress updates, PRD generation, advanced interactions, WebSocket-driven state changes, error detection/recovery, timing behaviors, navigation, accessibility, and retry/edge cases; includes a shared test utilities module for reliable, repeatable UI tests.
  • Chores
    • Updated test ignore pattern to exclude utility test helpers from test discovery.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 13, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Adds seven focused test suites and a shared testutils module for DiscoveryProgress, covering core flows, answer UI, progress, PRD lifecycle, WebSocket events, error recovery, timers, and task-generation interactions.

Changes

Cohort / File(s) Summary
DiscoveryProgress tests
web-ui/__tests__/components/DiscoveryProgress.advanced.test.tsx, web-ui/__tests__/components/DiscoveryProgress.answer.test.tsx, web-ui/__tests__/components/DiscoveryProgress.core.test.tsx, web-ui/__tests__/components/DiscoveryProgress.error.test.tsx, web-ui/__tests__/components/DiscoveryProgress.prd.test.tsx, web-ui/__tests__/components/DiscoveryProgress.progress.test.tsx, web-ui/__tests__/components/DiscoveryProgress.websocket.test.tsx
Adds comprehensive, focused test suites exercising rendering, timers (auto-minimize/auto-dismiss), keyboard shortcuts, progress updates, PRD generation lifecycle, WebSocket-driven state transitions, task-generation flows (mockGenerateTasks), error/retry paths, and navigation hooks. Pay attention to heavy mocking and timed/async interactions.
Test utilities & fixtures
web-ui/__tests__/components/DiscoveryProgress.testutils.tsx
New shared test utilities: mocked APIs (projectsApi, tasksApi), mock WebSocket client and message simulator, fixture builders (createDiscoveryResponse, etc.), mock helpers (mockGenerateTasks, mockGetPRD, mockTasksList), and setup/teardown helpers; centralizes repeated test setup.
Jest config
web-ui/jest.config.js
Adds ignore pattern for \.testutils\.tsx$ to testPathIgnorePatterns.

Sequence Diagram(s)

(omitted — changes are test additions and testing utilities; no new runtime control flow introduced)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 I hopped through tests with tiny feet,

Mocks and fixtures all neat and sweet,
Timers tick and websockets sing,
DiscoveryProgress now has wing,
Hooray — more green on CI's sheet! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor(tests): split DiscoveryProgress tests into focused files' clearly and accurately summarizes the main change: reorganizing a monolithic test file into multiple focused test files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/split-discovery-progress-tests

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2bbc740 and 43be9cb.

📒 Files selected for processing (1)
  • web-ui/jest.config.js
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-25T19:08:37.203Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-11-25T19:08:37.203Z
Learning: Applies to docs/web-ui/**/__tests__/**/*.test.{ts,tsx} : Create JavaScript test files colocated or in __tests__/ as *.test.ts

Applied to files:

  • web-ui/jest.config.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Frontend Unit Tests
  • GitHub Check: Backend Unit Tests
  • GitHub Check: E2E Smoke Tests (Chromium)
  • GitHub Check: opencode-review
🔇 Additional comments (1)
web-ui/jest.config.js (1)

12-12: LGTM!

The regex pattern correctly excludes .testutils.tsx files from Jest's test discovery, preventing utility modules from being treated as test suites.

One optional consideration for the future: if you ever add .testutils.ts files (without JSX), you'd need to generalize the pattern to \\.testutils\\.tsx?$. Not needed now since the PR specifically introduces .testutils.tsx files.


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

@macroscopeapp

macroscopeapp Bot commented Jan 13, 2026

Copy link
Copy Markdown
Contributor

Split DiscoveryProgress tests into focused suites and update Jest to ignore *.testutils.tsx in jest.config.js

Introduce targeted Jest/RTL suites for DiscoveryProgress covering WebSocket events, PRD generation, progress flow, answer input, core lifecycle, and error recovery, and add shared mocks/utilities while excluding *.testutils.tsx from test collection.

📍Where to Start

Start with shared helpers in DiscoveryProgress.testutils.tsx, then review event-driven cases in DiscoveryProgress.websocket.test.tsx.


Macroscope summarized 43be9cb.

@github-actions

Copy link
Copy Markdown
Contributor

Code Review Summary

This is a well-executed refactoring that significantly improves test maintainability. The split from a monolithic 3713-line file into 7 focused test files (4019 lines total including testutils) is a solid improvement.

✅ Strengths

Test Organization

  • Excellent separation by feature area (core, answer, progress, PRD, WebSocket, error, advanced)
  • Logical grouping with nested describe blocks
  • Each file is self-contained and focused
  • Easy to locate tests for specific functionality

Shared Utilities (testutils.tsx)

  • Clean extraction of common mocks, fixtures, and helpers
  • Mock factories (createIdleDiscovery, createDiscoveringWithQuestion, etc.) are well-designed
  • Proper setup/teardown functions (setupMocks, cleanupMocks)
  • WebSocket simulation helper is elegant

Test Quality

  • All 95 tests preserved (verified parity with original)
  • Good coverage of edge cases (validation errors, network failures, stuck states)
  • Proper use of fake timers with cleanup
  • Accessibility tests included (ARIA labels)
  • WebSocket event filtering by project_id tested

Code Style

  • Consistent with project conventions from CLAUDE.md
  • Uses Hugeicons correctly
  • Nova color palette applied (bg-destructive/10, text-success, etc.)
  • No hardcoded values

⚠️ Minor Issues

1. Original File Cleanup
The PR checklist notes that the original should be deleted after merge verification. Consider:

  • Deleting it now if all tests pass
  • Adding a comment at the top of the original file pointing to the new split files
  • This will prevent confusion about which file to maintain

2. Test Data Duplication
Some test files have duplicate mock data structures that could be extracted to testutils:

  • mockPlanningPhaseData in advanced.test.tsx (used 20+ times)
  • Initial/updated data pairs in progress.test.tsx

3. Line Length
Some test files have very long lines for inline mock data (e.g., DiscoveryProgress.answer.test.tsx:42-55). Consider extracting to fixtures for better readability.

4. Incomplete Mock Implementation
In DiscoveryProgress.answer.test.tsx:214-216, there's a comment noting 'Full submission flow will be tested when API integration is complete'. Consider either:

  • Completing the test now
  • Adding a TODO comment with issue reference
  • Moving to a separate .skip() test if intentionally omitted

📊 Test Coverage

File Tests Focus
core.test.tsx 24 Data fetching, phases, discovery states, auto-refresh
answer.test.tsx 13 Answer UI, validation, keyboard shortcuts
progress.test.tsx 7 Progress bar, question counter, completion flow
prd.test.tsx 6 PRD generation, View PRD button
websocket.test.tsx 8 All WebSocket event types
error.test.tsx 7 Stuck state, restart/retry flows
advanced.test.tsx 30 Minimized view, task generation

Total: 95 tests ✅ (parity verified)

🔍 Specific Observations

testutils.tsx

  • Line 56-61: Good use of data-testid for icon mocking
  • Line 115-126: Excellent cleanup function that clears all mocks and timers
  • Fixture functions (createIdleDiscovery, etc.) are well-designed

core.test.tsx

  • Line 488-543: Test using real timers for complex async - good choice
  • Line 546-666: Auto-refresh tests are comprehensive

websocket.test.tsx

  • Line 311-340: Excellent test for project_id filtering
  • Good coverage of all event types (discovery_starting, prd_generation_progress, etc.)

advanced.test.tsx

  • Line 745-764: Good test for task state initialization on mount
  • Line 812-843: Idempotent backend response handling is well-tested

🚀 Performance & Security

  • Performance: Fake timers properly used and cleaned up - no issues
  • Security: authFetch properly mocked; no security concerns
  • Memory: cleanupMocks() clears timers and mock handlers properly

✅ Recommendations

  1. Delete original file after confirming all tests pass (as noted in checklist)
  2. Extract mockPlanningPhaseData to testutils.tsx to reduce duplication
  3. Add JSDoc comments to fixture functions explaining when to use each
  4. Complete or document the incomplete test at answer.test.tsx:214

🎯 Overall Assessment

LGTM with minor improvements recommended

This is a high-quality refactoring that significantly improves maintainability while preserving 100% test coverage. The testutils extraction is particularly well-executed and will benefit future test development.

No blockers found. The code follows project conventions and is production-ready after addressing the minor issues above.

@github-actions

Copy link
Copy Markdown
Contributor

Code Review Summary

This is a well-executed refactoring that significantly improves test maintainability. The split from a monolithic 3713-line file into 7 focused test files (4019 lines total including testutils) is a solid improvement.

✅ Strengths

Test Organization

  • Excellent separation by feature area (core, answer, progress, PRD, WebSocket, error, advanced)
  • Logical grouping with nested describe blocks
  • Each file is self-contained and focused
  • Easy to locate tests for specific functionality

Shared Utilities (testutils.tsx)

  • Clean extraction of common mocks, fixtures, and helpers
  • Mock factories (createIdleDiscovery, createDiscoveringWithQuestion, etc.) are well-designed
  • Proper setup/teardown functions (setupMocks, cleanupMocks)
  • WebSocket simulation helper is elegant

Test Quality

  • All 95 tests preserved (verified parity with original)
  • Good coverage of edge cases (validation errors, network failures, stuck states)
  • Proper use of fake timers with cleanup
  • Accessibility tests included (ARIA labels)
  • WebSocket event filtering by project_id tested

Code Style

  • Consistent with project conventions from CLAUDE.md
  • Uses Hugeicons correctly
  • Nova color palette applied (bg-destructive/10, text-success, etc.)
  • No hardcoded values

⚠️ Minor Issues

1. Original File Cleanup
The PR checklist notes that original DiscoveryProgress.test.tsx should be deleted after merge verification. Consider:

  • Deleting it now if all tests pass
  • Adding a comment at the top of original file pointing to new split files
  • This will prevent confusion about which file to maintain

2. Test Data Duplication
Some test files have duplicate mock data structures that could be extracted to testutils:

  • mockPlanningPhaseData in advanced.test.tsx (used 20+ times)
  • Initial/updated data pairs in progress.test.tsx

3. Line Length
Some test files have very long lines for inline mock data (e.g., DiscoveryProgress.answer.test.tsx:42-55). Consider extracting to fixtures for better readability.

4. Incomplete Mock Implementation
In DiscoveryProgress.answer.test.tsx:214-216, there's a comment noting 'Full submission flow will be tested when API integration is complete'. Consider either:

  • Completing the test now
  • Adding a TODO comment with issue reference
  • Moving to a separate .skip() test if intentionally omitted

📊 Test Coverage

File Tests Focus
core.test.tsx 24 Data fetching, phases, discovery states, auto-refresh
answer.test.tsx 13 Answer UI, validation, keyboard shortcuts
progress.test.tsx 7 Progress bar, question counter, completion flow
prd.test.tsx 6 PRD generation, View PRD button
websocket.test.tsx 8 All WebSocket event types
error.test.tsx 7 Stuck state, restart/retry flows
advanced.test.tsx 30 Minimized view, task generation

Total: 95 tests ✅ (parity verified)

🔍 Specific Observations

testutils.tsx

  • Line 56-61: Good use of data-testid for icon mocking
  • Line 115-126: Excellent cleanup function that clears all mocks and timers
  • Fixture functions (createIdleDiscovery, etc.) are well-designed

core.test.tsx

  • Line 488-543: Test using real timers for complex async - good choice
  • Line 546-666: Auto-refresh tests are comprehensive

websocket.test.tsx

  • Line 311-340: Excellent test for project_id filtering
  • Good coverage of all event types (discovery_starting, prd_generation_progress, etc.)

advanced.test.tsx

  • Line 745-764: Good test for task state initialization on mount
  • Line 812-843: Idempotent backend response handling is well-tested

🚀 Performance & Security

  • Performance: Fake timers properly used and cleaned up - no issues
  • Security: authFetch properly mocked; no security concerns
  • Memory: cleanupMocks() clears timers and mock handlers properly

✅ Recommendations

  1. Delete original file after confirming all tests pass (as noted in checklist)
  2. Extract mockPlanningPhaseData to testutils.tsx to reduce duplication
  3. Add JSDoc comments to fixture functions explaining when to use each
  4. Complete or document incomplete test at answer.test.tsx:214

🎯 Overall Assessment

LGTM with minor improvements recommended

This is a high-quality refactoring that significantly improves maintainability while preserving 100% test coverage. The testutils extraction is particularly well-executed and will benefit future test development.

No blockers found. The code follows project conventions and is production-ready after addressing the minor issues above.

Split the monolithic DiscoveryProgress.test.tsx (2992 lines, 95 tests)
into 7 focused test files organized by feature area:

- core.test.tsx: Data fetching, loading states, phases (24 tests)
- answer.test.tsx: Answer UI - textarea, submit, validation (13 tests)
- progress.test.tsx: Progress bar, question counter, completion (7 tests)
- prd.test.tsx: PRD generation, View PRD button, minimize (6 tests)
- websocket.test.tsx: WebSocket message handlers (8 tests)
- error.test.tsx: Stuck state detection, restart/retry flows (7 tests)
- advanced.test.tsx: Minimized view, task generation, auto-minimize (30 tests)

Shared utilities extracted to testutils.tsx with mock factories,
setup/cleanup functions, and WebSocket simulation helpers.

All 95 tests pass. Test count parity verified with original file.
@github-actions

Copy link
Copy Markdown
Contributor

Code review posted successfully to PR #256.

Summary: LGTM with minor improvements recommended

The refactoring is well-executed - splitting 3713 lines into 7 focused test files with 95 tests preserved. Key strengths include excellent organization, clean testutils extraction, and comprehensive coverage. Minor recommendations include cleaning up the original file, reducing mock data duplication, and documenting incomplete tests. No blockers found.

New%20session%20-%202026-01-13T00%3A51%3A41.835Z
opencode session  |  github run

@frankbria
frankbria force-pushed the refactor/split-discovery-progress-tests branch from 5b2d789 to 2bbc740 Compare January 13, 2026 00:56

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
web-ui/__tests__/components/DiscoveryProgress.websocket.test.tsx (1)

77-85: Consider documenting why the 500ms delay is needed.

The jest.advanceTimersByTime(500) after simulating the WebSocket message appears to be waiting for some debounce or internal timing mechanism. If this is an implementation detail of the component, consider adding a brief comment explaining why this delay is necessary to prevent the test from becoming brittle if that timing changes.

       // Simulate WebSocket discovery_starting message
       simulateWsMessage({ type: 'discovery_starting', project_id: 1 });

-      // Should trigger a refresh
+      // Should trigger a debounced refresh (component debounces WS-triggered refreshes by 500ms)
       jest.advanceTimersByTime(500);
web-ui/__tests__/components/DiscoveryProgress.core.test.tsx (1)

487-543: Timer mode switching may cause test isolation issues.

Switching from fake to real timers mid-test with jest.useRealTimers() and then restoring jest.useFakeTimers() at the end can cause issues:

  1. If the test fails before line 542, fake timers won't be restored, potentially affecting subsequent tests.
  2. The cleanupMocks() in afterEach calls jest.useRealTimers(), so the manual restoration may be unnecessary.

Consider restructuring to avoid mid-test timer switching, or use a try-finally pattern:

♻️ Suggested improvement
     it('should transition to discovering state after successful start', async () => {
-      // Use real timers for this test since it involves complex async interactions
-      jest.useRealTimers();
+      // This test requires real timers - cleanupMocks() will restore them
+      jest.runOnlyPendingTimers();
+      jest.useRealTimers();

       // ... test body ...

-      }, { timeout: 3000 });
-
-      // Restore fake timers for other tests
-      jest.useFakeTimers();
+      }, { timeout: 3000 });
+      // Note: cleanupMocks() in afterEach will call useRealTimers(), 
+      // and the next test's setupMocks() will call useFakeTimers()
     });

Alternatively, consider extracting this test to a separate describe block with its own timer setup.

web-ui/__tests__/components/DiscoveryProgress.answer.test.tsx (2)

64-68: Consider testing behavior over implementation details.

Testing for specific CSS classes like resize-none and w-full couples the tests to implementation details. If the styling approach changes (e.g., using different utility classes or inline styles), these tests would break even if the behavior is correct.

Consider whether these assertions are testing a requirement (textarea should not be resizable and should be full-width) or implementation details. If the former, testing the computed styles might be more robust, though the current approach is acceptable for a component test suite.


527-562: Creative workaround for bypassing maxLength, but note the fragility.

Using Object.defineProperty to set a value beyond maxLength is a clever way to test validation logic that the browser would normally prevent. However, this approach:

  1. Tests a scenario that can't happen via normal user interaction (browser enforces maxLength)
  2. May behave differently across testing environments

This is acceptable if the goal is to test server-side validation handling for malicious inputs, but consider adding a comment explaining the purpose.

📝 Suggested comment
       // Type answer that's too long (textarea has maxLength=5000, so we need to simulate programmatically)
       const textarea = screen.getByPlaceholderText(/type your answer here/i) as HTMLTextAreaElement;
       const longAnswer = 'a'.repeat(5001);

-      // Manually set value to bypass maxLength (to test validation logic)
+      // Manually set value to bypass browser's maxLength enforcement.
+      // This tests the component's client-side validation as a defense-in-depth
+      // against malformed requests (e.g., API calls not going through the form).
       Object.defineProperty(textarea, 'value', {
web-ui/__tests__/components/DiscoveryProgress.testutils.tsx (1)

64-76: Inconsistent mock pattern for getDiscoveryProgress.

getDiscoveryProgress at line 66 is mocked inline as jest.fn() without an exported reference, while other methods (startProject, restartDiscovery, etc.) have corresponding exported mock functions (mockStartProject, mockRestartDiscovery). This creates an inconsistent test authoring experience:

// Other mocks - clean:
mockStartProject.mockResolvedValue(...);

// getDiscoveryProgress - requires casting:
(projectsApi.getDiscoveryProgress as jest.Mock).mockResolvedValue(...);
🔧 Optional: Add exported mock for consistency
 export const mockStartProject = jest.fn();
 export const mockRestartDiscovery = jest.fn();
 export const mockRetryPrdGeneration = jest.fn();
 export const mockGenerateTasks = jest.fn();
 export const mockGetPRD = jest.fn();
 export const mockTasksList = jest.fn();
+export const mockGetDiscoveryProgress = jest.fn();

 // ...

 jest.mock('@/lib/api', () => ({
   projectsApi: {
-    getDiscoveryProgress: jest.fn(),
+    getDiscoveryProgress: (...args: unknown[]) => mockGetDiscoveryProgress(...args),
     startProject: (...args: unknown[]) => mockStartProject(...args),
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84c9ded and 5b2d789.

📒 Files selected for processing (8)
  • web-ui/__tests__/components/DiscoveryProgress.advanced.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.answer.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.core.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.error.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.prd.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.progress.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.testutils.tsx
  • web-ui/__tests__/components/DiscoveryProgress.websocket.test.tsx
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2026-01-11T23:33:31.895Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.895Z
Learning: Applies to web-ui/src/lib/**/*.{ts,tsx} : Implement WebSocket automatic reconnection with exponential backoff (1s → 30s) and full state resync

Applied to files:

  • web-ui/__tests__/components/DiscoveryProgress.websocket.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.advanced.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.error.test.tsx
📚 Learning: 2026-01-11T23:33:31.895Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.895Z
Learning: Applies to web-ui/src/**/*.{ts,tsx} : Include auth token as query parameter in WebSocket connections (?token=TOKEN)

Applied to files:

  • web-ui/__tests__/components/DiscoveryProgress.websocket.test.tsx
📚 Learning: 2025-11-25T19:08:37.203Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-11-25T19:08:37.203Z
Learning: Applies to docs/web-ui/**/__tests__/**/*.test.{ts,tsx} : Create JavaScript test files colocated or in __tests__/ as *.test.ts

Applied to files:

  • web-ui/__tests__/components/DiscoveryProgress.websocket.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.progress.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.advanced.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.core.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.prd.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.answer.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.testutils.tsx
📚 Learning: 2026-01-11T23:33:31.895Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.895Z
Learning: Applies to tests/e2e/**/*.{ts,test.ts} : Use TEST_PROJECT_IDS.ACTIVE for tests requiring pre-seeded active phase with agents

Applied to files:

  • web-ui/__tests__/components/DiscoveryProgress.websocket.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.progress.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.advanced.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.core.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.error.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.prd.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.testutils.tsx
📚 Learning: 2026-01-11T23:33:31.895Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.895Z
Learning: Applies to tests/e2e/**/*.{ts,test.ts} : Use TEST_PROJECT_IDS.PLANNING for tests requiring pre-seeded planning phase tasks

Applied to files:

  • web-ui/__tests__/components/DiscoveryProgress.advanced.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.core.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.error.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.prd.test.tsx
  • web-ui/__tests__/components/DiscoveryProgress.testutils.tsx
📚 Learning: 2026-01-11T23:33:31.895Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.895Z
Learning: Applies to tests/**/*.{ts,tsx,test.ts} : Never use test.skip() inside test logic; skip at describe level or use separate test projects for different states

Applied to files:

  • web-ui/__tests__/components/DiscoveryProgress.advanced.test.tsx
📚 Learning: 2026-01-11T23:33:31.895Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.895Z
Learning: Applies to web-ui/src/components/**/*.{ts,tsx} : Wrap AgentStateProvider with ErrorBoundary component for graceful error handling

Applied to files:

  • web-ui/__tests__/components/DiscoveryProgress.error.test.tsx
🧬 Code graph analysis (7)
web-ui/__tests__/components/DiscoveryProgress.websocket.test.tsx (1)
web-ui/__tests__/components/DiscoveryProgress.testutils.tsx (3)
  • setupMocks (115-126)
  • cleanupMocks (131-134)
  • simulateWsMessage (48-50)
web-ui/__tests__/components/DiscoveryProgress.advanced.test.tsx (1)
web-ui/__tests__/components/DiscoveryProgress.testutils.tsx (7)
  • setupMocks (115-126)
  • cleanupMocks (131-134)
  • DiscoveryProgressResponse (14-14)
  • simulateWsMessage (48-50)
  • mockGetPRD (24-24)
  • mockTasksList (25-25)
  • mockGenerateTasks (23-23)
web-ui/__tests__/components/DiscoveryProgress.core.test.tsx (1)
web-ui/__tests__/components/DiscoveryProgress.testutils.tsx (7)
  • setupMocks (115-126)
  • cleanupMocks (131-134)
  • DiscoveryProgressResponse (14-14)
  • projectsApi (13-13)
  • render (11-11)
  • waitFor (11-11)
  • mockStartProject (20-20)
web-ui/__tests__/components/DiscoveryProgress.error.test.tsx (1)
web-ui/__tests__/components/DiscoveryProgress.testutils.tsx (9)
  • setupMocks (115-126)
  • cleanupMocks (131-134)
  • DiscoveryProgressResponse (14-14)
  • projectsApi (13-13)
  • render (11-11)
  • waitFor (11-11)
  • mockRestartDiscovery (21-21)
  • mockRetryPrdGeneration (22-22)
  • simulateWsMessage (48-50)
web-ui/__tests__/components/DiscoveryProgress.prd.test.tsx (1)
web-ui/__tests__/components/DiscoveryProgress.testutils.tsx (6)
  • setupMocks (115-126)
  • cleanupMocks (131-134)
  • DiscoveryProgressResponse (14-14)
  • simulateWsMessage (48-50)
  • mockGetPRD (24-24)
  • mockTasksList (25-25)
web-ui/__tests__/components/DiscoveryProgress.answer.test.tsx (1)
web-ui/__tests__/components/DiscoveryProgress.testutils.tsx (9)
  • setupMocks (115-126)
  • cleanupMocks (131-134)
  • DiscoveryProgressResponse (14-14)
  • projectsApi (13-13)
  • render (11-11)
  • waitFor (11-11)
  • screen (11-11)
  • fireEvent (11-11)
  • mockAuthFetch (88-88)
web-ui/__tests__/components/DiscoveryProgress.testutils.tsx (1)
web-ui/src/lib/api-client.ts (1)
  • authFetch (106-146)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: E2E Smoke Tests (Chromium)
  • GitHub Check: opencode-review
🔇 Additional comments (27)
web-ui/__tests__/components/DiscoveryProgress.websocket.test.tsx (2)

1-23: LGTM - Clean imports and well-documented file header.

The file header clearly documents the test coverage areas, and imports are properly consolidated from the shared test utilities module.


311-340: Good pattern for verifying message filtering.

Capturing the initial call count before sending the message for a different project ID and then asserting it remains unchanged is a solid approach for verifying the filtering logic.

web-ui/__tests__/components/DiscoveryProgress.prd.test.tsx (2)

1-25: LGTM - Well-organized imports and clear documentation.

The file header accurately describes the test coverage, and imports are properly consolidated.


186-258: Comprehensive multi-stage progress tracking test.

This test thoroughly validates the PRD generation lifecycle by simulating sequential WebSocket progress events (started → 10% → 30% → 80% → completed). This provides good coverage of the state machine transitions.

web-ui/__tests__/components/DiscoveryProgress.core.test.tsx (2)

1-29: LGTM - Comprehensive core functionality test suite.

Well-documented header with clear coverage areas. Imports include act which is necessary for the complex async interactions tested here.


639-666: Good test for timer cleanup on unmount.

This test properly verifies that the component cleans up its polling interval when unmounted, preventing memory leaks and unnecessary API calls.

web-ui/__tests__/components/DiscoveryProgress.error.test.tsx (3)

1-27: LGTM - Well-structured error handling test suite.

Clear documentation of test coverage areas and proper imports from shared utilities.


164-211: Good pattern for testing slow-resolving promises, but consider safer variable handling.

The let resolveRestart: () => void pattern with deferred assignment is valid, but using the non-null assertion (resolveRestart!()) could be risky if the mock implementation changes. The current usage is safe since the mockImplementation callback is synchronous.

This is a minor observation - the pattern works correctly as written.


301-359: Thorough test for loading state transitions during retry.

This test properly validates that:

  1. The retry button triggers the API call
  2. The error state is cleared and loading state appears
  3. The promise is cleaned up to prevent hanging tests
web-ui/__tests__/components/DiscoveryProgress.progress.test.tsx (3)

1-24: LGTM - Well-organized progress tracking tests.

Clear documentation referencing specific user stories (US8, US9, US10) and test IDs (T066, T072, etc.) provides excellent traceability to requirements.


39-129: Comprehensive progress update test with good assertions.

This test thoroughly validates the progress bar update flow:

  • Initial state verification (2/20, 10%)
  • Answer submission via mocked API
  • Timer advancement for state refresh
  • Updated state verification (3/20, 15%)
  • Previous question removal and textarea clearing

The assertions cover both the happy path and state transitions.


447-519: Good completion flow test covering UI cleanup.

This test verifies that upon discovery completion:

  • The final answer can be submitted
  • The "Discovery Complete" message appears
  • The answer textarea is removed
  • The submit button is hidden

This ensures the UI properly transitions to the post-discovery state.

web-ui/__tests__/components/DiscoveryProgress.advanced.test.tsx (5)

1-30: LGTM - Comprehensive advanced UI test suite.

Well-documented coverage areas including minimized view, task generation, and WebSocket event handling. Imports are properly consolidated from shared utilities.


259-269: Good use of shared mock data constant.

Extracting mockPlanningPhaseData as a constant reduces duplication across the Task Generation Button tests and ensures consistency.


376-379: Clever use of minimal timer advancement.

Using jest.advanceTimersByTime(100) after WebSocket simulation allows React state updates to propagate without triggering the 3-second auto-minimize timer. This prevents test interference while still testing the intended behavior.


796-809: Excellent fail-open resilience test.

Testing that a tasks fetch failure doesn't block the UI (showing the generate button anyway) demonstrates good resilience thinking. This ensures users can still proceed even if the tasks check fails.


812-873: Good idempotent backend response handling tests.

These tests verify that when the backend returns tasks_already_exist: true, the UI correctly transitions to the "tasks ready" state without showing errors. This ensures graceful handling of race conditions where tasks may have been generated by another process.

web-ui/__tests__/components/DiscoveryProgress.answer.test.tsx (3)

1-24: LGTM - Well-organized answer UI test suite.

Clear documentation referencing specific user stories and test coverage areas. Proper imports from shared utilities.


121-128: Good boundary test for character counter warning.

Testing the 4500-character threshold where the counter changes to destructive styling validates an important UX requirement. The assertions for class changes (text-destructive vs text-muted-foreground) are appropriate here since they're testing user-visible feedback.


673-717: Good duplicate submission prevention test.

Testing that rapid button clicks only result in a single API call is an important UX and data integrity test. The use of a never-resolving promise keeps the component in the submitting state to verify the guard.

web-ui/__tests__/components/DiscoveryProgress.testutils.tsx (7)

1-14: Well-organized test utility module.

Good pattern for centralizing re-exports. This reduces import boilerplate across the seven test files.


20-25: LGTM.

Standard mock function declarations for API operations.


31-50: Well-designed WebSocket testing utilities.

The handler registration/unregistration pattern and simulateWsMessage helper provide clean abstractions for WebSocket integration tests.


91-106: LGTM.

Child component mocks provide minimal implementations with test IDs for assertions.


115-134: Proper setup and cleanup patterns.

Good use of jest.runOnlyPendingTimers() before jest.useRealTimers() to avoid leaving dangling timers. The combination of clearAllMocks() plus individual mockReset() calls ensures both call history and mock implementations are reset.


140-152: Good fixture factory pattern.

The spread at line 151 performs a shallow merge, so overriding nested discovery properties requires spreading the full object. The specialized fixtures (createIdleDiscovery, createDiscoveringWithQuestion, etc.) effectively address this by providing complete pre-configured states.


154-201: Comprehensive fixture coverage.

The fixtures cover the key discovery states: idle, discovering (with/without question), and completed. Note that createCompletedDiscovery correctly transitions to phase: 'planning', which aligns with the component's lifecycle.

@github-actions

Copy link
Copy Markdown
Contributor

Code Review Summary

This is an excellent refactoring that significantly improves test maintainability. The split from a monolithic file into 7 focused test files with a shared testutils module is well-executed.

✅ Strengths

  • Excellent organization: Tests are logically grouped by feature area (core, answer, progress, PRD, WebSocket, error, advanced)
  • Clean testutils extraction: Mock factories, fixtures, and helper functions are well-designed and reduce duplication
  • Proper setup/teardown: and properly handle fake timers and mock resets
  • Comprehensive coverage: All 95 tests preserved with good edge case handling
  • Good documentation: File headers clearly state what each test file covers

⚠️ Minor Issues (already noted by CodeRabbit)

I agree with the observations from CodeRabbit:

  1. testutils.tsx:67 - is mocked inline while other APIs have exported mocks. Consider adding for consistency.

  2. core.test.tsx:489 - Timer mode switching mid-test ( then ) could cause isolation issues if test fails early.

  3. websocket.test.tsx:81 - The 500ms delay after WebSocket messages should be documented (debounce timing detail).

  4. answer.test.tsx:527-562 - Using to bypass maxLength is clever for testing validation, but this scenario can't happen in production due to browser enforcement.

💡 Additional Observation

Consider adding JSDoc comments to the fixture functions in testutils.tsx (e.g., createIdleDiscovery, createDiscoveringWithQuestion) explaining when to use each. This would help future test authors select the right fixture.

🎯 Overall Assessment

LGTM - This is production-ready code that follows project conventions. The minor issues mentioned are nitpicks and don't block the merge.

The refactoring successfully achieves its goal of improving maintainability while preserving 100% test coverage. Great work!

Add pattern to testPathIgnorePatterns to prevent Jest from treating
*.testutils.tsx utility files as test suites requiring tests.
@github-actions

Copy link
Copy Markdown
Contributor

Code Review Summary

This is an excellent refactoring that significantly improves test maintainability. The split from a 2992-line monolithic file into 7 focused test files is well-executed and follows best practices.

✅ Overall Assessment: LGTM with minor suggestions

Strengths

Test Organization

  • Logical separation by feature area (core, answer, progress, PRD, WebSocket, error, advanced)
  • Each file is self-contained and easy to navigate
  • Test count verified: 95 tests preserved (30+13+24+7+6+7+8)

Test Utilities

  • Excellent extraction of shared mocks, fixtures, and helpers in testutils.tsx
  • Proper setup/teardown patterns (setupMocks, cleanupMocks)
  • WebSocket simulation helper (simulateWsMessage) is elegant and reusable

Quality

  • Comprehensive coverage of edge cases (stuck states, network failures, validation errors)
  • Proper fake timer usage with cleanup
  • Follows project conventions from CLAUDE.md

Minor Suggestions (complementing previous reviews)

1. Extract mockPlanningPhaseData to testutils.tsx
Used 20+ times in advanced.test.tsx. Moving it to testutils would reduce duplication similar to how createIdleDiscovery, createDiscoveringWithQuestion, etc. are handled.

2. Original file cleanup
The PR checklist correctly notes that DiscoveryProgress.test.tsx (125KB) should be deleted after merge verification. Consider adding it to the PR now that all tests pass, or add a deprecation comment pointing to the new files.

3. Follow-up commit was necessary
Commit 43be9cb correctly excludes *.testutils.tsx from Jest discovery. This should have been part of the initial PR to avoid Jest errors, but good that it was fixed promptly.

Files Changed

File Lines Purpose
DiscoveryProgress.testutils.tsx +202 Shared mocks, fixtures, helpers
DiscoveryProgress.core.test.tsx +716 Data fetching, phases, auto-refresh
DiscoveryProgress.answer.test.tsx +718 Answer UI, validation, keyboard shortcuts
DiscoveryProgress.progress.test.tsx +546 Progress bar, question counter, completion
DiscoveryProgress.advanced.test.tsx +875 Minimized view, task generation
DiscoveryProgress.websocket.test.tsx +342 WebSocket event handling
DiscoveryProgress.prd.test.tsx +260 PRD generation lifecycle
DiscoveryProgress.error.test.tsx +361 Error handling, stuck states, retry

Conclusion

Production-ready refactoring that achieves its goals of improved maintainability and test organization. The minor suggestions above are optional improvements that can be addressed in follow-ups.

No blockers - this PR can be merged as-is.

@github-actions

Copy link
Copy Markdown
Contributor

Code review posted to PR #256: #256 (comment)

Summary: LGTM - Excellent refactoring

Split a 2992-line monolithic test file into 7 focused test files (95 tests preserved) with shared test utilities. Key strengths include logical feature-based organization, clean mock/factory extraction, proper timer cleanup, and comprehensive edge case coverage. Minor suggestions included extracting duplicate mock data and cleaning up the original file. No blockers.

New%20session%20-%202026-01-13T01%3A12%3A15.744Z
opencode session  |  github run

@frankbria
frankbria merged commit 64973be into main Jan 13, 2026
13 checks passed
@frankbria
frankbria deleted the refactor/split-discovery-progress-tests branch January 13, 2026 01:37
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.

[P1] Test file web-ui/__tests__/components/DiscoveryProgress.test.tsx is too large

1 participant