Skip to content

fix(e2e): resolve checkpoint UI test timeouts with race condition fix - #260

Merged
frankbria merged 2 commits into
mainfrom
fix/checkpoint-ui-tests-timeout
Jan 13, 2026
Merged

fix(e2e): resolve checkpoint UI test timeouts with race condition fix#260
frankbria merged 2 commits into
mainfrom
fix/checkpoint-ui-tests-timeout

Conversation

@frankbria

@frankbria frankbria commented Jan 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • Fixed race condition in checkpoint UI tests where response listener was set up after tab click
  • Ensured Project 1 has proper user_id=1 ownership in seed script for authorization
  • Added API health check test and comprehensive error monitoring for debugging
  • Improved testability with data-testid attributes for loading and error states

Root Cause

The tests were waiting for /checkpoints API response AFTER clicking the checkpoint tab, but the API call fires immediately on tab click, causing a race condition where the response was already received before the listener was set up.

Changes

  1. seed-test-data.py: Added explicit project ownership verification and checkpoint record verification
  2. test_checkpoint_ui.spec.ts: Fixed race condition by setting up listener BEFORE click, added health check test
  3. checkpoints.ts: Added CheckpointApiError class with status code tracking
  4. CheckpointList.tsx: Added data-testid for loading/error states, retry button

Test plan

  • TypeScript type checking passes
  • ESLint linting passes
  • Ruff Python linting passes
  • Frontend checkpoint tests pass (43 tests)
  • Backend checkpoint tests pass (24 tests)
  • Frontend build succeeds

Summary by CodeRabbit

  • Bug Fixes

    • Improved checkpoint API error handling with clearer status information and messages
    • Show 'N/A' for missing git commit in checkpoint list; added retry for checkpoint error state
  • Tests

    • New seed verification and checkpoint file existence checks during e2e setup
    • Added API health checks, centralized timeouts, error monitoring, request/response sync, and expanded UI loading/error assertions

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

Root cause: Tests were waiting for /checkpoints API response AFTER
clicking the checkpoint tab, but the API call fires immediately on
tab click, causing a race condition where the response was already
received before the listener was set up.

Fixes:
1. seed-test-data.py: Ensure Project 1 has user_id=1 for authorization
   - Added explicit ownership verification after test user creation
   - Added checkpoint record verification with file existence checks

2. test_checkpoint_ui.spec.ts: Fixed race condition
   - Set up API response listener BEFORE clicking checkpoint tab
   - Added comprehensive error monitoring and logging
   - Added API health check test that runs before main suite

3. checkpoints.ts: Enhanced error handling
   - Added CheckpointApiError class with status code tracking
   - Added specific logging for auth/authz errors (401/403)

4. CheckpointList.tsx: Improved testability
   - Added data-testid for loading and error states
   - Added retry button for error recovery

These changes ensure that:
- The checkpoint API is verified accessible before UI tests run
- Race conditions are prevented by proper listener ordering
- Error states are clearly identified in test output
- Project authorization is guaranteed through seed script
@coderabbitai

coderabbitai Bot commented Jan 13, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR adds data-integrity checks to the E2E seed script, strengthens E2E checkpoint tests with API health checks and error monitoring, introduces a typed CheckpointApiError and improved error handling in the checkpoints client, and adds test hooks (data-testids and retry) to the CheckpointList UI.

Changes

Cohort / File(s) Summary
E2E Test Seeding & Data Integrity
tests/e2e/seed-test-data.py
Ensures Project 1 exists with user_id=1, sets workspace_path, initializes status/phase as needed; verifies checkpoint records after seeding by checking DB and context file paths and emits warnings if checkpoint count mismatches expected (3).
E2E Checkpoint UI Testing
tests/e2e/test_checkpoint_ui.spec.ts
Adds API health-check suite using auth token and BACKEND_URL; introduces centralized TIMEOUTS, setupErrorMonitoring and getAuthToken usage; monitors /checkpoints requests, waits for API response before UI assertions, and expands loading/error/empty-state assertions and logging.
Checkpoint API Error Handling
web-ui/src/api/checkpoints.ts
Adds CheckpointApiError with message, statusCode, and endpoint; wraps listCheckpoints in try/catch, extracts numeric status code, logs status-specific warnings/errors, and rethrows enriched errors.
Checkpoint UI Testability
web-ui/src/components/checkpoints/CheckpointList.tsx
Adds data-testid attributes for loading/error states, shows N/A for missing git commit, and adds a Retry button to re-invoke loadCheckpoints on failure.

