| import fs from "node:fs/promises"; |
| import path from "node:path"; |
| import { |
| createPluginRegistryFixture, |
| describePluginRegistrationContract, |
| pluginRegistrationContractCases, |
| registerVirtualTestPlugin, |
| } from "openclaw/plugin-sdk/plugin-test-contracts"; |
| import { withTempHome } from "openclaw/plugin-sdk/test-env"; |
| import { typedCases } from "openclaw/plugin-sdk/test-fixtures"; |
| import { describe, expect, it } from "vitest"; |
|
|
| const echoCases = typedCases([ |
| { message: "alpha", expected: "scoped:alpha" }, |
| { message: "beta", expected: "scoped:beta" }, |
| ]); |
|
|
| describePluginRegistrationContract(pluginRegistrationContractCases.brave); |
|
|
| describe("plugin testing harness contracts", () => { |
| it("executes declared tools and reports missing tool contracts", async () => { |
| const previousHome = process.env.HOME; |
| const previousStateDir = process.env.OPENCLAW_STATE_DIR; |
|
|
| await withTempHome(async (home) => { |
| const stateDir = path.join(home, ".openclaw"); |
| await expect( |
| fs.stat(path.join(stateDir, "agents", "main", "sessions")), |
| ).resolves.toBeDefined(); |
| expect(process.env.HOME).toBe(home); |
| expect(process.env.OPENCLAW_STATE_DIR).toBe(stateDir); |
|
|
| const { config, registry } = createPluginRegistryFixture({ |
| plugins: { |
| entries: { |
| "fixture-echo": { |
| config: { prefix: "scoped" }, |
| }, |
| }, |
| }, |
| }); |
|
|
| registerVirtualTestPlugin({ |
| registry, |
| config, |
| id: "fixture-echo", |
| name: "Fixture Echo", |
| contracts: { tools: ["fixture_echo"] }, |
| register(api) { |
| const prefix = api.config.plugins?.entries?.["fixture-echo"]?.config?.prefix; |
| if (typeof prefix !== "string") { |
| throw new Error("fixture prefix missing"); |
| } |
| api.registerTool({ |
| name: "fixture_echo", |
| label: "Fixture Echo", |
| description: "Echo a fixture value", |
| parameters: {}, |
| execute: async (_toolCallId, params) => { |
| const message = (params as { message: string }).message; |
| return { |
| content: [{ type: "text", text: `${prefix}:${message}` }], |
| details: { home, message }, |
| }; |
| }, |
| }); |
| }, |
| }); |
|
|
| expect(registry.registry.tools).toHaveLength(1); |
| const registration = registry.registry.tools[0]; |
| expect(registration?.pluginId).toBe("fixture-echo"); |
| expect(registration?.names).toEqual(["fixture_echo"]); |
| const tool = registration?.factory({ workspaceDir: home }); |
| if (!tool || Array.isArray(tool)) { |
| throw new Error("expected one registered fixture tool"); |
| } |
| expect(tool.name).toBe("fixture_echo"); |
|
|
| for (const testCase of echoCases) { |
| await expect(tool.execute("fixture-call", { message: testCase.message })).resolves.toEqual({ |
| content: [{ type: "text", text: testCase.expected }], |
| details: { home, message: testCase.message }, |
| }); |
| } |
| expect(registry.registry.diagnostics).toEqual([]); |
|
|
| const missingContract = createPluginRegistryFixture(); |
| registerVirtualTestPlugin({ |
| registry: missingContract.registry, |
| config: missingContract.config, |
| id: "missing-contract", |
| name: "Missing Contract", |
| register(api) { |
| api.registerTool({ |
| name: "fixture_echo", |
| label: "Fixture Echo", |
| description: "Echo a fixture value", |
| parameters: {}, |
| execute: async () => ({ content: [], details: {} }), |
| }); |
| }, |
| }); |
|
|
| expect(missingContract.registry.registry.tools).toEqual([]); |
| expect(missingContract.registry.registry.diagnostics).toContainEqual({ |
| level: "error", |
| pluginId: "missing-contract", |
| source: "/virtual/missing-contract/index.ts", |
| message: "plugin must declare contracts.tools before registering agent tools", |
| }); |
| }); |
|
|
| expect(process.env.HOME).toBe(previousHome); |
| expect(process.env.OPENCLAW_STATE_DIR).toBe(previousStateDir); |
| }); |
| }); |
|
|