Skip to content

🐛 Don't fail CI when Vizzly API returns 5xx errors#190

Merged
Robdel12 merged 3 commits intomainfrom
resilient-api-errors
Jan 26, 2026
Merged

🐛 Don't fail CI when Vizzly API returns 5xx errors#190
Robdel12 merged 3 commits intomainfrom
resilient-api-errors

Conversation

@Robdel12
Copy link
Contributor

Summary

  • Add HTTP status code to API error context so commands can check it
  • Gracefully handle 5xx errors (500, 502, 503, 530 Cloudflare tunnel, etc.) in all CI-facing commands
  • Warn user but exit 0 so their CI doesn't fail due to Vizzly infrastructure issues
  • 4xx client errors still fail as expected

Motivation

Users were seeing their CI fail with errors like:

Test run failed:
API request failed: 530 - <!doctype html>...Cloudflare Tunnel error...

This is outside the user's control - their tests ran fine, only the visual comparison couldn't happen because Vizzly's API was temporarily unavailable.

Changes

  • src/api/client.js - Add status to error context
  • src/commands/run.js - Handle 5xx gracefully
  • src/commands/upload.js - Handle 5xx gracefully
  • src/commands/status.js - Handle 5xx gracefully + add DI for testability
  • src/commands/finalize.js - Handle 5xx gracefully
  • New/updated tests for all affected commands

Test plan

  • npm test passes (1817 tests)
  • npm run lint passes
  • Manual test with simulated 5xx error

When Vizzly's infrastructure has issues (Cloudflare 530, server errors),
the CLI now warns the user but doesn't fail their CI. The user's tests
still ran - only the visual comparison couldn't happen.

- Add status code to API error context for checking
- Gracefully handle 5xx errors in run, upload, status, finalize commands
- Add dependency injection to status command for testability
- Add tests verifying 5xx errors don't exit(1) but 4xx errors still do
@vizzly-testing

This comment has been minimized.

@claude
Copy link

claude bot commented Jan 26, 2026

Code Review

This PR addresses a real user pain point by gracefully handling 5xx errors from Vizzly's infrastructure so that users' CI pipelines don't fail due to temporary API unavailability. The implementation is solid overall, with excellent test coverage and consistent patterns across all affected commands.

✅ Strengths

  1. Clear motivation and scope - The PR directly solves the problem described where users' CI failed with Cloudflare 530 errors outside their control.

  2. Consistent implementation - The error handling pattern is uniformly applied across all CI-facing commands (run, upload, status, finalize).

  3. Excellent test coverage - Each command has dedicated tests for:

    • 5xx error graceful handling (500, 502, 503, 530)
    • 4xx error still failing as expected
    • Proper exit codes and warning messages
  4. Proper separation of concerns - The status field is added at the API client level, making it available to all error handlers.

  5. Good UX - Warning messages are clear and reassure users that "your tests still ran" while visual comparison was skipped.

🔍 Code Quality Observations

1. Missing test for API client context (Non-blocking)

The new context: { status } addition in src/api/client.js isn't tested directly in tests/api/client.test.js. While the commands test this indirectly, it would be valuable to have a unit test verifying that VizzlyError includes the status code in context when thrown.

Suggested test:

it('includes status code in error context', async () => {
  let client = createApiClient({
    token: 'test-token',
    baseUrl: 'https://api.test',
  });

  mockFetch.mock.mockImplementation(async () => ({
    ok: false,
    status: 500,
    headers: new Map(),
    text: async () => 'Internal Server Error',
  }));

  await assert.rejects(
    () => client.request('/api/test'),
    error => {
      assert.strictEqual(error.context?.status, 500);
      return true;
    }
  );
});

2. Edge case: Status 599 (Non-blocking)

The condition status >= 500 correctly handles all 5xx codes. However, it might be worth adding one test with status 599 to document the upper boundary behavior, though this is more for completeness than a real concern.

3. Type safety consideration (Non-blocking)