Sequence Diagram(s)

sequenceDiagram
  participant Test as E2E Test (Playwright)
  participant Auth as Auth Service
  participant Backend as Backend API (/checkpoints)
  participant DB as Database
  participant FS as Filesystem (checkpoint files)

  Test->>Auth: request auth token (getAuthToken)
  Auth-->>Test: returns token
  Test->>Backend: GET /checkpoints (with token)
  Backend->>DB: query checkpoints for Project 1
  DB-->>Backend: checkpoint records
  Backend->>FS: verify checkpoint DB/context files (seed verification)
  FS-->>Backend: file existence/status
  Backend-->>Test: 200 + checkpoints array (or error)
  Test->>UI: open CheckpointList and wait for /checkpoints response
  UI-->>Test: render loading → list or error (uses data-testid hooks)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 I hopped through seeds in moonlit code,

I checked each file along the road,
Tokens fetched and endpoints pinged,
No phantom checkpoints left unhinged,
Re-tests dance — the logs are glowed ✨

🚥 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 accurately describes the main fix: resolving checkpoint UI test timeouts by addressing a race condition in test listener registration.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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 fix/checkpoint-ui-tests-timeout

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

Fix E2E checkpoint UI test timeouts by making Checkpoint UI Workflow race-safe and adding API pre-checks, and update seeding in seed-test-data.py to enforce user_id=1 and workspace path creation

Add a race-condition-safe checkpoints response listener and an API health test in the E2E suite, introduce CheckpointApiError with status parsing in web-ui/src/api/checkpoints.ts, and add loading/error test selectors with a retry button in CheckpointList.tsx; update seed-test-data.py to upsert project ownership and verify checkpoint file paths.

📍Where to Start

Start with the beforeEach in test_checkpoint_ui.spec.ts to review the race-safe page.waitForResponse registration and TIMEOUTS usage, then the listCheckpoints function in checkpoints.ts for error handling changes.


Macroscope summarized f7c98fe.

@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 (2)
web-ui/src/components/checkpoints/CheckpointList.tsx (1)

300-310: Error state with retry functionality.

The error block now includes a data-testid for testability and a Retry button for error recovery. This aligns well with the enhanced error handling in checkpoints.ts.

Consider adding an accessible label to the Retry button for screen readers:

♿ Accessibility suggestion
           <button
             onClick={loadCheckpoints}
             className="mt-2 text-sm text-primary hover:underline"
+            aria-label="Retry loading checkpoints"
           >
             Retry
           </button>
tests/e2e/test_checkpoint_ui.spec.ts (1)

69-70: Consider using a more specific type.

The checkpointApiResponsePromise variable could use Playwright's Response type instead of any for better type safety.

♻️ Type improvement
+import { test, expect, Response } from '@playwright/test';
 ...
-  let checkpointApiResponsePromise: Promise<any> | null = null;
+  let checkpointApiResponsePromise: Promise<Response> | null = null;
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5751b5a and c797e9a.

📒 Files selected for processing (4)
  • tests/e2e/seed-test-data.py
  • tests/e2e/test_checkpoint_ui.spec.ts
  • web-ui/src/api/checkpoints.ts
  • web-ui/src/components/checkpoints/CheckpointList.tsx
🧰 Additional context used
📓 Path-based instructions (4)
web-ui/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web-ui/src/**/*.{ts,tsx}: Use TypeScript 5.3+ for frontend development
Use React 18 and Next.js 14 for frontend development
Use Tailwind CSS for styling with Nova design system template
Use shadcn/ui components from @/components/ui/ for UI elements
Use Hugeicons (@hugeicons/react) for all icons, never mix with lucide-react
Use Nova color palette variables (bg-card, text-foreground, etc.) instead of hardcoded color values
Use cn() utility for conditional CSS classes in React components
Use process.env.NEXT_PUBLIC_API_URL with fallback to http://localhost:8080 for API endpoint configuration
Include auth token as query parameter in WebSocket connections (?token=TOKEN)
Store auth tokens in localStorage with key 'auth_token' and include token in API requests via Authorization header

Files:

  • web-ui/src/api/checkpoints.ts
  • web-ui/src/components/checkpoints/CheckpointList.tsx
