Write an extension
Test it
Test an extension with node:test and the in-memory host.
An extension’s tests are ordinary tests. memoryHost runs the real Agent over
an in-memory database, and script stands in for the model, so they need no
provider account and no network. This file uses Node’s built-in test runner.
import assert from "node:assert/strict";import { test } from "node:test";import { memoryHost } from "@fungi.computer/shiitake/testing";import client from "./client.js";import { bookmarks } from "./extension.js";import { readOnlySave } from "./grants.js";import { bookmarkRoundTrip } from "./run.js";
await test("the model and a person both save links the client can draw", async () => { const rows = await bookmarkRoundTrip(); assert.deepEqual( rows.map((row) => row.title), ["Fungi", "Shiitake docs"], );});
await test("a host without the commands grant refuses saves", async () => { await assert.rejects(readOnlySave(), /Extension is unavailable/);});
await test("each Session keeps its own bookmarks", async () => { const host = await memoryHost({ extensions: [bookmarks] }); try { for (const id of ["first", "second"]) { const session = host.agent.session(id); await session.send("Start.", { requestId: id }); await host.settle(id); await session.extension(bookmarks.manifest.id).call("add", { url: "https://fungi.computer/", title: id, }); } for (const id of ["first", "second"]) { const slot = (await host.agent.session(id).read()).extensions.bookmarks; const rows = client.contribute?.(slot).panel ?? []; assert.deepEqual( rows.map((row) => row.title), [id], ); } } finally { await host.close(); }});
await test("the client draws nothing from a broken projection", () => { const contribution = client.contribute?.({ status: "running", revision: "sha256:fixture", value: [{ url: 42 }], }); assert.deepEqual(contribution?.panel, []);});Each test checks one promise the extension makes:
- The model and a person can both save links, and the client draws them.
- A host that withholds
commandsrefuses saves. - Each Session keeps its own bookmarks.
- A broken projection renders no rows rather than invented ones.
node --import tsx --test bookmarks/checks.tsThe summary at the end of its output reads:
ℹ tests 4ℹ pass 4ℹ fail 0The Shiitake package runs this same file in its own test suite.
The test host is not a sandbox: scripted tool calls run the admitted operation directly in your process, and no model-written code is evaluated. That makes it right for tests and wrong for production.
Next: Ship it.