race day tester + fixa open practice start och decoder-omritning
Nytt browser-test för start/paus/fortsätt/finish och byte till nästa heat i kön, mot en simulerad decoder-socket (ingen riktig AMMC-hårdvara). Hittade och fixade två buggar under vägen: - Open Practice på sponsor/track-event kunde inte startas trots grönt ljus i förkontrollen (separat, striktare kontroll saknade samma undantag) - Race Day-vyn ritades aldrig om när decodern anslöt/kopplades ner Testramverket hanterar nu även native alert()/confirm()-dialoger automatiskt, annars fryser en headless körning helt.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { runOverlaySmoke } from "./browser_overlays.js";
|
||||
import { runRaceSetupSmoke } from "./browser_race_setup.js";
|
||||
import { runRaceDaySmoke } from "./browser_race_day.js";
|
||||
import assert from "node:assert/strict";
|
||||
import { spawn } from "node:child_process";
|
||||
import { existsSync, mkdtempSync, rmSync } from "node:fs";
|
||||
@@ -42,7 +43,7 @@ try {
|
||||
const base = `http://127.0.0.1:${port}`;
|
||||
launch(process.execPath, ["server.js"], { env: { ...process.env, HOST: "127.0.0.1", PORT: String(port), RC_TIMING_DATA_DIR: join(temporary, "data"), RC_TIMING_PID_FILE: "" } });
|
||||
await waitFor(async () => (await fetch(base + "/api/health")).ok, "isolated server");
|
||||
const initial = { classes: [{ id: "test_class", name: "Test Class" }], drivers: [], cars: [], events: [], sessions: [], resultsBySession: {}, settings: { language: "en", autoReconnect: false, backendUrl: base }, training: {} };
|
||||
const initial = { classes: [{ id: "test_class", name: "Test Class" }], drivers: [], cars: [], events: [], sessions: [], resultsBySession: {}, settings: { language: "en", autoReconnect: false, backendUrl: base, raceAudio: { enabled: false } }, training: {} };
|
||||
const seedResponse = await fetch(base + "/api/state", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(initial) });
|
||||
assert.equal(seedResponse.ok, true);
|
||||
launch(chrome, ["--headless", "--disable-gpu", "--no-first-run", "--no-default-browser-check", "--disable-background-networking", ...(process.env.RC_BROWSER_NO_SANDBOX === "1" ? ["--no-sandbox"] : []), `--user-data-dir=${join(temporary, "browser")}`, `--remote-debugging-port=${debugPort}`, "about:blank"]);
|
||||
@@ -53,6 +54,7 @@ try {
|
||||
let nextId = 0;
|
||||
const requests = new Map();
|
||||
const errors = [];
|
||||
const dialogs = [];
|
||||
socket.addEventListener("message", event => {
|
||||
const message = JSON.parse(event.data);
|
||||
if (message.id) {
|
||||
@@ -60,6 +62,13 @@ try {
|
||||
requests.delete(message.id);
|
||||
if (message.error) request?.reject(new Error(message.error.message)); else request?.resolve(message.result);
|
||||
} else if (message.method === "Runtime.exceptionThrown") errors.push(message.params.exceptionDetails.text + ": " + (message.params.exceptionDetails.exception?.description || ""));
|
||||
// A native confirm()/alert() blocks the page's JS thread until dismissed. Nothing in a
|
||||
// headless run can click it, so every scenario would hang forever on the first one;
|
||||
// auto-accept and record it so an unexpected dialog still surfaces as a finding.
|
||||
else if (message.method === "Page.javascriptDialogOpening") {
|
||||
dialogs.push({ type: message.params.type, message: message.params.message });
|
||||
send("Page.handleJavaScriptDialog", { accept: true });
|
||||
}
|
||||
});
|
||||
function send(method, params = {}) {
|
||||
return new Promise((resolve, reject) => { const id = ++nextId; requests.set(id, { resolve, reject }); socket.send(JSON.stringify({ id, method, params })); });
|
||||
@@ -108,6 +117,7 @@ try {
|
||||
console.log("PASS create/edit/reload and draft retention: " + collection);
|
||||
}
|
||||
await runRaceSetupSmoke({ evaluate, navigate, fill, savedState, waitFor, pause });
|
||||
await runRaceDaySmoke({ evaluate, navigate, fill, savedState, waitFor, pause, base, dialogs });
|
||||
await navigate("classes", "classForm");
|
||||
await send("Network.emulateNetworkConditions", { offline: true, latency: 0, downloadThroughput: -1, uploadThroughput: -1 });
|
||||
await fill("classForm", { name: "Offline Draft" });
|
||||
@@ -150,6 +160,7 @@ try {
|
||||
await waitFor(async () => await evaluate('document.getElementById("publicTrainingConnection")?.dataset.state === "current"'), "mobile retry recovered");
|
||||
console.log("PASS mobile offline status preserves profile nodes and retry recovers");
|
||||
assert.deepEqual(errors, []);
|
||||
if (dialogs.length) console.log("NOTE auto-accepted native dialog(s):", JSON.stringify(dialogs));
|
||||
console.log("PASS offline save failure, local draft retention, retry and confirmed saved status");
|
||||
} finally {
|
||||
socket?.close();
|
||||
|
||||
Reference in New Issue
Block a user