tests/**/*.{ts,tsx,test.ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Never use test.skip() inside test logic; skip at describe level or use separate test projects for different states

Files:

  • tests/e2e/test_checkpoint_ui.spec.ts
tests/e2e/**/*.{ts,test.ts}

📄 CodeRabbit inference engine (CLAUDE.md)

tests/e2e/**/*.{ts,test.ts}: Use loginUser() helper from tests/e2e/test-utils.ts for authentication in E2E tests
Assert UI elements existence with expect(element).toBeVisible() - fail if missing, never silently pass
Use TEST_PROJECT_IDS.PLANNING for tests requiring pre-seeded planning phase tasks
Use TEST_PROJECT_IDS.ACTIVE for tests requiring pre-seeded active phase with agents

Files:

  • tests/e2e/test_checkpoint_ui.spec.ts
web-ui/src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web-ui/src/components/**/*.{ts,tsx}: Use React Context with useReducer for centralized state management in Dashboard
Wrap AgentStateProvider with ErrorBoundary component for graceful error handling
Use React.memo on Dashboard sub-components and useMemo for derived state to optimize performance

Files:

  • web-ui/src/components/checkpoints/CheckpointList.tsx
🧠 Learnings (8)
📚 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/src/api/checkpoints.ts
  • web-ui/src/components/checkpoints/CheckpointList.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} : Use process.env.NEXT_PUBLIC_API_URL with fallback to http://localhost:8080 for API endpoint configuration

Applied to files:

  • web-ui/src/api/checkpoints.ts
📚 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:

  • tests/e2e/test_checkpoint_ui.spec.ts
  • tests/e2e/seed-test-data.py
📚 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 loginUser() helper from tests/e2e/test-utils.ts for authentication in E2E tests

Applied to files:

  • tests/e2e/test_checkpoint_ui.spec.ts
📚 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:

  • tests/e2e/test_checkpoint_ui.spec.ts
  • tests/e2e/seed-test-data.py
📚 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:

  • tests/e2e/test_checkpoint_ui.spec.ts
📚 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} : Assert UI elements existence with expect(element).toBeVisible() - fail if missing, never silently pass

Applied to files:

  • tests/e2e/test_checkpoint_ui.spec.ts
📚 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:

  • tests/e2e/test_checkpoint_ui.spec.ts
🧬 Code graph analysis (3)
web-ui/src/api/checkpoints.ts (3)
web-ui/src/api/context.ts (1)
  • listCheckpoints (103-110)
web-ui/src/types/checkpoints.ts (1)
  • Checkpoint (17-28)
web-ui/src/lib/api-client.ts (1)
  • authFetch (106-146)
tests/e2e/test_checkpoint_ui.spec.ts (2)
tests/e2e/e2e-config.ts (2)
  • FRONTEND_URL (14-14)
  • BACKEND_URL (11-11)
tests/e2e/test-utils.ts (3)
  • loginUser (483-500)
  • getAuthToken (560-562)
  • setupErrorMonitoring (64-104)
tests/e2e/seed-test-data.py (1)
tests/test_review_api.py (1)
  • project_id (95-103)
⏰ 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 (10)
web-ui/src/api/checkpoints.ts (2)

16-28: Well-structured custom error class.

The CheckpointApiError class properly extends Error, sets the name property for proper error identification, and includes useful debugging properties (statusCode, endpoint).


38-63: Error handling provides good debugging context.

The try/catch wrapper with status code extraction and contextual logging will help diagnose authentication and authorization issues during tests. The status code extraction relies on the error message format from authFetch ("Request failed: ${status}"), which is a reasonable coupling within the same codebase.

One consideration: if authFetch throws an error without following this format (e.g., network errors, JSON parse errors), statusCode will be 0. This is handled gracefully but may reduce debugging visibility for non-HTTP errors.

web-ui/src/components/checkpoints/CheckpointList.tsx (1)

276-283: Loading state testability improvement.

Adding data-testid="checkpoint-loading" enables E2E tests to wait for loading completion before asserting UI state, directly supporting the PR's goal of fixing test timeouts.

tests/e2e/seed-test-data.py (2)

121-182: Project ownership verification addresses authorization issues.

This change ensures Project 1 has user_id=1 for the test user, which is critical for the checkpoint API's authorization checks. The upsert pattern (UPDATE then INSERT if no rows affected) is appropriate for handling both fresh installs and re-runs.

The verification query at lines 169-181 provides immediate feedback if the update fails, which aids debugging.


