test(e2e): Playwright key-flow suite + frontend self-check batch#11
Conversation
RadixSortPlayground sets positiveOnly={false}, so users can type
negative numbers into the custom-input box. radixSort then crashed:
Math.floor(v/exp)%10 yields a negative bucket index for v<0, so
buckets[negative] is undefined and .push throws — the ErrorBoundary
fallback ("该模块加载失败") replaced the whole visualization. A second
mode: an all-negative array made maxVal<0 → Math.log10 → NaN → maxDigits
NaN → the distribute loop never ran, silently returning the input
unsorted.
Fix: shift every value by offset = max(0, -min) so bucketing runs on
non-negative values (shifting is monotonic, preserving order), while
buckets still store and display the original values. When the input is
already non-negative offset is 0, so behavior — and all presets/classic
examples — are byte-identical to before.
Found via a throwaway render+step smoke over all 123 algorithms plus an
edge-input correctness sweep (empty/single/dupes/reverse/negatives).
Only radixsort was user-reachable-broken (countingsort mishandles
negatives too but its playground keeps positiveOnly=true, filtering
them at input). New radixSort.test.js locks it: negatives, all-negative,
zero, 50 random signed arrays. Verified end-to-end in a real browser:
'-3 1 -1 0 2 -5' now sorts to -5,-3,-1,0,1,2 with no crash. 203 tests.
Add a subtle GitHub-linked attribution badge (github.com/roclee2692) to the AI course hero's top-right corner, since that module was contributed by them. External link opens in a new tab with rel=noreferrer noopener.
…#1/#4) Turns the throwaway bug-hunt that found the radix crash into permanent regression guards, closing the exact coverage holes that let it hide: - src/test/setup.js: polyfill scrollIntoView/scrollTo/ResizeObserver (jsdom lacks them; without these a step-through test throws before reaching real interaction paths) - algorithmSmoke.test.jsx: render every one of the 123 algorithms and step through — catches crashes the old typeof-fn checks never could - sortingCorrectness.test.js: every sort on its actual input domain asserts sorted + length-preserved — would have caught the radix bug 203 -> 403 tests.
compare/swap/sorted were distinguished only by yellow/red/green — red- green colorblind users can't tell swap from sorted. Add a redundant shape channel: Legend gains optional per-item symbol (compare / swap / sorted glyphs, backward-compatible), SortingViz pointer row uses distinct glyphs per state and marks sorted labels — legible even in grayscale.
- jsconfig.json: step 1 of type-safety migration — editor cross-file nav, autocomplete, JSDoc hints. checkJs stays false (flipping it floods an unannotated codebase); path: JSDoc on data/ -> checkJs -> TypeScript. - docs/FRONTEND_SELF_CHECK.md: reusable 12-dimension industrial-grade checklist scored against this project + paste-ready red-team prompt.
Upgrades type safety from editor-only jsconfig to enforced checking:
typescript devDep + tsconfig.typecheck.json (checkJs on a curated,
currently-passing include list) + npm run typecheck (folded into
npm run check) + a Typecheck step in CI. The include set is 8 pure-logic
modules and grows over time (strangler-fig adoption).
Wiring checkJs up surfaced and fixed real gaps: import.meta.env lacked
Vite types (add src/vite-env.d.ts), SyncService options had no JSDoc,
stepProtocol accessed props on {object}, hoverStyle used undefined
CSSProperties + a stray em-dash, supabase.js set a non-standard window
flag. npm ci stays in sync; 405 tests + build green.
CONTRIBUTING.md documents the quality gate (lint/typecheck/test/build + CI), conventions, and how to add an algorithm. docConsistency.test.js scans living Markdown for backtick-wrapped repo paths and asserts they exist — it immediately caught two real drifts, now fixed: AGENTS.md referenced a gone supabase/functions path, FRONTEND_SELF_CHECK had the wrong algorithmSmoke.test.jsx path. Archives (*_REPORT/CHANGELOG) are excluded as point-in-time snapshots.
Extends the color-blind-safe pattern from sorting viz to the two other main viz families: - GraphViz: unvisited nodes get a dashed border (a 'pending' shape cue), visited/current stay solid — visited vs unvisited no longer relies on fill color alone (WCAG 1.4.1). - SvgTreeViz: red-black nodes carry an R/B letter badge — red-vs-dark-gray is a pure-color semantic that red-green colorblind users can't parse. - SvgCanvas gains an ariaLabel prop → role=img + aria-label; graph and tree viz emit a live state summary (e.g. '当前访问节点 A,已访问 2 个') so screen readers get a description instead of an opaque SVG. Pattern is now reusable (SvgCanvas.ariaLabel + strategy badge) for the remaining long-tail viz. Verified in browser: RB tree shows R/B badges + aria; BFS shows 5 dashed unvisited / 2 solid visited + dynamic aria. 405 tests, typecheck, lint green.
Adds the E2E layer jsdom can't cover — real Chromium, real routing, real persistence: - playwright.config.js (testDir e2e/, auto webServer on 5173, chromium) - e2e/smoke.spec.js: home loads, algorithm step-through changes the STEP description, theme toggle flips data-theme, and favorite persists across a reload + lands in localStorage. - npm run test:e2e; a separate CI job installs the browser and runs it (kept off the fast lint/typecheck/test/build job so it doesn't slow the main gate). - .gitignore ignores Playwright artifacts. All 4 flows pass locally against a real dev server. Self-check doc: #4 → green; scorecard now 12/12 green (green = a gate guards the line, not that the work is finished — TS migration, more E2E, long-tail a11y remain as incremental).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR adds a Playwright-based end-to-end (E2E) “key flow” smoke suite and wires it into CI, while also bundling several frontend self-check improvements (typecheck gate, stronger JS/DOM test stability, accessibility cues, and correctness regressions) to harden the app’s critical visualization and learning flows.
Changes:
- Add Playwright E2E smoke tests + config, and run them in CI as a separate job.
- Add a progressive
tsccheckJs “typecheck subset” (script + config) and include it innpm run checkand CI. - Strengthen frontend self-check coverage: radixSort negative-number fix + regression tests, doc drift guard, and multiple a11y improvements (non-color cues + aria summaries).
Reviewed changes
Copilot reviewed 26 out of 29 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
tsconfig.typecheck.json |
Adds a dedicated tsc project for progressive checkJs typechecking on a curated JS subset. |
src/vite-env.d.ts |
Adds Vite client type reference for typechecking. |
src/utils/stepProtocol.js |
Tightens JSDoc types for step parsing parameters. |
src/utils/hoverStyle.js |
Adjusts JSDoc types for hover style helpers. |
src/test/setup.js |
Adds jsdom polyfills (scroll APIs + ResizeObserver) to unblock interaction-path tests. |
src/styles/vizTokens.js |
Extends sorting legend items with non-color symbols. |
src/services/storage/SyncService.js |
Adds JSDoc typing for DI-style deps in sync service creation. |
src/pages/AIPage.jsx |
Adds an AI module contributor credit badge in the hero section. |
src/lib/supabase.js |
Avoids writing non-standard window.* properties without an explicit any cast. |
src/data/sortingCorrectness.test.js |
Adds sorting correctness regression tests across supported input domains. |
src/data/docConsistency.test.js |
Adds a Markdown “doc drift” guard ensuring referenced repo paths exist. |
src/data/algorithmSmoke.test.jsx |
Adds a full-playground render + step-through smoke guard for all algorithms. |
src/components/svg/SvgTreeViz.jsx |
Adds RB-tree non-color badge cue + forwards aria labeling to the canvas. |
src/components/svg/SvgCanvas.jsx |
Adds optional ariaLabel → role="img" + aria-label support for SVG canvases. |
src/components/SortingViz.jsx |
Adds non-color glyph cues for compare/swap and a completion marker in the index row. |
src/components/playgrounds/shared.jsx |
Enhances Legend to optionally render a symbol channel for a11y. |
src/components/GraphViz.jsx |
Adds aria summary label + dashed outline cue for unvisited nodes. |
src/algorithms/sorting/radixSort.test.js |
Adds radixSort regression tests including negative inputs. |
src/algorithms/sorting/radixSort.js |
Fixes radixSort for negative numbers via monotonic offset shifting. |
playwright.config.js |
Adds Playwright config with a Vite dev-server webServer integration. |
package.json |
Adds typecheck + test:e2e scripts and Playwright/TypeScript dev dependencies; updates check. |
package-lock.json |
Updates lockfile for new dev dependencies (Playwright + TypeScript). |
jsconfig.json |
Adds JS project config for editor navigation + gradual typing migration. |
e2e/smoke.spec.js |
Adds E2E smoke coverage for home, stepping, theme toggle, and favorite persistence. |
docs/FRONTEND_SELF_CHECK.md |
Documents the self-check dimensions and newly added test/typecheck gates. |
CONTRIBUTING.md |
Documents local dev, quality gates, and the typecheck/E2E workflows. |
AGENTS.md |
Updates referenced Supabase documentation/schema pointers. |
.gitignore |
Ignores Playwright artifact directories. |
.github/workflows/ci.yml |
Adds typecheck step and a separate E2E job that installs browsers and runs Playwright. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // 若已是"已收藏"(历史状态),先取消,回到干净起点 | ||
| if ((await favBtn.textContent())?.includes('已收藏')) { | ||
| await favBtn.click() | ||
| await expect(favBtn).toHaveText(/^收藏|收藏$/) |
| if (st.isDirectory()) { | ||
| // 只递归 docs/ 与根;避免扫进 src 里的注释 | ||
| if (full === path.join(ROOT, 'docs')) collectMarkdown(full, acc) | ||
| } else if (name.endsWith('.md')) { |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d855d368e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const offset = minVal < 0 ? -minVal : 0 | ||
| const shifted = (v) => v + offset |
There was a problem hiding this comment.
Update radix lesson snippets for negatives
With this offset path, the playground now accepts and correctly visualizes negative arrays, but the algorithm page still shows pseudocode/C++/Python in src/data/algorithms/sorting.js that buckets on raw v and uses raw maxVal. For inputs such as -3 1 -1, users see the visualization succeed while the displayed C++ can index negative buckets and the Python ordering is different, so the teaching snippets/pseudocode should either use the same offset or the UI should keep rejecting negatives.
Useful? React with 👍 / 👎.
What
Adds an end-to-end test layer and bundles the outstanding frontend self-check work that was sitting unpushed on
master.Headline change (
9d855d3):e2e/smoke.spec.jscovering key user flows,playwright.config.js..github/workflows/ci.yml..gitignoreentries for Playwright artifacts (test-results/,playwright-report/,blob-report/,.playwright/).package.json/package-lock.json.CONTRIBUTING.mdanddocs/FRONTEND_SELF_CHECK.md.Why
Closes the last gap in the frontend self-check series (#4 → green): the visualization key-flows had only mount/smoke coverage; this drives them end-to-end in CI.
Reviewer notes
master, not just the E2E commit. The rest are the earlier self-check series (a11y non-color channels chore(deps): bump the minor-and-patch group with 13 updates #8, checkJs enforcement chore(deps): bump the minor-and-patch group with 4 updates #10, doc-drift guard refactor(playground): deepen Playground layer onto PlaygroundShell (3 cards) #12, radixsort negative-input fix, render smoke/edge-correctness Enrich AI course and long-term finance framework #1/Install Vercel Web Analytics #4, AI-course contributor credit). They ride along because they were never pushed toorigin/master.masterwas 8 ahead / 6 behindorigin/master. GitHub may show this branch as behindorigin/master; a rebase/merge onto the latestorigin/mastermay be needed before merge..agents/,.claude/skills/,skills-lock.json) was deliberately left out of this PR.🤖 Generated with Claude Code