Testing Svelte 5 Forms via MCP Automation
Context
KoproGo runs Svelte 5.55 in legacy mode (export let + $: reactive
statements). There is no svelte.config.js with runes: true — all 178
components use classic reactivity.
The Problem
When using MCP browser automation tools (e.g. Claude Cowork Chrome extension), programmatic input setters like:
// This does NOT trigger Svelte's bind:value
inputElement.value = "new text";
…do not trigger Svelte’s bind:value two-way binding. The DOM input
shows the new value, but the Svelte component state stays empty. Consequently:
Form validation reads empty fields and blocks submission silently
The
handleSubmit()function sends empty/stale values to the backendThe audit falsely reports “POST 400 — missing field building_id” etc.
The Fix: Dispatch a Native InputEvent
After setting the value programmatically, dispatch an InputEvent to trigger
Svelte’s event listener:
// Step 1: Use the native HTMLInputElement setter (bypasses any framework proxy)
const nativeSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
"value"
).set;
nativeSetter.call(inputElement, "new text");
// Step 2: Dispatch an InputEvent so Svelte picks up the change
inputElement.dispatchEvent(new InputEvent("input", { bubbles: true }));
For Select Elements
const nativeSetter = Object.getOwnPropertyDescriptor(
window.HTMLSelectElement.prototype,
"value"
).set;
nativeSetter.call(selectElement, "option_value");
selectElement.dispatchEvent(new Event("change", { bubbles: true }));
Preferred: Use Playwright’s Native Methods
Playwright’s page.fill() and page.selectOption() already dispatch the
correct events internally. Use them instead of raw DOM manipulation:
// Playwright — correct, triggers bind:value
await page.fill('[data-testid="ticket-title-input"]', "Fuite robinet");
await page.selectOption('[data-testid="ticket-priority-select"]', "High");
Why This Matters
Audits v1 through v7 (April 2026) repeatedly flagged forms as “broken”
because the MCP automation tool used form_input which does NOT dispatch
InputEvent. The forms work perfectly for real human users typing on a
keyboard. See docs/cowork/Plan-Maury-2026-04-13.md STORY-P7-501.
Future: Runes Migration
When KoproGo migrates to Svelte 5 runes ($state, $props, $derived),
this workaround will no longer be necessary — runes use fine-grained
reactivity that does not depend on DOM events for state synchronization.
See Epic P7-6 in the Maury plan.