Skip to content

perf(tests): speed up E2E test suite#93

Merged
nitrocode merged 4 commits into
mainfrom
copilot/speed-up-e2e-tests
Apr 26, 2026
Merged

perf(tests): speed up E2E test suite#93
nitrocode merged 4 commits into
mainfrom
copilot/speed-up-e2e-tests

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 26, 2026

  • Increase reaper auto-hide assertion timeout 4200 ms → 6000 ms (CI flakiness headroom)
  • Rename "total counter grows over time" → "total counter stays non-empty over time" (assertions only check liveness, not growth)
  • Add expect(text).toBeTruthy() null-guard before text.trim() / text.toLowerCase() in session counter and rate event polls
  • All E2E tests pass (48 passed, 31 skipped; 1 unrelated pre-existing flaky test confirmed passes on re-run)

Summary by CodeRabbit

  • Tests
    • Improved test execution speed by enabling full parallel mode in the test runner.
    • Enhanced test reliability by replacing fixed timeout delays with polling-based assertions for dynamic content and rendering.
    • Optimized page load detection strategy for faster test completion.

Agent-Logs-Url: https://github.com/nitrocode/token-deathclock/sessions/50c7ed30-3b70-4e1d-b2b0-6887115a948a

Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

📝 Walkthrough

Walkthrough

I pity the fool who don't parallelize their tests, fool! This PR enables full parallel test execution in Playwright and sets worker concurrency to 4 in CI environments. It also revamps e2e test wait strategies, replacing fixed timeouts with polling mechanisms and adjusting mobile timeout buffers for stability, sucka!

Changes

Cohort / File(s) Summary
Test Configuration
playwright.config.js
Enables fullyParallel mode and conditionally sets workers to 4 in CI, lettin' Playwright handle defaults otherwise, fool!
E2E Test Waits & Timeouts
tests/e2e/death-clock.spec.js
Replaces waitForLoadState('networkidle') with waitForLoadState('load') on initial page readiness. Converts fixed waitForTimeout() delays to dynamic polling with expect().toPass() for UI elements and Chart.js rendering. Updates total counter test semantics and increases mobile grim reaper timeout from 5s to 6s, sucka!

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • PR #67: Both PRs modify the e2e death-clock test suite, with this PR adjusting test timing and wait strategies while the other adds mobile test coverage, fool!
  • PR #86: This PR's e2e test changes directly concern the same Doomsday Clock UI elements that the retrieved PR removes from the codebase, I say, I say!
  • PR #66: Both PRs update tests/e2e/death-clock.spec.js and address mobile Playwright test behavior, with this PR refining waits and timeouts while the other expands mobile tab-bar test coverage, sucka!
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'perf(tests): speed up E2E test suite' directly and accurately summarizes the main objective of the pull request - optimizing E2E test performance.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch copilot/speed-up-e2e-tests

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 26, 2026

👁️ PR Preview

🚀 Open Preview

Deployed from commit 4f5387b · Updates on every push to this PR
(Preview is removed automatically when the PR is closed.)

Screenshots

Desktop Mobile
Desktop Mobile

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (0dec8d7) to head (4f5387b).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##              main       #93   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            1         1           
  Lines          242       242           
  Branches       109       109           
=========================================
  Hits           242       242           
Flag Coverage Δ
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5470bb0...4f5387b. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/e2e/death-clock.spec.js (1)

60-66: Mr. T says: Guard against null before calling trim()/toLowerCase().

Right now, a transient null textContent can throw and make failures noisy. Add a truthy assertion first, same style as waitForCounter.

🛡️ Null-safe assertion tweak
   await expect(async () => {
     const text = await page.locator('#sessionCounter').textContent();
+    expect(text).toBeTruthy();
     expect(text.trim()).not.toBe('');
     expect(text).toMatch(/\d/);
   }).toPass({ timeout: 3000 });
   await expect(async () => {
     const text = await page.locator('#rateEvent').textContent();
+    expect(text).toBeTruthy();
     expect(text.trim()).not.toBe('');
     expect(text.toLowerCase()).toContain('tokens');
   }).toPass({ timeout: 3000 });

Also applies to: 78-82

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/e2e/death-clock.spec.js` around lines 60 - 66, The test's inline expect
callback reads page.locator('#sessionCounter').textContent() and calls
trim()/toMatch directly, which can throw if text is null; update the anonymous
async assertion in the 'session counter populates after a moment' test (and the
similar block around lines 78-82) to first assert the text is truthy (e.g.,
expect(text).toBeTruthy()) before calling text.trim() or text.toLowerCase(),
matching the null-safe pattern used by waitForCounter; ensure you reference the
same locator '#sessionCounter' and keep the overall polling/assertion structure
intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/e2e/death-clock.spec.js`:
- Around line 391-392: Increase the auto-hide assertion timeout to reduce CI
flakiness: update the expect call that checks the bubble element (the await
expect(bubble).not.toHaveClass(/visible/, { timeout: 4200 })) to use a larger
buffer (e.g. timeout: 6000 or 7000) so the UI timer-based assertion has enough
headroom on slow CI workers.
- Around line 85-97: The test named "total counter grows over time" only checks
non-empty text, so either rename the test to reflect current behavior (e.g.,
"total counter stays non-empty over time") or update assertions to confirm
actual growth by using the existing waitForCounter and
page.locator('#totalCounter') values: parse the visible text from
page.locator('#totalCounter').textContent() into a numeric value (accounting for
formatting/units) and assert the second value is greater than the first; locate
the test block named 'total counter grows over time' and modify its title or
replace the non-empty assertions with numeric comparison logic referencing
waitForCounter and page.locator('#totalCounter').