The pattern error.context?.status uses optional chaining which is good, but there's no check that status is actually a number. If an error without proper context is thrown, undefined >= 500 would be false, which is the desired behavior. This is fine, but worth noting.

4. Inconsistent return in status.js (Very minor)

In src/commands/status.js:263, the 5xx handler just returns void after output.cleanup(), while other commands return { success: true, result: { skipped: true } }. This inconsistency is likely fine since statusCommand doesn't document a return value contract, but worth noting for consistency.

🔒 Security Considerations

No security concerns. The change is purely defensive - gracefully degrading when the API is unavailable.

⚡ Performance Considerations

No performance impact. This only affects the error path.

🧪 Test Coverage

Excellent coverage:

  • New tests in 4 files covering all modified commands
  • Tests verify both 5xx graceful handling AND 4xx still failing
  • Tests verify exit codes, warning messages, and return values
  • Tests cover Cloudflare-specific errors (530) and standard 5xx codes

Minor gap:

📋 Suggestions

Priority: Low

  1. Add unit test for error.context.status in tests/api/client.test.js (see suggestion in observation ✨ Add npmignore file, reduce release size #1)
  2. Consider adding a test case with status 599 to document upper boundary behavior
  3. Make statusCommand return value consistent with other commands (return object instead of void)

✨ Overall Assessment

This is a high-quality PR that solves a real problem with a clean, well-tested implementation. The suggested improvements are minor and don't block merging. The code follows the repository's patterns and conventions nicely.

Recommendation: Approve with optional suggestions for follow-up

@vizzly-testing

This comment has been minimized.

@vizzly-testing

This comment has been minimized.

1 similar comment
@vizzly-testing

This comment has been minimized.

- Add unit tests for error.context.status in API client
- Make statusCommand return value consistent with other commands
@Robdel12 Robdel12 enabled auto-merge (squash) January 26, 2026 13:52
@vizzly-testing
Copy link

Vizzly - Visual Test Results

CLI Reporter - 14 changes need review
Status Count
Passed 5
Changed 14
Auto-approved 5
Changes needing review (14)

fullscreen-viewer · Firefox · 375×667 · 158.5% diff

fullscreen-viewer

search-no-results · Firefox · 1920×1080 · 0.2% diff

search-no-results

filter-failed-only · Firefox · 1920×1080 · 1.2% diff

filter-failed-only

search-homepage · Firefox · 1920×1080 · 0.3% diff

search-homepage

viewer-slide-mode · Firefox · 1920×1080 · 0.2% diff

viewer-slide-mode

viewer-toggle-mode · Firefox · 1920×1080 · 0.7% diff

viewer-toggle-mode

...and 8 more in Vizzly.

Review changes

CLI TUI - Processing...

Build in progress...


resilient-api-errors · 09f89084

@vizzly-testing
Copy link

Vizzly - Visual Test Results

CLI Reporter - 14 changes need review
Status Count
Passed 5
Changed 14
Auto-approved 5
Changes needing review (14)

fullscreen-viewer · Firefox · 375×667 · 158.5% diff

fullscreen-viewer

search-no-results · Firefox · 1920×1080 · 0.2% diff

search-no-results

filter-failed-only · Firefox · 1920×1080 · 1.2% diff

filter-failed-only

search-homepage · Firefox · 1920×1080 · 0.3% diff

search-homepage

viewer-slide-mode · Firefox · 1920×1080 · 0.2% diff

viewer-slide-mode

viewer-toggle-mode · Firefox · 1920×1080 · 0.7% diff

viewer-toggle-mode

...and 8 more in Vizzly.

Review changes

CLI TUI - 1 change needs review
Status Count
Changed 1
Auto-approved 4
Changes needing review (1)

vizzly-help · 1202×1430 · 556.8% diff

vizzly-help

Review changes


resilient-api-errors · 09f89084

@Robdel12 Robdel12 merged commit dcf24dc into main Jan 26, 2026
21 of 25 checks passed
@Robdel12 Robdel12 deleted the resilient-api-errors branch January 26, 2026 13:53
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