Files
return-youtube-dislike/Extensions/UserScript/live/live-full-run-contract.spec.js
T
Anarios e500088e65 Prepare 4.0.5 Firefox update and Shorts fixes
Add Firefox data consent, repair contributor sign-in, and introduce optional Hide clutter buttons. Harden video navigation, voting, and action layouts with shared browser regression coverage and reproducible release packaging.
2026-09-06 12:51:12 +02:00

138 lines
5.5 KiB
JavaScript

/**
* @jest-environment node
*/
const fs = require("node:fs");
const path = require("node:path");
const packageManifest = require("../../../package.json");
const {
LiveValidationIncompleteError,
REQUIRED_PRODUCTION_REACTION_SCENARIOS,
assertFullLiveReactionCompletion,
buildLiveRuntimeArtifact,
readFullLiveRuntime,
requireProductionReactionApproval,
requireUserscriptInstallAcknowledgement,
} = require("../e2e/live/live-full-run-contract");
test.each(["extension", "userscript"])("selects and builds the exact %s live runtime before a full run", (runtime) => {
const spawnSyncImpl = jest.fn(() => ({ status: 0 }));
const environment = { npm_execpath: "C:\\node\\node_modules\\npm\\bin\\npm-cli.js", RYD_LIVE_RUNTIME: runtime };
expect(readFullLiveRuntime(environment)).toBe(runtime);
expect(
buildLiveRuntimeArtifact(runtime, {
environment,
nodeExecutable: "C:\\node\\node.exe",
platform: "win32",
repositoryRoot: "repository",
spawnSyncImpl,
}),
).toEqual({ runtime, script: `build:live:${runtime}` });
expect(spawnSyncImpl).toHaveBeenCalledWith(
"C:\\node\\node.exe",
["C:\\node\\node_modules\\npm\\bin\\npm-cli.js", "run", `build:live:${runtime}`],
{
cwd: "repository",
env: environment,
stdio: "inherit",
},
);
});
test("uses a Windows command shell only when the npm CLI path is unavailable", () => {
const spawnSyncImpl = jest.fn(() => ({ status: 0 }));
const environment = { RYD_LIVE_RUNTIME: "extension" };
buildLiveRuntimeArtifact("extension", {
environment,
platform: "win32",
repositoryRoot: "repository",
spawnSyncImpl,
});
expect(spawnSyncImpl).toHaveBeenCalledWith("npm.cmd", ["run", "build:live:extension"], {
cwd: "repository",
env: environment,
shell: true,
stdio: "inherit",
});
});
test("a failed live build prevents the full runner from continuing", () => {
expect(() =>
buildLiveRuntimeArtifact("extension", {
spawnSyncImpl: () => ({ status: 2 }),
}),
).toThrow("build:live:extension failed with exit code 2");
});
test.each([undefined, "", "browser"])("rejects unsupported full-live runtime %p", (runtime) => {
expect(() => readFullLiveRuntime({ RYD_LIVE_RUNTIME: runtime })).toThrow(/RYD_LIVE_RUNTIME/);
});
test("classifies only both completed production reaction scenarios as a full run", () => {
expect(REQUIRED_PRODUCTION_REACTION_SCENARIOS).toEqual(["post-navigation-vote", "reaction-matrix"]);
expect(
assertFullLiveReactionCompletion({
"post-navigation-vote": { videoId: "abcdefghijk" },
"reaction-matrix": [{ action: "like" }],
}),
).toEqual({
classification: "full",
completedScenarioIds: REQUIRED_PRODUCTION_REACTION_SCENARIOS,
productionReactionsCompleted: true,
releaseReady: true,
});
});
test.each([
[null, /no production reaction results/],
[{}, /post-navigation-vote, reaction-matrix/],
[{ "post-navigation-vote": {} }, /reaction-matrix/],
[{ "reaction-matrix": [] }, /post-navigation-vote/],
[{ "post-navigation-vote": null, "reaction-matrix": {} }, /post-navigation-vote/],
])("rejects incomplete full-live reaction results %#", (results, message) => {
expect(() => assertFullLiveReactionCompletion(results)).toThrow(message);
});
test("SKIP is an explicit incomplete failure, not a successful full run", () => {
expect(() => requireProductionReactionApproval("SKIP")).toThrow(LiveValidationIncompleteError);
expect(() => requireProductionReactionApproval(" skip ")).toThrow(/production reaction scenarios were skipped/);
expect(requireProductionReactionApproval("extension:abcdefghijk:123")).toBe("extension:abcdefghijk:123");
});
test("a freshly built userscript requires an explicit installation acknowledgement", () => {
expect(requireUserscriptInstallAcknowledgement("INSTALLED")).toBe(true);
expect(() => requireUserscriptInstallAcknowledgement("SKIP")).toThrow(LiveValidationIncompleteError);
expect(() => requireUserscriptInstallAcknowledgement("")).toThrow(/not acknowledged as installed/);
});
test("package commands distinguish full reaction validation from the read-only Playwright suite", () => {
expect(packageManifest.scripts["test:live:youtube"]).toBe(
"node Extensions/UserScript/e2e/live/live-interactive-runner.js",
);
expect(packageManifest.scripts["test:live:youtube:full"]).toBe("npm run test:live:youtube");
expect(packageManifest.scripts["test:live:youtube:interactive"]).toBe("npm run test:live:youtube");
expect(packageManifest.scripts["test:live:youtube:read-only"]).toBe(
"playwright test --config playwright.live-youtube.config.js",
);
});
test("the read-only Playwright suite cannot silently register a skipped reaction test", () => {
const source = fs.readFileSync(path.resolve(__dirname, "../e2e/live/live-youtube.live.e2e.js"), "utf8");
expect(source).toContain('test.describe("live YouTube RYD read-only smoke"');
expect(source).not.toMatch(/\btest\.skip\s*\(/);
expect(source).not.toContain("reaction-matrix");
expect(source).not.toContain("post-navigation-vote");
expect(source).toContain("LIVE_VALIDATION_READ_ONLY_COMPLETE");
expect(source).toContain("releaseReady: false");
});
test("standalone artifact runners verify current source before consuming existing output", () => {
expect(packageManifest.scripts["test:e2e:userscript:run"]).toMatch(/^npm run check:userscript-artifact && /);
expect(packageManifest.scripts["test:e2e:artifacts"]).toMatch(
/^npm run check:extension-artifact && npm run check:userscript-artifact && /,
);
});