From e08eba674c195596228834bf3c1ef4f94e6b118e Mon Sep 17 00:00:00 2001 From: Jinjing <6427696+AmethystLiang@users.noreply.github.com> Date: Mon, 3 Aug 2026 03:07:52 -0700 Subject: [PATCH] test(terminal): cover live macOS Korean syllable flush (#12284) --- .../terminal-macos-2set-korean-native.spec.ts | 63 ++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/tests/e2e/terminal-macos-2set-korean-native.spec.ts b/tests/e2e/terminal-macos-2set-korean-native.spec.ts index 31c900a41..e29413f7c 100644 --- a/tests/e2e/terminal-macos-2set-korean-native.spec.ts +++ b/tests/e2e/terminal-macos-2set-korean-native.spec.ts @@ -32,13 +32,47 @@ function typeNativeTwoSetKorean(processId: number, keyCodes: readonly number[]): ]) } +function typeNativeTwoSetKoreanPreedit(processId: number, keyCodes: readonly number[]): void { + execFileSync('osascript', [ + '-e', + `tell application "System Events" to set frontmost of first application process whose unix id is ${processId} to true`, + '-e', + 'tell application "System Events"', + '-e', + `repeat with currentKeyCode in {${keyCodes.join(', ')}}`, + '-e', + 'key code (currentKeyCode as integer)', + '-e', + 'delay 0.1', + '-e', + 'end repeat', + '-e', + 'end tell' + ]) +} + +function commitNativeComposition(): void { + execFileSync('osascript', ['-e', 'tell application "System Events" to key code 36']) +} + +async function readActiveComposition(page: Page): Promise { + return page.evaluate(() => { + const textarea = document.querySelector('.xterm-helper-textarea:focus') + const composition = textarea?.parentElement?.querySelector( + '.composition-view.active' + ) + return composition?.textContent?.replaceAll('\u200e', '') ?? null + }) +} + async function runNativeScenario( page: Page, testInfo: TestInfo, testRepoPath: string, processId: number, keyCodes: readonly number[], - expectedText: string + expectedText: string, + preCommit?: { committedText: string; preeditText: string } ): Promise { await waitForSessionReady(page) await waitForActiveWorktree(page) @@ -55,7 +89,16 @@ async function runNativeScenario( await startTerminalImeByteReader(page, ptyId, reader) await focusActiveTerminalInput(page) await installTerminalImeBoundaryProbe(page) - typeNativeTwoSetKorean(processId, keyCodes) + if (preCommit) { + typeNativeTwoSetKoreanPreedit(processId, keyCodes) + await expect.poll(() => readActiveComposition(page)).toBe(preCommit.preeditText) + await expect + .poll(async () => (await readTerminalImeBoundaryTrace(page)).onData.join('')) + .toBe(preCommit.committedText) + commitNativeComposition() + } else { + typeNativeTwoSetKorean(processId, keyCodes) + } const receivedBytes = await waitForTerminalImeBytes(page, reader) expect(receivedBytes).toEqual([Buffer.from(`${expectedText}\n`).toString('hex')]) @@ -109,4 +152,20 @@ test.describe('Native macOS 2-Set Korean terminal input @headful', () => { 'ㅐㅏ묘' ) }) + + test('flushes each syllable while the next remains in preedit', async ({ + electronApp, + orcaPage, + testRepoPath + }, testInfo) => { + await runNativeScenario( + orcaPage, + testInfo, + testRepoPath, + electronApp.process().pid!, + [15, 40, 1, 40, 14, 40], + '가나다', + { committedText: '가나', preeditText: '다' } + ) + }) })