1191-1217: Checkpoint verification improves seed data reliability.

The post-seeding verification loop confirms that checkpoint records exist and their associated files are present. This catches seeding issues early rather than during test execution.

tests/e2e/test_checkpoint_ui.spec.ts (5)

22-66: API health check provides early failure detection.

This pre-test verification ensures the checkpoint API is accessible before running UI tests. If the API is down or misconfigured, tests will fail here with a clear diagnostic rather than timing out in UI tests.

The test correctly uses loginUser() and getAuthToken() helpers per coding guidelines.


119-126: Core race condition fix: listener before action.

This is the key fix for the test timeouts. By setting up waitForResponse before clicking the checkpoint tab, the listener is guaranteed to capture the API response that fires immediately on click.

Previously, the click could trigger the API call and receive a response before any listener was registered, causing indefinite waits.


170-173: Fixed wait avoids flaky timing.

The 500ms timeout after API response capture gives the UI time to render. While fixed timeouts can be fragile, this is appropriate here since it's a buffer after confirmed API completion rather than a substitute for proper waits.

The subsequent assertions (lines 181-194) properly wait for actual UI state rather than relying solely on this timeout.


177-191: Improved error state detection prevents silent failures.

The loading indicator check and error state detection (lines 186-191) ensure tests fail with actionable messages rather than timing out. This aligns with the coding guideline: "Assert UI elements existence with expect(element).toBeVisible() - fail if missing, never silently pass."


423-436: Consistent race condition fix pattern in new project test.

The same fix pattern is correctly applied here: set up the response listener before clicking the tab, then await it after the click. This ensures the empty state test is equally robust against the race condition.

@github-actions

Copy link
Copy Markdown
Contributor

Code Review: PR #260 - fix(e2e): resolve checkpoint UI test timeouts

Summary

This PR fixes a race condition in checkpoint UI E2E tests by ensuring response listeners are set up before tab clicks trigger API calls. It also improves test data verification, adds error handling, and adds testability features like data-testid attributes.


✅ Strengths

  1. Race Condition Fix (Critical)

    • Lines 119-124 in test_checkpoint_ui.spec.ts: Setting up waitForResponse before clicking the tab is the correct approach to avoid race conditions
    • This follows Playwright best practices for handling API responses
  2. Comprehensive Error Monitoring

    • Added health check test that verifies API accessibility before main test suite
    • Detailed console logging for debugging API failures
    • Proper error propagation (explicitly throws on error states instead of silent passes)
  3. Improved Error Handling

    • New CheckpointApiError class with status code tracking
    • Context-aware error messages for 401/403/404/500 responses
    • Retry button in CheckpointList component allows manual recovery
  4. Testability Improvements

    • Added data-testid attributes for loading and error states
    • Explicit waits for DOM updates with proper timeouts
    • No test.skip() usage within test logic (follows CLAUDE.md guidelines)

⚠️ Issues & Suggestions

1. Potential Runtime Error - Missing Null Check (High Priority)

File: web-ui/src/components/checkpoints/CheckpointList.tsx:424

{checkpoint.git_commit.substring(0, 7)}

Issue: If checkpoint.git_commit is null, undefined, or an empty string, this will throw a runtime error.

Fix:

{checkpoint.git_commit ? checkpoint.git_commit.substring(0, 7) : 'N/A'}

2. Fragile Error Parsing (Medium Priority)

File: web-ui/src/api/checkpoints.ts:43

const statusMatch = (error as Error)?.message?.match(/Request failed: (\d+)/);

Issue: This relies on a specific error message format. If authFetch changes its error format, this parsing will break silently.

Suggestion: Either:

  • Make error format part of the authFetch contract
  • Add a fallback: const statusCode = statusMatch ? parseInt(statusMatch[1], 10) : 0;
  • Consider catching the Response object directly in a try-catch around the fetch

3. Console Debugging Statements in Tests (Low Priority)

Files: Multiple locations in test_checkpoint_ui.spec.ts

The test file contains many console.log statements for debugging:

console.log('[Health Check] Auth token obtained');
console.log(`[Health Check] Checkpoint API status: ${status}`);
// ... many more

Suggestion: Consider removing or gating these behind a debug flag for cleaner test output in CI/CD. However, they are useful for local debugging, so this is low priority.


4. Missing Null Safety in CheckpointList Sorting (Low Priority)

