fdm/scripts/verify-browser.js

156 lines
5.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { chromium } from "@playwright/test";
import assert from "node:assert/strict";
import { mkdir, writeFile } from "node:fs/promises";
const browser = await chromium.launch({
executablePath:
process.env.BROWSER_PATH ||
"C:/Users/ikun/AppData/Local/ms-playwright/chromium_headless_shell-1234/chrome-headless-shell-win64/chrome-headless-shell.exe",
headless: true,
args: [
"--enable-webgl",
"--use-angle=swiftshader",
"--enable-unsafe-swiftshader",
],
});
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 1,
});
const page = await context.newPage();
const errors = [];
const reports = [];
page.on("pageerror", (error) => errors.push(error.message));
await mkdir("artifacts", { recursive: true });
try {
const session = await context.newCDPSession(page);
await session.send("Network.enable");
await session.send("Network.setCacheDisabled", { cacheDisabled: true });
await page.goto("http://127.0.0.1:4178", { waitUntil: "networkidle" });
await page.waitForFunction(() =>
document.querySelector("#total-distance").textContent.includes("158.6"),
);
await page.locator("#play").click();
await page.locator("#timeline").fill("650");
await page.waitForTimeout(300);
await page.screenshot({
path: "artifacts/desktop-original.png",
fullPage: true,
});
const sampleCanvas = () => {
const canvas = document.querySelector("#scene canvas");
const copy = document.createElement("canvas");
copy.width = 80;
copy.height = 60;
const context = copy.getContext("2d");
context.drawImage(canvas, 0, 0, 80, 60);
const pixels = context.getImageData(0, 0, 80, 60).data;
const colors = new Set();
let sum = 0;
for (let i = 0; i < pixels.length; i += 4) {
colors.add(`${pixels[i]},${pixels[i + 1]},${pixels[i + 2]}`);
sum += pixels[i] + pixels[i + 1] + pixels[i + 2];
}
return {
colors: colors.size,
sum,
width: canvas.width,
height: canvas.height,
};
};
const originalCanvas = await page.evaluate(sampleCanvas);
assert.ok(originalCanvas.colors > 40, "三维画面不是空白");
const pausedValue = await page.locator("#timeline").inputValue();
await page.waitForTimeout(500);
assert.equal(await page.locator("#timeline").inputValue(), pausedValue);
await page.locator("#play").click();
await page.waitForTimeout(250);
assert.notEqual(await page.locator("#timeline").inputValue(), pausedValue);
await page.locator("#play").click();
await page.locator("#demo-mode").click();
await page.locator("#layer").fill("65");
await page.waitForTimeout(300);
assert.equal(await page.locator("#layer-value").textContent(), "65 / 100 层");
await page.screenshot({ path: "artifacts/desktop-demo.png", fullPage: true });
const demoCanvas = await page.evaluate(sampleCanvas);
assert.ok(demoCanvas.colors > 40);
assert.notEqual(demoCanvas.sum, originalCanvas.sum);
await page.locator("#view-top").click();
await page.waitForTimeout(300);
assert.notEqual((await page.evaluate(sampleCanvas)).sum, demoCanvas.sum);
await page.locator("#view-perspective").click();
await page.locator("#nozzle").uncheck();
await page.waitForTimeout(200);
assert.notEqual((await page.evaluate(sampleCanvas)).sum, demoCanvas.sum);
await page.locator("#nozzle").check();
await page.locator('[data-tech="nozzle"]').click();
assert.equal(
await page.locator("#tech-dialog").evaluate((element) => element.open),
true,
);
await page.locator("#dialog-action").click();
assert.equal(
await page.locator("#tech-dialog").evaluate((element) => element.open),
false,
);
for (const [width, height] of [
[1920, 1080],
[1440, 900],
[1366, 768],
[1280, 720],
[390, 844],
]) {
await page.setViewportSize({ width, height });
await page.waitForTimeout(300);
const layout = await page.evaluate(() => {
const footer = document.querySelector("footer").getBoundingClientRect();
return {
scrollWidth: document.documentElement.scrollWidth,
scrollHeight: document.documentElement.scrollHeight,
width: innerWidth,
height: innerHeight,
footerBottom: footer.bottom,
scene: document
.querySelector("#scene")
.getBoundingClientRect()
.toJSON(),
fileBottom: document
.querySelector(".file-section")
.getBoundingClientRect().bottom,
playerBottom: document.querySelector(".player").getBoundingClientRect()
.bottom,
technologyTop: document
.querySelector(".technology-strip")
.getBoundingClientRect().top,
};
});
reports.push(layout);
assert.ok(layout.scrollWidth <= width + 1, `宽度溢出 ${width}`);
if (width >= 1100)
assert.ok(
layout.scrollHeight <= height + 1,
`桌面单屏溢出 ${width}×${height}: ${layout.scrollHeight}`,
);
if (width >= 1100)
assert.ok(
Math.max(layout.fileBottom, layout.playerBottom) < layout.technologyTop,
`内容重叠 ${width}×${height}`,
);
await page.screenshot({
path: `artifacts/viewport-${width}.png`,
fullPage: true,
});
assert.ok((await page.evaluate(sampleCanvas)).colors > 40);
}
assert.deepEqual(errors, []);
console.log(
JSON.stringify({ originalCanvas, demoCanvas, reports, errors }, null, 2),
);
await writeFile(
"artifacts/browser-report.json",
JSON.stringify({ originalCanvas, demoCanvas, reports, errors }, null, 2),
);
} finally {
await browser.close();
}