diff --git a/src/renderer/src/components/new-workspace/smart-workspace-name-input-surface.tsx b/src/renderer/src/components/new-workspace/smart-workspace-name-input-surface.tsx index 277f24da30b..d43695e1c01 100644 --- a/src/renderer/src/components/new-workspace/smart-workspace-name-input-surface.tsx +++ b/src/renderer/src/components/new-workspace/smart-workspace-name-input-surface.tsx @@ -192,6 +192,8 @@ export function renderSmartWorkspaceNameInput( applyEmojiReplacement(completedEmoji) return } + // A pending emoji caret frame would otherwise yank the caret back mid-typing. + cancelLocalInputFocusFrame() onValueChange(nextValue) setEmojiCursor(nextCursor) if (!disabled && mode !== 'text') { diff --git a/tests/e2e/linear-url-workspace-entry.spec.ts b/tests/e2e/linear-url-workspace-entry.spec.ts index 76e17e11ffe..d1cb2677257 100644 --- a/tests/e2e/linear-url-workspace-entry.spec.ts +++ b/tests/e2e/linear-url-workspace-entry.spec.ts @@ -97,6 +97,10 @@ async function releaseHeldLinearLookup(page: Page): Promise { async function pasteLinearUrl(page: Page, input: ReturnType): Promise { await page.evaluate((text) => window.api.ui.writeClipboardText(text), LINEAR_URL) + // X selection ownership is async; pasting before it lands delivers stale text. + await expect + .poll(() => page.evaluate(() => window.api.ui.readClipboardText()), { timeout: 5_000 }) + .toBe(LINEAR_URL) await input.focus() await page.keyboard.press(pasteChord()) } diff --git a/tests/e2e/native-chat-first-flush-race.spec.ts b/tests/e2e/native-chat-first-flush-race.spec.ts index 1362a882902..2e85e2dc132 100644 --- a/tests/e2e/native-chat-first-flush-race.spec.ts +++ b/tests/e2e/native-chat-first-flush-race.spec.ts @@ -141,10 +141,24 @@ test.describe('Native chat first-flush transcript race (#8401)', () => { path: path.join(screenshotDir, '01-loading-no-error.png') }) - // Why: a short real delay proves the first readSession attempt already - // hit the not-yet-flushed file (returning notFound) and the renderer's - // backoff retry — not a lucky first read — is what picks it up below. - await orcaPage.waitForTimeout(1_500) + // Why observe, not sleep: 1_500ms is exactly UNFLUSHED_SETTLE_MS, so a fixed + // wait straddles the boundary where the host reports the transcript pending + // and the renderer cancels its own retry. Read through the same IPC instead, + // proving the miss directly. A notFound is never cached, so this cannot + // perturb the hydration the assertions below measure. + await expect + .poll( + () => + orcaPage.evaluate( + ({ id, file }) => + window.api.nativeChat + .readSession('claude', id, 50, file) + .then((result) => Boolean(result && 'error' in result && result.notFound)), + { id: sessionId, file: transcriptPath } + ), + { timeout: 10_000, message: 'transcript resolved before the first flush' } + ) + .toBe(true) await expect(orcaPage.getByText(ERROR_TITLE)).toHaveCount(0) const userText = 'Explain the native chat first-flush race fix for #8401' diff --git a/tests/e2e/orchestration-idle-mail-delivery.spec.ts b/tests/e2e/orchestration-idle-mail-delivery.spec.ts index cffa6415208..9d90aed1875 100644 --- a/tests/e2e/orchestration-idle-mail-delivery.spec.ts +++ b/tests/e2e/orchestration-idle-mail-delivery.spec.ts @@ -653,7 +653,12 @@ test.describe('orchestration delivery to a cold-parked agent', () => { const parkingDelayMs = 500 test.use({ - orcaAppExtraEnv: { ORCA_E2E_TERMINAL_PARKING_DELAY_MS: String(parkingDelayMs) } + orcaAppExtraEnv: { + ORCA_E2E_TERMINAL_PARKING_DELAY_MS: String(parkingDelayMs), + // The working-title round trip (PTY -> daemon -> main) must beat the Enter + // timer; 500ms is a production heuristic, not a budget CI can honour. + ORCA_E2E_ORCHESTRATION_POINTER_ENTER_DELAY_MS: '5000' + } }) test('keeps one pointer and one idempotent prompt on the same parked PTY', async ({ diff --git a/tests/e2e/slept-workspace-remount-wake.spec.ts b/tests/e2e/slept-workspace-remount-wake.spec.ts index f820a7c7f69..54109a6b532 100644 --- a/tests/e2e/slept-workspace-remount-wake.spec.ts +++ b/tests/e2e/slept-workspace-remount-wake.spec.ts @@ -66,7 +66,7 @@ test('remounting a slept hidden pane does not respawn its PTY', async ({ orcaPag expect(sample.tabPtyHints[0], 'sleep must keep the session id as a wake hint').toBeTruthy() const remounted = await orcaPage.evaluate( - (tabId) => window.__store?.getState().remountTerminalTabForRecovery(tabId) ?? false, + (tabId) => window.__store?.getState().remountTerminalTabForRecovery(tabId).remounted ?? false, sleptTabId ) expect(remounted, 'remountTerminalTabForRecovery did not find the slept tab').toBe(true) diff --git a/tests/e2e/tasks-page.spec.ts b/tests/e2e/tasks-page.spec.ts index b8f57a1996f..962f86de0c5 100644 --- a/tests/e2e/tasks-page.spec.ts +++ b/tests/e2e/tasks-page.spec.ts @@ -13,6 +13,9 @@ import { GITHUB_TASK_SEARCH_IDLE_MS } from '../../src/renderer/src/components/us // on a loaded runner, so one slow keystroke committed a prefix and failed the assertion. const TASK_SEARCH_TYPING_DELAY_MS = Math.round(GITHUB_TASK_SEARCH_IDLE_MS / 6) const TASK_SEARCH_SETTLE_MS = GITHUB_TASK_SEARCH_IDLE_MS + 50 +// Why derived: the probe must outlast the idle window plus a React commit and two +// store round trips; a flat 2s left ~1.2s of slack on a single-worker runner. +const TASK_SEARCH_PROBE_TIMEOUT_MS = GITHUB_TASK_SEARCH_IDLE_MS * 6 type RenderedTaskSource = { source: string @@ -411,7 +414,9 @@ test.describe('Tasks page', () => { await input.fill('') await expect - .poll(async () => readTaskSearchRequestProbe(orcaPage), { timeout: 2_000 }) + .poll(async () => readTaskSearchRequestProbe(orcaPage), { + timeout: TASK_SEARCH_PROBE_TIMEOUT_MS + }) .toEqual({ countQueries: ['is:issue is:open'], fetchQueries: ['is:issue is:open'] }) await resetTaskSearchRequestProbe(orcaPage) @@ -422,7 +427,9 @@ test.describe('Tasks page', () => { // The contract is that no prefix of the typed query is ever queried, not that the // probe is empty at one instant: exactly one request per surface, for the final value. await expect - .poll(async () => readTaskSearchRequestProbe(orcaPage), { timeout: 2_000 }) + .poll(async () => readTaskSearchRequestProbe(orcaPage), { + timeout: TASK_SEARCH_PROBE_TIMEOUT_MS + }) .toEqual({ countQueries: ['is:issue rate'], fetchQueries: ['is:issue rate'] }) await resetTaskSearchRequestProbe(orcaPage) @@ -430,7 +437,9 @@ test.describe('Tasks page', () => { await input.press('Enter') await expect - .poll(async () => readTaskSearchRequestProbe(orcaPage), { timeout: 2_000 }) + .poll(async () => readTaskSearchRequestProbe(orcaPage), { + timeout: TASK_SEARCH_PROBE_TIMEOUT_MS + }) .toEqual({ countQueries: ['is:issue ratex'], fetchQueries: ['is:issue ratex'] }) await orcaPage.waitForTimeout(TASK_SEARCH_SETTLE_MS) expect(await readTaskSearchRequestProbe(orcaPage)).toEqual({