test: cover lazy map and rig startup flows

This commit is contained in:
sjg
2026-08-01 22:34:22 +02:00
parent ddb33b6ff3
commit a1a8d1d1d3
3 changed files with 74 additions and 17 deletions
@@ -5499,12 +5499,10 @@ function navigateToTab(name, options = {}) {
const panel = document.getElementById(`tab-${name}`);
if (!panel) return;
panel.style.display = "";
const tmpl = panel.querySelector("template");
if (tmpl) {
panel.appendChild(tmpl.content.cloneNode(true));
tmpl.remove();
panel.querySelectorAll(".sub-tab-bar").forEach(_wireSubTabBar);
if (decoderRegistry.length) applyDecoderRegistryVisibility();
materializeTabPanel(panel);
if (name === "map" || name === "statistics") {
const peer = document.getElementById(name === "map" ? "tab-statistics" : "tab-map");
if (peer) materializeTabPanel(peer);
}
if (updateHistory) {
updateTabHistory(name, replaceHistory);
@@ -5523,6 +5521,15 @@ function navigateToTab(name, options = {}) {
void refreshRecorderStatus();
}
}
function materializeTabPanel(panel) {
const tmpl = panel.querySelector("template");
if (tmpl) {
panel.appendChild(tmpl.content.cloneNode(true));
tmpl.remove();
panel.querySelectorAll(".sub-tab-bar").forEach(_wireSubTabBar);
if (decoderRegistry.length) applyDecoderRegistryVisibility();
}
}
window.navigateToTab = navigateToTab;
requiredElement("tab-bar").addEventListener("click", (e) => {
const btn = e.target instanceof Element ? e.target.closest(".tab[data-tab]") : null;
@@ -4599,15 +4599,13 @@ function navigateToTab(name: TabName, options: { updateHistory?: boolean; replac
const panel = document.getElementById(`tab-${name}`);
if (!panel) return;
panel.style.display = "";
// Clone deferred <template> content into the panel before any tab-specific init.
const tmpl = panel.querySelector("template");
if (tmpl) {
panel.appendChild(tmpl.content.cloneNode(true));
tmpl.remove();
// Wire sub-tab bars inside the freshly cloned content.
panel.querySelectorAll<HTMLElement>(".sub-tab-bar").forEach(_wireSubTabBar);
// Re-run decoder visibility for about-tab elements now in the DOM.
if (decoderRegistry.length) applyDecoderRegistryVisibility();
materializeTabPanel(panel);
// Map and statistics share one lazy module. Materialize both contracts before
// importing it so initialization never depends on which of the two tabs was
// opened first.
if (name === "map" || name === "statistics") {
const peer = document.getElementById(name === "map" ? "tab-statistics" : "tab-map");
if (peer) materializeTabPanel(peer);
}
if (updateHistory) {
updateTabHistory(name, replaceHistory);
@@ -4624,6 +4622,19 @@ function navigateToTab(name: TabName, options: { updateHistory?: boolean; replac
void refreshRecorderStatus();
}
}
function materializeTabPanel(panel: HTMLElement): void {
// Clone deferred <template> content into the panel before any tab-specific init.
const tmpl = panel.querySelector("template");
if (tmpl) {
panel.appendChild(tmpl.content.cloneNode(true));
tmpl.remove();
// Wire sub-tab bars inside the freshly cloned content.
panel.querySelectorAll<HTMLElement>(".sub-tab-bar").forEach(_wireSubTabBar);
// Re-run decoder visibility for about-tab elements now in the DOM.
if (decoderRegistry.length) applyDecoderRegistryVisibility();
}
}
window.navigateToTab = navigateToTab;
requiredElement("tab-bar").addEventListener("click", (e) => {
@@ -12,11 +12,25 @@ import { chromium } from "playwright-core";
const frontendDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
const webDir = path.resolve(frontendDir, "../assets/web");
const generatedDir = path.join(webDir, "generated");
const rigItems = ["rig-a", "rig-b"].map((remote) => ({
remote,
display_name: remote === "rig-a" ? "Primary fixture" : "Secondary fixture",
manufacturer: "Smoke",
model: "Fixture",
supported_modes: ["FM"],
tx: false,
filter_controls: false,
initialized: true,
latitude: null,
longitude: null,
}));
const rigsResponse = { rigs: rigItems, active_remote: "rig-a" };
const selectedRigs = [];
const jsonRoutes = new Map([
["/auth/session", { authenticated: true, role: "control", auth_disabled: true }],
["/decoders", []],
["/rigs", { rigs: [], active_remote: null }],
["/rigs", rigsResponse],
["/status", {
info: {
manufacturer: "Smoke",
@@ -62,7 +76,8 @@ const jsonRoutes = new Map([
clients: 1,
rigctl_clients: 0,
audio_clients: 0,
remotes: [],
active_remote: "rig-a",
remotes: ["rig-a", "rig-b"],
show_sdr_gain_control: false,
initial_map_zoom: 10,
spectrum_coverage_margin_hz: 50_000,
@@ -96,6 +111,16 @@ function assetPath(urlPath) {
const server = http.createServer(async (request, response) => {
const url = new URL(request.url ?? "/", "http://127.0.0.1");
if (url.pathname === "/select_rig" && request.method === "POST") {
const remote = url.searchParams.get("remote");
if (remote) {
rigsResponse.active_remote = remote;
jsonRoutes.get("/status").active_remote = remote;
selectedRigs.push(remote);
}
response.writeHead(200).end();
return;
}
if (jsonRoutes.has(url.pathname)) {
response.writeHead(200, { "content-type": "application/json" });
response.end(JSON.stringify(jsonRoutes.get(url.pathname)));
@@ -144,6 +169,20 @@ try {
await page.locator("#content").waitFor({ state: "visible" });
assert.equal(await page.locator("#auth-gate").isVisible(), false);
assert.equal(await page.locator("#tab-main").isVisible(), true);
await page.locator("summary", { hasText: "Audio controls" }).click();
assert.equal(await page.locator("#rx-audio-btn").count(), 1);
const rigPicker = page.locator("#header-rig-switch-select");
await rigPicker.locator("option").nth(1).waitFor({ state: "attached" });
await rigPicker.selectOption("rig-b");
await page.waitForTimeout(100);
assert.deepEqual(selectedRigs, ["rig-b"]);
await page.locator('.tab[data-tab="map"]').click();
await page.locator("#aprs-map .leaflet-pane").first().waitFor({ state: "attached" });
assert.equal(new URL(page.url()).pathname, "/map");
await page.locator('.tab[data-tab="main"]').click();
assert.equal(new URL(page.url()).pathname, "/");
await page.locator('.tab[data-tab="about"]').click();
await page.locator("#tab-about").waitFor({ state: "visible" });