test(agent-skills): unit tests for catalog + openapi + cli parsers

agentSkills-catalog.test.ts (30 tests):
- getCatalog(): 42 total, 22 api, 20 cli
- API_SKILL_IDS/CLI_SKILL_IDS length assertions
- ID regex format, uniqueness, required fields
- getSkillById happy path + null for unknown/empty
- filterCatalog by category, area, combined, empty
- refreshCatalog() invalidates cache (new array reference)
- computeCoverage() shape validation
- rawUrl/githubUrl URL format assertions

agentSkills-openapiParser.test.ts (9 tests):
- Fixture YAML: paths Map, area groupings (providers, api-keys, inference)
- OpenapiPath field validation
- Missing file throws
- Empty paths YAML returns empty Maps
- Real openapi.yaml: providers area ≥5 endpoints (integration)

agentSkills-cliRegistryParser.test.ts (10 tests):
- Fixture .mjs: commands Map, families Map, ≥5 provider subcommands
- Description extraction, isSubcommand flag, flags extraction
- Skips unrecognised files, throws on missing dir
- Real providers.mjs: ≥5 commands (integration)
This commit is contained in:
diegosouzapw
2026-05-27 20:32:08 -03:00
parent 0a95372746
commit 15838348c3
3 changed files with 790 additions and 0 deletions

View File