---

Nitpick comments:
In `@tests/e2e/death-clock.spec.js`:
- Around line 60-66: The test's inline expect callback reads
page.locator('#sessionCounter').textContent() and calls trim()/toMatch directly,
which can throw if text is null; update the anonymous async assertion in the
'session counter populates after a moment' test (and the similar block around
lines 78-82) to first assert the text is truthy (e.g.,
expect(text).toBeTruthy()) before calling text.trim() or text.toLowerCase(),
matching the null-safe pattern used by waitForCounter; ensure you reference the
same locator '#sessionCounter' and keep the overall polling/assertion structure
intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f9c69a1c-4770-4367-96cc-0e0d3a70e038

📥 Commits

Reviewing files that changed from the base of the PR and between e403cd9 and 4f552c7.

📒 Files selected for processing (3)
  • .github/workflows/e2e-tests.yml
  • playwright.config.js
  • tests/e2e/death-clock.spec.js

Comment thread tests/e2e/death-clock.spec.js Outdated
Comment thread tests/e2e/death-clock.spec.js Outdated
@nitrocode
Copy link
Copy Markdown
Owner

@copilot resolve the merge conflicts in this pull request

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 26, 2026

@copilot resolve the merge conflicts in this pull request

Merge conflicts resolved in bf3f1f9. The only conflict was .github/workflows/e2e-tests.yml — deleted in main (consolidated into ci.yml) and modified in this branch; resolved by removing the file. The tests/e2e/death-clock.spec.js conflict was auto-merged cleanly. All 268 unit tests pass.

@nitrocode nitrocode enabled auto-merge (squash) April 26, 2026 22:28
@nitrocode
Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Signed-off-by: RB <7775707+nitrocode@users.noreply.github.com>
github-actions Bot added a commit that referenced this pull request Apr 26, 2026
github-actions Bot added a commit that referenced this pull request Apr 26, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/e2e/death-clock.spec.js (1)

68-74: Optional cleanup: de-duplicate the two inline polling blocks.

I pity the fool maintainin’ the same polling shape twice—extract one tiny helper with a predicate so these checks stay in one place.

♻️ Small refactor sketch
+async function waitForTextReady(page, selector, assertText, timeout = 3000) {
+  await expect(async () => {
+    const text = await page.locator(selector).textContent();
+    expect(text).toBeTruthy();
+    expect(text.trim()).not.toBe('');
+    await assertText(text);
+  }).toPass({ timeout });
+}
+
-  await expect(async () => {
-    const text = await page.locator('#sessionCounter').textContent();
-    expect(text).toBeTruthy();
-    expect(text.trim()).not.toBe('');
-    expect(text).toMatch(/\d/);
-  }).toPass({ timeout: 3000 });
+  await waitForTextReady(page, '#sessionCounter', async (text) => {
+    expect(text).toMatch(/\d/);
+  });
 
-  await expect(async () => {
-    const text = await page.locator('#rateEvent').textContent();
-    expect(text).toBeTruthy();
-    expect(text.trim()).not.toBe('');
-    expect(text.toLowerCase()).toContain('tokens');
-  }).toPass({ timeout: 3000 });
+  await waitForTextReady(page, '#rateEvent', async (text) => {
+    expect(text.toLowerCase()).toContain('tokens');
+  });

Also applies to: 86-91

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/e2e/death-clock.spec.js` around lines 68 - 74, Extract the duplicated
polling logic into a small helper (e.g., an async waitFor or assertEventually)
that accepts an async predicate callback and a timeout and internally runs the
existing expect(async () => { ... }).toPass({ timeout }) pattern; then replace
both inline blocks that call page.locator('#sessionCounter').textContent() and
assert truthiness/trim/match with a single call to that helper, keeping the same
assertions inside the predicate so behavior is unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/e2e/death-clock.spec.js`:
- Around line 68-74: Extract the duplicated polling logic into a small helper
(e.g., an async waitFor or assertEventually) that accepts an async predicate
callback and a timeout and internally runs the existing expect(async () => { ...
}).toPass({ timeout }) pattern; then replace both inline blocks that call
page.locator('#sessionCounter').textContent() and assert truthiness/trim/match
with a single call to that helper, keeping the same assertions inside the
predicate so behavior is unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 22945a29-100a-4975-a90e-af6c0affbee7

📥 Commits

Reviewing files that changed from the base of the PR and between 4f552c7 and 4f5387b.

📒 Files selected for processing (1)
  • tests/e2e/death-clock.spec.js

@nitrocode nitrocode merged commit b272b7b into main Apr 26, 2026
9 checks passed
@nitrocode nitrocode deleted the copilot/speed-up-e2e-tests branch April 26, 2026 23:01
github-actions Bot added a commit that referenced this pull request Apr 26, 2026
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.

2 participants