Summary
Agent Bundle already uses Rstest extensively inside its own repository. The
missing product feature is a generated, consumer-facing harness that understands
compiled routes, Agent Document rendering, MCP/CLI/script projections, browser
Apps, host artifacts, and the framework's dev/build lifecycle.
Make framework testing a first-class compiler output rather than requiring every
plugin author to reconstruct internal entrypoints or protocol clients.
The current examples show the gap at two levels:
- Audiobook Curator runs bare
rstest tests, so it receives no generated
framework-aware project configuration or route helpers.
- the full RSC runtime example carries a manual
rstest.config.ts with its own
include glob, serialized worker pool, Node environment, time scaling, and
expanded timeout for real Rsbuild compiles and child processes.
Those are valid repository tests, but plugin authors should not have to learn or
copy that setup merely to test an Agent Bundle project.
Existing capabilities to preserve
The repository already has:
- Rstest unit and integration configurations;
- Rslib-aware compilation support;
- Rstest browser and React integration;
- Playwright-backed browser tests;
- real MCP client/server wire tests;
- packed-consumer and deleted-source artifact tests;
- Workbench and MCP App browser tests;
- native host smoke gates.
This issue packages and generates the useful framework boundaries for consumer
projects. It does not replace the repository's test infrastructure.
Goals
- Let consumers test routes without importing generated implementation details.
- Test the same compiled route graph used by build and development.
- Make final documents and streaming render events directly assertable.
- Provide real MCP, CLI, script, browser-App, and packed-artifact harnesses.
- Make target capability and host artifact regressions visible before release.
- Keep unit tests fast while preserving explicit end-to-end proof levels.
Proposed public surface
Agent Bundle supplies an Rstest integration and generated test module:
// rstest.config.ts
import { defineConfig } from '@rstest/core';
import { agentBundleRstest } from 'agent-bundle/rstest';
export default defineConfig({
plugins: [agentBundleRstest()],
});
V1 ships agent-bundle/rstest and agent-bundle/test as explicit subpath
exports of the existing package with Rstest as an optional peer. A separate
package is unnecessary until dependency or release-boundary evidence requires
one.
Tests import stable framework helpers rather than source registries:
import {
renderRoute,
invokeMcpTool,
invokeCli,
runScript,
} from 'agent-bundle/test';
it('renders a bounded inventory result across MCP and CLI', async () => {
const route = await renderRoute('mcp:curator:inventory', {
source: fixtureRoot,
});
expect(route.final).toMatchAgentDocumentSnapshot();
expect(route.events).toMatchAgentRenderSequence([
'shell',
'progress',
'replace',
'complete',
]);
const mcp = await invokeMcpTool('curator', 'inventory', {
source: fixtureRoot,
});
expect(mcp.structuredContent).toEqual(route.final.value);
const cli = await invokeCli(['inventory', fixtureRoot, '--output', 'json']);
expect(JSON.parse(cli.stdout)).toEqual(route.final.value);
});
Test levels
1. Route unit harness
- loads the compiled route contract;
- injects test capabilities, filesystem roots, environment, clock, and
cancellation;
- renders through the real Agent renderer;
- captures shell/progress/patch/error/complete events;
- never opens a transport or builds host artifacts.
2. Projection contract harness
- offers an official SDK in-memory client/server mode for fast protocol
contract proof and labels it in-memory;
- separately invokes the packed generated MCP server through a subprocess/stdio
transport for process, stdout, and lifecycle proof;
- invokes the generated CLI dispatcher with captured stdout/stderr;
- executes plain and rendered scripts;
- compares final meaning across projections without requiring byte-identical
presentation.
3. Browser harness
- compiles each MCP App or Workbench surface through its exact production-owning
Agent Bundle/Rsbuild compiler function;
- mounts them through Rstest browser/React facilities;
- tests accessibility, bridge contracts, consent, resource binding, and render
stream presentation;
- uses Playwright only where a real browser process or navigation boundary is
required.
4. Artifact harness
- builds the package through the real Agent Bundle compiler;
- installs or copies the packed output into a clean consumer;
- reports packed-tarball install and copied-artifact proof as distinct modes;
- deletes project source where applicable;
- validates manifests and provenance;
- exercises CLI, MCP, scripts, Apps, and selected native host layouts.
These levels must remain visibly separate. A route-unit pass is not an artifact
or host-integration receipt.
Compiler coupling
The compiler generates a test manifest alongside the route manifest:
interface AgentBundleTestManifest {
routes: Readonly<Record<string, TestableRouteDescriptor>>;
projections: Readonly<Record<string, ProjectionDescriptor>>;
apps: Readonly<Record<string, BrowserAppDescriptor>>;
targets: readonly string[];
artifactExpectations: ArtifactExpectationSet;
}
The Rstest integration consumes this manifest to configure transforms, aliases,
test environments, generated types, and fixture lifecycles. Consumer tests do
not manually reproduce Rslib or Rsbuild configuration.
Generated fixtures and capabilities
Framework fixtures should provide:
- isolated project and output roots;
- strict environment allowlists;
- fake clocks only when the route explicitly receives a clock capability;
- bounded child-process fixtures;
- real AbortSignal cancellation;
- deterministic MCP client/server pairs;
- render-event collection with size/rate enforcement;
- explicit target capability fixtures for text, image, audio, resources, and
progress without pretending unsupported content is accepted;
- explicit browser origin and bridge setup;
- disposable packed-consumer directories.
- request-context provider fixtures with explicit identity provenance;
- production-driver conformance fixtures for optional durable state;
- native event projection fixtures that never claim to be host dispatch;
- notice delivery and receipt fixtures with supported/unavailable routes;
No fake transport or in-memory artifact may be presented as end-to-end proof.
Each helper states the proof level it supplies.
Matchers
Proposed matchers:
expect(document).toMatchAgentDocumentSnapshot();
expect(events).toMatchAgentRenderSequence([...]);
expect(result).toSatisfyMcpResultContract();
expect(artifact).toContainDeclaredRoute('mcp:curator:inventory');
expect(projections).toHaveEquivalentFinalValue();
Snapshots must preserve semantically important structure without pinning noisy
generated identifiers, timestamps, or bundler implementation details.
Failure diagnostics
Failures should report:
- route identity and source;
- config and generated-manifest provenance;
- active projection and target;
- last render event and boundary;
- captured stdout/stderr/logs with byte bounds;
- cancellation/timeout state;
- packed artifact path when relevant;
- a direct command for rerunning the narrow failing layer.
Migration and delivery
- Extract stable helpers from existing internal Rstest suites without weakening
their assertions.
- Generate a test manifest from the new route compiler.
- Ship route-render and event-stream harnesses first.
- Add MCP/CLI/script projection helpers.
- Add Rsbuild browser-App support.
- Add packed/deleted-source consumer helpers.
- Convert public examples to the consumer harness.
- Update
create-agent-bundle templates with one route test and one compiled
projection test.
Acceptance criteria
- A scaffolded project runs useful framework-aware Rstest tests without copying
Agent Bundle's internal build setup.
- Route tests use the real compiler contract and real Agent renderer.
- Fast MCP tests cross the official SDK in-memory transport, and process-level
MCP tests separately cross the packed subprocess/stdio boundary.
- Browser tests compile through the same Rsbuild profile used by production.
- Artifact tests prove behavior after source deletion.
- Audio and other non-text content is projected only when the target capability
fixture advertises support; fallback and fail-closed paths are both tested.
- Failure output identifies route, projection, target, and provenance.
- The harness never labels a fixture or in-memory substitute as packed,
transport, browser, or host proof.
Design references
Stack position
Full meta-framework stack
Summary
Agent Bundle already uses Rstest extensively inside its own repository. The
missing product feature is a generated, consumer-facing harness that understands
compiled routes, Agent Document rendering, MCP/CLI/script projections, browser
Apps, host artifacts, and the framework's dev/build lifecycle.
Make framework testing a first-class compiler output rather than requiring every
plugin author to reconstruct internal entrypoints or protocol clients.
The current examples show the gap at two levels:
rstest tests, so it receives no generatedframework-aware project configuration or route helpers.
rstest.config.tswith its owninclude glob, serialized worker pool, Node environment, time scaling, and
expanded timeout for real Rsbuild compiles and child processes.
Those are valid repository tests, but plugin authors should not have to learn or
copy that setup merely to test an Agent Bundle project.
Existing capabilities to preserve
The repository already has:
This issue packages and generates the useful framework boundaries for consumer
projects. It does not replace the repository's test infrastructure.
Goals
Proposed public surface
Agent Bundle supplies an Rstest integration and generated test module:
V1 ships
agent-bundle/rstestandagent-bundle/testas explicit subpathexports of the existing package with Rstest as an optional peer. A separate
package is unnecessary until dependency or release-boundary evidence requires
one.
Tests import stable framework helpers rather than source registries:
Test levels
1. Route unit harness
cancellation;
2. Projection contract harness
contract proof and labels it in-memory;
transport for process, stdout, and lifecycle proof;
presentation.
3. Browser harness
Agent Bundle/Rsbuild compiler function;
stream presentation;
required.
4. Artifact harness
These levels must remain visibly separate. A route-unit pass is not an artifact
or host-integration receipt.
Compiler coupling
The compiler generates a test manifest alongside the route manifest:
The Rstest integration consumes this manifest to configure transforms, aliases,
test environments, generated types, and fixture lifecycles. Consumer tests do
not manually reproduce Rslib or Rsbuild configuration.
Generated fixtures and capabilities
Framework fixtures should provide:
progress without pretending unsupported content is accepted;
No fake transport or in-memory artifact may be presented as end-to-end proof.
Each helper states the proof level it supplies.
Matchers
Proposed matchers:
Snapshots must preserve semantically important structure without pinning noisy
generated identifiers, timestamps, or bundler implementation details.
Failure diagnostics
Failures should report:
Migration and delivery
their assertions.
create-agent-bundletemplates with one route test and one compiledprojection test.
Acceptance criteria
Agent Bundle's internal build setup.
MCP tests separately cross the packed subprocess/stdio boundary.
fixture advertises support; fallback and fail-closed paths are both tested.
transport, browser, or host proof.
Design references
Stack position
their own conformance modules to this stable harness contract.
cross-process composition proof.
Full meta-framework stack