import assert from "node:assert/strict"; // Regression coverage for the Settings page's tab restructuring (previously one long // scrolling page: Connection, Audio, Appearance & overlay, System & backup all at once). // Tabs must show exactly one group of panels at a time, default to Connection on first // load, and - the actual bug class this guards against - keep the selection when the page // re-renders in place (e.g. after saving the form), not silently reset back to Connection. // activeSettingsTab is a module-level variable specifically so it survives that re-render. export async function runSettingsTabsSmoke({ evaluate, navigate, waitFor, savedState }) { await navigate("settings", "settingsForm"); const activeTab = () => evaluate(`document.querySelector(".settings-tab.active")?.dataset.settingsTab`); const panelVisibility = () => evaluate(` Object.fromEntries(Array.from(document.querySelectorAll("[data-settings-panel]")) .map((panel) => [panel.dataset.settingsPanel, !panel.hidden])) `); assert.equal(await activeTab(), "connection", "Connection is the default tab on first load"); let visible = await panelVisibility(); assert.equal(visible.connection, true, "connection panel visible by default"); assert.equal(visible.audio, false, "audio panel hidden by default"); assert.equal(visible.appearance, false, "appearance panel hidden by default"); assert.equal(visible.system, false, "system panel hidden by default"); console.log("PASS settings defaults to the Connection tab with only that panel visible"); for (const tab of ["audio", "appearance", "system", "connection"]) { await evaluate(`document.querySelector('[data-settings-tab="${tab}"]').click()`); assert.equal(await activeTab(), tab, `clicking the ${tab} tab activates it`); visible = await panelVisibility(); for (const [panelId, isVisible] of Object.entries(visible)) { assert.equal(isVisible, panelId === tab, `after switching to ${tab}, panel ${panelId} should be ${panelId === tab ? "visible" : "hidden"}`); } } console.log("PASS clicking each settings tab shows only its own panel and hides the rest"); await evaluate(`document.querySelector('[data-settings-tab="system"]').click()`); assert.equal(await activeTab(), "system"); // Submitting the settings form re-renders the whole page in place (no navigation), which // is exactly the path that used to drop the user back onto the Connection tab. await evaluate(`document.getElementById("settingsForm").requestSubmit()`); assert.equal(await activeTab(), "system", "the selected tab survives an in-place re-render after saving, instead of resetting to Connection"); visible = await panelVisibility(); assert.equal(visible.system, true); assert.equal(visible.connection, false); console.log("PASS the active settings tab is preserved across a save-triggered re-render"); // The old "Audio ยท Legacy" panel is gone; "Calls during a race" defaults to passing tone // only and survives a save. await evaluate(`document.querySelector('[data-settings-tab="audio"]').click()`); assert.equal(await evaluate(`/Legacy/.test(document.querySelector('[data-settings-panel="audio"]').innerText)`), false, "no legacy audio panel"); assert.equal(await evaluate(`Boolean(document.querySelector('[name="audioEnabled"], [name="passingSoundMode"]'))`), false, "no legacy sound switches"); const callouts = () => evaluate(`document.querySelector('[name="raceAudioRaceCallouts"]').value`); assert.equal(await callouts(), "passing"); await evaluate(`(() => { document.querySelector('[name="raceAudioRaceCallouts"]').value = "full"; document.getElementById("settingsForm").requestSubmit(); })()`); assert.equal(await callouts(), "full", "speaker mode is saved"); await evaluate(`(() => { document.querySelector('[name="raceAudioRaceCallouts"]').value = "passing"; document.getElementById("settingsForm").requestSubmit(); })()`); assert.equal(await callouts(), "passing"); console.log("PASS the legacy audio panel is gone and race calls default to passing tone only"); // The sidebar "update available" link opens Settings on System & backup at Updates, even // when another tab was the last one used. await evaluate(`document.querySelector('[data-settings-tab="connection"]').click()`); await navigate("dashboard", "view"); await evaluate(`(() => { const link = document.getElementById("appUpdateAvailable"); link.hidden = false; link.click(); })()`); await waitFor(async () => (await activeTab()) === "system", "update link lands on System & backup"); assert.equal(await evaluate(`Boolean(document.getElementById("settingsUpdateSection")) && !document.getElementById("settingsUpdateSection").closest("[data-settings-panel]").hidden`), true, "the update section is visible"); console.log("PASS the sidebar update link opens Settings on System & backup -> Updates"); // One public address (domain / DynDNS) for every driver's mobile profile, set here. const status = () => evaluate(`document.getElementById("settingsPublicAddressStatus").textContent`); await evaluate(`(() => { document.getElementById("settingsPublicBaseUrl").value = "ftp://nope"; document.getElementById("settingsPublicBaseSave").click(); })()`); await waitFor(async () => /complete http|komplett http/i.test(await status()), "an invalid address is refused"); await evaluate(`(() => { document.getElementById("settingsPublicBaseUrl").value = "https://klubben.dyndns.org:8443/some/path"; document.getElementById("settingsPublicBaseSave").click(); })()`); await waitFor(async () => (await savedState()).settings.publicBaseUrl === "https://klubben.dyndns.org:8443", "saved as the origin, port kept"); await waitFor(async () => (await status()).includes("https://klubben.dyndns.org:8443"), "shown as in use"); await navigate("training", "view"); await waitFor(async () => Boolean(await evaluate(`document.querySelector("#training-overview-driver option:nth-child(2), #training-driver option:nth-child(2)")`)), "a driver to open"); await evaluate(`(() => { const select = document.getElementById("training-overview-driver") || document.getElementById("training-driver"); select.value = select.options[1].value; select.dispatchEvent(new Event("change")); })()`); await waitFor(async () => (await evaluate(`document.querySelector(".training-public-address")?.textContent || ""`)).includes("https://klubben.dyndns.org:8443"), "the driver's share panel shows the address"); await evaluate(`document.getElementById("trainingPublicAddressSettings").click()`); await waitFor(async () => (await activeTab()) === "system" && Boolean(await evaluate(`document.getElementById("settingsPublicBaseUrl")`)), "Change in Settings opens System"); await evaluate(`(() => { document.getElementById("settingsPublicBaseUrl").value = ""; document.getElementById("settingsPublicBaseSave").click(); })()`); await waitFor(async () => (await savedState()).settings.publicBaseUrl === "", "cleared again for the rest of the suite"); console.log("PASS one public address for all mobile profiles is set under Settings and shown in the share panel"); }