fdm/scripts/verify-thermal.js

172 lines
6.7 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.notEqual((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.mouse.wheel(0, 300);
await page.waitForTimeout(500);
assert.deepEqual((await signal()).cameraPosition, start.cameraPosition);
assert.deepEqual((await signal()).cameraQuaternion, start.cameraQuaternion);
assert.ok((await signal()).travel > start.travel);
report.fixedSectionCamera = 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();
}