← Files DataARCHIVED FILE
tests/plugin-config.test.mjs
7.38 KB · Sep 30, 2026 · 23:19 UTC
import assert from "node:assert/strict";
import { existsSync, readFileSync } from "node:fs";
import { test } from "node:test";
const readJson = (path) => JSON.parse(readFileSync(new URL(path, import.meta.url), "utf8"));
test("plugin release metadata remains synchronized", () => {
const plugin = readJson("../.codex-plugin/plugin.json");
const pluginPackage = readJson("../package.json");
const packageLock = readJson("../package-lock.json");
assert.equal(pluginPackage.version, plugin.version);
assert.equal(packageLock.version, plugin.version);
assert.equal(packageLock.packages[""].version, plugin.version);
});
test("the root test environment declares React for nested Data app tests", () => {
const pluginPackage = readJson("../package.json");
const packageLock = readJson("../package-lock.json");
const reactVersion = pluginPackage.devDependencies.react;
const lockedReact = packageLock.packages["node_modules/react"];
assert.equal(reactVersion, "^19.2.3");
assert.equal(packageLock.packages[""].devDependencies.react, reactVersion);
assert.ok(lockedReact);
assert.match(lockedReact.resolved, /^https:\/\/registry\.npmjs\.org\/react\/-\/react-[^/]+\.tgz$/u);
assert.equal(pluginPackage.dependencies?.react, undefined);
});
test("plugin dependencies preserve optional installation and categorized provider identities", () => {
const plugin = readJson("../.codex-plugin/plugin.json");
const dependencies = plugin.extensions["com.openai"].dependencies;
const identities = new Set();
assert.equal(plugin.apps, undefined, "Dependency resolution must not rely on the legacy app mapping");
assert.ok(Array.isArray(dependencies) && dependencies.length > 0);
for (const dependency of dependencies) {
assert.equal(dependency.isRequired, false, "Missing integrations must not prevent installing Data");
assert.match(dependency.name, /^[A-Za-z0-9][A-Za-z0-9._-]*$/u);
assert.match(dependency.marketplace, /^[A-Za-z0-9][A-Za-z0-9._-]*$/u);
const identity = `${dependency.name.toLowerCase()}@${dependency.marketplace}`;
assert.equal(identities.has(identity), false, `Duplicate provider identity: ${identity}`);
identities.add(identity);
assert.ok(Array.isArray(dependency.categories) && dependency.categories.length > 0);
assert.equal(new Set(dependency.categories).size, dependency.categories.length);
for (const category of dependency.categories) {
assert.equal(typeof category, "string");
assert.ok(category.length > 0 && category === category.trim());
assert.doesNotMatch(category, /[\u0000-\u001f\u007f-\u009f]/u);
}
}
});
test("the bundled demo is a well-formed seven-column CSV", () => {
const rows = readFileSync(new URL("../assets/demo-product-growth.csv", import.meta.url), "utf8")
.trim()
.split(/\r?\n/u);
assert.equal(
rows[0],
"week_start,acquisition_channel,signups,activated_users,paid_conversions,revenue_usd,support_tickets",
);
assert.ok(rows.length > 1);
assert.ok(rows.every((row) => row.split(",").length === 7));
});
test("dashboard and report surfaces ship the shared Data app runtime", () => {
const pluginPackage = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
assert.equal(existsSync(new URL("../templates/data-app/base/src/App.jsx", import.meta.url)), true);
assert.equal(existsSync(new URL("../templates/data-app/base/src/DataAppShell.jsx", import.meta.url)), true);
assert.equal(
existsSync(new URL("../templates/data-app/base/src/content/dashboard/DashboardContent.jsx", import.meta.url)),
true,
);
assert.equal(
existsSync(new URL("../templates/data-app/base/src/content/report/ReportContent.jsx", import.meta.url)),
true,
);
assert.equal(existsSync(new URL("../templates/data-app/base/AGENTS.md", import.meta.url)), true);
assert.equal(existsSync(new URL("../templates/data-app/base/src/data-app-public.jsx", import.meta.url)), true);
assert.equal(existsSync(new URL("../templates/data-app/base/protected-runtime.json", import.meta.url)), true);
assert.match(
pluginPackage.scripts.test,
/templates\/data-app\/base\/tests\/\*\.test\.mjs/u,
"The ordinary plugin test command must include protected starter and integrity coverage",
);
assert.equal(existsSync(new URL("../skills/build-dashboard/templates/base/package.json", import.meta.url)), false);
assert.equal(existsSync(new URL("../skills/build-report/templates/base/package.json", import.meta.url)), false);
});
test("report documents use a neutral fallback preset and preserve supplied templates", () => {
const documentSkill = readFileSync(new URL("../skills/convert-to-doc/SKILL.md", import.meta.url), "utf8");
assert.match(documentSkill, /If strong candidates exist in memory or user context, suggest them and include a link/u);
assert.match(documentSkill, /If none exist, use the Documents plugin's built-in `google_docs_default` preset/u);
assert.match(
documentSkill,
/Only create a cover page, title page, or introductory page if the selected template includes one/u,
);
assert.match(documentSkill, /preserve its layout and formatting/u);
assert.match(documentSkill, /delete unused sections only when the document is complete/u);
});
test("document and slide exports reuse local or hosted Data apps and build a requested source when needed", () => {
const documentSkill = readFileSync(new URL("../skills/convert-to-doc/SKILL.md", import.meta.url), "utf8");
const slidesSkill = readFileSync(new URL("../skills/convert-to-slides/SKILL.md", import.meta.url), "utf8");
const routingSkill = readFileSync(new URL("../skills/index/SKILL.md", import.meta.url), "utf8");
const appActions = readFileSync(
new URL("../templates/data-app/base/src/data-app-actions.js", import.meta.url),
"utf8",
);
for (const skill of [documentSkill, slidesSkill]) {
assert.match(skill, /For a local app, use its `dist\/index\.html` and `src\/data\.json` directly/u);
assert.match(skill, /reviewed snapshot from `\/api\/snapshot`/u);
assert.match(skill, /saved presentation state from `\/api\/presentation`/u);
assert.match(skill, /Reject other remote sources/u);
assert.match(skill, /Do not create an intermediate report or rebuild the app/u);
assert.doesNotMatch(skill, /\$build-report/u);
}
for (const name of ["convert-to-doc", "convert-to-slides"]) {
const qualifiedName = `data-analytics:${name}`;
const route = routingSkill.split(`### ${name}\n`)[1]?.split("\n### ")[0];
assert.ok(route, `Missing ${name} route`);
assert.match(route, /when an existing Data app is identified/u);
assert.match(route, /If no Data app exists, ask the user to choose whether to build a dashboard or a report/u);
assert.match(route, /invoke \$build-dashboard or \$build-report for that choice/u);
assert.match(route, new RegExp(`invoke \\$${qualifiedName} once the chosen app is built and verified`, "u"));
assert.match(appActions, new RegExp(`\\$${qualifiedName}`, "u"));
}
assert.doesNotMatch([routingSkill, appActions].join("\n"), /report-to-(?:doc|slides)/u);
});
test("the Data app uses reviewed data for its document title", () => {
const html = readFileSync(new URL("../templates/data-app/base/index.html", import.meta.url), "utf8");
const main = readFileSync(new URL("../templates/data-app/base/src/main.jsx", import.meta.url), "utf8");
assert.match(html, /<title>Data app<\/title>/u);
assert.match(main, /document\.title = reviewedSnapshot\.title/u);
});
SHA-256: 785d84902b4ed5a3ac595b3def2fce0a8ac3aa66ecfe852afab39adb7b344876