173 lines
6.8 KiB
JavaScript
173 lines
6.8 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: 180000,
|
|
});
|
|
await page.locator('[data-technology="thermal"]').click();
|
|
const signal = () =>
|
|
page.locator("#scene").getAttribute("data-thermal").then(JSON.parse);
|
|
const pixels = () =>
|
|
page.evaluate(() => {
|
|
const canvas = document.createElement("canvas");
|
|
canvas.width = 160;
|
|
canvas.height = 100;
|
|
const ctx = canvas.getContext("2d");
|
|
ctx.drawImage(document.querySelector("#scene canvas"), 0, 0, 160, 100);
|
|
return [...ctx.getImageData(0, 0, 160, 100).data];
|
|
});
|
|
await page.waitForTimeout(300);
|
|
const before = await pixels();
|
|
const start = await signal();
|
|
await page.waitForTimeout(1200);
|
|
const after = await pixels();
|
|
report.changedPixels = after.filter((v, i) => v !== before[i]).length;
|
|
assert.ok(report.changedPixels > 50);
|
|
assert.equal((await signal()).fanAngle, start.fanAngle);
|
|
assert.deepEqual((await signal()).cameraPosition, start.cameraPosition);
|
|
assert.deepEqual((await signal()).cameraQuaternion, start.cameraQuaternion);
|
|
const sceneBounds = await page.locator('#scene').boundingBox();
|
|
await page.mouse.move(sceneBounds.x + sceneBounds.width / 2, sceneBounds.y + sceneBounds.height / 2);
|
|
await page.mouse.down();
|
|
await page.mouse.move(sceneBounds.x + sceneBounds.width / 2 + 100, sceneBounds.y + sceneBounds.height / 2 + 60, { steps: 12 });
|
|
await page.mouse.up();
|
|
await page.waitForTimeout(500);
|
|
assert.notDeepEqual((await signal()).cameraPosition, start.cameraPosition);
|
|
assert.notDeepEqual((await signal()).cameraQuaternion, start.cameraQuaternion);
|
|
assert.equal((await signal()).fanAngle, start.fanAngle);
|
|
assert.ok((await signal()).travel > start.travel);
|
|
report.fixedComponentRotation = true;
|
|
report.interactiveCamera = true;
|
|
await page.screenshot({ path: "artifacts/thermal-animation.png" });
|
|
await page.locator("#fan-target").fill("0");
|
|
await page.waitForTimeout(300);
|
|
const stopped = (await signal()).fanAngle;
|
|
await page.waitForTimeout(500);
|
|
assert.equal((await signal()).fanAngle, stopped);
|
|
await page.locator("#thermal-fault").click();
|
|
await page.waitForTimeout(300);
|
|
report.disturbance = await signal();
|
|
assert.ok(report.disturbance.power > 80);
|
|
assert.ok(report.disturbance.melt.width < 0.44);
|
|
assert.ok(report.disturbance.melt.cold > 0.1);
|
|
await page.screenshot({ path: "artifacts/melt-cold.png" });
|
|
await page.locator("#clear-fault").click();
|
|
await page.locator("#overheat-fault").click();
|
|
await page.waitForTimeout(400);
|
|
report.overheat = await signal();
|
|
assert.ok(report.overheat.melt.spread > 1.2);
|
|
assert.equal(report.overheat.power, 0);
|
|
await page.screenshot({ path: "artifacts/melt-overheat.png" });
|
|
await page.locator("#clear-fault").click();
|
|
await page.locator("#vision-fault").click();
|
|
await page.waitForTimeout(2500);
|
|
assert.equal((await signal()).vision, true);
|
|
assert.equal((await signal()).feed, 75);
|
|
await page.screenshot({ path: "artifacts/thermal-defect.png" });
|
|
await page.waitForFunction(
|
|
() => !JSON.parse(document.querySelector("#scene").dataset.thermal).vision,
|
|
null,
|
|
{ timeout: 15000 },
|
|
);
|
|
await page.locator("#pid").uncheck();
|
|
await page.locator("#vision-fault").click();
|
|
await page.waitForTimeout(8500);
|
|
assert.equal((await signal()).vision, true);
|
|
assert.equal((await signal()).power, 0);
|
|
await page.locator("#clear-fault").click();
|
|
await page.locator("#thermal-pause").click();
|
|
await page.waitForTimeout(250);
|
|
const paused = await signal();
|
|
await page.waitForTimeout(500);
|
|
assert.equal((await signal()).travel, paused.travel);
|
|
await page.locator("#thermal-pause").click();
|
|
await page.locator("#reset-thermal").click();
|
|
for (const [width, height] of [
|
|
[1920, 1080],
|
|
[1366, 768],
|
|
[1280, 720],
|
|
[390, 844],
|
|
]) {
|
|
await page.setViewportSize({ width, height });
|
|
await page.waitForTimeout(400);
|
|
const layout = await page.evaluate(() => ({
|
|
width: document.documentElement.scrollWidth,
|
|
height: document.documentElement.scrollHeight,
|
|
}));
|
|
assert.equal(layout.width, width);
|
|
if (width > 1000) assert.equal(layout.height, height);
|
|
const bounds = await page.evaluate(() => {
|
|
const rect = (selector) =>
|
|
document.querySelector(selector).getBoundingClientRect().toJSON();
|
|
return {
|
|
scene: rect("#scene"),
|
|
analysis: rect(".melt-analysis"),
|
|
loop: rect(".thermal-loop"),
|
|
caption: rect(".thermal-mode .scene-mode-caption"),
|
|
process: rect(".process"),
|
|
controls: rect(".control-panel"),
|
|
};
|
|
});
|
|
assert.ok(bounds.scene.bottom <= bounds.caption.top + 2);
|
|
if (width > 740) assert.ok(bounds.scene.right <= bounds.analysis.left + 2);
|
|
else assert.ok(bounds.caption.bottom <= bounds.analysis.top + 2);
|
|
assert.ok(bounds.analysis.bottom <= bounds.loop.top + 2);
|
|
assert.ok(bounds.loop.bottom <= bounds.process.bottom);
|
|
if (width <= 740) assert.ok(bounds.process.bottom <= bounds.controls.top);
|
|
for (const id of ["melt-section", "melt-inspection"]) {
|
|
assert.ok(
|
|
await page
|
|
.locator(`#${id}`)
|
|
.evaluate(
|
|
(canvas) =>
|
|
new Set(
|
|
canvas
|
|
.getContext("2d")
|
|
.getImageData(0, 0, canvas.width, canvas.height).data,
|
|
).size > 50,
|
|
),
|
|
);
|
|
}
|
|
assert.ok((await pixels()).some((v, i) => i % 4 !== 3 && v > 150));
|
|
await page.screenshot({
|
|
path: `artifacts/thermal-animation-${width}.png`,
|
|
fullPage: true,
|
|
});
|
|
}
|
|
await page.locator('[data-technology="model"]').click();
|
|
assert.ok(await page.locator("#thermal-overlay").isHidden());
|
|
assert.deepEqual(errors, []);
|
|
await writeFile(
|
|
"artifacts/thermal-report.json",
|
|
JSON.stringify({ ...report, errors }, null, 2),
|
|
);
|
|
console.log(JSON.stringify({ ...report, errors }, null, 2));
|
|
} finally {
|
|
await browser.close();
|
|
}
|