docs/solutions/test-failures/2026-05-23-slate-v2-mobile-example-proofs-must-separate-native-pointer-from-semantic-editing.md
Mobile Playwright rows reused desktop click and keyboard assumptions for state-field and multi-root examples. That made good architecture look broken because raw mobile clicks landed at browser-chosen caret positions or raced root activation.
keyboard.insertText(...) appended before the
last character instead of at the end.p inside never instead of after
nodes..Header editor set the active root, but immediate text insertion
could still mutate main.navigator.clipboard.writeText(...) was denied in the mobile project before
clipboard permission parity was added.Use deterministic editor intent for rows that prove model/history/root behavior, and keep raw pointer proof isolated to the row that actually claims pointer activation. For multi-root examples, create harnesses for each root instead of reaching into browser-handle internals.
const bodyEditor = await openExample(page, 'multi-root-document', {
surface: { scope: '#multi-root-main-surface' },
})
const headerEditor = bodyEditor.rootAt('#multi-root-header')
const focusRootByLabel = async (
page: Page,
label: string,
editor: SlateBrowserEditorHarness
) => {
await page.getByText(label).click({ force: true })
await expect(editor.root).toBeFocused()
}
await focusRootByLabel(page, 'Header editor', headerEditor)
await headerEditor.selection.collapse({ path: [0, 0], offset: 27 })
await headerEditor.insertText('Draft ')
For input fields, explicitly place the input caret before appending:
await input.click()
await input.evaluate((element) => {
element.setSelectionRange(element.value.length, element.value.length)
})
await page.keyboard.insertText(' typed')
For mobile root-local paste, use the Slate browser handle when the row is about clipboard ingress behavior, and keep native clipboard transport to browser projects that prove it honestly.
The Slate browser handle goes through the editor runtime, selection authority, history, and DOM repair path without relying on mobile viewport click geometry. That keeps the assertions about root-local editing, history, and state fields deterministic.
The raw pointer row still uses a real mouse click against the inactive root text surface, so pointer activation remains covered instead of being silently converted into a semantic helper.
locator.click() as a deterministic caret setup
unless the row is specifically about pointer activation.