Files
Live_RC/tests/browser_drivers_page.js
larssand f65e526948 feat(drivers): test a driver's spoken name and keep search focus while typing
Adds a Test pronunciation button (forms and list) that plays the
passing sound and real announcements with the spoken name through race
audio. Fixes the Drivers/Cars search losing focus after one letter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 08:35:47 +02:00

61 lines
3.5 KiB
JavaScript

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 } });
}
}