File: web-ui/src/components/checkpoints/CheckpointList.tsx:64

const sorted = data.sort(...);

Issue: If API returns null or an invalid type, this will fail. However, since listCheckpoints already handles this at line 40 (return response.checkpoints ?? []), this is protected.

Observation: Good defensive programming in listCheckpoints - the sort is safe.


5. Hardcoded Timeout Values (Informational)

File: test_checkpoint_ui.spec.ts

Multiple hardcoded timeout values:

{ timeout: 10000 }
{ timeout: 15000 }

Suggestion: Consider extracting these to constants at the top of the file:

const TIMEOUTS = {
  API_RESPONSE: 10000,
  CHECKPOINT_LOAD: 15000,
  DOM_UPDATE: 5000,
} as const;

This makes timeout management easier and test expectations clearer.


📊 Test Coverage

Good:

  • Health check test validates API accessibility
  • Multiple test scenarios including empty state
  • Tests for create, delete, restore, and metadata display
  • Console error monitoring to catch runtime issues

Consider Adding:

  • Test for the CheckpointApiError handling in the UI
  • Test for network failure scenarios (what happens if API is unreachable?)
  • Test for the retry button functionality

🔒 Security Review

No security concerns found.

  • The test data seeding script properly checks for production environment (lines 25-30)
  • Test credentials are clearly documented as test-only
  • No sensitive data exposure in error messages
  • Authorization checks properly use the seeded user_id=1

📈 Performance Considerations

Good:

  • AbortController for cancelling in-flight diff requests
  • Proper cleanup on component unmount
  • Diff cache limit (max 10 items) prevents memory bloat

Consideration:

  • The retry button could trigger rapid successive API calls if clicked repeatedly. Consider adding a brief debounce or loading state.

🎯 Code Quality

Following Project Conventions (from CLAUDE.md):
✅ Using Nova color palette variables (bg-primary, text-destructive, etc.)
✅ Using Hugeicons (not lucide-react)
✅ Using shadcn UI components
✅ Using data-testid attributes for testing
✅ No test.skip() within test logic
✅ Proper TypeScript typing


📝 Final Verdict

Approve with Minor Changes Recommended

The race condition fix is solid and follows best practices. The error handling improvements are valuable. The only blocking issue is the missing null check for checkpoint.git_commit at line 424.

Required Changes (Before Merge):

  1. Add null safety check for checkpoint.git_commit.substring(0, 7)

Recommended Changes (Can Be Follow-up):

  1. Extract timeout values to constants
  2. Consider gating debug console statements

Overall: This is a well-structured PR that addresses a critical test stability issue. The code quality is good and follows project conventions.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Blocking Issue: Missing Null Safety Check

I found a potential runtime error that should be fixed before merging.

Issue

File:

{checkpoint.git_commit.substring(0, 7)}

Problem

If is null, undefined, or an empty string, this will throw a runtime error when displaying checkpoints.

Fix

{checkpoint.git_commit ? checkpoint.git_commit.substring(0, 7) : 'N/A'}

This would gracefully handle the edge case instead of crashing the component.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Blocking Issue: Missing Null Safety Check

I found a potential runtime error that should be fixed before merging.

Issue

File: web-ui/src/components/checkpoints/CheckpointList.tsx:424

{checkpoint.git_commit.substring(0, 7)}

Problem

If checkpoint.git_commit is null, undefined, or an empty string, this will throw a runtime error when displaying checkpoints.

Fix

{checkpoint.git_commit ? checkpoint.git_commit.substring(0, 7) : 'N/A'}

This would gracefully handle the edge case instead of crashing the component.

@github-actions

Copy link
Copy Markdown
Contributor

Review Complete ✓

I've posted a comprehensive code review for PR #260:

Key Findings

✅ Strengths:

  • Fixed critical race condition by setting up response listeners before tab clicks
  • Added comprehensive error monitoring and health check test
  • Implemented CheckpointApiError with status code tracking
  • Added data-testid attributes for better testability
  • Follows all project conventions (Nova palette, Hugeicons, no test.skip())

⚠️ Blocking Issue:

  • Line 424 in CheckpointList.tsx: Missing null check for checkpoint.git_commit.substring(0, 7) will crash if git_commit is null/undefined

📝 Recommendations (non-blocking):

  • Consider extracting hardcoded timeout values to constants
  • Error parsing in checkpoints.ts relies on specific message format (could be fragile)
  • Test console.debug() statements could be gated for cleaner CI output

