mirror of
https://github.com/Alvin-Zilverstand/return-youtube-dislike.git
synced 2026-09-13 02:14:43 +02:00
e500088e65
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.
117 lines
4.7 KiB
JavaScript
117 lines
4.7 KiB
JavaScript
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
const { test, expect } = require("@playwright/test");
|
|
const {
|
|
CREDENTIAL_KEY,
|
|
VIDEO_A,
|
|
createFakeBackend,
|
|
injectGeneratedUserscript,
|
|
installGmEnvironment,
|
|
installHermeticRoutes,
|
|
openWatchFixture,
|
|
} = require("./harness");
|
|
const {
|
|
USERSCRIPT_WATCH_VISUAL_PROFILE,
|
|
attachVisualFailureScreenshot,
|
|
expectNoStructuralLayoutShift,
|
|
expectWatchVisualState,
|
|
readWatchVisualContract,
|
|
waitForBarRatio,
|
|
} = require("../../e2e/watch-visual-contract");
|
|
const { getWatchNeutralBaselineId, registerWatchVisualContract } = require("../../e2e/watch-visual-scenarios");
|
|
const { annotateVisualEvidence, captureOptionalVisualEvidence } = require("../../e2e/visual-evidence");
|
|
|
|
const REPOSITORY_ROOT = path.resolve(__dirname, "../../..");
|
|
const VISUAL_REVIEW_DIRECTORY = path.join(REPOSITORY_ROOT, "test-results", "visual-review", "userscript");
|
|
const EXISTING_CREDENTIALS = {
|
|
userId: "ExistingUserscriptCredential000000000001",
|
|
registrationConfirmed: true,
|
|
};
|
|
const BASE_COUNTS = { likes: 300, dislikes: 100 };
|
|
|
|
async function captureVisualReview(page, name) {
|
|
const outputPath = path.join(VISUAL_REVIEW_DIRECTORY, `${name}.png`);
|
|
return captureOptionalVisualEvidence({
|
|
capture: async (screenshotPath) => {
|
|
fs.mkdirSync(VISUAL_REVIEW_DIRECTORY, { recursive: true });
|
|
await page.locator("#top-row").screenshot({
|
|
animations: "disabled",
|
|
path: screenshotPath,
|
|
});
|
|
},
|
|
outputPath,
|
|
});
|
|
}
|
|
|
|
function monitorRuntime(page) {
|
|
const consoleErrors = [];
|
|
const pageErrors = [];
|
|
page.on("console", (message) => {
|
|
if (message.type() === "error") consoleErrors.push(message.text());
|
|
});
|
|
page.on("pageerror", (error) => pageErrors.push(error.message));
|
|
return { consoleErrors, pageErrors };
|
|
}
|
|
|
|
async function launchVisualFixture({ context, page }, initialState) {
|
|
const runtime = monitorRuntime(page);
|
|
const backend = createFakeBackend({
|
|
countsByVideo: { [VIDEO_A]: BASE_COUNTS },
|
|
fixture: { initialState },
|
|
});
|
|
await installGmEnvironment(context, { [CREDENTIAL_KEY]: EXISTING_CREDENTIALS });
|
|
await installHermeticRoutes(context, backend);
|
|
await openWatchFixture(page, VIDEO_A);
|
|
await injectGeneratedUserscript(page);
|
|
|
|
await expect(page.locator('[data-ryd-role="dislike"] #text')).toHaveText(String(BASE_COUNTS.dislikes));
|
|
await expect(page.locator(USERSCRIPT_WATCH_VISUAL_PROFILE.container)).toBeVisible();
|
|
return { backend, ...runtime };
|
|
}
|
|
|
|
registerWatchVisualContract({
|
|
runtime: "userscript",
|
|
test,
|
|
async runScenario({ fixtures: { context, page }, scenario, testInfo }) {
|
|
const { transition, viewport } = scenario;
|
|
await page.setViewportSize({ width: viewport.width, height: viewport.height });
|
|
try {
|
|
const harness = await launchVisualFixture({ context, page }, transition.initialState);
|
|
const before = await readWatchVisualContract(page, USERSCRIPT_WATCH_VISUAL_PROFILE);
|
|
expectWatchVisualState(before, transition.initialState, BASE_COUNTS, viewport, USERSCRIPT_WATCH_VISUAL_PROFILE);
|
|
const neutralBaselineId = getWatchNeutralBaselineId(scenario);
|
|
if (neutralBaselineId) {
|
|
annotateVisualEvidence(testInfo, await captureVisualReview(page, neutralBaselineId));
|
|
}
|
|
|
|
await page.locator(`[data-ryd-role="${transition.action}"] button`).click();
|
|
await expect.poll(() => harness.backend.requestsFor("POST", "/interact/confirmVote").length).toBe(1);
|
|
|
|
const nextCounts = {
|
|
likes: BASE_COUNTS.likes + transition.likesDelta,
|
|
dislikes: BASE_COUNTS.dislikes + transition.dislikesDelta,
|
|
};
|
|
await waitForBarRatio(page, nextCounts, USERSCRIPT_WATCH_VISUAL_PROFILE);
|
|
const after = await readWatchVisualContract(page, USERSCRIPT_WATCH_VISUAL_PROFILE);
|
|
expectWatchVisualState(after, transition.nextState, nextCounts, viewport, USERSCRIPT_WATCH_VISUAL_PROFILE);
|
|
expectNoStructuralLayoutShift(before, after);
|
|
|
|
expect(harness.backend.requestsFor("GET", "/votes")).toHaveLength(1);
|
|
expect(harness.backend.requestsFor("POST", "/interact/vote")).toHaveLength(1);
|
|
expect(harness.backend.requestsFor("POST", "/interact/vote")[0].body).toMatchObject({
|
|
userId: EXISTING_CREDENTIALS.userId,
|
|
value: transition.value,
|
|
videoId: VIDEO_A,
|
|
});
|
|
expect(harness.backend.requestsFor("POST", "/interact/confirmVote")).toHaveLength(1);
|
|
expect(harness.backend.blockedRequests).toEqual([]);
|
|
expect(harness.consoleErrors).toEqual([]);
|
|
expect(harness.pageErrors).toEqual([]);
|
|
annotateVisualEvidence(testInfo, await captureVisualReview(page, scenario.id));
|
|
} catch (error) {
|
|
await attachVisualFailureScreenshot(testInfo, page, scenario.id);
|
|
throw error;
|
|
}
|
|
},
|
|
});
|