feat(test): route-unit consumer test harness (#103 stage 1) - #151
Conversation
🦋 Changeset detectedLatest commit: c34feb3 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Route modules had no way to be tested except through a full artifact build. This adds the route-unit proof level as two public subpaths. `agent-bundle/rstest` exposes `agentBundleRstest()`: it runs the project preparation the build and `inspect` already use — one route-graph compile, no artifact — and returns a plain Rstest configuration carrying the compiled test manifest, the route loaders, React's `react-server` resolution on both the process and the bundler, and the automatic JSX runtime. `agent-bundle/test` exposes `renderRoute`, which executes a route by compiled id or by module through the runtime's real final-only Flight dispatcher and request store and resolves to the final Agent Document, plus `expectDocument` matchers over the Agent Document contracts and `testManifest()` for iterating the route inventory in process. Failures name the route, target kind, module provenance, and manifest digest. `@agent-bundle/runtime`, `@rstest/core`, and `react` are optional peers: a project that does not test routes installs none of them, and declaring them is also what keeps them external in the published bundle instead of vendoring a second React server copy whose RSC manifest is not the consumer's.
7b07c9d to
c34feb3
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b07c9d237
ℹ️ 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".
…API (wave 3.5 stage 1) (#154) - sqlite driver: connection owned by a Layer + per-store scoped runtime; BEGIN IMMEDIATE / COMMIT / ROLLBACK as Effect.acquireUseRelease with rollback-on-failed-commit; SqliteConnection as a Context.Service - typed AgentStateError error channel end to end; sqlite/system throws map to the existing corrupt/unavailable codes, unexpected throws stay defects and still roll the transaction back - memory driver: same stateEffect channel; store close is the scope finalizer - driver close now settles pending opens with store-closed before resolving (new race tests pin it for both drivers) - packaging test additionally proves root/plugin entries ship no effect bytes - host-artifacts example test: allow the optional react peer that #151 added (pre-existing failure on main; hard deps stay banned) - agent-patterns/effect-scope.md: document the transaction idiom the rewrite settled on (dogfood feedback)
Bind route loaders to the manifest that produced them, so an explicit manifest cannot silently execute the registered project's module for a colliding route id and report the other manifest's provenance. Separate an absent document value from an emitted null in toHaveValue, record request-scoped progress even when the caller supplies its own reporter, validate the generated registry version where the helpers read it, and correct the README's request-context example.
…ots, workspace-free published manifest (#183) Three independent breakages kept hosted CI red on main: - scripts/run-examples-check.mjs launched npm_execpath through the current Node executable, but pnpm/setup on hosted runners exposes a native shim (bare command name), so `node pnpm` failed with MODULE_NOT_FOUND. The script now execs non-JavaScript entrypoints directly. - The sqlite migration (#149) made the example kernel return the durable prefix at the original commit revision on idempotent replays; the retired JSONL kernel returned the current head. Re-running a fixture after a reset therefore reported the pre-reset state version and failed the runtime playground e2e on every Node line. Replays now read the head again. - #151 added `"@agent-bundle/runtime": "workspace:*"` to the published agent-bundle devDependencies, tripping the release audit (npm refuses tarball manifests with workspace ranges). The optional peer is now satisfied through a pnpm-workspace override instead of a shipped range.
Closes the stage-1 slice of #103: route modules can now be tested without building an artifact.
Shipped
agent-bundle/rstest—agentBundleRstest(options?)returns a plain Rstest configuration object (thindefineConfiginput; no plugin surface yet):It runs one compiler pass — the same
ProjectService.prepare()the build andinspectuse, which owns route-graph compilation — and projects that graph into a test manifest. No second compile, no artifact build. The manifest and per-route loaders are written to a generated setup module under the project's gitignored.agent-bundle/test/, so the bundler transforms the route.tsxmodules the same way the build does.agent-bundle/test—renderRoute(routeId | module, { input, args, context, limits, progress, signal })executes a route through the runtime's public final-only Flight dispatcher (#144) and request store (#113) and resolves to the final Agent Document (#140), the ordered render events, the resolved provenance, and theresultSchema-parsed value.expectDocument(...)matchers:toHaveStatus,toContainMarkdown,toContainText,toHaveValue,toHaveError,toHaveNodeKinds.testManifest()exposes the compiled route inventory so per-route assertions iterate in process. Every failure names the route id, target kind, module, project root, and route-graph digest.Proof level discipline. One level ships, labeled
route-unitin the manifest, in every provenance record, and in the failure text. No placeholders for the transport, packed, or browser levels.Packaging.
@agent-bundle/runtime,@rstest/core, andreactare optional peers. The existing packed boundary test now asserts a skills-only consumer installs none of them (and that no directory for them exists on disk); its tree walk previously counted unmet optional peers as installed, which is fixed here. Declaring the peers is also what keeps them external in the published bundle — before this,dist/vendored a 410 KB copy of the Flight server whose bundler-injected RSC manifest was not the consumer project's, which is exactly how the audiobook adoption test failed until the peer was declared.Pools. The level needs Node's
react-servercondition, a per-process flag, so it runs as its own pool (pnpm test:route-unit, built from the shipped helper) and the workspace pools excludetests/route-unit/**. No new build or pack is added to any pool; the adoption example reuses the singleexamples:checkbuild.Adoption proof
examples/audiobook-curator/tests/route-unit/routes.test.tsrenders the migratedprompt:curator/curateroute (feat(routes): migrate audiobook curator to public authoring #150) withrenderRouteand asserts status, text, and structured value, plus the manifest compile with no build. 2 tests.packages/agent-bundle/fixtures/route-harness/is the framework's own fixture project (tool, event, resource, app routes) driving 10 route-unit tests: context overrides, progress capture, refused kinds, unknown routes, render errors, and result-schema rejection.Stage-1 follow-ups (deliberately not here)
react-servercondition and JSX runtime, and any docs beyond the README section.Scoped results
pnpm test:unit— 141 files, 1972 tests, 0 failurespnpm test:route-unit— 10 passedexamples/audiobook-curator: pnpm test:routes— 2 passed;pnpm test35 passed;pnpm typecheckcleanrsc-runtime-optional-packaging(packed) — 1 passedpublic-api(integration, loads every public subpath) — 7 passedpnpm lint,pnpm typecheck,pnpm lint:package(publint x3) — clean