🔒 Security & Performance:

  • No security concerns
  • Good performance practices (AbortController, cleanup, cache limits)

Overall: Approve with minor changes - the race condition fix is solid and follows best practices. Only the null safety check on git_commit needs fixing before merge.

Review posted at: #260 (comment)

New%20session%20-%202026-01-13T08%3A40%3A09.524Z
opencode session  |  github run

Changes based on PR #260 review comments:

1. **Blocking fix**: Add null safety for checkpoint.git_commit
   - Prevents runtime crash if git_commit is null/undefined
   - Shows 'N/A' as fallback

2. **Accessibility**: Add aria-label to Retry button
   - Improves screen reader support per CodeRabbit suggestion

3. **Type safety**: Use Playwright's Response type
   - Replace `Promise<any>` with `Promise<Response>` for better type checking

4. **Maintainability**: Extract timeout constants
   - Centralized TIMEOUTS object for easier test maintenance
   - Documents purpose of each timeout value
@frankbria

Copy link
Copy Markdown
Owner Author

Review Feedback Addressed ✅

I've pushed commit f7c98fe addressing all review feedback:

🔴 Blocking Issue (Fixed)

  • Null safety for checkpoint.git_commit - Added fallback to 'N/A' if null/undefined

🟡 Nitpicks (Fixed)

  • Accessibility - Added aria-label="Retry loading checkpoints" to Retry button
  • Type safety - Changed Promise<any> to Promise<Response> using Playwright's type
  • Timeout constants - Extracted all hardcoded timeouts to TIMEOUTS object with documentation

Not Addressed (Intentional)

  • Console debugging statements - Left in place as they provide valuable debugging output during CI failures and don't affect test results. Can be gated behind a debug flag in a follow-up if needed.

All tests pass (43 frontend checkpoint tests, 24 backend checkpoint tests).

@github-actions

Copy link
Copy Markdown
Contributor

Code Review: Additional Assessment

After reviewing the files, I can confirm this PR addresses the race condition issue effectively. Most feedback from previous reviews has already been incorporated.

✅ Already Addressed (from previous reviews)

  1. Timeout Constants - Already extracted to TIMEOUTS object at test_checkpoint_ui.spec.ts:22-31
  2. Type Safety - checkpointApiResponsePromise already uses Promise<Response> type (line 85)
  3. Null Safety - git_commit check already properly handled with ternary operator (CheckpointList.tsx:425)
  4. Accessibility - Retry button already has aria-label attribute (CheckpointList.tsx:306)

🎯 Current Code Quality Assessment

Strengths:

  • Race condition fix is sound: Setting up waitForResponse before clicking tab (test_checkpoint_ui.spec.ts:136-139) is the correct Playwright pattern
  • Error handling is comprehensive: New CheckpointApiError class provides valuable debugging context with status codes
  • Defensive programming: Null checks, proper cleanup with AbortController, and mounted ref pattern in CheckpointList component
  • Testability improvements: data-testid attributes enable reliable E2E testing

📝 Minor Suggestions (Non-blocking)

1. Error parsing fragility (Informational)
File: web-ui/src/api/checkpoints.ts:43
The regex parsing relies on authFetch maintaining its error message format. Consider making this an explicit contract between the two modules.

2. Seed data warning threshold (Low priority)
File: tests/e2e/seed-test-data.py:1216-1217
The warning about checkpoint count is intentionally non-blocking for flexible test environments, but consider making it configurable if this becomes problematic in CI.

3. Debug console statements (Optional)
Multiple console.log statements in test_checkpoint_ui.spec.ts are useful for local debugging. Consider gating these behind a DEBUG flag for cleaner CI output.

🔒 Security & Performance

  • ✅ No security concerns identified
  • ✅ Good performance practices (AbortController, cache limits, proper cleanup)
  • ✅ Production environment check in seed script (lines 25-30)

📋 Overall Verdict

✅ Approve - This PR is ready to merge. The race condition fix is solid, error handling improvements add value, and the code follows all project conventions from CLAUDE.md.

The changes effectively address the checkpoint UI test timeout issue without introducing new risks.

@github-actions

Copy link
Copy Markdown
Contributor

Review posted: #260 (comment)

Summary

This PR is ready to merge. The race condition fix is sound, and most issues from previous reviews have already been addressed:

