Skip to content

Playwright fill()/pressSequentially() don't trigger Svelte 5 bind:value state updates #473

Description

@kwannoel

Problem

In e2e tests, Playwright's fill() and pressSequentially() set the DOM textarea value but do NOT update Svelte 5's $state variable bound via bind:value. This means sendMessage() reads an empty string from the state variable even though the textarea visually contains text.

Reproduction

Component:

<script lang="ts">
  let messageInput = $state("");
  function sendMessage() {
    console.log(messageInput); // Always "" after fill()
  }
</script>
<textarea bind:value={messageInput}></textarea>
<button onclick={sendMessage}>Send</button>

Test:

await textarea.fill("Hello");
await page.locator("button").click();
// sendMessage logs "" instead of "Hello"

Root cause

Svelte 5 uses event delegation — bind:value handlers are attached at the document root, not directly on the element. Playwright's synthetic events may not properly trigger this delegation chain.

Workaround

Use bind:this to get a DOM ref and read .value directly:

let textareaEl: HTMLTextAreaElement | undefined = $state();

function sendMessage() {
  const msg = (textareaEl?.value ?? messageInput).trim();
  // ...
}

<textarea bind:this={textareaEl} bind:value={messageInput} />

Affected tests

  • e2e/specs/companion-mode.spec.ts — "companion channel accepts message input"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions