test: cover lazy map and rig startup flows
This commit is contained in:
@@ -5499,12 +5499,10 @@ function navigateToTab(name, options = {}) {
|
|||||||
const panel = document.getElementById(`tab-${name}`);
|
const panel = document.getElementById(`tab-${name}`);
|
||||||
if (!panel) return;
|
if (!panel) return;
|
||||||
panel.style.display = "";
|
panel.style.display = "";
|
||||||
const tmpl = panel.querySelector("template");
|
materializeTabPanel(panel);
|
||||||
if (tmpl) {
|
if (name === "map" || name === "statistics") {
|
||||||
panel.appendChild(tmpl.content.cloneNode(true));
|
const peer = document.getElementById(name === "map" ? "tab-statistics" : "tab-map");
|
||||||
tmpl.remove();
|
if (peer) materializeTabPanel(peer);
|
||||||
panel.querySelectorAll(".sub-tab-bar").forEach(_wireSubTabBar);
|
|
||||||
if (decoderRegistry.length) applyDecoderRegistryVisibility();
|
|
||||||
}
|
}
|
||||||
if (updateHistory) {
|
if (updateHistory) {
|
||||||
updateTabHistory(name, replaceHistory);
|
updateTabHistory(name, replaceHistory);
|
||||||
@@ -5523,6 +5521,15 @@ function navigateToTab(name, options = {}) {
|
|||||||
void refreshRecorderStatus();
|
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;
|
window.navigateToTab = navigateToTab;
|
||||||
requiredElement("tab-bar").addEventListener("click", (e) => {
|
requiredElement("tab-bar").addEventListener("click", (e) => {
|
||||||
const btn = e.target instanceof Element ? e.target.closest(".tab[data-tab]") : null;
|
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}`);
|
const panel = document.getElementById(`tab-${name}`);
|
||||||
if (!panel) return;
|
if (!panel) return;
|
||||||
panel.style.display = "";
|
panel.style.display = "";
|
||||||
// Clone deferred <template> content into the panel before any tab-specific init.
|
materializeTabPanel(panel);
|
||||||
const tmpl = panel.querySelector("template");
|
// Map and statistics share one lazy module. Materialize both contracts before
|
||||||
if (tmpl) {
|
// importing it so initialization never depends on which of the two tabs was
|
||||||
panel.appendChild(tmpl.content.cloneNode(true));
|
// opened first.
|
||||||
tmpl.remove();
|
if (name === "map" || name === "statistics") {
|
||||||
// Wire sub-tab bars inside the freshly cloned content.
|
const peer = document.getElementById(name === "map" ? "tab-statistics" : "tab-map");
|
||||||
panel.querySelectorAll<HTMLElement>(".sub-tab-bar").forEach(_wireSubTabBar);
|
if (peer) materializeTabPanel(peer);
|
||||||
// Re-run decoder visibility for about-tab elements now in the DOM.
|
|
||||||
if (decoderRegistry.length) applyDecoderRegistryVisibility();
|
|
||||||
}
|
}
|
||||||
if (updateHistory) {
|
if (updateHistory) {
|
||||||
updateTabHistory(name, replaceHistory);
|
updateTabHistory(name, replaceHistory);
|
||||||
@@ -4624,6 +4622,19 @@ function navigateToTab(name: TabName, options: { updateHistory?: boolean; replac
|
|||||||
void refreshRecorderStatus();
|
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;
|
window.navigateToTab = navigateToTab;
|
||||||
|
|
||||||
requiredElement("tab-bar").addEventListener("click", (e) => {
|
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 frontendDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
||||||
const webDir = path.resolve(frontendDir, "../assets/web");
|
const webDir = path.resolve(frontendDir, "../assets/web");
|
||||||
const generatedDir = path.join(webDir, "generated");
|
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([
|
const jsonRoutes = new Map([
|
||||||
["/auth/session", { authenticated: true, role: "control", auth_disabled: true }],
|
["/auth/session", { authenticated: true, role: "control", auth_disabled: true }],
|
||||||
["/decoders", []],
|
["/decoders", []],
|
||||||
["/rigs", { rigs: [], active_remote: null }],
|
["/rigs", rigsResponse],
|
||||||
["/status", {
|
["/status", {
|
||||||
info: {
|
info: {
|
||||||
manufacturer: "Smoke",
|
manufacturer: "Smoke",
|
||||||
@@ -62,7 +76,8 @@ const jsonRoutes = new Map([
|
|||||||
clients: 1,
|
clients: 1,
|
||||||
rigctl_clients: 0,
|
rigctl_clients: 0,
|
||||||
audio_clients: 0,
|
audio_clients: 0,
|
||||||
remotes: [],
|
active_remote: "rig-a",
|
||||||
|
remotes: ["rig-a", "rig-b"],
|
||||||
show_sdr_gain_control: false,
|
show_sdr_gain_control: false,
|
||||||
initial_map_zoom: 10,
|
initial_map_zoom: 10,
|
||||||
spectrum_coverage_margin_hz: 50_000,
|
spectrum_coverage_margin_hz: 50_000,
|
||||||
@@ -96,6 +111,16 @@ function assetPath(urlPath) {
|
|||||||
|
|
||||||
const server = http.createServer(async (request, response) => {
|
const server = http.createServer(async (request, response) => {
|
||||||
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
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)) {
|
if (jsonRoutes.has(url.pathname)) {
|
||||||
response.writeHead(200, { "content-type": "application/json" });
|
response.writeHead(200, { "content-type": "application/json" });
|
||||||
response.end(JSON.stringify(jsonRoutes.get(url.pathname)));
|
response.end(JSON.stringify(jsonRoutes.get(url.pathname)));
|
||||||
@@ -144,6 +169,20 @@ try {
|
|||||||
await page.locator("#content").waitFor({ state: "visible" });
|
await page.locator("#content").waitFor({ state: "visible" });
|
||||||
assert.equal(await page.locator("#auth-gate").isVisible(), false);
|
assert.equal(await page.locator("#auth-gate").isVisible(), false);
|
||||||
assert.equal(await page.locator("#tab-main").isVisible(), true);
|
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[data-tab="about"]').click();
|
||||||
await page.locator("#tab-about").waitFor({ state: "visible" });
|
await page.locator("#tab-about").waitFor({ state: "visible" });
|
||||||
|
|||||||
Reference in New Issue
Block a user