✅ Already Fixed:

  • Timeout constants extracted to TIMEOUTS object
  • Type safety improved (Promise<Response>)
  • Null safety check for git_commit
  • Accessibility label on Retry button

🎯 Key Strengths:

  • Race condition fix follows Playwright best practices (set up listener before click)
  • Comprehensive error handling with CheckpointApiError class
  • Defensive programming (AbortController, cleanup patterns, null checks)
  • All code follows project conventions from CLAUDE.md

📝 Minor Non-blocking Suggestions:

  1. Error parsing in checkpoints.ts relies on specific message format (fragile but acceptable)
  2. Debug console statements could be gated for CI
  3. Seed data warning is intentionally non-blocking

No blocking issues found. The changes effectively fix checkpoint UI test timeouts without introducing security or performance risks.

New%20session%20-%202026-01-13T09%3A04%3A29.358Z
opencode session  |  github run

@frankbria
frankbria merged commit d509647 into main Jan 13, 2026
11 of 12 checks passed

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/e2e/test_checkpoint_ui.spec.ts (1)

278-307: Tests conditionally skip core assertions based on checkpoint availability.

The tests should show restore confirmation dialog, should display checkpoint diff preview, should display checkpoint metadata, and should allow deleting checkpoint all use runtime count checks to conditionally execute their main assertions:

const count = await checkpointItems.count();
if (count > 0) {
  // assertions for checkpoint feature
} else {
  // verify empty state only
}

This pattern violates the coding guideline: "Never use test.skip() inside test logic; skip at describe level or use separate test projects for different states." If checkpoints are unavailable (whether by seed failure or runtime issue), these tests pass without validating their stated functionality.

Additionally, the test uses hardcoded PROJECT_ID = '1' while other E2E test files correctly use TEST_PROJECT_IDS.PLANNING or TEST_PROJECT_IDS.ACTIVE to guarantee pre-seeded data in the appropriate state.

Consider:

  1. Using TEST_PROJECT_IDS.ACTIVE (or PLANNING) which has guaranteed checkpoint data seeded
  2. Creating separate test suites for "with checkpoints" vs "empty state" scenarios
  3. Using describe-level skipping or separate test projects for different states
🧹 Nitpick comments (4)
tests/e2e/test_checkpoint_ui.spec.ts (4)

61-79: Potential double consumption of response body.

The response body is read as text on line 62 (response.text()), then response.json() is called on line 77. In Playwright's API context, calling both on the same response should work since APIResponse allows multiple reads, but this pattern is redundant. Consider parsing JSON once and reusing it.

♻️ Suggested simplification
-    // Log response body for debugging
-    const body = await response.text();
-    if (status !== 200) {
-      console.log(`[Health Check] Error response: ${body}`);
-    } else {
-      try {
-        const data = JSON.parse(body);
-        console.log(`[Health Check] Found ${data.checkpoints?.length || 0} checkpoints`);
-      } catch {
-        console.log(`[Health Check] Response: ${body.substring(0, 200)}`);
-      }
-    }
-
-    // Verify response
-    expect(status).toBe(200);
-
-    const data = await response.json();
+    // Verify response
+    expect(status).toBe(200);
+
+    const data = await response.json();
+    console.log(`[Health Check] Found ${data.checkpoints?.length || 0} checkpoints`);
+
     expect(data).toHaveProperty('checkpoints');
     expect(Array.isArray(data.checkpoints)).toBe(true);

333-333: Inconsistent timeout usage - consider using TIMEOUTS.UI_RENDER.

This hardcoded 1000ms differs from TIMEOUTS.UI_RENDER (500ms). The same inconsistency appears on line 454. For maintainability, consider either using the centralized constant or adding a new constant (e.g., TIMEOUTS.DIFF_RENDER) if a longer delay is intentional.

♻️ Suggested change
-    await page.waitForTimeout(1000);
+    await page.waitForTimeout(TIMEOUTS.UI_RENDER);

Or add a new constant if longer delay is needed:

const TIMEOUTS = {
  // ...existing
  /** Delay for complex UI rendering (diffs, large lists) */
  COMPLEX_RENDER: 1000,
} as const;

322-330: Consider logging more context when diff API times out.

The catch block logs a generic message but doesn't indicate this could be a problem. While the subsequent assertion (line 342) ensures some content appears, silently swallowing the timeout could mask diff API issues. Consider logging at warning level or tracking this for test stability analysis.


365-369: Consider verifying git SHA element presence if it should always exist.

