mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-19 22:10:51 +00:00
test: merge bundle loader fixture cases
This commit is contained in:
@@ -321,6 +321,48 @@ function createPluginRuntimeAliasFixture(params?: { srcBody?: string; distBody?:
|
||||
return { root, srcFile, distFile };
|
||||
}
|
||||
|
||||
function loadBundleFixture(params: {
|
||||
pluginId: string;
|
||||
build: (bundleRoot: string) => void;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
onlyPluginIds?: string[];
|
||||
}) {
|
||||
useNoBundledPlugins();
|
||||
const workspaceDir = makeTempDir();
|
||||
const stateDir = makeTempDir();
|
||||
const bundleRoot = path.join(workspaceDir, ".openclaw", "extensions", params.pluginId);
|
||||
params.build(bundleRoot);
|
||||
return withEnv({ OPENCLAW_STATE_DIR: stateDir, ...params.env }, () =>
|
||||
loadOpenClawPlugins({
|
||||
workspaceDir,
|
||||
onlyPluginIds: params.onlyPluginIds ?? [params.pluginId],
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
[params.pluginId]: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
cache: false,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function expectNoUnwiredBundleDiagnostic(
|
||||
registry: ReturnType<typeof loadOpenClawPlugins>,
|
||||
pluginId: string,
|
||||
) {
|
||||
expect(
|
||||
registry.diagnostics.some(
|
||||
(diag) =>
|
||||
diag.pluginId === pluginId &&
|
||||
diag.message.includes("bundle capability detected but not wired"),
|
||||
),
|
||||
).toBe(false);
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
clearPluginLoaderCache();
|
||||
if (prevBundledDir === undefined) {
|
||||
@@ -376,147 +418,113 @@ describe("bundle plugins", () => {
|
||||
expect(plugin?.bundleCapabilities).toContain("skills");
|
||||
});
|
||||
|
||||
it("treats Claude command roots and settings as supported bundle surfaces", () => {
|
||||
useNoBundledPlugins();
|
||||
const workspaceDir = makeTempDir();
|
||||
const stateDir = makeTempDir();
|
||||
const bundleRoot = path.join(workspaceDir, ".openclaw", "extensions", "claude-skills");
|
||||
mkdirSafe(path.join(bundleRoot, "commands"));
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, "commands", "review.md"),
|
||||
"---\ndescription: fixture\n---\n",
|
||||
);
|
||||
fs.writeFileSync(path.join(bundleRoot, "settings.json"), '{"hideThinkingBlock":true}', "utf-8");
|
||||
|
||||
const registry = withEnv({ OPENCLAW_STATE_DIR: stateDir }, () =>
|
||||
loadOpenClawPlugins({
|
||||
workspaceDir,
|
||||
onlyPluginIds: ["claude-skills"],
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
"claude-skills": {
|
||||
enabled: true,
|
||||
it.each([
|
||||
{
|
||||
name: "treats Claude command roots and settings as supported bundle surfaces",
|
||||
pluginId: "claude-skills",
|
||||
expectedFormat: "claude",
|
||||
expectedCapabilities: ["skills", "commands", "settings"],
|
||||
build: (bundleRoot: string) => {
|
||||
mkdirSafe(path.join(bundleRoot, "commands"));
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, "commands", "review.md"),
|
||||
"---\ndescription: fixture\n---\n",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, "settings.json"),
|
||||
'{"hideThinkingBlock":true}',
|
||||
"utf-8",
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "treats bundle MCP as a supported bundle surface",
|
||||
pluginId: "claude-mcp",
|
||||
expectedFormat: "claude",
|
||||
expectedCapabilities: ["mcpServers"],
|
||||
build: (bundleRoot: string) => {
|
||||
mkdirSafe(path.join(bundleRoot, ".claude-plugin"));
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".claude-plugin", "plugin.json"),
|
||||
JSON.stringify({
|
||||
name: "Claude MCP",
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".mcp.json"),
|
||||
JSON.stringify({
|
||||
mcpServers: {
|
||||
probe: {
|
||||
command: "node",
|
||||
args: ["./probe.mjs"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
cache: false,
|
||||
}),
|
||||
);
|
||||
|
||||
const plugin = registry.plugins.find((entry) => entry.id === "claude-skills");
|
||||
expect(plugin?.status).toBe("loaded");
|
||||
expect(plugin?.bundleFormat).toBe("claude");
|
||||
expect(plugin?.bundleCapabilities).toEqual(
|
||||
expect.arrayContaining(["skills", "commands", "settings"]),
|
||||
);
|
||||
expect(
|
||||
registry.diagnostics.some(
|
||||
(diag) =>
|
||||
diag.pluginId === "claude-skills" &&
|
||||
diag.message.includes("bundle capability detected but not wired"),
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("treats bundle MCP as a supported bundle surface", () => {
|
||||
useNoBundledPlugins();
|
||||
const workspaceDir = makeTempDir();
|
||||
const bundleRoot = path.join(workspaceDir, ".openclaw", "extensions", "claude-mcp");
|
||||
mkdirSafe(path.join(bundleRoot, ".claude-plugin"));
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".claude-plugin", "plugin.json"),
|
||||
JSON.stringify({
|
||||
name: "Claude MCP",
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".mcp.json"),
|
||||
JSON.stringify({
|
||||
mcpServers: {
|
||||
probe: {
|
||||
command: "node",
|
||||
args: ["./probe.mjs"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const registry = loadOpenClawPlugins({
|
||||
workspaceDir,
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
"claude-mcp": {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
},
|
||||
cache: false,
|
||||
});
|
||||
},
|
||||
{
|
||||
name: "treats Cursor command roots as supported bundle skill surfaces",
|
||||
pluginId: "cursor-skills",
|
||||
expectedFormat: "cursor",
|
||||
expectedCapabilities: ["skills", "commands"],
|
||||
build: (bundleRoot: string) => {
|
||||
mkdirSafe(path.join(bundleRoot, ".cursor-plugin"));
|
||||
mkdirSafe(path.join(bundleRoot, ".cursor", "commands"));
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".cursor-plugin", "plugin.json"),
|
||||
JSON.stringify({
|
||||
name: "Cursor Skills",
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".cursor", "commands", "review.md"),
|
||||
"---\ndescription: fixture\n---\n",
|
||||
);
|
||||
},
|
||||
},
|
||||
])("$name", ({ pluginId, expectedFormat, expectedCapabilities, build }) => {
|
||||
const registry = loadBundleFixture({ pluginId, build });
|
||||
const plugin = registry.plugins.find((entry) => entry.id === pluginId);
|
||||
|
||||
const plugin = registry.plugins.find((entry) => entry.id === "claude-mcp");
|
||||
expect(plugin?.status).toBe("loaded");
|
||||
expect(plugin?.bundleFormat).toBe("claude");
|
||||
expect(plugin?.bundleCapabilities).toEqual(expect.arrayContaining(["mcpServers"]));
|
||||
expect(
|
||||
registry.diagnostics.some(
|
||||
(diag) =>
|
||||
diag.pluginId === "claude-mcp" &&
|
||||
diag.message.includes("bundle capability detected but not wired"),
|
||||
),
|
||||
).toBe(false);
|
||||
expect(plugin?.bundleFormat).toBe(expectedFormat);
|
||||
expect(plugin?.bundleCapabilities).toEqual(expect.arrayContaining(expectedCapabilities));
|
||||
expectNoUnwiredBundleDiagnostic(registry, pluginId);
|
||||
});
|
||||
|
||||
it("warns when bundle MCP only declares unsupported non-stdio transports", () => {
|
||||
useNoBundledPlugins();
|
||||
const workspaceDir = makeTempDir();
|
||||
const stateDir = makeTempDir();
|
||||
const bundleRoot = path.join(workspaceDir, ".openclaw", "extensions", "claude-mcp-url");
|
||||
fs.mkdirSync(path.join(bundleRoot, ".claude-plugin"), { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".claude-plugin", "plugin.json"),
|
||||
JSON.stringify({
|
||||
name: "Claude MCP URL",
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".mcp.json"),
|
||||
JSON.stringify({
|
||||
mcpServers: {
|
||||
remoteProbe: {
|
||||
url: "http://127.0.0.1:8787/mcp",
|
||||
},
|
||||
},
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const registry = withEnv(
|
||||
{
|
||||
const registry = loadBundleFixture({
|
||||
pluginId: "claude-mcp-url",
|
||||
env: {
|
||||
OPENCLAW_HOME: stateDir,
|
||||
OPENCLAW_STATE_DIR: stateDir,
|
||||
},
|
||||
() =>
|
||||
loadOpenClawPlugins({
|
||||
workspaceDir,
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
"claude-mcp-url": {
|
||||
enabled: true,
|
||||
},
|
||||
build: (bundleRoot) => {
|
||||
mkdirSafe(path.join(bundleRoot, ".claude-plugin"));
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".claude-plugin", "plugin.json"),
|
||||
JSON.stringify({
|
||||
name: "Claude MCP URL",
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".mcp.json"),
|
||||
JSON.stringify({
|
||||
mcpServers: {
|
||||
remoteProbe: {
|
||||
url: "http://127.0.0.1:8787/mcp",
|
||||
},
|
||||
},
|
||||
},
|
||||
cache: false,
|
||||
}),
|
||||
);
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const plugin = registry.plugins.find((entry) => entry.id === "claude-mcp-url");
|
||||
expect(plugin?.status).toBe("loaded");
|
||||
@@ -530,55 +538,6 @@ describe("bundle plugins", () => {
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("treats Cursor command roots as supported bundle skill surfaces", () => {
|
||||
useNoBundledPlugins();
|
||||
const workspaceDir = makeTempDir();
|
||||
const stateDir = makeTempDir();
|
||||
const bundleRoot = path.join(workspaceDir, ".openclaw", "extensions", "cursor-skills");
|
||||
mkdirSafe(path.join(bundleRoot, ".cursor-plugin"));
|
||||
mkdirSafe(path.join(bundleRoot, ".cursor", "commands"));
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".cursor-plugin", "plugin.json"),
|
||||
JSON.stringify({
|
||||
name: "Cursor Skills",
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(bundleRoot, ".cursor", "commands", "review.md"),
|
||||
"---\ndescription: fixture\n---\n",
|
||||
);
|
||||
|
||||
const registry = withEnv({ OPENCLAW_STATE_DIR: stateDir }, () =>
|
||||
loadOpenClawPlugins({
|
||||
workspaceDir,
|
||||
onlyPluginIds: ["cursor-skills"],
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
"cursor-skills": {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
cache: false,
|
||||
}),
|
||||
);
|
||||
|
||||
const plugin = registry.plugins.find((entry) => entry.id === "cursor-skills");
|
||||
expect(plugin?.status).toBe("loaded");
|
||||
expect(plugin?.bundleFormat).toBe("cursor");
|
||||
expect(plugin?.bundleCapabilities).toEqual(expect.arrayContaining(["skills", "commands"]));
|
||||
expect(
|
||||
registry.diagnostics.some(
|
||||
(diag) =>
|
||||
diag.pluginId === "cursor-skills" &&
|
||||
diag.message.includes("bundle capability detected but not wired"),
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
|
||||
Reference in New Issue
Block a user