192 lines
6.5 KiB
JavaScript
192 lines
6.5 KiB
JavaScript
import { chromium } from "@playwright/test";
|
|
import assert from "node:assert/strict";
|
|
import { writeFile } from "node:fs/promises";
|
|
|
|
const url = process.env.FDM_URL || "http://127.0.0.1:4178";
|
|
assert.ok((await fetch(url)).ok);
|
|
const browser = await chromium.launch({
|
|
executablePath:
|
|
"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 errors = [];
|
|
const report = [];
|
|
try {
|
|
const page = await browser.newPage({
|
|
viewport: { width: 1440, height: 900 },
|
|
});
|
|
page.on("pageerror", (error) => errors.push(error.message));
|
|
const cdp = await page.context().newCDPSession(page);
|
|
await cdp.send("Network.enable");
|
|
await cdp.send("Network.setCacheDisabled", { cacheDisabled: true });
|
|
await page.goto(url);
|
|
await page.waitForSelector("#loading[hidden]", {
|
|
state: "attached",
|
|
timeout: 60000,
|
|
});
|
|
const initialTime = await page.locator("#timeline").inputValue();
|
|
const pixels = () => {
|
|
const canvas = document.createElement("canvas");
|
|
canvas.width = 100;
|
|
canvas.height = 80;
|
|
const context = canvas.getContext("2d");
|
|
context.drawImage(document.querySelector("#scene canvas"), 0, 0, 100, 80);
|
|
return [...context.getImageData(0, 0, 100, 80).data];
|
|
};
|
|
for (let stage = 0; stage < 4; stage++) {
|
|
await page.locator(`[data-stage="${stage}"]`).click();
|
|
if (stage >= 2) {
|
|
await page.waitForFunction(() =>
|
|
Number(document.querySelector("#scene").dataset.workflowProgress) > 0.08,
|
|
null, { timeout: 90000 });
|
|
}
|
|
await page.waitForTimeout(500);
|
|
const before = await page.evaluate(pixels);
|
|
await page.waitForTimeout(2500);
|
|
const after = await page.evaluate(pixels);
|
|
const changed = after.filter(
|
|
(value, index) => value !== before[index],
|
|
).length;
|
|
assert.ok(changed > 70, `步骤 ${stage + 1} 有实际画面变化`);
|
|
assert.equal(
|
|
await page.locator("#scene").getAttribute("data-workflow-stage"),
|
|
String(stage),
|
|
);
|
|
assert.ok(
|
|
await page.locator(`[data-workflow-panel="${stage}"]`).isVisible(),
|
|
);
|
|
assert.ok(await page.locator(".temperature").isHidden());
|
|
await page.screenshot({ path: `artifacts/workflow-${stage + 1}.png` });
|
|
report.push({ stage, changed });
|
|
}
|
|
await page.locator("#workflow-pause").click();
|
|
await page.waitForTimeout(200);
|
|
const frozen = await page
|
|
.locator("#scene")
|
|
.getAttribute("data-workflow-progress");
|
|
await page.waitForTimeout(400);
|
|
assert.equal(
|
|
await page.locator("#scene").getAttribute("data-workflow-progress"),
|
|
frozen,
|
|
);
|
|
await page.locator("#workflow-prev").click();
|
|
assert.equal(
|
|
await page.locator("#workflow-title").textContent(),
|
|
"运动路径规划",
|
|
);
|
|
await page.locator("#workflow-next").click();
|
|
assert.equal(
|
|
await page.locator("#workflow-title").textContent(),
|
|
"逐层沉积与反馈",
|
|
);
|
|
await page.locator("#workflow").click();
|
|
await page.waitForTimeout(250);
|
|
assert.equal(await page.locator("#timeline").inputValue(), initialTime);
|
|
assert.ok(await page.locator("#workflow-presentation").isHidden());
|
|
await page.locator("#workflow").click();
|
|
for (let stage = 0; stage < 4; stage++) {
|
|
await page.waitForFunction(
|
|
(value) =>
|
|
document.querySelector("#scene").dataset.workflowStage ===
|
|
String(value),
|
|
stage,
|
|
{ timeout: 18000 },
|
|
);
|
|
}
|
|
await page.waitForFunction(
|
|
() => document.querySelector("#scene").dataset.workflowProgress === "1.000",
|
|
{ timeout: 18000 },
|
|
);
|
|
await page.locator('[data-technology="nozzle"]').click();
|
|
assert.equal(
|
|
await page.locator("#scene").getAttribute("data-workflow-stage"),
|
|
null,
|
|
);
|
|
await page.locator('[data-technology="model"]').click();
|
|
await page.locator('[data-stage="2"]').click();
|
|
await page.locator("#slow-layer").click();
|
|
assert.equal(
|
|
await page.locator("#scene").getAttribute("data-workflow-stage"),
|
|
null,
|
|
);
|
|
for (const [width, height] of [
|
|
[1920, 1080],
|
|
[1366, 768],
|
|
[1280, 720],
|
|
]) {
|
|
await page.setViewportSize({ width, height });
|
|
await page.locator('[data-stage="1"]').click();
|
|
await page.waitForTimeout(800);
|
|
const layout = await page.evaluate(() => {
|
|
const panel = document
|
|
.querySelector('[data-panel="model"]')
|
|
.getBoundingClientRect();
|
|
const foot = document
|
|
.querySelector('[data-panel="model"] .tech-footnote')
|
|
.getBoundingClientRect();
|
|
return {
|
|
width: document.documentElement.scrollWidth,
|
|
height: document.documentElement.scrollHeight,
|
|
panelBottom: panel.bottom,
|
|
footBottom: foot.bottom,
|
|
};
|
|
});
|
|
assert.equal(layout.width, width);
|
|
assert.equal(layout.height, height);
|
|
assert.ok(layout.footBottom <= layout.panelBottom + 1);
|
|
for (let stage = 0; stage < 4; stage++) {
|
|
await page.locator(`[data-stage="${stage}"]`).click();
|
|
await page.waitForTimeout(150);
|
|
const detail = await page
|
|
.locator(".workflow-detail")
|
|
.evaluate((element) => ({
|
|
height: element.clientHeight,
|
|
scroll: element.scrollHeight,
|
|
}));
|
|
assert.ok(
|
|
detail.scroll <= detail.height + 1,
|
|
`${width} 步骤 ${stage} 内容完整显示`,
|
|
);
|
|
}
|
|
await page.screenshot({ path: `artifacts/workflow-${width}.png` });
|
|
}
|
|
await page.setViewportSize({ width: 390, height: 844 });
|
|
for (let stage = 0; stage < 4; stage++) {
|
|
await page.locator(`[data-stage="${stage}"]`).click();
|
|
await page.waitForTimeout(500);
|
|
const before = await page.evaluate(pixels);
|
|
await page.waitForTimeout(600);
|
|
const after = await page.evaluate(pixels);
|
|
assert.ok(after.some((value, index) => value !== before[index]));
|
|
assert.ok(
|
|
await page.evaluate(
|
|
() => document.documentElement.scrollWidth <= innerWidth,
|
|
),
|
|
);
|
|
assert.ok(
|
|
await page.evaluate(
|
|
() =>
|
|
document.querySelector("#workflow-command").textContent ===
|
|
document.querySelector("#raw-command").textContent,
|
|
),
|
|
);
|
|
await page.screenshot({
|
|
path: `artifacts/workflow-mobile-${stage + 1}.png`,
|
|
fullPage: true,
|
|
});
|
|
}
|
|
assert.deepEqual(errors, []);
|
|
await writeFile(
|
|
"artifacts/workflow-report.json",
|
|
JSON.stringify({ url, report, errors }, null, 2),
|
|
);
|
|
console.log(JSON.stringify({ report, errors }, null, 2));
|
|
} finally {
|
|
await browser.close();
|
|
}
|