@@ -0,0 +1,239 @@
import test from "node:test";
import assert from "node:assert/strict";
// Dynamic imports to pick up ESM modules with tsx
const { getCatalog, getSkillById, filterCatalog, computeCoverage, refreshCatalog, API_SKILL_IDS, CLI_SKILL_IDS } =
await import("../../src/lib/agentSkills/catalog.ts");
// ─── Counts ───────────────────────────────────────────────────────────────────
test("getCatalog() returns exactly 42 entries", () => {
refreshCatalog();
const catalog = getCatalog();
assert.equal(catalog.length, 42, `Expected 42 but got ${catalog.length}`);
});
test("API_SKILL_IDS has exactly 22 entries", () => {
assert.equal(API_SKILL_IDS.length, 22);
});
test("CLI_SKILL_IDS has exactly 20 entries", () => {
assert.equal(CLI_SKILL_IDS.length, 20);
});
test("getCatalog() contains exactly 22 api skills", () => {
const apiSkills = getCatalog().filter((s) => s.category === "api");
assert.equal(apiSkills.length, 22);
});
test("getCatalog() contains exactly 20 cli skills", () => {
const cliSkills = getCatalog().filter((s) => s.category === "cli");
assert.equal(cliSkills.length, 20);
});
// ─── ID format ────────────────────────────────────────────────────────────────
test("all skill IDs match regex ^[a-z][a-z0-9-]*$", () => {
const ID_REGEX = /^[a-z][a-z0-9-]*$/;
for (const skill of getCatalog()) {
assert.match(
skill.id,
ID_REGEX,
`Skill ID "${skill.id}" does not match expected format`,
);
}
});
test("all skill IDs are unique (no duplicates)", () => {
const ids = getCatalog().map((s) => s.id);
const uniqueIds = new Set(ids);
assert.equal(
uniqueIds.size,
ids.length,
`Duplicate IDs found: ${ids.filter((id, i) => ids.indexOf(id) !== i).join(", ")}`,
);
});
// ─── Required fields ──────────────────────────────────────────────────────────
test("all skills have non-empty name and description", () => {
for (const skill of getCatalog()) {
assert.ok(skill.name.length > 0, `Skill ${skill.id} has empty name`);
assert.ok(skill.description.length > 0, `Skill ${skill.id} has empty description`);
}
});
test("all skills have rawUrl and githubUrl as valid GitHub URLs", () => {
for (const skill of getCatalog()) {
assert.ok(
skill.rawUrl.startsWith("https://raw.githubusercontent.com/"),
`Skill ${skill.id}: rawUrl "${skill.rawUrl}" is not a GitHub raw URL`,
);
assert.ok(
skill.githubUrl.startsWith("https://github.com/"),
`Skill ${skill.id}: githubUrl "${skill.githubUrl}" is not a GitHub blob URL`,
);
assert.ok(
skill.rawUrl.endsWith("/SKILL.md"),
`Skill ${skill.id}: rawUrl does not end with /SKILL.md`,
);
}
});
test("api skills have area matching API_SKILL_IDS derived IDs", () => {
const catalog = getCatalog();
for (const id of API_SKILL_IDS) {
const skill = catalog.find((s) => s.id === id);
assert.ok(skill, `API skill ID "${id}" not found in catalog`);
assert.equal(skill!.category, "api", `Skill "${id}" expected category api, got ${skill!.category}`);
}
});
test("cli skills have area matching CLI_SKILL_IDS derived IDs", () => {
const catalog = getCatalog();
for (const id of CLI_SKILL_IDS) {
const skill = catalog.find((s) => s.id === id);
assert.ok(skill, `CLI skill ID "${id}" not found in catalog`);
assert.equal(skill!.category, "cli", `Skill "${id}" expected category cli, got ${skill!.category}`);
}
});
// ─── getSkillById ─────────────────────────────────────────────────────────────
test("getSkillById('omni-providers') returns the omni-providers entry", () => {
const skill = getSkillById("omni-providers");
assert.ok(skill, "Expected skill to be found");
assert.equal(skill!.id, "omni-providers");
assert.equal(skill!.category, "api");
assert.equal(skill!.area, "providers");
});
test("getSkillById('cli-serve') returns the cli-serve entry", () => {
const skill = getSkillById("cli-serve");
assert.ok(skill);
assert.equal(skill!.id, "cli-serve");
assert.equal(skill!.category, "cli");
assert.equal(skill!.isEntry, true);
});
test("getSkillById('omni-auth') returns entry with isEntry=true", () => {
const skill = getSkillById("omni-auth");
assert.ok(skill);
assert.equal(skill!.isEntry, true);
});
test("getSkillById('does-not-exist') returns null", () => {
const skill = getSkillById("does-not-exist");
assert.equal(skill, null);
});
test("getSkillById('') returns null", () => {
const skill = getSkillById("");
assert.equal(skill, null);
});
// ─── filterCatalog ────────────────────────────────────────────────────────────
test("filterCatalog({ category: 'api' }) returns 22 api skills", () => {
const skills = filterCatalog({ category: "api" });
assert.equal(skills.length, 22);
for (const s of skills) {
assert.equal(s.category, "api");
}
});
test("filterCatalog({ category: 'cli' }) returns 20 cli skills", () => {
const skills = filterCatalog({ category: "cli" });
assert.equal(skills.length, 20);
for (const s of skills) {
assert.equal(s.category, "cli");
}
});
test("filterCatalog({ area: 'providers' }) returns exactly omni-providers", () => {
const skills = filterCatalog({ area: "providers" });
assert.equal(skills.length, 1);
assert.equal(skills[0].id, "omni-providers");
});
test("filterCatalog({ category: 'api', area: 'mcp' }) returns omni-mcp", () => {
const skills = filterCatalog({ category: "api", area: "mcp" });
assert.equal(skills.length, 1);
assert.equal(skills[0].id, "omni-mcp");
});
test("filterCatalog({ area: 'nonexistent' }) returns empty array", () => {
const skills = filterCatalog({ area: "nonexistent" });
assert.equal(skills.length, 0);
});
test("filterCatalog({}) returns full catalog (42 entries)", () => {
const skills = filterCatalog({});
assert.equal(skills.length, 42);
});
// ─── refreshCatalog ───────────────────────────────────────────────────────────
test("refreshCatalog() causes getCatalog() to re-derive (returns fresh array)", () => {
const first = getCatalog();
refreshCatalog();
const second = getCatalog();
// Different array reference after refresh
assert.notEqual(first, second);
// But same content
assert.equal(first.length, second.length);
assert.equal(first[0].id, second[0].id);
});
// ─── computeCoverage ─────────────────────────────────────────────────────────
test("computeCoverage() returns valid SkillCoverage shape", () => {
const cov = computeCoverage();
assert.ok(typeof cov.api === "object");
assert.equal(cov.api.total, 22);
assert.ok(typeof cov.api.have === "number");
assert.ok(cov.api.have >= 0 && cov.api.have <= 22);
assert.ok(typeof cov.cli === "object");
assert.equal(cov.cli.total, 20);
assert.ok(typeof cov.cli.have === "number");
assert.ok(cov.cli.have >= 0 && cov.cli.have <= 20);
assert.equal(cov.totalSkills, cov.api.have + cov.cli.have);
// generatedAt must be a valid ISO datetime string
assert.ok(!isNaN(Date.parse(cov.generatedAt)), `generatedAt "${cov.generatedAt}" is not a valid ISO date`);
});
test("computeCoverage() api.have + cli.have = totalSkills", () => {
const cov = computeCoverage();
assert.equal(cov.totalSkills, cov.api.have + cov.cli.have);
});
// ─── Cache behaviour ─────────────────────────────────────────────────────────
test("getCatalog() returns the same array reference on repeated calls (cached)", () => {
refreshCatalog();
const first = getCatalog();
const second = getCatalog();
assert.strictEqual(first, second, "Expected same cached array reference");
});
// ─── Canonical IDs check ─────────────────────────────────────────────────────
test("API_SKILL_IDS first entry is omni-auth", () => {
assert.equal(API_SKILL_IDS[0], "omni-auth");
});
test("API_SKILL_IDS last entry is omni-inference", () => {
assert.equal(API_SKILL_IDS[API_SKILL_IDS.length - 1], "omni-inference");
});
test("CLI_SKILL_IDS first entry is cli-serve", () => {
assert.equal(CLI_SKILL_IDS[0], "cli-serve");
});
test("CLI_SKILL_IDS last entry is cli-setup", () => {
assert.equal(CLI_SKILL_IDS[CLI_SKILL_IDS.length - 1], "cli-setup");
});

