Files
opportunities-extension/tests/architecture.test.cjs

82 lines
4.5 KiB
JavaScript

const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const vm = require("node:vm");
const { createHash } = require("node:crypto");
const { test } = require("node:test");
const { sources, vendorSources, composeScript } = require("../scripts/compose.cjs");
const { loadApplication } = require("./support/application.cjs");
const root = path.resolve(__dirname, "..");
const read = file => fs.readFileSync(path.join(root, file), "utf8");
const json = value => JSON.parse(JSON.stringify(value));
test("every source belongs to an explicit runtime composition, with no duplicate factories", () => {
const actual = fs.readdirSync(path.join(root, "src"), { recursive: true })
.filter(file => file.endsWith(".js")).map(file => `src/${file.replaceAll(path.sep, "/")}`).sort();
assert.deepEqual([...new Set([...Object.values(sources).flat(), ...Object.values(vendorSources).flat()])].sort(), actual);
for (const files of Object.values(vendorSources)) {
for (const file of files) {
assert.doesNotThrow(() => new vm.Script(read(file)));
assert.doesNotMatch(read(file), /\beval\s*\(|\bnew\s+Function\s*\(/, file);
}
}
for (const [target, files] of Object.entries(sources)) {
assert.equal(new Set(files).size, files.length);
const factories = files.flatMap(file => [...read(file).matchAll(/^function (\w+)\(/gm)].map(match => match[1]));
assert.equal(new Set(factories).size, factories.length, target);
assert.equal(composeScript(target), composeScript(target));
assert.doesNotThrow(() => new vm.Script(composeScript(target)));
for (const file of files) {
const source = read(file);
assert.doesNotMatch(source, /\beval\s*\(|\bnew\s+Function\s*\(|\bimportScripts\s*\(|\brequire\s*\(|^\s*(?:import|export)\s/m, file);
if (file.endsWith("/application.js") || file.endsWith("/main.js")) continue;
const declaration = source.match(/^function (\w+)\(/m)[1];
for (const factory of factories.filter(name => name !== declaration)) {
assert.doesNotMatch(source, new RegExp(`\\b${factory}\\s*\\(`), `${file} must receive dependencies, not construct ${factory}`);
}
}
}
assert.deepEqual(sources.content.filter(file => sources.background.includes(file)), ["src/shared/time-dates.js", "src/shared/messages.js", "src/shared/debug-body.js"]);
});
test("Redwood cascade is byte-identical to the characterized original", () => {
const hash = createHash("sha256").update(read("src/content/styles/redwood.css")).digest("hex");
assert.equal(hash, "eaeb7e53757d48a3095f9111c5029d2c923d0dcab92af23454ccd14bdcfc81c4");
});
test("fiscal module can run alone without DOM, browser APIs or network", () => {
const factory = new vm.Script(`${read("src/features/opportunities/fiscal-periods.js")}\ncreateOpportunitiesFiscalPeriods;`).runInNewContext();
assert.deepEqual(json(factory().getFiscalPeriodRange("Current Fiscal Year", new Date(2027, 0, 15))), {
startCloseDate: "2026-06-01T00:00:00.000Z", endCloseDate: "2027-06-01T00:00:00.000Z"
});
});
test("per-frame state and credentials do not leak between application instances", () => {
const a = loadApplication("content");
const b = loadApplication("content");
for (const key of Object.keys(a).filter(key => key.endsWith("State"))) assert.notEqual(a[key], b[key], key);
a.authSessionState.accessToken = "synthetic-general";
a.authSalesCommonState.salesCommonToken = { access_token: "synthetic-scoped", expiresAt: 123 };
a.productsContentState.opptyProductsByNumber.set("TEST", { items: [] });
a.aiSummaryState.aiSummariesByOptyNumber.set("TEST", { summaryText: "Synthetic" });
assert.equal(b.authSessionState.accessToken, "");
assert.equal(b.authSalesCommonState.salesCommonToken, null);
assert.equal(b.productsContentState.opptyProductsByNumber.size, 0);
assert.equal(b.aiSummaryState.aiSummariesByOptyNumber.size, 0);
});
test("blocked localStorage access remains lazy and handled by preference fallbacks", () => {
const context = {};
Object.defineProperty(context, "localStorage", { get() { throw new Error("Storage blocked"); } });
const app = loadApplication("content", context);
assert.doesNotThrow(() => app.preferencesStorage.getSavedOpportunityTypeValues());
assert.equal(app.preferencesStorage.getSavedOpptyProductsCacheHours(), 24);
});
test("visual fixtures load modules without eval or rewriting source markers", () => {
for (const file of ["tests/fixtures/consumption-trend.html", "tests/fixtures/extension.js"]) {
assert.doesNotMatch(read(file), /\beval\s*\(|testableSource|src\/content\.js/);
}
});