Add interactive playground with WASM discovery and Pyodide test execution#126
Add interactive playground with WASM discovery and Pyodide test execution#126thejchap wants to merge 27 commits into
Conversation
…tion Feature-gate tryke_discovery and tryke_reporter behind a `native` feature so the parsing and reporting pipelines can compile to wasm32. Add a new tryke_wasm crate that exposes discover(), format_results(), and format_collect() to JavaScript via wasm-bindgen. The playground frontend (React 19 + Vite + Monaco + xterm.js) runs entirely client-side: WASM handles static test discovery on every keystroke, Pyodide executes tests in a Web Worker, and results flow through real tryke reporters rendered in an xterm.js terminal. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0d0d8d7876
ℹ️ 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".
There was a problem hiding this comment.
Pull request overview
Adds a browser playground for tryke that combines client-side Rust/WASM discovery/report formatting with a React/Vite UI and Pyodide-based Python test execution.
Changes:
- Adds a new
tryke_wasmcrate and feature-gates native-only discovery/reporter dependencies. - Adds a React playground with Monaco editing, discovery panels, graph visualization, terminal output, examples, and a Pyodide worker.
- Moves
DiscoveredFileintotryke_typesand updates workspace/package configuration for WASM support.
Reviewed changes
Copilot reviewed 30 out of 34 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
.claude/launch.json |
Adds playground launch configuration. |
.gitignore |
Ignores Node/build/generated playground artifacts. |
Cargo.lock |
Updates dependency lockfile for WASM-related changes. |
Cargo.toml |
Adjusts workspace dependencies and adds WASM bindings dependencies. |
crates/tryke/Cargo.toml |
Enables native features for CLI dependencies. |
crates/tryke_discovery/Cargo.toml |
Adds native feature gating for discovery dependencies. |
crates/tryke_discovery/src/db.rs |
Re-exports moved DiscoveredFile. |
crates/tryke_discovery/src/lib.rs |
Gates native-only APIs and exposes source discovery/import resolution for WASM. |
crates/tryke_reporter/Cargo.toml |
Adds native feature gating for reporter dependencies. |
crates/tryke_reporter/src/clear.rs |
Makes terminal clearing native-only. |
crates/tryke_reporter/src/lib.rs |
Gates native-only reporter modules/exports. |
crates/tryke_server/Cargo.toml |
Enables native features for server dependencies. |
crates/tryke_types/src/lib.rs |
Moves DiscoveredFile into shared types. |
crates/tryke_wasm/Cargo.toml |
Adds the WASM crate manifest. |
crates/tryke_wasm/src/lib.rs |
Exposes discovery and reporter formatting functions through wasm-bindgen. |
playground/bun.lock |
Adds frontend dependency lockfile. |
playground/index.html |
Adds Vite app HTML entrypoint. |
playground/package.json |
Defines playground scripts and frontend dependencies. |
playground/tsconfig.json |
Adds TypeScript configuration. |
playground/vite.config.ts |
Configures Vite plugins and WASM handling. |
playground/src/Editor/Chrome.tsx |
Implements playground shell, file tabs, examples, WASM/Pyodide wiring, and run controls. |
playground/src/Editor/DiscoveryPanel.tsx |
Displays discovered tests, hooks, errors, and dynamic import status. |
playground/src/Editor/Editor.tsx |
Connects editor, discovery, graph, and output panels. |
playground/src/Editor/GraphView.tsx |
Renders import graph visualization. |
playground/src/Editor/SecondarySideBar.tsx |
Adds secondary panel tabs. |
playground/src/Editor/SourceEditor.tsx |
Adds Monaco Python editor wrapper. |
playground/src/Editor/TerminalOutput.tsx |
Adds xterm.js output rendering. |
playground/src/Editor/constants.ts |
Adds default files and curated examples. |
playground/src/Editor/index.tsx |
Exports playground chrome component. |
playground/src/Editor/types.ts |
Defines playground TypeScript data types. |
playground/src/main.tsx |
Mounts the React app. |
playground/src/styles/global.css |
Adds Tailwind imports and playground theme tokens. |
playground/src/vite-env.d.ts |
Adds Vite/raw Python module typings. |
playground/src/workers/pyodide.worker.ts |
Adds Pyodide initialization and browser-side Python test runner. |
Comments suppressed due to low confidence (1)
playground/src/workers/pyodide.worker.ts:81
- This error outcome uses the same invalid wire format as the import-error path:
TestOutcome::Errorexpectsdetailto contain amessagefield, not a string. As written, a missing discovered function makes reporter formatting fail and shows raw JSON in the terminal.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Add Cmd+R keyboard shortcut to run tests - Add tryke logo to nav bar and as favicon - Keep output tab active when editing (don't reset to discovery) - Add Multi-file imports example with import graph visualization - Add Fixtures & Depends example with yield fixtures and DI - Fix import graph edge resolution (path prefix mismatch) - Add fixture dependency resolution to Pyodide runner - Write all playground files to virtual FS for cross-file imports - Fix error outcome detail format for WASM reporter compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2456afda90
ℹ️ 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".
Set up linting and formatting tooling for the playground TypeScript/TSX code with pre-commit hooks so checks run automatically. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 34 out of 39 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (3)
playground/src/Editor/Chrome.tsx:181
handleAddFileaccepts a name that already exists, which creates duplicate React keys for the file tabs and causes later test execution to write multiple playground files to the same Pyodide path. Reject duplicate normalized filenames (or switch to stable unique ids while still preventing duplicate on-disk paths) before appending the new file.
const handleAddFile = useCallback(() => {
if (!newFileName) return;
const name = newFileName.endsWith(".py")
? newFileName
: `${newFileName}.py`;
setFiles((prev) => [...prev, { name, source: "" }]);
playground/src/workers/pyodide.worker.ts:81
- Writing each playground file with
open()assumes every parent directory already exists. If a user adds a file such aspkg/helpers.pyto test package-style imports, the worker raisesFileNotFoundErrorbefore any tests run. Create the parent directories in the Pyodide FS before writing each file (and similarly for the single-file path).
playground/src/Editor/Chrome.tsx:278 - The file tabs are implemented as clickable
divs, so they are not focusable or activatable from the keyboard. Usebuttonelements (or add the appropriate tab roles,tabIndex, and keyboard handlers) so users who do not use a mouse can switch files.
<div
key={file.name}
className={`flex items-center gap-1 px-3 py-1.5 text-xs cursor-pointer border-r border-border ${
i === activeFileIndex
? "bg-bg text-text"
: "text-text-dim hover:text-text hover:bg-surface-hover"
}`}
onClick={() => setActiveFileIndex(i)}
>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 22716697ca
ℹ️ 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".
- Add .gitignore for playground (node_modules, dist, .vite) - Discovery panel groups tests by describe blocks as a collapsible tree - Split Graph tab into Import Graph and Fixture Graph with scope labels - Fix terminal output by using term.reset() instead of term.clear() - Add display names to @test and expect() across all examples - Default to describe blocks example with auto-run on load - Re-run tests on source change (debounced 500ms) - Change run shortcut from Cmd+R to Cmd+Enter - Make logo a link to playground root, add Docs link to navbar Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A ⊞ toggle in the tab bar switches between single-tab and stacked mode, where all four panels (Discovery, Import Graph, Fixture Graph, Output) render vertically in a scrollable container. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tooltips on: run button, example/reporter pickers, Pyodide status badge, docs link, file add/remove buttons, and skip/todo/xfail badges (showing the reason text) and hook scope labels. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dccc1a338a
ℹ️ 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".
Running tests no longer overrides the active tab — the output panel updates in place regardless of which view is selected. Fixed test.cases examples that incorrectly mixed positional specs with a name= kwarg. Added a Kitchen Sink example with multi-file imports, fixtures, describe blocks, parametrized cases, and markers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Custom Monaco theme matching the Catppuccin Mocha UI colors - Stacked layout: Output on top (50%), Discovery/Import Graph/Fixture Graph evenly split below with overflow-y scrolling - Use Annotated[T, Depends(fixture)] form in all examples; update Pyodide runner to resolve Depends from type annotations - Remove name= kwargs from @test decorators (use function names) - Rename "Hooks" to "Fixtures" in Discovery panel and tooltips - Kitchen Sink: test file listed first, source file second Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e48ae11109
ℹ️ 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".
…spinner - Extract test execution logic from worker.py into runner.py, reducing worker.py by ~270 lines of duplicated code - Create playground.py as a thin harness that delegates to runner.run_test - Move RunTestResultWire and AssertionWire to tryke_types so the WASM crate can accept the flat runner format directly, eliminating the Python-side _to_wire conversion entirely - Extract inline example Python code from constants.ts into standalone .py files under playground/examples/ so ruff can lint/format them - Add playground/examples to ruff src config with appropriate per-file ignores for example code - Show a loading spinner in the output panel while Pyodide loads - Pass pyodideReady through to Editor for conditional rendering Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 56 out of 61 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (1)
python/tryke/playground.py:37
- The single-file path has the same nested-path failure:
open('/home/pyodide/{filename}', 'w')raises iffilenameincludes a directory. Ensure parent directories exist before writing the active file.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e6b1c6ea3b
ℹ️ 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".
| if case_index < len(cases): | ||
| case_label = cases[case_index].label | ||
|
|
||
| result = run_test(fn, xfail=t.get("xfail"), case_label=case_label) |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rollup converts static imports from CDN URLs into global variable references (output.globals), causing ReferenceError in production. Switch to dynamic import() with @vite-ignore so the CDN module is loaded at runtime instead of being bundled. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ddb69c505d
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e1b4710a5d
ℹ️ 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".
- Set tryke_guard.__TRYKE_TESTING__ = True in the Pyodide worker init so tests inside guard blocks execute at runtime (matching the native worker behavior). - Normalize file paths in discover_multi by joining filenames with root before passing to discover_file_from_source. Fixes relative import resolution for nested files (e.g. pkg/test_api.py) where candidate paths need the root prefix for starts_with checks. - Share a HookExecutor across the test loop in playground.py so per-scope fixtures are resolved once and reused, matching the native worker's fixture lifecycle. The frontend now sends WASM- discovered hooks alongside tests; playground.py registers them with a HookExecutor and passes it to run_test. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Trim to the essential patterns: scope fixture, Annotated Depends, describe blocks, to_raise, and parametrized cases. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Rust HookItem uses skip_serializing_if = "Vec::is_empty", so the groups field is absent when empty. Use .get() with a default instead of direct key access. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 581d184906
ℹ️ 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".
- Use stable root "." for single-file discover() so nested files like pkg/test_api.py keep their full module_path. - Validate user filenames: reject paths with ".." or that shadow the bundled tryke package under /home/pyodide. - Add run request IDs so stale Pyodide results from a previous run are discarded instead of overwriting the current output. - Add python/tryke_guard.py, Cargo.toml, and Cargo.lock to the playground workflow trigger paths. - Use button with role="tab" and aria-selected for file tabs; add aria-label to the panel layout toggle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add tryke.py and tryke_guard.py to the reserved names so a user tab cannot shadow the bundled framework module. - Use div[role=tab] with tabIndex and keyboard handler instead of a button to avoid nesting interactive elements (the close button was inside the tab button). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d56be4d36
ℹ️ 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".
Context
Adds a browser-based playground (similar to Ruff's playground) that lets users write Python tests, see discovered tests/hooks in real-time, visualize import graphs, and execute tests — all entirely client-side with no backend.
Changes
tryke_discoveryandtryke_reporterbehind anativefeature so parsing and reporting compile towasm32-unknown-unknowntryke_wasmcrate exposingdiscover(),format_results(),format_collect(), anddiscover_multi()viawasm-bindgenDiscoveredFiletotryke_typesso the WASM crate can use it without pulling in salsa/rayonuseDeferredValue)Test plan
cargo clippy --workspace --all-targets --all-features -- -D warnings— cleancargo nextest run --workspace --all-features— 651 passeduvx prek run -a— all hooks passwasm-pack build crates/tryke_wasm --target web— builds cleanlycd playground && bun run build— production build succeeds🤖 Generated with Claude Code