View File

@@ -0,0 +1,304 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
// Dynamic import to pick up ESM module
const { parseCliRegistry, getCommandsForFamily } = await import(
"../../src/lib/agentSkills/cliRegistryParser.ts"
);
// ─── Fixture helpers ──────────────────────────────────────────────────────────
/**
* Creates a temporary directory mirroring bin/cli/commands/,
* writes fixture .mjs files, changes CWD, returns cleanup fn.
*/
function withFixtureCli(
files: Record<string, string>,
): { cleanup: () => void } {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-cli-test-"));
const commandsDir = path.join(tmpDir, "bin", "cli", "commands");
fs.mkdirSync(commandsDir, { recursive: true });
for (const [filename, content] of Object.entries(files)) {
fs.writeFileSync(path.join(commandsDir, filename), content, "utf-8");
}
const originalCwd = process.cwd();
process.chdir(tmpDir);
return {
cleanup() {
process.chdir(originalCwd);
fs.rmSync(tmpDir, { recursive: true, force: true });
},
};
}
// ─── Fixture content ──────────────────────────────────────────────────────────
const FIXTURE_PROVIDERS_MJS = `
export function registerProviders(program) {
const providers = program.command('providers').description('Manage provider connections');
providers
.command('list')
.description('List configured provider connections')
.option('--json', 'Print machine-readable JSON')
.action(async (opts) => {});
providers
.command('available')
.description('Show available providers in the catalog')
.option('--search <query>', 'Filter by id or name')
.option('--category <category>', 'Filter by category')
.action(async (opts) => {});
providers
.command('test <idOrName>')
.description('Test a configured provider connection')
.action(async (idOrName, opts) => {});
providers
.command('test-all')
.description('Test all active provider connections')
.action(async (opts) => {});
providers
.command('validate')
.description('Validate local provider configuration')
.action(async (opts) => {});
providers
.command('rotate <idOrName>')
.description('Rotate API key for a provider connection')
.option('--new-key <key>', 'New API key value')
.option('--dry-run', 'Preview without writing')
.action(async (idOrName, opts) => {});
providers
.command('status')
.description('Show provider connection status and expiry')
.option('--json', 'JSON output')
.action(async (opts) => {});
}
`;
const FIXTURE_HEALTH_MJS = `
export function registerHealth(program) {
const health = program
.command('health')
.description('Check server health status')
.option('-v, --verbose', 'Show extended info')
.option('--json', 'Output as JSON')
.action(async (opts) => {});
health
.command('components')
.description('List health components and status')
.action(async (opts) => {});
health
.command('watch')
.description('Live dashboard — refresh every N seconds')
.option('--interval <s>', 'Refresh interval in seconds')
.action(async (opts) => {});
}
`;
const FIXTURE_KEYS_MJS = `
export function registerKeys(program) {
const keys = program.command('keys').description('Manage OmniRoute API keys');
keys
.command('list')
.description('List all API keys')
.option('--json', 'JSON output')
.action(async (opts) => {});
keys
.command('create')
.description('Create a new API key')
.option('--name <name>', 'Key name')
.action(async (opts) => {});
keys
.command('revoke <id>')
.description('Revoke an API key')
.action(async (id, opts) => {});
}
`;
// ─── Tests ────────────────────────────────────────────────────────────────────
test("parseCliRegistry() returns commands Map and families Map", () => {
const { cleanup } = withFixtureCli({
"providers.mjs": FIXTURE_PROVIDERS_MJS,
"health.mjs": FIXTURE_HEALTH_MJS,
});
try {
const result = parseCliRegistry();
assert.ok(result.commands instanceof Map, "commands should be a Map");
assert.ok(result.families instanceof Map, "families should be a Map");
assert.ok(result.commands.size > 0, "commands should not be empty");
assert.ok(result.families.size > 0, "families should not be empty");
} finally {
cleanup();
}
});
test("parseCliRegistry() recognises providers family with ≥5 subcommands", () => {
const { cleanup } = withFixtureCli({
"providers.mjs": FIXTURE_PROVIDERS_MJS,
});
try {
const { families } = parseCliRegistry();
const providerCmds = families.get("cli-providers");
assert.ok(providerCmds, "Expected 'cli-providers' family to exist");
assert.ok(
providerCmds!.length >= 5,
`Expected ≥5 provider commands, got ${providerCmds!.length}: ${providerCmds!.map((c) => c.name).join(", ")}`,
);
} finally {
cleanup();
}
});
test("parseCliRegistry() recognises health family commands", () => {
const { cleanup } = withFixtureCli({
"health.mjs": FIXTURE_HEALTH_MJS,
});
try {
const { families } = parseCliRegistry();
const healthCmds = families.get("cli-health");
assert.ok(healthCmds, "Expected 'cli-health' family to exist");
assert.ok(
healthCmds!.length >= 2,
`Expected ≥2 health commands, got ${healthCmds!.length}`,
);
} finally {
cleanup();
}
});
test("parseCliRegistry() extracts description for each command", () => {
const { cleanup } = withFixtureCli({
"providers.mjs": FIXTURE_PROVIDERS_MJS,
"keys.mjs": FIXTURE_KEYS_MJS,
});
try {
const { commands } = parseCliRegistry();
// Top-level providers command should have description
const providers = [...commands.values()].find((c) => c.name === "providers");
assert.ok(providers, "Expected providers command");
assert.ok(
providers!.description.length > 0,
`Expected non-empty description for providers, got: "${providers!.description}"`,
);
} finally {
cleanup();
}
});
test("parseCliRegistry() marks subcommands with isSubcommand=true (after first)", () => {
const { cleanup } = withFixtureCli({
"providers.mjs": FIXTURE_PROVIDERS_MJS,
});
try {
const { families } = parseCliRegistry();
const providerCmds = families.get("cli-providers")!;
// After the first (top-level) entry, rest should be subcommands
const subCmds = providerCmds.filter((c) => c.isSubcommand);
assert.ok(
subCmds.length >= 4,
`Expected ≥4 subcommands (list, available, test, etc.), got ${subCmds.length}`,
);
} finally {
cleanup();
}
});
test("parseCliRegistry() extracts flags from .option() calls", () => {
const { cleanup } = withFixtureCli({
"providers.mjs": FIXTURE_PROVIDERS_MJS,
});
try {
const { commands } = parseCliRegistry();
// Find a command that has options
const rotate = [...commands.values()].find((c) => c.name.includes("rotate"));
// Flags might be present if parsing found them
if (rotate) {
// If rotate exists and has flags, verify format
for (const flag of rotate.flags) {
assert.ok(
typeof flag === "string" && flag.length > 0,
`Invalid flag: "${flag}"`,
);
}
}
} finally {
cleanup();
}
});
test("parseCliRegistry() skips unrecognised .mjs files", () => {
const { cleanup } = withFixtureCli({
"unknown-custom.mjs": `export function register(p) {}`,
"providers.mjs": FIXTURE_PROVIDERS_MJS,
});
try {
const { families } = parseCliRegistry();
// No family should be mapped from unknown-custom
const hasUnknown = [...families.keys()].some((k) =>
String(k).includes("unknown-custom"),
);
assert.equal(hasUnknown, false, "unknown-custom.mjs should not create a family");
// providers.mjs should still be parsed
assert.ok(families.has("cli-providers"), "Expected cli-providers family from providers.mjs");
} finally {
cleanup();
}
});
test("parseCliRegistry() throws if commands directory is missing", () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-cli-missing-"));
const originalCwd = process.cwd();
process.chdir(tmpDir);
try {
assert.throws(
() => parseCliRegistry(),
/cliRegistryParser: could not read/,
"Expected error when commands dir is missing",
);
} finally {
process.chdir(originalCwd);
fs.rmSync(tmpDir, { recursive: true, force: true });
}
});
// ─── Integration test: real providers.mjs (always runs — it's in the repo) ───
test("parseCliRegistry() with real providers.mjs: providers family has ≥5 commands", () => {
// This test uses the actual project files (not a fixture).
// We rely on the CWD being the worktree root during `npm run test:unit`.
const result = parseCliRegistry();
const providerCmds = result.families.get("cli-providers");
assert.ok(providerCmds, "Expected cli-providers family from real providers.mjs");
assert.ok(
providerCmds!.length >= 5,
`Expected ≥5 real provider commands, got ${providerCmds!.length}: ${providerCmds!.map((c) => c.name).join(", ")}`,
);
});
test("getCommandsForFamily('cli-providers') with real files: returns ≥5 strings", () => {
const commands = getCommandsForFamily("cli-providers");
assert.ok(
commands.length >= 5,
`Expected ≥5 cli-providers commands, got ${commands.length}`,
);
for (const cmd of commands) {
assert.ok(typeof cmd === "string" && cmd.length > 0, `Invalid command name: "${cmd}"`);
}
});

