Skip to content

test(recommendations): Playwright E2E smoke suite for the recommendations flow (closes #167) - #394

Merged
cristim merged 7 commits into
mainfrom
test/issue-167-recs-smoke-test
Jul 22, 2026
Merged

cristim merged 7 commits into
mainfrom
test/issue-167-recs-smoke-test

Conversation

@cristim

@cristim cristim commented May 14, 2026 •

Copy link
Copy Markdown
Member

Full Playwright E2E smoke suite for the Recommendations flow (closes #167)

Lands a hermetic, Chromium-only Playwright end-to-end smoke suite for the frontend Recommendations page, plus the CI job that runs it. This started as WIP scaffolding; the spec and CI wiring are now complete, so the PR is no longer a draft.

What this PR adds

File Purpose
frontend/tests-e2e/recommendations.spec.ts (136 lines) The 4 E2E tests (see below)
frontend/tests-e2e/fixtures/recs.ts (337 lines) Canned API responses: 3 providers x 4 services x 2 terms, savings [10, 50, 100, 150, 250, 1200], so filter expressions like >100 / 50..200 narrow to known row counts
frontend/playwright.config.ts Chromium-only, hermetic; boots npx serve against the built dist/; network-layer API mocking via page.route; CI-friendly retention
.github/workflows/frontend-e2e.yml "Frontend E2E (PR)" job: runs on PRs touching frontend/; Node 24, npm ci + build + playwright install chromium + npm run test:e2e; uploads the Playwright report as an artifact on failure (SHA-pinned actions)
frontend/package.json + frontend/package-lock.json @playwright/test + serve deps; test:e2e / test:e2e:install scripts
frontend jest config Excludes tests-e2e/ from jest's pickup so unit runs are unaffected
.gitignore Ignores playwright-report/, test-results/, tests-e2e/.cache/

What the suite covers (4 tests in recommendations.spec.ts)

  1. Numeric filter narrows the rows - applies a numeric savings-filter expression and asserts the row count and the live "Showing N" summary match the fixture.
  2. Loading and zero-result states - asserts the skeleton loading rows render, a no-match filter shows the empty state, and the filter controls stay usable throughout (no loss of filter UI).
  3. Selection to purchase-execute - selects a row, asserts the sticky action summary (1 selected, across 1 cell), opens the Configure Purchase dialog, submits, and asserts the recorded POST /api/purchases/execute request body shape.
  4. Plan from selection - opens the plan modal, asserts the provider/service/term/payment/account fields pre-fill from the selected recommendation, submits, and asserts the plan request carries the exact selected-recommendation snapshot.

Design choices

  • Chromium-only and hermetic: boots the production bundle via serve and mocks the API at the network layer (page.route) with per-test fixtures - no backend required, fully deterministic.
  • CI: sibling to the existing Frontend build (PR) job; runs only when frontend/ changes.

Status: complete (no longer WIP). Currently MERGEABLE/CLEAN.

Summary by CodeRabbit

  • Tests
    • Introduced Playwright-based end-to-end smoke testing for the frontend, with dedicated runner scripts and configuration.
    • Added E2E fixtures to mock recommendation-related API behavior and seed authentication for consistent runs.
    • Added end-to-end coverage for recommendations filtering, delayed-load UI states, selection/purchase execution, and “plan from selected” flows.
    • Updated Jest discovery and coverage to exclude E2E tests from local unit test runs.
  • Chores
    • Updated repository ignore rules to prevent committing Playwright reports, test results, and e2e cache artifacts.
  • Documentation
    • Added CI automation to run the frontend E2E suite on relevant pull requests and upload reports on failures.

@cristim cristim added priority/p2 Backlog-worthy severity/medium Moderate harm urgency/this-sprint Within the current sprint impact/internal Team-internal only effort/s Hours type/chore Maintenance / non-user-visible triaged Item has been triaged labels May 14, 2026
@coderabbitai

coderabbitai Bot commented May 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds frontend Playwright end-to-end infrastructure, deterministic Recommendations API fixtures, CI execution, and smoke tests covering filtering, loading states, purchase execution, and plan creation.

Changes

Recommendations E2E Test Infrastructure

Layer / File(s) Summary
Playwright Tooling and Runtime Wiring
.gitignore, frontend/package.json, frontend/playwright.config.ts
Adds Playwright scripts and dependencies, excludes E2E tests from Jest discovery and coverage, ignores generated artifacts, and serves the built frontend for Chromium tests.
Recommendations Mock Fixture
frontend/tests-e2e/fixtures/recs.ts
Defines seeded data, authentication seeding, request recording, delayed recommendation responses, and mocked account, recommendation, purchase, plan, and detail endpoints.
Recommendations Browser Validation
frontend/tests-e2e/recommendations.spec.ts
Tests numeric filtering, loading and empty states, selection-driven purchase execution, and plan creation request payloads.
Pull Request E2E Execution
.github/workflows/frontend-e2e.yml
Runs frontend build and Chromium Playwright tests for applicable pull requests and uploads failure artifacts.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Test as Recommendations E2E test
  participant Browser as Browser application
  participant Fixture as mockApi(page)
  participant CI as GitHub Actions

  CI->>Browser: Serve built frontend
  Test->>Browser: Open Opportunities
  Browser->>Fixture: Request recommendations and account data
  Fixture->>Browser: Return seeded mock responses
  Test->>Browser: Apply filters or select recommendation
  Browser->>Fixture: Submit purchase or plan request
  Fixture->>Browser: Return deterministic response
Loading

Possibly related PRs

  • LeanerCloud/CUDly#160: The smoke tests validate Recommendations filtering, action, purchase, and plan flows introduced in that PR.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Only 4 smoke tests are added, so required coverage for sorting, sticky box, DOM cleanup, scroll-dismiss, and aria-busy is still unverified. Add tests or evidence for the remaining checklist items and attach the required screenshots, DOM snapshots, and network captures.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed All changes support the Playwright Recommendations smoke effort, with no unrelated features or broad refactors evident.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: adding Playwright-based recommendations E2E smoke-test scaffolding.
✨ 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 test/issue-167-recs-smoke-test

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

@cristim

cristim commented May 20, 2026

Copy link
Copy Markdown
Member Author

Rebase attempt against current feat/multicloud-web-frontend: only a frontend/package-lock.json conflict (package.json auto-merged cleanly). Needs a manual npm install to regenerate the lockfile. This is a WIP scaffolding PR, deferring to the issue owner to refresh.

@cristim
cristim force-pushed the test/issue-167-recs-smoke-test branch from 88b9f83 to d0b3020 Compare May 27, 2026 11:26
@cristim

cristim commented May 27, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor
✅ 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.

@cristim

cristim commented May 27, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor
✅ 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.

@cristim

cristim commented May 27, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@cristim

cristim commented May 27, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@cristim

cristim commented May 28, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@cristim

cristim commented May 30, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

Rate Limit Exceeded

@cristim have exceeded the limit for the number of chat messages per hour. Please wait 54 minutes and 0 seconds before sending another message.

@cristim

cristim commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@cristim

cristim commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
Action 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.

@cristim

cristim commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@cristim

cristim commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@cristim
cristim force-pushed the test/issue-167-recs-smoke-test branch from 3ac42fc to 48e5084 Compare July 20, 2026 20:56
@cristim

cristim commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

Phase-1 investigation update (2026-07-21)

The PR body understates what has already landed on the branch. Recap:

What the branch actually contains (6 commits, head 48e508414, base origin/main):

File State
frontend/playwright.config.ts (82 lines) landed
frontend/tests-e2e/fixtures/recs.ts (337 lines) landed
frontend/tests-e2e/recommendations.spec.ts (136 lines) landed (2026-07-19)
.github/workflows/frontend-e2e.yml (61 lines) landed (Playwright Chromium CI job wired)
frontend/package.json + package-lock.json + .gitignore landed

So the spec was written, the CI job was wired, and the follow-up items the original body listed are done.

Current CI status on the head commit (all green): Playwright Chromium (Frontend E2E PR), Frontend build (PR), Lint Code, Unit Tests, Integration Tests, E2E Tests, Build Docker Image, Security Scanning, Snyk, Trivy, gosec, all three Terraform validate jobs, both parity jobs, CI Success, pre-commit, both sanity dry runs, and CodeRabbit final review state = SUCCESS.

CodeRabbit history: four full review cycles between 2026-06-05 and 2026-07-09, all findings addressed with code (route-precedence, dep-version bumps, lockfile sync, comment-count corrections).

Rebase footprint vs origin/main: only 7 files touched; a merge-tree probe shows a single content conflict, and it is only in frontend/package-lock.json (mechanical -- regenerate via npm install --package-lock-only after rebase). Nothing else conflicts.

Verdict: Proceed as-is. The scaffolding is not redundant (no other Playwright infra exists on main), the spec is written, CI is green, and CodeRabbit is clean. All that is needed is a rebase to resolve the package-lock.json conflict, one green re-run of the pipeline, and this can move out of draft to ready-for-review.

Note for reviewers: the PR title still says "scaffolding for E2E smoke (WIP for #167)" but the branch now covers everything issue #167 asks for that is testable outside a live browser session. Recommend the title be updated to test(recommendations): Playwright smoke coverage for column filters + sticky bottom action box (closes #167) when moving out of draft.

@cristim
cristim force-pushed the test/issue-167-recs-smoke-test branch from 48e5084 to 4336b51 Compare July 21, 2026 19:51
@cristim

cristim commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

Rebased onto latest main (previous head 48e508414 → new head 4336b5121). No source changes; only frontend/package-lock.json differences from resolving the trivial rebase conflict and running npm install --package-lock-only. Please re-confirm the review passes on the rebased head.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

@cristim: Re-reviewing the rebased head (4336b5121) to confirm the lockfile-only resolution passes.

✅ Action performed

Review finished.

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.

@cristim

cristim commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

Post-rebase status + recommended next steps

Rebased. The branch has been rebased onto origin/main (previous head 48e508414 -> new head 4336b5121). The only rebase touch was frontend/package-lock.json, resolved with -Xtheirs and reconciled by npm install --package-lock-only (which reported "up to date, 0 vulnerabilities"). Local verification:

Check Exit Notes
npm ci 0 883 packages, 0 vulnerabilities
npx tsc --noEmit 0 No errors
npm test (jest) 1 8 pre-existing locale-dependent failures in utils.test.ts / approval-details.test.ts / riexchange.test.ts. Confirmed reproducing identically on unmodified origin/main (exit 1, same 8 failures). Root cause: system locale de_DE.UTF-8 + tests that call Intl.NumberFormat() without pinning en-US. None of these files are touched by PR #394. CI (en-US locale runners) shows Unit Tests SUCCESS on the rebased head.

CodeRabbit re-review has been triggered on the rebased head; a cr-watch-pr394 monitor is polling for its response and will flag any new findings. CI is being watched by ci-watch-4336b512-pr394 and the first batch of check-runs (Playwright Chromium, Frontend build, pre-commit, sanity, parity, Snyk, Terraform validates) is already green.

Closes # determination: #167, not #160

The PR body references both #167 and #160. To be unambiguous:

Recommendation: the eventual Closes trailer / GitHub keyword on merge should be Closes #167. #160 can stay in the body as a reference / "smoke suite for PR #160", not as a closing keyword.

Stale title / body

The current title still says test(recommendations): scaffolding for E2E smoke (WIP for #167) and the body opens with "Status: WIP - scaffolding only, spec still pending". Neither is true any more:

  • The spec is written (frontend/tests-e2e/recommendations.spec.ts, 4 tests) as of commit bf94f9768 (originally 9a3e7d0c2 pre-rebase, 2026-07-19).
  • CI wiring is done (.github/workflows/frontend-e2e.yml, "Playwright Chromium" job) in the same commit.
  • CodeRabbit reached SUCCESS across 4 review cycles between 2026-06-05 and 2026-07-09, with all findings addressed with code (route-precedence, dep-version bumps, lockfile sync, comment-count corrections).

Recommended new title (conventional-commit, when moving out of draft):
test(recommendations): Playwright smoke coverage for column filters + sticky bottom action box (closes #167)

Recommended body edit: replace the "Status: WIP - scaffolding only" opening with a summary that (a) references the current commits, (b) states the closing keyword Closes #167, and (c) references #160 as the feature under test rather than a closing target.

Next steps

  1. Wait for CR to re-confirm clean on the rebased head (already triggered above).
  2. Once CR posts SUCCESS: author updates title/body per above and takes the PR out of draft.
  3. Human merge. No self-merge from an agent.

The rebase-in-place is the light-touch way to land what's already been reviewed 4 times without discarding CR history or authorship. Not opening a successor PR.

@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: 1

🧹 Nitpick comments (1)
frontend/tests-e2e/recommendations.spec.ts (1)

42-67: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Tight timing margin between injected delay and assertions may flake in CI.

delayNextRecommendationsFetch(3_000) (line 46) delays the fetch by 3s, and the subsequent assertions (lines 49, 52) rely on the default Playwright expect timeout to catch up. Under CI load, the combined delay + render/network round-trip could exceed the default 5s expect timeout with little margin, causing intermittent flakes.

Consider passing an explicit longer timeout to these polling assertions (e.g. { timeout: 8_000 }) to decouple the test from the injected delay value.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/tests-e2e/recommendations.spec.ts` around lines 42 - 67, Increase
the timeout for the loading-state assertions in the test “shows loading and
zero-result filter states without losing filter controls” to provide margin
beyond the 3-second delay and CI rendering/network latency. Apply an explicit
timeout such as 8,000 ms to the relevant polling assertions, including the
skeleton-row count and recommendations filter live-region checks, without
changing the test flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/frontend-e2e.yml:
- Around line 30-31: Update the Checkout step using actions/checkout to set
persist-credentials to false, preventing the GitHub token from being retained
for subsequent npm and build steps.

---

Nitpick comments:
In `@frontend/tests-e2e/recommendations.spec.ts`:
- Around line 42-67: Increase the timeout for the loading-state assertions in
the test “shows loading and zero-result filter states without losing filter
controls” to provide margin beyond the 3-second delay and CI rendering/network
latency. Apply an explicit timeout such as 8,000 ms to the relevant polling
assertions, including the skeleton-row count and recommendations filter
live-region checks, without changing the test flow.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32945be0-9e4b-4e90-889d-e16f6e7f349d

📥 Commits

Reviewing files that changed from the base of the PR and between d5f98fe and 4336b51.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • .github/workflows/frontend-e2e.yml
  • .gitignore
  • frontend/package.json
  • frontend/playwright.config.ts
  • frontend/tests-e2e/fixtures/recs.ts
  • frontend/tests-e2e/recommendations.spec.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • .gitignore
  • frontend/playwright.config.ts
  • frontend/package.json
  • frontend/tests-e2e/fixtures/recs.ts

Comment thread .github/workflows/frontend-e2e.yml
@cristim

cristim commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

Security Scanning failure on rebased head is pre-existing repo debt, not introduced by this PR

The Security Scanning check is red on rebased head 4336b5121 due to GO-2026-5970 — "Infinite loop on invalid input in golang.org/x/text" (found in v0.38.0, fixed in v0.39.0). govulncheck flags two reachable call sites in internal/server/scheduledauth/validator.go:269 (Validator.Warmup -> http.Client.Do -> norm.Form.*) and internal/database/connection.go:319 (Connection.TryAdvisoryLock -> pgxpool.Acquire -> norm.Form.*).

This is not a regression from PR #394:

  • PR test(recommendations): Playwright E2E smoke suite for the recommendations flow (closes #167) #394 touches only frontend/ + .github/workflows/frontend-e2e.yml + .gitignore. Zero Go changes.
  • Security Scanning was SUCCESS on both origin/main (d2e52d9e6) and the pre-rebase PR head (48e508414). It failed here because the govulncheck DB advanced between those runs and the run on this rebased head.
  • Per repo policy (feedback_no_masking_ci_debt) we don't gate-suppress newly-published CVEs on a test-only PR. The fix is a one-line golang.org/x/text v0.38.0 -> v0.39.0 bump that belongs on main, not on this PR.

A separate fix targeting main is being handled. Once that lands and main is green, this branch can be rebased onto it to clear the Security Scanning check, or a human can merge #394 with the known pre-existing red since the failure is not introduced by this PR's diff.

@cristim

cristim commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

Pushed e17114a67 on top of 4336b5121 to address the zizmor artipacked finding on .github/workflows/frontend-e2e.yml: added with: persist-credentials: false under the Checkout step. The Playwright job does no authenticated git ops, so the checkout token is unnecessary and is now scrubbed from .git/config before any third-party scripts run. Please re-review.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

@cristim: Re-reviewing the workflow hardening on e17114a67, including the persist-credentials: false checkout configuration.

✅ Action performed

Review finished.

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.

@cristim

cristim commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

Rate-limit reset window is now open. This is a Fair-Usage recovery: force a full re-scan of e17114a67, which includes the persist-credentials: false hardening on the frontend-e2e checkout in addition to the rebased-onto-main Playwright scaffolding + spec + CI wiring.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Your plan includes PR reviews subject to rate limits. Reviews are available now.

cristim added 7 commits July 22, 2026 23:30
Sets up the Playwright infrastructure for the #160 smoke suite without
yet writing the actual smoke spec. The spec itself is the remaining
work and is tracked in the draft-PR description.

What this lays down:

  - frontend/package.json: @playwright/test 1.50.x + serve 14.x as
    devDependencies; `test:e2e` + `test:e2e:install` npm scripts.
  - frontend/playwright.config.ts: Chromium-only, hermetic (boots
    `npx serve` against the production webpack bundle in dist/),
    `page.route`-based API mocking, retain-on-failure trace/screenshot/
    video, single worker on CI for predictable artefacts.
  - frontend/tests-e2e/fixtures/recs.ts (301 lines): canned API
    fixtures covering 3 providers x 4 services x 2 terms with savings
    spanning [10, 50, 100, 150, 250, 1200] so numeric filter
    expressions narrow to known row counts. `mockApi(page)` wires
    `/api/recommendations`, `/api/recommendations/freshness`,
    `/api/recommendations/refresh`, `/api/accounts`, `/api/session`,
    `/api/dashboard`, `/api/plans`, `/api/purchases/execute` and
    returns a `{ calls }` recorder for per-test assertions.
  - frontend/jest config: excludes tests-e2e/ from jest's pickup so
    the unit-test suite stays fast.
  - .gitignore: ignores playwright-report/, test-results/,
    tests-e2e/.cache/ — generated per run, not committed.

Remaining work (kept as a WIP commit because the predecessor agent
hit the stream-idle watchdog before reaching this step):
  - Write tests-e2e/recommendations.spec.ts that exercises the #160
    flow end-to-end: load page, apply a column filter, verify row
    count narrows correctly, select rows, verify sticky bottom action
    box surfaces the right summary + dispatches the correct POST.
  - (Optionally) wire test:e2e into a CI workflow alongside the
    test:unit job.
Playwright executes page.route handlers in reverse-registration order (last
registered = first executed). The catch-all '**/api/**' was registered last,
causing it to intercept all requests before the specific handlers could run.
Move it to be registered first so specific routes (public-info, auth/me,
recommendations, etc.) correctly take precedence.

Also correct the RECS fixture comment cardinalities that were out of sync
with actual data:
- "50..200" (inclusive range per parseNumericFilter): 13 rows, not 9
- "5, 50..200, >1000": 14 rows, not 11 (literal "5" matches no rows;
  ">1000" adds r04 with savings=1200 to the 13-row set)

Bump minimum version bounds for devDependencies to current latest:
- @playwright/test: ^1.50.0 -> ^1.60.0
- serve: ^14.2.0 -> ^14.2.6
The previous commit bumped @playwright/test to ^1.60.0 and serve to
^14.2.6 in package.json, but package-lock.json's root package entry
still recorded the old ^1.50.0 / ^14.2.0 ranges, which makes `npm ci`
fail its package.json/lockfile sync check. The resolved versions were
already 1.60.0 / 14.2.6, so this is a metadata-only sync via
`npm install --package-lock-only`.

Verified: npm ci, npx tsc --noEmit (incl. playwright.config.ts and
tests-e2e/fixtures/recs.ts), npm test (77 suites / 2553 tests pass,
jest still excludes tests-e2e/), go build ./... after rebasing onto
origin/main.
…tions wildcard

**/api/recommendations/freshness and .../refresh were registered before
**/api/recommendations* in mockApi(). Playwright executes handlers in
reverse-registration order, so the wildcard (registered later) was
winning and returning the full recs list instead of the freshness/refresh
payloads. Move both specific handlers to after the wildcard so they take
precedence as intended.
Exercise filtering, loading, selection, purchase, and plan flows through
the production frontend bundle. Run the Chromium smoke suite for frontend
pull requests and retain browser artifacts when it fails.
Regenerate the frontend lockfile against the dependency versions pinned on
main so npm ci can install the rebased Playwright test dependencies.
The Playwright job runs `npm ci`, `npm run build`, and `npx playwright
install` — none of these need the actions/checkout token. Setting
`persist-credentials: false` scrubs the credential from `.git/config` so
the token is not accessible to third-party install scripts that run in
the same job. Addresses the CodeRabbit / zizmor `artipacked` finding.
@cristim
cristim force-pushed the test/issue-167-recs-smoke-test branch from e17114a to ab4eb36 Compare July 22, 2026 21:32
@cristim

cristim commented Jul 22, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

Rebased onto latest main (which now includes PR #1484 golang.org/x/text v0.39.0 and PR #1486 fast-uri/svgo lockfile fixes). New head is ab4eb36f0aa60280b1edc2dc1c7f1412ba0a52e8, superseding e17114a67. Local verification post-rebase:

  • npm ci: exit 0
  • npx tsc --noEmit: exit 0
  • npm audit --audit-level=high: exit 0, 0 vulnerabilities
  • jest unit tests: same 8 pre-existing locale-dependent failures as on unmodified main, no regression

Please full-review this head. The PR's own contribution (Playwright infra + spec + persist-credentials: false on the frontend-e2e checkout) is unchanged from e17114a67; only the rebase drift (lockfile updates inherited from #1486) differs. The prior full-review ping on e17114a67 was acknowledged with "Reviews are available now" but no substantive review followed. Force a full re-scan on the new SHA so the CR verdict is unambiguous.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

@cristim: Triggering a full review of the rebased head ab4eb36f0aa60280b1edc2dc1c7f1412ba0a52e8, including the inherited lockfile drift and the Playwright workflow hardening.

✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. Your recent PR review activity is in the 95th percentile or higher among CodeRabbit users, so adaptive limits apply. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 8 minutes.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Autofix skipped. No unresolved CodeRabbit review comments with fix instructions found.

@cristim
cristim marked this pull request as ready for review July 22, 2026 22:30
@cristim
cristim merged commit 59db0f1 into main Jul 22, 2026
21 checks passed
@cristim cristim changed the title test(recommendations): scaffolding for E2E smoke (WIP for #167) test(recommendations): Playwright E2E smoke suite for the recommendations flow (closes #167) Jul 22, 2026
@cristim
cristim deleted the test/issue-167-recs-smoke-test branch July 27, 2026 11:10
cristim added a commit that referenced this pull request Sep 27, 2026
* test(recommendations): scaffolding for E2E smoke (WIP for #167)

Sets up the Playwright infrastructure for the #160 smoke suite without
yet writing the actual smoke spec. The spec itself is the remaining
work and is tracked in the draft-PR description.

What this lays down:

  - frontend/package.json: @playwright/test 1.50.x + serve 14.x as
    devDependencies; `test:e2e` + `test:e2e:install` npm scripts.
  - frontend/playwright.config.ts: Chromium-only, hermetic (boots
    `npx serve` against the production webpack bundle in dist/),
    `page.route`-based API mocking, retain-on-failure trace/screenshot/
    video, single worker on CI for predictable artefacts.
  - frontend/tests-e2e/fixtures/recs.ts (301 lines): canned API
    fixtures covering 3 providers x 4 services x 2 terms with savings
    spanning [10, 50, 100, 150, 250, 1200] so numeric filter
    expressions narrow to known row counts. `mockApi(page)` wires
    `/api/recommendations`, `/api/recommendations/freshness`,
    `/api/recommendations/refresh`, `/api/accounts`, `/api/session`,
    `/api/dashboard`, `/api/plans`, `/api/purchases/execute` and
    returns a `{ calls }` recorder for per-test assertions.
  - frontend/jest config: excludes tests-e2e/ from jest's pickup so
    the unit-test suite stays fast.
  - .gitignore: ignores playwright-report/, test-results/,
    tests-e2e/.cache/ — generated per run, not committed.

Remaining work (kept as a WIP commit because the predecessor agent
hit the stream-idle watchdog before reaching this step):
  - Write tests-e2e/recommendations.spec.ts that exercises the #160
    flow end-to-end: load page, apply a column filter, verify row
    count narrows correctly, select rows, verify sticky bottom action
    box surfaces the right summary + dispatches the correct POST.
  - (Optionally) wire test:e2e into a CI workflow alongside the
    test:unit job.

* test(e2e/recs): fix catch-all route precedence + update fixture counts

Playwright executes page.route handlers in reverse-registration order (last
registered = first executed). The catch-all '**/api/**' was registered last,
causing it to intercept all requests before the specific handlers could run.
Move it to be registered first so specific routes (public-info, auth/me,
recommendations, etc.) correctly take precedence.

Also correct the RECS fixture comment cardinalities that were out of sync
with actual data:
- "50..200" (inclusive range per parseNumericFilter): 13 rows, not 9
- "5, 50..200, >1000": 14 rows, not 11 (literal "5" matches no rows;
  ">1000" adds r04 with savings=1200 to the 13-row set)

Bump minimum version bounds for devDependencies to current latest:
- @playwright/test: ^1.50.0 -> ^1.60.0
- serve: ^14.2.0 -> ^14.2.6

* test(e2e/recs): sync package-lock root ranges after dep bumps

The previous commit bumped @playwright/test to ^1.60.0 and serve to
^14.2.6 in package.json, but package-lock.json's root package entry
still recorded the old ^1.50.0 / ^14.2.0 ranges, which makes `npm ci`
fail its package.json/lockfile sync check. The resolved versions were
already 1.60.0 / 14.2.6, so this is a metadata-only sync via
`npm install --package-lock-only`.

Verified: npm ci, npx tsc --noEmit (incl. playwright.config.ts and
tests-e2e/fixtures/recs.ts), npm test (77 suites / 2553 tests pass,
jest still excludes tests-e2e/), go build ./... after rebasing onto
origin/main.

* fix(e2e/recs): register freshness and refresh routes after recommendations wildcard

**/api/recommendations/freshness and .../refresh were registered before
**/api/recommendations* in mockApi(). Playwright executes handlers in
reverse-registration order, so the wildcard (registered later) was
winning and returning the full recs list instead of the freshness/refresh
payloads. Move both specific handlers to after the wildcard so they take
precedence as intended.

* test(recommendations): add Playwright smoke coverage

Exercise filtering, loading, selection, purchase, and plan flows through
the production frontend bundle. Run the Chromium smoke suite for frontend
pull requests and retain browser artifacts when it fails.

* fix(e2e): sync lockfile after rebase

Regenerate the frontend lockfile against the dependency versions pinned on
main so npm ci can install the rebased Playwright test dependencies.

* ci(e2e): set persist-credentials false on frontend-e2e checkout

The Playwright job runs `npm ci`, `npm run build`, and `npx playwright
install` — none of these need the actions/checkout token. Setting
`persist-credentials: false` scrubs the credential from `.git/config` so
the token is not accessible to third-party install scripts that run in
the same job. Addresses the CodeRabbit / zizmor `artipacked` finding.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/internal Team-internal only priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged type/chore Maintenance / non-user-visible urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test(recommendations): end-to-end browser smoke for PR #160 (column filters + bottom action box)

1 participant