test(agents): dedupe agent and cron test scaffolds

This commit is contained in:
Peter Steinberger
2026-03-02 06:40:42 +00:00
parent 281494ae52
commit 7e29d604ba
38 changed files with 3114 additions and 4486 deletions

View File

@@ -47,85 +47,93 @@ function buildRegistry(params: { acpxRoot: string; helperRoot: string }): Plugin
};
}
function createSinglePluginRegistry(params: {
pluginRoot: string;
skills: string[];
}): PluginManifestRegistry {
return {
diagnostics: [],
plugins: [
{
id: "helper",
name: "Helper",
channels: [],
providers: [],
skills: params.skills,
origin: "workspace",
rootDir: params.pluginRoot,
source: params.pluginRoot,
manifestPath: path.join(params.pluginRoot, "openclaw.plugin.json"),
},
],
};
}
async function setupAcpxAndHelperRegistry() {
const workspaceDir = await tempDirs.make("openclaw-");
const acpxRoot = await tempDirs.make("openclaw-acpx-plugin-");
const helperRoot = await tempDirs.make("openclaw-helper-plugin-");
await fs.mkdir(path.join(acpxRoot, "skills"), { recursive: true });
await fs.mkdir(path.join(helperRoot, "skills"), { recursive: true });
hoisted.loadPluginManifestRegistry.mockReturnValue(buildRegistry({ acpxRoot, helperRoot }));
return { workspaceDir, acpxRoot, helperRoot };
}
async function setupPluginOutsideSkills() {
const workspaceDir = await tempDirs.make("openclaw-");
const pluginRoot = await tempDirs.make("openclaw-plugin-");
const outsideDir = await tempDirs.make("openclaw-outside-");
const outsideSkills = path.join(outsideDir, "skills");
return { workspaceDir, pluginRoot, outsideSkills };
}
afterEach(async () => {
hoisted.loadPluginManifestRegistry.mockReset();
await tempDirs.cleanup();
});
describe("resolvePluginSkillDirs", () => {
it("keeps acpx plugin skills when ACP is enabled", async () => {
const workspaceDir = await tempDirs.make("openclaw-");
const acpxRoot = await tempDirs.make("openclaw-acpx-plugin-");
const helperRoot = await tempDirs.make("openclaw-helper-plugin-");
await fs.mkdir(path.join(acpxRoot, "skills"), { recursive: true });
await fs.mkdir(path.join(helperRoot, "skills"), { recursive: true });
hoisted.loadPluginManifestRegistry.mockReturnValue(
buildRegistry({
acpxRoot,
helperRoot,
}),
);
it.each([
{
name: "keeps acpx plugin skills when ACP is enabled",
acpEnabled: true,
expectedDirs: ({ acpxRoot, helperRoot }: { acpxRoot: string; helperRoot: string }) => [
path.resolve(acpxRoot, "skills"),
path.resolve(helperRoot, "skills"),
],
},
{
name: "skips acpx plugin skills when ACP is disabled",
acpEnabled: false,
expectedDirs: ({ helperRoot }: { acpxRoot: string; helperRoot: string }) => [
path.resolve(helperRoot, "skills"),
],
},
])("$name", async ({ acpEnabled, expectedDirs }) => {
const { workspaceDir, acpxRoot, helperRoot } = await setupAcpxAndHelperRegistry();
const dirs = resolvePluginSkillDirs({
workspaceDir,
config: {
acp: { enabled: true },
acp: { enabled: acpEnabled },
} as OpenClawConfig,
});
expect(dirs).toEqual([path.resolve(acpxRoot, "skills"), path.resolve(helperRoot, "skills")]);
});
it("skips acpx plugin skills when ACP is disabled", async () => {
const workspaceDir = await tempDirs.make("openclaw-");
const acpxRoot = await tempDirs.make("openclaw-acpx-plugin-");
const helperRoot = await tempDirs.make("openclaw-helper-plugin-");
await fs.mkdir(path.join(acpxRoot, "skills"), { recursive: true });
await fs.mkdir(path.join(helperRoot, "skills"), { recursive: true });
hoisted.loadPluginManifestRegistry.mockReturnValue(
buildRegistry({
acpxRoot,
helperRoot,
}),
);
const dirs = resolvePluginSkillDirs({
workspaceDir,
config: {
acp: { enabled: false },
} as OpenClawConfig,
});
expect(dirs).toEqual([path.resolve(helperRoot, "skills")]);
expect(dirs).toEqual(expectedDirs({ acpxRoot, helperRoot }));
});
it("rejects plugin skill paths that escape the plugin root", async () => {
const workspaceDir = await tempDirs.make("openclaw-");
const pluginRoot = await tempDirs.make("openclaw-plugin-");
const outsideDir = await tempDirs.make("openclaw-outside-");
const outsideSkills = path.join(outsideDir, "skills");
const { workspaceDir, pluginRoot, outsideSkills } = await setupPluginOutsideSkills();
await fs.mkdir(path.join(pluginRoot, "skills"), { recursive: true });
await fs.mkdir(outsideSkills, { recursive: true });
const escapePath = path.relative(pluginRoot, outsideSkills);
hoisted.loadPluginManifestRegistry.mockReturnValue({
diagnostics: [],
plugins: [
{
id: "helper",
name: "Helper",
channels: [],
providers: [],
skills: ["./skills", escapePath],
origin: "workspace",
rootDir: pluginRoot,
source: pluginRoot,
manifestPath: path.join(pluginRoot, "openclaw.plugin.json"),
},
],
} satisfies PluginManifestRegistry);
hoisted.loadPluginManifestRegistry.mockReturnValue(
createSinglePluginRegistry({
pluginRoot,
skills: ["./skills", escapePath],
}),
);
const dirs = resolvePluginSkillDirs({
workspaceDir,
@@ -136,10 +144,7 @@ describe("resolvePluginSkillDirs", () => {
});
it("rejects plugin skill symlinks that resolve outside plugin root", async () => {
const workspaceDir = await tempDirs.make("openclaw-");
const pluginRoot = await tempDirs.make("openclaw-plugin-");
const outsideDir = await tempDirs.make("openclaw-outside-");
const outsideSkills = path.join(outsideDir, "skills");
const { workspaceDir, pluginRoot, outsideSkills } = await setupPluginOutsideSkills();
const linkPath = path.join(pluginRoot, "skills-link");
await fs.mkdir(outsideSkills, { recursive: true });
await fs.symlink(
@@ -148,22 +153,12 @@ describe("resolvePluginSkillDirs", () => {
process.platform === "win32" ? ("junction" as const) : ("dir" as const),
);
hoisted.loadPluginManifestRegistry.mockReturnValue({
diagnostics: [],
plugins: [
{
id: "helper",
name: "Helper",
channels: [],
providers: [],
skills: ["./skills-link"],
origin: "workspace",
rootDir: pluginRoot,
source: pluginRoot,
manifestPath: path.join(pluginRoot, "openclaw.plugin.json"),
},
],
} satisfies PluginManifestRegistry);
hoisted.loadPluginManifestRegistry.mockReturnValue(
createSinglePluginRegistry({
pluginRoot,
skills: ["./skills-link"],
}),
);
const dirs = resolvePluginSkillDirs({
workspaceDir,