From e87dc6b86e06f7fcfcfa9dc5e7d3788a1634cef3 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Wed, 17 Jun 2026 15:54:57 -0700 Subject: [PATCH 01/20] Create iOS browserstack test --- src/e2e/iOS/__tests__/caret.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index 29e773dc8f0..4877e4113d4 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -16,6 +16,7 @@ import newThought from '../helpers/newThought' import paste from '../helpers/paste' import tap from '../helpers/tap' import waitForEditable from '../helpers/waitForEditable' +import waitForElement from '../helpers/waitForElement' import waitUntil from '../helpers/waitUntil' // tests succeeds individually, but fails when there are too many tests running in parallel @@ -251,4 +252,17 @@ describe('Caret', () => { expect(selectionTextContent).toBe('new') expect(childrenTexts).toEqual(['foo', 'bar']) }) + + it('Focus is prevented after clearing the cursor', async () => { + await newThought('Hello') + await hideKeyboardByTappingDone() + + const homeNodeHandle = await waitForElement('[data-testid="home"]') + await tap(homeNodeHandle) + + const editableNodeHandle = await getEditable('Hello') + await tap(editableNodeHandle, { horizontalTapLine: 'right' }) + + expect(document.activeElement).toBe(document.body) + }) }) From eccf583d023b216a2b03765ecd846ad2f2db77c3 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Fri, 19 Jun 2026 11:28:21 -0700 Subject: [PATCH 02/20] Check activeElemnt in browser.execute --- src/e2e/iOS/__tests__/caret.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index 4877e4113d4..f92308bd5ba 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -263,6 +263,7 @@ describe('Caret', () => { const editableNodeHandle = await getEditable('Hello') await tap(editableNodeHandle, { horizontalTapLine: 'right' }) - expect(document.activeElement).toBe(document.body) + const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) + expect(activeElementIsBody).toBe(true) }) }) From 83c35d59eb4399f2e33ae0c00324379026a91183 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Thu, 18 Jun 2026 14:26:43 -0700 Subject: [PATCH 03/20] Fix TransitionStyle error caused by radix-ui version bump --- src/components/Thought.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Thought.tsx b/src/components/Thought.tsx index b3087284916..7ba1863a42e 100644 --- a/src/components/Thought.tsx +++ b/src/components/Thought.tsx @@ -1,5 +1,5 @@ import { unescape } from 'html-escaper' -import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' +import React, { type CSSProperties, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import { shallowEqual, useDispatch, useSelector } from 'react-redux' import { css, cx } from '../../styled-system/css' import { childRecipe, invalidOptionRecipe } from '../../styled-system/recipes' @@ -167,7 +167,7 @@ const useCol1Alignment = ({ path, value, isTableCol1 }: UseCol1AlignParams) => { return cursorParentId ? getChildren(state, cursorParentId).map(t => t.value) : [] }, shallowEqual) - interface TransitionStyle { + interface TransitionStyle extends CSSProperties { transform: string transition: string } From 6225800b532522eba744b1103e7b4af25ed5553d Mon Sep 17 00:00:00 2001 From: Ethan James Date: Fri, 19 Jun 2026 11:50:35 -0700 Subject: [PATCH 04/20] Move tap position right --- src/e2e/iOS/__tests__/caret.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index f92308bd5ba..46b13cc6a26 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -261,7 +261,7 @@ describe('Caret', () => { await tap(homeNodeHandle) const editableNodeHandle = await getEditable('Hello') - await tap(editableNodeHandle, { horizontalTapLine: 'right' }) + await tap(editableNodeHandle, { horizontalTapLine: 'right', x: 4 }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) From 560a62d3c7e663531e51a18d8cb7f01d8367e1f9 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Fri, 19 Jun 2026 12:04:10 -0700 Subject: [PATCH 05/20] Increase lint:src old space size --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0648b695693..459bc941abe 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "deploy:staging2": "yarn lint && yarn build && firebase hosting:channel:deploy staging2 --expires 30d", "lint:lockfile": "npx lockfile-lint", "lint:no-npm": "node ./scripts/no-files.js package-lock.json", - "lint:src": "FORCE_COLOR=1 eslint . --cache --rule 'no-console: [2, { allow: [error, info, warn] }]'", + "lint:src": "FORCE_COLOR=1 NODE_OPTIONS=--max-old-space-size=4096 eslint . --cache --rule 'no-console: [2, { allow: [error, info, warn] }]'", "lint:tsc": "tsc", "lint": "FORCE_COLOR=1 npm-run-all --serial \"lint:*\"", "postinstall": "yarn build:packages && git config core.hooksPath .hooks && yarn build:styles", From ddc823abe5d0fc2d79b14b10048bd966e0fb45c2 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Fri, 19 Jun 2026 13:08:20 -0700 Subject: [PATCH 06/20] Nudge tap position right --- src/e2e/iOS/__tests__/caret.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index 46b13cc6a26..f0e746571e1 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -261,7 +261,7 @@ describe('Caret', () => { await tap(homeNodeHandle) const editableNodeHandle = await getEditable('Hello') - await tap(editableNodeHandle, { horizontalTapLine: 'right', x: 4 }) + await tap(editableNodeHandle, { horizontalTapLine: 'right', x: 5 }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) From d2a202ca4b7ca3a76d4c38f8bc59e3dde30a66f5 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Tue, 23 Jun 2026 15:34:00 -0700 Subject: [PATCH 07/20] Profile events in test --- src/util/initEvents.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/util/initEvents.ts b/src/util/initEvents.ts index ca14738b786..750a0efe4e2 100644 --- a/src/util/initEvents.ts +++ b/src/util/initEvents.ts @@ -289,8 +289,12 @@ const initEvents = (store: Store) => { } } + /** Profile touchstart event for debugging the Browserstack test. */ + const onTouchStart = (e: TouchEvent) => console.info('touchstart', e.touches[0].clientX, e.touches[0].clientY) + /** Stops the scroll-at-edge when dragging stops. */ - const onTouchEnd = () => { + const onTouchEnd = (e: TouchEvent) => { + console.info('touchend', e.changedTouches[0].clientX, e.changedTouches[0].clientY) scrollAtEdge.stop() } @@ -377,8 +381,11 @@ const initEvents = (store: Store) => { window.addEventListener('popstate', onPopstate) window.addEventListener('mousemove', onMouseMove) // Note: touchstart may not be propagated after dragHold + window.addEventListener('touchstart', onTouchStart) window.addEventListener('touchmove', onTouchMove) window.addEventListener('touchend', onTouchEnd) + window.addEventListener('mousedown', (e: MouseEvent) => console.info('mousedown', e.clientX, e.clientY)) + window.addEventListener('mouseup', (e: MouseEvent) => console.info('mouseup', e.clientX, e.clientY)) window.addEventListener('beforeunload', onBeforeUnload) window.addEventListener('scroll', updateScrollTop) window.addEventListener('dragenter', dragEnter) @@ -406,6 +413,7 @@ const initEvents = (store: Store) => { window.removeEventListener('keyup', keyUp) window.removeEventListener('popstate', onPopstate) window.removeEventListener('mousemove', onMouseMove) + window.removeEventListener('touchstart', onTouchStart) window.removeEventListener('touchmove', onTouchMove) window.removeEventListener('touchend', onTouchEnd) window.removeEventListener('beforeunload', onBeforeUnload) From 363ac00c970cba73aabfce9e484f1b8dcc1a2101 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Tue, 23 Jun 2026 15:46:37 -0700 Subject: [PATCH 08/20] Add more logging to browserstack test --- src/e2e/iOS/__tests__/caret.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index f0e746571e1..db4490804b3 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -256,10 +256,10 @@ describe('Caret', () => { it('Focus is prevented after clearing the cursor', async () => { await newThought('Hello') await hideKeyboardByTappingDone() - + console.info('Tapping home') const homeNodeHandle = await waitForElement('[data-testid="home"]') await tap(homeNodeHandle) - + console.info('Tapping Hello') const editableNodeHandle = await getEditable('Hello') await tap(editableNodeHandle, { horizontalTapLine: 'right', x: 5 }) From 866f8318a68f4d4fe881c045126afa895a72dd40 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Tue, 23 Jun 2026 15:58:33 -0700 Subject: [PATCH 09/20] Nudge tap position down --- src/e2e/iOS/__tests__/caret.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index db4490804b3..ec30aa97b13 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -261,7 +261,7 @@ describe('Caret', () => { await tap(homeNodeHandle) console.info('Tapping Hello') const editableNodeHandle = await getEditable('Hello') - await tap(editableNodeHandle, { horizontalTapLine: 'right', x: 5 }) + await tap(editableNodeHandle, { horizontalTapLine: 'right', y: 14 }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) From 721993fd45a333e1b98244d3772288f02728e6de Mon Sep 17 00:00:00 2001 From: Ethan James Date: Tue, 23 Jun 2026 16:08:40 -0700 Subject: [PATCH 10/20] Remove redundant event profiling --- src/util/initEvents.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/util/initEvents.ts b/src/util/initEvents.ts index 750a0efe4e2..ca14738b786 100644 --- a/src/util/initEvents.ts +++ b/src/util/initEvents.ts @@ -289,12 +289,8 @@ const initEvents = (store: Store) => { } } - /** Profile touchstart event for debugging the Browserstack test. */ - const onTouchStart = (e: TouchEvent) => console.info('touchstart', e.touches[0].clientX, e.touches[0].clientY) - /** Stops the scroll-at-edge when dragging stops. */ - const onTouchEnd = (e: TouchEvent) => { - console.info('touchend', e.changedTouches[0].clientX, e.changedTouches[0].clientY) + const onTouchEnd = () => { scrollAtEdge.stop() } @@ -381,11 +377,8 @@ const initEvents = (store: Store) => { window.addEventListener('popstate', onPopstate) window.addEventListener('mousemove', onMouseMove) // Note: touchstart may not be propagated after dragHold - window.addEventListener('touchstart', onTouchStart) window.addEventListener('touchmove', onTouchMove) window.addEventListener('touchend', onTouchEnd) - window.addEventListener('mousedown', (e: MouseEvent) => console.info('mousedown', e.clientX, e.clientY)) - window.addEventListener('mouseup', (e: MouseEvent) => console.info('mouseup', e.clientX, e.clientY)) window.addEventListener('beforeunload', onBeforeUnload) window.addEventListener('scroll', updateScrollTop) window.addEventListener('dragenter', dragEnter) @@ -413,7 +406,6 @@ const initEvents = (store: Store) => { window.removeEventListener('keyup', keyUp) window.removeEventListener('popstate', onPopstate) window.removeEventListener('mousemove', onMouseMove) - window.removeEventListener('touchstart', onTouchStart) window.removeEventListener('touchmove', onTouchMove) window.removeEventListener('touchend', onTouchEnd) window.removeEventListener('beforeunload', onBeforeUnload) From 25c17d8069546680038b7643abc6e19e6c0ceaea Mon Sep 17 00:00:00 2001 From: Ethan James Date: Tue, 23 Jun 2026 16:09:12 -0700 Subject: [PATCH 11/20] Try to match touch event position in browserstack test --- src/e2e/iOS/__tests__/caret.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index ec30aa97b13..cb06d442a9e 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -261,7 +261,7 @@ describe('Caret', () => { await tap(homeNodeHandle) console.info('Tapping Hello') const editableNodeHandle = await getEditable('Hello') - await tap(editableNodeHandle, { horizontalTapLine: 'right', y: 14 }) + await tap(editableNodeHandle, { horizontalTapLine: 'right', x: 12 }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) From dee9340b603bb03606786092dc4537e5f812c7c0 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Tue, 23 Jun 2026 16:15:49 -0700 Subject: [PATCH 12/20] Tweak touch event position --- src/e2e/iOS/__tests__/caret.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index cb06d442a9e..02fce928154 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -261,7 +261,7 @@ describe('Caret', () => { await tap(homeNodeHandle) console.info('Tapping Hello') const editableNodeHandle = await getEditable('Hello') - await tap(editableNodeHandle, { horizontalTapLine: 'right', x: 12 }) + await tap(editableNodeHandle, { horizontalTapLine: 'right', x: 12.3333, y: 12 }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) From 48794aeb3218b263e96fc890be8954e4685c0c2c Mon Sep 17 00:00:00 2001 From: Ethan James Date: Wed, 24 Jun 2026 14:23:46 -0700 Subject: [PATCH 13/20] Use gesture in test to trigger compatability events --- src/e2e/iOS/__tests__/caret.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index 02fce928154..9266b866107 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -260,8 +260,8 @@ describe('Caret', () => { const homeNodeHandle = await waitForElement('[data-testid="home"]') await tap(homeNodeHandle) console.info('Tapping Hello') - const editableNodeHandle = await getEditable('Hello') - await tap(editableNodeHandle, { horizontalTapLine: 'right', x: 12.3333, y: 12 }) + + await gesture('', { xStart: 145, yStart: 90, segmentLength: 0, waitMs: 100 }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) From 8050965b801734c9b4a125ed0249fbfb0f0ca0b4 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Wed, 24 Jun 2026 14:52:39 -0700 Subject: [PATCH 14/20] Nudge y position of gesture --- src/e2e/iOS/__tests__/caret.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index 9266b866107..9c2e3e55b6d 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -261,7 +261,7 @@ describe('Caret', () => { await tap(homeNodeHandle) console.info('Tapping Hello') - await gesture('', { xStart: 145, yStart: 90, segmentLength: 0, waitMs: 100 }) + await gesture('', { xStart: 145, yStart: 78, segmentLength: 0, waitMs: 100 }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) From b24f3775dcce7fe292a96a1eb647f9d21c977822 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Mon, 29 Jun 2026 11:52:46 -0700 Subject: [PATCH 15/20] Fix y position of gesture --- src/e2e/iOS/__tests__/caret.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index 9c2e3e55b6d..1b0d14847d8 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -261,7 +261,7 @@ describe('Caret', () => { await tap(homeNodeHandle) console.info('Tapping Hello') - await gesture('', { xStart: 145, yStart: 78, segmentLength: 0, waitMs: 100 }) + await gesture('', { xStart: 145, yStart: 104, segmentLength: 0, waitMs: 100 }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) From a2f9c788d9d7e58f520b68c5a628f49147efaeeb Mon Sep 17 00:00:00 2001 From: Ethan James Date: Mon, 29 Jun 2026 13:24:24 -0700 Subject: [PATCH 16/20] Add pointerType option to tap helper --- src/e2e/iOS/__tests__/caret.ts | 5 ++--- src/e2e/iOS/helpers/tap.ts | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index 1b0d14847d8..e8de02f9cd5 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -256,12 +256,11 @@ describe('Caret', () => { it('Focus is prevented after clearing the cursor', async () => { await newThought('Hello') await hideKeyboardByTappingDone() - console.info('Tapping home') + const homeNodeHandle = await waitForElement('[data-testid="home"]') await tap(homeNodeHandle) - console.info('Tapping Hello') - await gesture('', { xStart: 145, yStart: 104, segmentLength: 0, waitMs: 100 }) + await tap(await waitForEditable('Hello'), { horizontalTapLine: 'right', x: 5, pointerType: 'touch' }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) diff --git a/src/e2e/iOS/helpers/tap.ts b/src/e2e/iOS/helpers/tap.ts index 824f792f39e..dc7033fcbec 100644 --- a/src/e2e/iOS/helpers/tap.ts +++ b/src/e2e/iOS/helpers/tap.ts @@ -5,6 +5,8 @@ import type { Element } from 'webdriverio' interface Options { // Where in the horizontal line (inside) of the target node should be tapped horizontalTapLine?: 'left' | 'right' + // Pointer type to use for the tap action. Defaults to 'mouse'. + pointerType?: 'mouse' | 'touch' // Specify specific node on editable to tap. Overrides horizontalClickLine offset?: number // Number of pixels of x offset to add to the tap coordinates @@ -21,7 +23,7 @@ interface Options { */ const tap = async ( nodeHandle: Element, - { horizontalTapLine = 'left', offset, x = 0, y = 0, releaseDelayMs = 100 }: Options = {}, + { horizontalTapLine = 'left', offset, x = 0, y = 0, pointerType = 'mouse', releaseDelayMs = 100 }: Options = {}, ) => { // Ensure element exists and has an elementId const exists = await nodeHandle.isExisting() @@ -98,7 +100,7 @@ const tap = async ( { type: 'pointer', id: 'pointer1', - parameters: { pointerType: 'mouse' }, + parameters: { pointerType }, actions: [ { type: 'pointerMove', From 0573ddce09dd8f3b227473b5a241164fc1cf7308 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Mon, 29 Jun 2026 13:35:18 -0700 Subject: [PATCH 17/20] Nudge x position of tap --- src/e2e/iOS/__tests__/caret.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index e8de02f9cd5..ea082a5f84d 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -260,7 +260,7 @@ describe('Caret', () => { const homeNodeHandle = await waitForElement('[data-testid="home"]') await tap(homeNodeHandle) - await tap(await waitForEditable('Hello'), { horizontalTapLine: 'right', x: 5, pointerType: 'touch' }) + await tap(await waitForEditable('Hello'), { horizontalTapLine: 'right', x: 6, pointerType: 'touch' }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) From a98264563fd5156319f2b7756672704d096e2ae6 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Mon, 29 Jun 2026 13:52:53 -0700 Subject: [PATCH 18/20] Add y:60 to tap call in new test --- src/e2e/iOS/__tests__/caret.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index ea082a5f84d..2b1e8c011bd 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -260,7 +260,7 @@ describe('Caret', () => { const homeNodeHandle = await waitForElement('[data-testid="home"]') await tap(homeNodeHandle) - await tap(await waitForEditable('Hello'), { horizontalTapLine: 'right', x: 6, pointerType: 'touch' }) + await tap(await waitForEditable('Hello'), { horizontalTapLine: 'right', x: 6, y: 60, pointerType: 'touch' }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) expect(activeElementIsBody).toBe(true) From 786dc620974a4b7a203c308bca2bd0ad21968a14 Mon Sep 17 00:00:00 2001 From: Ethan James Date: Tue, 30 Jun 2026 12:21:48 -0700 Subject: [PATCH 19/20] Failing browserstack test before main merge --- src/e2e/iOS/__tests__/caret.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index 2b1e8c011bd..d3d2ea416ff 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -260,9 +260,18 @@ describe('Caret', () => { const homeNodeHandle = await waitForElement('[data-testid="home"]') await tap(homeNodeHandle) - await tap(await waitForEditable('Hello'), { horizontalTapLine: 'right', x: 6, y: 60, pointerType: 'touch' }) + await tap(await waitForEditable('Hello'), { horizontalTapLine: 'right', x: 20 + 6, y: 60, pointerType: 'touch' }) + + // Wait for focus to be cleared and activeElement to be body + await waitUntil(async () => { + const isBody = await browser.execute(() => document.activeElement === document.body) + const nodeType = await browser.execute(() => document.activeElement?.nodeType) + console.info('activeElement check - isBody:', isBody, 'nodeType:', nodeType) + return isBody + }) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) + console.info('Final check - activeElementIsBody:', activeElementIsBody) expect(activeElementIsBody).toBe(true) }) }) From cbda5777d00bb317ab048a30f91b520cb33480cc Mon Sep 17 00:00:00 2001 From: Ethan James Date: Fri, 3 Jul 2026 14:55:58 -0700 Subject: [PATCH 20/20] Update test with click handler --- src/e2e/iOS/__tests__/caret.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/e2e/iOS/__tests__/caret.ts b/src/e2e/iOS/__tests__/caret.ts index d3d2ea416ff..87d41810ef8 100644 --- a/src/e2e/iOS/__tests__/caret.ts +++ b/src/e2e/iOS/__tests__/caret.ts @@ -16,7 +16,6 @@ import newThought from '../helpers/newThought' import paste from '../helpers/paste' import tap from '../helpers/tap' import waitForEditable from '../helpers/waitForEditable' -import waitForElement from '../helpers/waitForElement' import waitUntil from '../helpers/waitUntil' // tests succeeds individually, but fails when there are too many tests running in parallel @@ -257,21 +256,18 @@ describe('Caret', () => { await newThought('Hello') await hideKeyboardByTappingDone() - const homeNodeHandle = await waitForElement('[data-testid="home"]') - await tap(homeNodeHandle) + // Use a native WebDriver click on the inner anchor to clear the cursor. + // A synthetic tap() (performActions pointer events) does not fire the real + // click event that HomeLink's fastClick onClick handler relies on, so the + // cursor would never be cleared. + await browser.$('[data-testid="home"] a').click() - await tap(await waitForEditable('Hello'), { horizontalTapLine: 'right', x: 20 + 6, y: 60, pointerType: 'touch' }) + await tap(await waitForEditable('Hello'), { horizontalTapLine: 'right', x: 6, y: 60, pointerType: 'touch' }) // Wait for focus to be cleared and activeElement to be body - await waitUntil(async () => { - const isBody = await browser.execute(() => document.activeElement === document.body) - const nodeType = await browser.execute(() => document.activeElement?.nodeType) - console.info('activeElement check - isBody:', isBody, 'nodeType:', nodeType) - return isBody - }) + await waitUntil(() => browser.execute(() => document.activeElement === document.body)) const activeElementIsBody = await browser.execute(() => document.activeElement === document.body) - console.info('Final check - activeElementIsBody:', activeElementIsBody) expect(activeElementIsBody).toBe(true) }) })