commit f63bdce033bb271e9155d5c331b6c1b09d949175
parent 95ca71949f2ce9c4d86ac3c12a511315d5f42c83
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Thu, 1 Oct 2026 01:46:47 -0400
editor(e2e): forms-keep-input reads a controlled element once, as the refusal shows
Without forms/Controlled.tsx the reset leaves a controlled checkbox, radio or
select showing what it mounted with only until the next re-render that reaches
it (the editor's auto-refresh, 5 s by default), so a polled assertion passed on
main for the worker list. Those reads are now single, made in the commit the
reset ran in. The case for ChannelForm create also sets the platform select and
a handling radio, which are controlled and posted. Against main's app code
(8ea7c4f1) all 18 cases fail.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
1 file changed, 50 insertions(+), 24 deletions(-)
diff --git a/editor/e2e/forms-keep-input.spec.ts b/editor/e2e/forms-keep-input.spec.ts
@@ -60,6 +60,14 @@ const named = (scope: Locator | Page, name: string) =>
const alert = (page: Page, text: RegExp) =>
page.getByRole("alert").filter({ hasText: text });
+// A CONTROLLED checkbox, radio or select is read ONCE, as the refusal shows,
+// not polled. Without forms/Controlled.tsx the reset leaves it showing what it
+// mounted with only until the next re-render that reaches it — the editor's
+// auto-refresh, 5 s by default — so a polled assertion passes on code without
+// the fix. The refusal appears in the commit the reset ran in.
+const checkedNow = (loc: Locator) => loc.isChecked();
+const valueNow = (loc: Locator) => loc.inputValue();
+
test("SiteForm create: a refused site id keeps every field", async ({
page,
}) => {
@@ -89,6 +97,14 @@ test("SiteForm create: a refused site id keeps every field", async ({
await form.getByRole("button", { name: "Create site" }).click();
await expect(alert(page, /site id must be/i)).toBeVisible();
+ expect(
+ await checkedNow(form.locator('input[name="accent"][value="brass"]')),
+ ).toBe(true);
+ expect(
+ await checkedNow(
+ form.getByRole("checkbox", { name: /include test youtube channel/i }),
+ ),
+ ).toBe(true);
await expect(named(form, "siteId")).toHaveValue("Not A Valid Id!");
await expect(named(form, "siteTitle")).toHaveValue("Typed Title");
@@ -103,12 +119,6 @@ test("SiteForm create: a refused site id keeps every field", async ({
await expect(named(form, "pwa")).toBeChecked();
await expect(named(form, "archives")).not.toBeChecked();
await expect(named(form, "listed")).toBeChecked();
- await expect(
- form.locator('input[name="accent"][value="brass"]'),
- ).toBeChecked();
- await expect(
- form.getByRole("checkbox", { name: /include test youtube channel/i }),
- ).toBeChecked();
});
test("SiteForm edit: a refused Public URL keeps every field", async ({
@@ -134,6 +144,9 @@ test("SiteForm edit: a refused Public URL keeps every field", async ({
await form.getByRole("button", { name: "Save site" }).click();
await expect(alert(page, /public url must be/i)).toBeVisible();
+ expect(
+ await checkedNow(form.locator('input[name="accent"][value="violet"]')),
+ ).toBe(true);
await expect(named(form, "siteTitle")).toHaveValue("Alpha Typed");
await expect(named(form, "headerTitle")).toHaveValue("Alphalyzer");
@@ -145,9 +158,6 @@ test("SiteForm edit: a refused Public URL keeps every field", async ({
await expect(named(form, "hubUrl")).toHaveValue("https://hub.example");
await expect(named(form, "duplicates")).not.toBeChecked();
await expect(named(form, "transcriptDownloads")).not.toBeChecked();
- await expect(
- form.locator('input[name="accent"][value="violet"]'),
- ).toBeChecked();
// Nothing was written.
const site = await readJson<{ siteTitle: string }>(
"test-transcripts/sites/alpha/site.json",
@@ -188,6 +198,7 @@ test("SettingsForm: a refused page size keeps every field, and a save after it s
await form.getByRole("button", { name: "Save settings" }).click();
await expect(alert(page, /between/)).toBeVisible();
+ expect(await checkedNow(featured)).toBe(true);
await expect(named(form, "adminTitle")).toHaveValue("Typed Admin");
await expect(named(form, "maxTranscriptPageBytes")).toHaveValue("42");
@@ -202,7 +213,6 @@ test("SettingsForm: a refused page size keeps every field, and a save after it s
await expect(named(form, "reportDebouncePreset")).toHaveValue("lazy");
await expect(named(form, "maxParallelBuilds")).toHaveValue("7");
await expect(named(form, "dockerImage")).toHaveValue("typed-image");
- await expect(featured).toBeChecked();
// THE SUCCESS PATH: fix the one bad field and save. The selects show the
// stored choice afterwards (a select's default reached the DOM only at mount
@@ -240,6 +250,10 @@ test("ChannelForm create: a refused slug keeps every field", async ({
await named(form, "name").fill("Typed Channel");
await named(form, "slug").fill("test-youtube"); // already exists
await named(form, "url").fill("https://www.youtube.com/@typed/videos");
+ // Create mode's platform select and handling radios are controlled AND
+ // posted: a stale one would be sent by the next submit.
+ await named(form, "platform").selectOption("rumble");
+ await form.locator('input[name="handling"][value="transcribe"]').check();
const member = form.getByRole("checkbox", { name: "Include on Alpha Site" });
const memberWas = await member.isChecked();
await member.setChecked(!memberWas);
@@ -266,13 +280,17 @@ test("ChannelForm create: a refused slug keeps every field", async ({
await form.getByRole("button", { name: /create channel/i }).click();
await expect(form.getByText(/already exists/i)).toBeVisible();
+ expect(await valueNow(named(form, "platform"))).toBe("rumble");
+ expect(
+ await checkedNow(form.locator('input[name="handling"][value="transcribe"]')),
+ ).toBe(true);
+ expect(await checkedNow(member)).toBe(!memberWas);
await expect(named(form, "name")).toHaveValue("Typed Channel");
await expect(named(form, "slug")).toHaveValue("test-youtube");
await expect(named(form, "url")).toHaveValue(
"https://www.youtube.com/@typed/videos",
);
- await expect(member).toBeChecked({ checked: !memberWas });
await expect(named(form, "fetchPlaylist")).not.toBeChecked();
await expect(named(form, "prioritizeDownload")).toBeChecked();
await expect(named(form, "audioFormat")).toHaveValue("opus");
@@ -469,7 +487,8 @@ test("CutReleaseForm: a bad version keeps it and the commit box", async ({
const before = await readFile(changelog, "utf8").catch(() => null);
await writeFile(
changelog,
- "# Changelog\n\n## [Unreleased]\n- a pending bullet\n\n## [9.9.9] - 2024-01-01\n- old\n",
+ "# Changelog\n\n## [Unreleased]\n- a pending bullet\n\n" +
+ "## [9.9.9] - 2024-01-01\n- old\n",
);
try {
await page.goto("/changelog");
@@ -593,10 +612,10 @@ test("DigestSettingsForm: a refused write keeps every field, the section boxes t
await withSettingsUnwritable(async () => {
await form.getByRole("button", { name: "Save digest settings" }).click();
await expect(form.getByRole("alert")).toBeVisible();
+ expect(await checkedNow(box("tags"))).toBe(true);
+ expect(await checkedNow(box("chapters"))).toBe(false);
});
- await expect(box("tags")).toBeChecked();
- await expect(box("chapters")).not.toBeChecked();
await expect(named(form, "digestTimestampMode")).toHaveValue("absolute");
await expect(named(form, "digestPromptVariant")).toHaveValue("typed-variant");
await expect(named(form, "digestYieldToCpuWorkers")).toBeChecked();
@@ -650,6 +669,7 @@ test("SchedulerSettingsForm: a refused write keeps every field, a cadence select
await withSettingsUnwritable(async () => {
await form.getByRole("button", { name: "Save controls" }).click();
await expect(form.getByRole("alert")).toBeVisible();
+ expect(await valueNow(sweep)).toBe("4320");
});
await expect(named(form, "syncSchedulerEnabled")).toBeChecked({
@@ -664,7 +684,6 @@ test("SchedulerSettingsForm: a refused write keeps every field, a cadence select
await expect(named(form, "syncSchedulerMaxConcurrentSyncs")).toHaveValue("4");
await expect(named(form, "syncSchedulerQuietHoursStart")).toHaveValue("22");
await expect(named(form, "syncSchedulerQuietHoursEnd")).toHaveValue("6");
- await expect(sweep).toHaveValue("4320");
});
test("SavedVideosControls: a refused write keeps the box and the cadence", async ({
@@ -683,6 +702,9 @@ test("SavedVideosControls: a refused write keeps the box and the cadence", async
await withSettingsUnwritable(async () => {
await form.getByRole("button", { name: "Save backup config" }).click();
await expect(form.getByRole("alert")).toBeVisible();
+ expect(await valueNow(form.getByLabel("Backup interval unit"))).toBe(
+ "days",
+ );
});
await expect(page.getByLabel("backup destination")).toHaveValue(
@@ -690,7 +712,6 @@ test("SavedVideosControls: a refused write keeps the box and the cadence", async
);
await expect(page.getByLabel("scheduled backup enabled")).toBeChecked();
await expect(form.getByLabel("Backup interval amount")).toHaveValue("3");
- await expect(form.getByLabel("Backup interval unit")).toHaveValue("days");
});
test("WorkersConfigForm: a refused list keeps the Enabled boxes as set", async ({
@@ -698,10 +719,15 @@ test("WorkersConfigForm: a refused list keeps the Enabled boxes as set", async (
}) => {
await resetData("empty");
await writeSettings({
- workers: [
- { id: "gpu", name: "GPU", kind: "local", enabled: true, priority: 0, appId: "whisper-cpp", config: {} },
- { id: "cpu", name: "CPU", kind: "local", enabled: true, priority: 1, appId: "whisper-cpp", config: {} },
- ],
+ workers: ["gpu", "cpu"].map((id, priority) => ({
+ id,
+ name: id.toUpperCase(),
+ kind: "local",
+ enabled: true,
+ priority,
+ appId: "whisper-cpp",
+ config: {},
+ })),
});
await page.goto("/workers");
const form = page.locator('form[data-settings-block="workers"]');
@@ -712,8 +738,8 @@ test("WorkersConfigForm: a refused list keeps the Enabled boxes as set", async (
await form.getByRole("button", { name: "Save workers" }).click();
await expect(alert(page, /at least one worker must be enabled/i)).toBeVisible();
- // Controlled boxes: before slice FK the reset put them back to ticked while
- // the list still said off.
- await expect(form.getByLabel("worker 1 enabled")).not.toBeChecked();
- await expect(form.getByLabel("worker 2 enabled")).not.toBeChecked();
+ // Controlled boxes: before slice FK the reset put them back to ticked, while
+ // the list still said off, until the next re-render.
+ expect(await checkedNow(form.getByLabel("worker 1 enabled"))).toBe(false);
+ expect(await checkedNow(form.getByLabel("worker 2 enabled"))).toBe(false);
});