View File

@@ -0,0 +1,247 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
// Dynamic import to pick up ESM module
const { parseOpenapi, getEndpointsForArea } = await import("../../src/lib/agentSkills/openapiParser.ts");
// ─── Fixture helpers ──────────────────────────────────────────────────────────
/**
* Creates a temporary directory with a minimal openapi.yaml fixture,
* changes CWD to it, and returns a cleanup function.
*/
function withFixtureOpenapi(yamlContent: string): { cleanup: () => void } {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-openapi-test-"));
const docsDir = path.join(tmpDir, "docs", "reference");
fs.mkdirSync(docsDir, { recursive: true });
fs.writeFileSync(path.join(docsDir, "openapi.yaml"), yamlContent, "utf-8");
const originalCwd = process.cwd();
process.chdir(tmpDir);
return {
cleanup() {
process.chdir(originalCwd);
fs.rmSync(tmpDir, { recursive: true, force: true });
},
};
}
// ─── Fixture YAML ─────────────────────────────────────────────────────────────
const FIXTURE_YAML = `
openapi: 3.1.0
info:
title: OmniRoute Test
version: 1.0.0
paths:
/api/providers:
get:
tags: [Providers]
summary: List provider connections
description: Returns all configured provider connections.
post:
tags: [Providers]
summary: Add provider connection
/api/providers/{id}:
get:
tags: [Providers]
summary: Get provider by id
patch:
tags: [Providers]
summary: Update provider connection
delete:
tags: [Providers]
summary: Remove provider connection
/api/providers/{id}/test:
post:
tags: [Providers]
summary: Test provider connection
/api/keys:
get:
tags: [APIKeys]
summary: List API keys
post:
tags: [APIKeys]
summary: Create API key
/api/keys/{id}:
delete:
tags: [APIKeys]
summary: Revoke API key
/api/usage/analytics:
get:
tags: [Usage]
summary: Get usage analytics
/api/v1/chat/completions:
post:
tags: [Chat]
summary: Create chat completion
/api/settings:
get:
tags: [Settings]
summary: Get settings
put:
tags: [Settings]
summary: Update settings
`;
// ─── Tests using fixture ──────────────────────────────────────────────────────
test("parseOpenapi() returns paths Map with all operations from fixture", () => {
const { cleanup } = withFixtureOpenapi(FIXTURE_YAML);
try {
const { paths } = parseOpenapi();
assert.ok(paths instanceof Map, "paths should be a Map");
assert.ok(paths.size > 0, "paths should not be empty");
// Spot-check a few keys
assert.ok(paths.has("GET /api/providers"), "Expected GET /api/providers");
assert.ok(paths.has("POST /api/providers"), "Expected POST /api/providers");
assert.ok(paths.has("GET /api/providers/{id}"), "Expected GET /api/providers/{id}");
assert.ok(paths.has("DELETE /api/providers/{id}"), "Expected DELETE /api/providers/{id}");
assert.ok(paths.has("POST /api/v1/chat/completions"), "Expected POST /api/v1/chat/completions");
} finally {
cleanup();
}
});
test("parseOpenapi() groups /api/providers/* under 'providers' area", () => {
const { cleanup } = withFixtureOpenapi(FIXTURE_YAML);
try {
const { areas } = parseOpenapi();
const providerOps = areas.get("providers");
assert.ok(providerOps, "Expected 'providers' area to exist");
assert.ok(
providerOps!.length >= 5,
`Expected at least 5 provider endpoints, got ${providerOps!.length}`,
);
const paths = providerOps!.map((op) => op.path);
assert.ok(paths.includes("/api/providers"), "Expected /api/providers");
assert.ok(paths.includes("/api/providers/{id}"), "Expected /api/providers/{id}");
assert.ok(paths.includes("/api/providers/{id}/test"), "Expected /api/providers/{id}/test");
} finally {
cleanup();
}
});
test("parseOpenapi() groups /api/keys/* under 'api-keys' area", () => {
const { cleanup } = withFixtureOpenapi(FIXTURE_YAML);
try {
const { areas } = parseOpenapi();
const keyOps = areas.get("api-keys");
assert.ok(keyOps, "Expected 'api-keys' area to exist");
assert.ok(keyOps!.length >= 2, `Expected at least 2 key endpoints, got ${keyOps!.length}`);
} finally {
cleanup();
}
});
test("parseOpenapi() groups /api/v1/* under 'inference' area", () => {
const { cleanup } = withFixtureOpenapi(FIXTURE_YAML);
try {
const { areas } = parseOpenapi();
const inferenceOps = areas.get("inference");
assert.ok(inferenceOps, "Expected 'inference' area to exist");
assert.ok(
inferenceOps!.length >= 1,
`Expected at least 1 inference endpoint, got ${inferenceOps!.length}`,
);
assert.ok(
inferenceOps!.some((op) => op.path === "/api/v1/chat/completions"),
"Expected /api/v1/chat/completions in inference area",
);
} finally {
cleanup();
}
});
test("parseOpenapi() OpenapiPath entries have required fields", () => {
const { cleanup } = withFixtureOpenapi(FIXTURE_YAML);
try {
const { paths } = parseOpenapi();
for (const [key, op] of paths) {
assert.ok(typeof op.method === "string" && op.method.length > 0, `${key}: method missing`);
assert.ok(typeof op.path === "string" && op.path.length > 0, `${key}: path missing`);
assert.ok(typeof op.summary === "string", `${key}: summary not a string`);
assert.ok(Array.isArray(op.tags), `${key}: tags not an array`);
}
} finally {
cleanup();
}
});
test("parseOpenapi() throws if openapi.yaml is missing", () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "omni-openapi-missing-"));
const originalCwd = process.cwd();
process.chdir(tmpDir);
try {
assert.throws(
() => parseOpenapi(),
/openapiParser: could not read/,
"Expected error when openapi.yaml is missing",
);
} finally {
process.chdir(originalCwd);
fs.rmSync(tmpDir, { recursive: true, force: true });
}
});
test("parseOpenapi() returns empty areas Map for YAML with no paths", () => {
const emptyPathsYaml = `
openapi: 3.1.0
info:
title: Empty
version: 1.0.0
paths: {}
`;
const { cleanup } = withFixtureOpenapi(emptyPathsYaml);
try {
const { paths, areas } = parseOpenapi();
assert.equal(paths.size, 0);
assert.equal(areas.size, 0);
} finally {
cleanup();
}
});
// ─── Integration test: real openapi.yaml (gated) ─────────────────────────────
const SKIP_REAL = process.env.SKIP_REAL_OPENAPI === "1";
test(
"parseOpenapi() with real openapi.yaml: providers area has ≥5 endpoints",
{ skip: SKIP_REAL ? "SKIP_REAL_OPENAPI=1" : false },
() => {
// This test runs from the project root (the worktree).
// It will fail if openapi.yaml doesn't exist — that's intentional.
const { areas } = parseOpenapi();
const providerOps = areas.get("providers");
assert.ok(providerOps, "Expected 'providers' area in real OpenAPI spec");
assert.ok(
providerOps!.length >= 5,
`Expected ≥5 provider endpoints in real spec, got ${providerOps!.length}`,
);
},
);
test(
"getEndpointsForArea('providers') with real openapi.yaml: returns ≥5 strings",
{ skip: SKIP_REAL ? "SKIP_REAL_OPENAPI=1" : false },
() => {
const endpoints = getEndpointsForArea("providers");
assert.ok(
endpoints.length >= 5,
`Expected ≥5 provider endpoint strings, got ${endpoints.length}: ${endpoints.join(", ")}`,
);
// Each entry should match "METHOD /path"
for (const ep of endpoints) {
assert.match(ep, /^[A-Z]+ \//, `Endpoint "${ep}" does not match METHOD /path format`);
}
},
);