import assert from "node:assert/strict"; // Drivers page: the search field keeps focus while a whole name is typed (it used to lose it // after the first letter, because every keystroke re-renders the page), and "Test // pronunciation" speaks the spoken name - the unsaved one in the form - through race audio. export async function runDriversPageSmoke({ evaluate, navigate, savedState, waitFor, base }) { const patchState = async (patch) => { const current = await savedState(); Object.assign(current, patch); const response = await fetch(base + "/api/state", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(current) }); assert.equal(response.ok, true); }; const seeded = await savedState(); await patchState({ drivers: [...seeded.drivers, { id: "dp_anders", name: "DP Anders", speechName: "Anders the Rocket", transponder: "8550001" }], settings: { ...seeded.settings, ttsEngine: "browser", raceAudio: { ...seeded.settings.raceAudio, enabled: true, muted: false, language: "sv", events: {} } }, }); try { await navigate("drivers", "driverForm"); // Type letter by letter, like a person. for (const letter of "DP And") { const ok = await evaluate(`(() => { const input = document.getElementById("driverBrandFilter"); if (document.activeElement !== input) input.focus(); input.value += ${JSON.stringify(letter)}; input.setSelectionRange(input.value.length, input.value.length); input.dispatchEvent(new Event("input", { bubbles: true })); return document.activeElement?.id === "driverBrandFilter"; })()`); assert.equal(ok, true, `focus kept after typing "${letter}"`); } assert.equal(await evaluate(`document.getElementById("driverBrandFilter").value`), "DP And"); assert.match(await evaluate(`document.querySelector(".panel table, table")?.innerText || document.body.innerText`), /DP Anders/); console.log("PASS the driver search keeps focus so a whole name can be typed"); // Capture what the browser voice is asked to say. await evaluate(`(() => { window.__spoken = []; window.speechSynthesis.speak = (utterance) => { window.__spoken.push(utterance.text); setTimeout(() => utterance.onend?.(), 10); }; })()`); await evaluate(`document.querySelector('[data-driver-voice-row="dp_anders"]').click()`); await waitFor(async () => (await evaluate(`window.__spoken.join(" | ")`)).includes("Anders the Rocket"), "the saved spoken name is read out"); // In the add form: an unsaved nickname is what you hear. await evaluate(`(() => { window.__spoken = []; const form = document.getElementById("driverForm"); form.elements.name.value = "New Kid"; form.elements.speechName.value = "Kiddo"; form.querySelector("[data-driver-voice-test]").click(); })()`); await waitFor(async () => (await evaluate(`window.__spoken.join(" | ")`)).includes("Kiddo"), "the unsaved nickname is read out"); assert.equal((await savedState()).drivers.some((driver) => driver.name === "New Kid"), false, "testing doesn't save the driver"); console.log("PASS Test pronunciation reads the spoken name (also an unsaved one) through race audio"); } finally { const current = await savedState(); await patchState({ drivers: current.drivers.filter((driver) => driver.id !== "dp_anders"), settings: { ...current.settings, raceAudio: seeded.settings.raceAudio, ttsEngine: seeded.settings.ttsEngine } }); } }