Skip to content

Commit 73c02bb

Browse files
fix(ci): align tests with #180/#182/#190 so the post-merge safety net can go green (#197)
* test: align hook expectations with sorted normalization (#180) and the example's semantic event route (#182) Both features merged while main CI was already red, so their outdated sibling tests were never caught: normalizeHooks now orders hooks by stable id, the rsc-agent-runtime example declares one tool/after event route instead of per-host prebuilt hooks, and the workbench therefore exposes the simulatable Hooks capability page. * fix(ci): keep route-unit proofs out of the example plain test pool * fix(ci): defer to the mainline Skill IR digest canonicalization (#191)
1 parent 8c77ce6 commit 73c02bb

4 files changed

Lines changed: 25 additions & 16 deletions

File tree

‎examples/rsc-agent-runtime/rstest.config.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import { defineConfig } from '@rstest/core';
33
import { timeScale } from './tests/support/time-scale.ts';
44

55
export default defineConfig({
6+
// Route-unit proofs need the framework-generated configuration
7+
// (rstest.route-unit.config.ts via `pnpm test:routes`), so they are not
8+
// swept into this plain Node pool where no test manifest is registered.
9+
exclude: ['tests/route-unit/**'],
610
include: ['tests/**/*.test.{ts,tsx}'],
711
pool: { maxWorkers: 1 },
812
testEnvironment: 'node',

‎examples/rsc-agent-runtime/tests/dev-provider.integration.test.ts‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -375,12 +375,16 @@ test('declares an optional runtime while keeping Claude and Codex artifacts buil
375375
provider: './src/dev/provider.ts',
376376
servers: [expect.objectContaining({ name: 'timeline', transport: 'stdio' })],
377377
});
378-
// One prebuilt hook declaration per host, each carrying its own `--host`
379-
// argument.
380-
expect(prepared.model?.hooks).toEqual(expect.arrayContaining([
381-
expect.objectContaining({ prebuiltPath: 'runtime/hook/index.js', targets: ['claude'] }),
382-
expect.objectContaining({ prebuiltPath: 'runtime/hook/index.js', targets: ['codex'] }),
383-
]));
378+
// The example declares one semantic event route (src/events/tool/after.tsx)
379+
// that serves both hosts through the generated native wrappers.
380+
expect(prepared.model?.hooks).toEqual([
381+
expect.objectContaining({
382+
event: 'afterTool',
383+
eventRoute: expect.objectContaining({ event: 'tool/after' }),
384+
id: 'hook:event-route:tool-after',
385+
targets: ['claude', 'codex'],
386+
}),
387+
]);
384388

385389
const artifact = await new ArtifactService({ epochStore: new EpochStore({ projectRoot: root }) }).build(prepared);
386390
if (artifact.outcome !== 'succeeded') throw new Error(JSON.stringify(artifact.diagnostics));

‎packages/agent-bundle/tests/hooks.test.ts‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,13 +1306,15 @@ it('normalizes a mixed hook fixture and reports malformed hook declarations', as
13061306
targets: hook.targets,
13071307
timeout: hook.timeout,
13081308
tools: hook.tools,
1309+
// Normalization orders hooks by their stable id, not by declaration
1310+
// order, so mixed configured and conventional hooks emit deterministically.
13091311
}))).toEqual([
13101312
{
1311-
event: 'sessionStart',
1312-
name: 'session-start-session-start-7ab7e8a5',
1313+
event: 'afterTool',
1314+
name: 'after-tool-record-87785f02',
13131315
targets: ['claude', 'codex'],
13141316
timeout: undefined,
1315-
tools: [],
1317+
tools: ['file.write', 'shell'],
13161318
},
13171319
{
13181320
event: 'beforeTool',
@@ -1329,11 +1331,11 @@ it('normalizes a mixed hook fixture and reports malformed hook declarations', as
13291331
tools: ['shell'],
13301332
},
13311333
{
1332-
event: 'afterTool',
1333-
name: 'after-tool-record-87785f02',
1334+
event: 'sessionStart',
1335+
name: 'session-start-session-start-7ab7e8a5',
13341336
targets: ['claude', 'codex'],
13351337
timeout: undefined,
1336-
tools: ['file.write', 'shell'],
1338+
tools: [],
13371339
},
13381340
{
13391341
event: 'stop',

‎packages/workbench/tests/runtime-playground.e2e.test.ts‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,9 @@ e2e('renders the capability-gated Runtime sibling in the real RSC workbench', {
3535
await expect(page.getByRole('link', { name: 'Inspector' })).toHaveCount(0, { timeout: browserTimeout });
3636
await expect(page.getByRole('link', { name: 'Runtime' })).toBeVisible({ timeout: browserTimeout });
3737

38-
// The example's hooks are prebuilt payload commands packaged like native
39-
// hooks, so no simulatable hook wrappers exist and the Hooks and
40-
// Playground capability pages stay hidden alongside them.
41-
await expect(page.getByRole('link', { name: 'Hooks' })).toHaveCount(0, { timeout: browserTimeout });
38+
// The example declares a semantic event route rendered through generated
39+
// native wrappers, so the simulatable Hooks capability page is available.
40+
await expect(page.getByRole('link', { exact: true, name: 'Hooks' })).toBeVisible({ timeout: browserTimeout });
4241
for (const sibling of ['artifacts', 'logs'] as const) {
4342
await page.goto(workbenchUrl(fixture.url, sibling));
4443
await expect(page.locator(`#${sibling}`)).toBeVisible({ timeout: browserTimeout });

0 commit comments

Comments
 (0)