From ab6b76c8ed16b543358dd02517eaf4a893d012fb Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 1 Aug 2026 20:11:18 -0700 Subject: [PATCH] test(e2e): select the IBus engine by read-back, not exit status Co-authored-by: Orca --- .../scripts/run-terminal-ibus-engine-e2e.mjs | 21 ++++++++++++++++--- tests/e2e/terminal-ibus-engine-native.spec.ts | 13 ++++++++---- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/config/scripts/run-terminal-ibus-engine-e2e.mjs b/config/scripts/run-terminal-ibus-engine-e2e.mjs index 11d8a7b69c0..7f0eba0df1a 100644 --- a/config/scripts/run-terminal-ibus-engine-e2e.mjs +++ b/config/scripts/run-terminal-ibus-engine-e2e.mjs @@ -110,6 +110,7 @@ function configureEngine(profile) { async function waitForEngine(ibusProcess, profile) { const deadline = Date.now() + 15_000 let lastFailure = '' + let attempts = 0 while (Date.now() < deadline) { if (ibusProcess.exitCode !== null) { throw new Error(`ibus-daemon exited early with code ${ibusProcess.exitCode}`) @@ -118,18 +119,32 @@ async function waitForEngine(ibusProcess, profile) { encoding: 'utf8', stdio: 'pipe' }) - if (result.status === 0) { + // Why: the selection lands over D-Bus first and only then runs setxkbmap, which + // exits non-zero — silently — for any engine declaring no XKB layout of its own. + // Read the engine back instead of trusting the status. + const active = spawnSync('ibus', ['engine'], { encoding: 'utf8', stdio: 'pipe' }) + if (active.status === 0 && active.stdout.trim() === profile.ibusEngineName) { return } - lastFailure = (result.stderr || result.stdout || '').trim() + attempts += 1 + lastFailure = [ + `status=${result.status} signal=${result.signal ?? 'none'}`, + result.error ? `error=${result.error.message}` : '', + result.stderr?.trim() ? `stderr=${result.stderr.trim()}` : '', + result.stdout?.trim() ? `stdout=${result.stdout.trim()}` : '', + `active=${active.stdout?.trim() || '(none)'}` + ] + .filter(Boolean) + .join(' | ') await delay(100) } // Why: the engine name a package registers is not always its apt suffix, so the // available list is the only thing that tells you which of the two is wrong. const available = commandOutput('ibus', ['list-engine']) throw new Error( - `Timed out while selecting the IBus ${profile.ibusEngineName} engine.\n` + + `Timed out while selecting the IBus ${profile.ibusEngineName} engine after ${attempts} attempts.\n` + `Last 'ibus engine' failure: ${lastFailure || '(no output)'}\n` + + `Engine ibus reports as current: ${commandOutput('ibus', ['engine'])}\n` + `Engines ibus reports as available:\n${available}` ) } diff --git a/tests/e2e/terminal-ibus-engine-native.spec.ts b/tests/e2e/terminal-ibus-engine-native.spec.ts index 033e1bb8753..c52a16a242c 100644 --- a/tests/e2e/terminal-ibus-engine-native.spec.ts +++ b/tests/e2e/terminal-ibus-engine-native.spec.ts @@ -85,10 +85,15 @@ async function focusNativeTerminalWindow( await expect.poll(() => page.title(), { timeout: 5_000 }).toBe(title) runXdotool('search', '--onlyvisible', '--name', title, 'windowfocus', '--sync') - execFileSync('ibus', ['engine', engine.ibusEngineName], { - stdio: 'pipe', - timeout: NATIVE_COMMAND_TIMEOUT_MS - }) + try { + execFileSync('ibus', ['engine', engine.ibusEngineName], { + stdio: 'pipe', + timeout: NATIVE_COMMAND_TIMEOUT_MS + }) + } catch { + // Why: selection succeeds over D-Bus before the non-zero exit an engine with no + // XKB layout of its own produces; the read-back below is the real assertion. + } const active = execFileSync('ibus', ['engine'], { encoding: 'utf8', timeout: NATIVE_COMMAND_TIMEOUT_MS