The current logic silently passes if no [data-testid="checkpoint-git-sha"] element exists. If every checkpoint should display git SHA (even as 'N/A'), consider making this a required assertion. If it's truly optional UI, the current approach is acceptable.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c797e9a and f7c98fe.

📒 Files selected for processing (2)
  • tests/e2e/test_checkpoint_ui.spec.ts
  • web-ui/src/components/checkpoints/CheckpointList.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • web-ui/src/components/checkpoints/CheckpointList.tsx
🧰 Additional context used
📓 Path-based instructions (2)
tests/**/*.{ts,tsx,test.ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Never use test.skip() inside test logic; skip at describe level or use separate test projects for different states

Files:

  • tests/e2e/test_checkpoint_ui.spec.ts
tests/e2e/**/*.{ts,test.ts}

📄 CodeRabbit inference engine (CLAUDE.md)

tests/e2e/**/*.{ts,test.ts}: Use loginUser() helper from tests/e2e/test-utils.ts for authentication in E2E tests
Assert UI elements existence with expect(element).toBeVisible() - fail if missing, never silently pass
Use TEST_PROJECT_IDS.PLANNING for tests requiring pre-seeded planning phase tasks
Use TEST_PROJECT_IDS.ACTIVE for tests requiring pre-seeded active phase with agents

Files:

  • tests/e2e/test_checkpoint_ui.spec.ts
🧠 Learnings (6)
📚 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:

  • tests/e2e/test_checkpoint_ui.spec.ts
📚 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 loginUser() helper from tests/e2e/test-utils.ts for authentication in E2E tests

Applied to files:

  • tests/e2e/test_checkpoint_ui.spec.ts
📚 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:

  • tests/e2e/test_checkpoint_ui.spec.ts
📚 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:

  • tests/e2e/test_checkpoint_ui.spec.ts
📚 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} : Assert UI elements existence with expect(element).toBeVisible() - fail if missing, never silently pass

Applied to files:

  • tests/e2e/test_checkpoint_ui.spec.ts
📚 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:

  • tests/e2e/test_checkpoint_ui.spec.ts
⏰ 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). (1)
  • GitHub Check: Backend Unit Tests
🔇 Additional comments (5)
tests/e2e/test_checkpoint_ui.spec.ts (5)

18-31: LGTM!

Well-structured timeout constants with clear JSDoc documentation. Centralizing these values improves maintainability.


134-159: LGTM - Race condition fix correctly implemented.

The critical fix is properly implemented: the response listener is registered before clicking the tab, ensuring the API response is captured regardless of how quickly it returns. The logging and error handling in the catch block provide good observability.


180-229: Good addition of loading and error state detection.

The explicit handling of loading indicator (lines 196-199) and error state (lines 201-206) with a fail-fast approach improves test reliability. The conditional count === 0 check is reasonable here since the test verifies the listing behavior regardless of data presence.


411-469: LGTM - Good empty state regression test.

This test properly validates the fix for the .sort is not a function error by:

  1. Creating a fresh project without checkpoints
  2. Capturing console errors during the test
  3. Asserting no function-related errors occurred

The approach of creating a new project is appropriate here since the test specifically needs an empty checkpoint state.


15-16: Import TEST_PROJECT_IDS constant from e2e-config instead of hardcoding project ID.

Follow the established pattern used in all other E2E tests. Import TEST_PROJECT_IDS from ./e2e-config and use TEST_PROJECT_IDS.DISCOVERY to match the current default behavior ('1') while maintaining consistency across the test suite.

Current code
const FRONTEND_URL = process.env.FRONTEND_URL || 'http://localhost:3001';
const PROJECT_ID = process.env.E2E_TEST_PROJECT_ID || '1';

Should be:

import { FRONTEND_URL, BACKEND_URL, TEST_PROJECT_IDS } from './e2e-config';

const PROJECT_ID = TEST_PROJECT_IDS.DISCOVERY;

The checkpoint UI tests verify generic checkpoint functionality that works across all project phases. Using the DISCOVERY constant (which defaults to '1') preserves existing behavior while aligning with test data conventions used throughout the E2E suite.

⛔ Skipped due to learnings
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
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
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 loginUser() helper from tests/e2e/test-utils.ts for authentication in E2E tests
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
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} : Use process.env.NEXT_PUBLIC_API_URL with fallback to http://localhost:8080 for API endpoint configuration

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