Skip to content

Commit be6951b

Browse files
committed
fix(e2e): scope tauri-webdriver cache per matrix row + readiness via stdout
- Cache key for the tauri-webdriver intermediary now includes matrix.label. ubuntu-22 and ubuntu-24 were sharing Linux-X64-tauri-webdriver-v0.1.2; a binary cached from 24.04 linked against GLIBC_2.39 and crashed on 22.04. - globalSetup waits for the intermediary's "tauri-webdriver running on port" stdout marker instead of HTTP-probing /status. The /status route forwards to the in-app server on :4445, which isn't spawned until a per-spec webdriverio.remote() call ships the binary-path capability — so the probe timed out by design on every non-22.04 row.
1 parent 3ba47e9 commit be6951b

2 files changed

Lines changed: 47 additions & 48 deletions

File tree

.github/workflows/e2e-webview.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,10 @@ jobs:
190190
path: |
191191
~/.cargo/bin/tauri-webdriver
192192
~/.cargo/bin/tauri-webdriver.exe
193-
key: ${{ runner.os }}-${{ runner.arch }}-tauri-webdriver-v0.1.2
193+
# Include matrix.label so ubuntu-22.04 and ubuntu-24.04 don't share
194+
# a binary — a cache populated on 24.04 links against GLIBC_2.39
195+
# and won't run on 22.04 ("GLIBC_2.39 not found").
196+
key: ${{ runner.os }}-${{ runner.arch }}-${{ matrix.label }}-tauri-webdriver-v0.1.2
194197

195198
- name: Install tauri-webdriver intermediary
196199
if: steps.gate.outputs.skip != 'true' && steps.cache-twd.outputs.cache-hit != 'true'

e2e-webview/setup/global.ts

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { spawn, type ChildProcess } from 'node:child_process';
2-
import { setTimeout as delay } from 'node:timers/promises';
32
import fs from 'node:fs';
43
import path from 'node:path';
54

6-
const HOST = '127.0.0.1';
7-
const PORT = 4444;
85
const READY_TIMEOUT_MS = 30_000;
9-
const POLL_INTERVAL_MS = 250;
10-
const STATUS_URL = `http://${HOST}:${PORT}/status`;
6+
// The intermediary prints this marker to stdout once its listener is bound.
7+
// We can't HTTP-probe /status because the intermediary forwards /status to
8+
// the in-app server on :4445, which isn't spawned until a per-spec
9+
// `webdriverio.remote()` call delivers the binary-path capability — so any
10+
// pre-session HTTP probe fails by design.
11+
const READY_MARKER = /tauri-webdriver running on port/i;
1112

1213
const REPORTS_DIR = path.resolve('./reports');
1314
fs.mkdirSync(REPORTS_DIR, { recursive: true });
@@ -23,53 +24,48 @@ export default async function globalSetup() {
2324
shell: process.platform === 'win32',
2425
});
2526

26-
driver.stdout?.on('data', (chunk: Buffer) => {
27-
stdoutLog.write(chunk);
28-
process.stdout.write(chunk);
29-
});
30-
driver.stderr?.on('data', (chunk: Buffer) => {
31-
stderrLog.write(chunk);
32-
process.stderr.write(chunk);
33-
});
34-
35-
type ExitInfo = { code: number | null; signal: NodeJS.Signals | null };
36-
const exitState: { value: ExitInfo | null } = { value: null };
37-
driver.once('exit', (code, signal) => {
38-
exitState.value = { code, signal };
39-
});
27+
const ready = new Promise<void>((resolve, reject) => {
28+
const timer = setTimeout(() => {
29+
reject(
30+
new Error(
31+
`tauri-webdriver did not print readiness marker within ${READY_TIMEOUT_MS}ms. ` +
32+
`See ${path.relative(process.cwd(), stderrPath)} for driver output.`,
33+
),
34+
);
35+
}, READY_TIMEOUT_MS);
4036

41-
const spawnFailed = new Promise<never>((_, reject) => {
42-
driver.once('error', (err) =>
43-
reject(new Error(`tauri-webdriver failed to spawn: ${(err as Error).message}`)),
44-
);
45-
});
37+
let stdoutBuf = '';
38+
driver.stdout?.on('data', (chunk: Buffer) => {
39+
stdoutLog.write(chunk);
40+
process.stdout.write(chunk);
41+
stdoutBuf += chunk.toString('utf8');
42+
if (READY_MARKER.test(stdoutBuf)) {
43+
clearTimeout(timer);
44+
resolve();
45+
}
46+
});
47+
driver.stderr?.on('data', (chunk: Buffer) => {
48+
stderrLog.write(chunk);
49+
process.stderr.write(chunk);
50+
});
4651

47-
const ready = (async () => {
48-
const deadline = Date.now() + READY_TIMEOUT_MS;
49-
while (Date.now() < deadline) {
50-
const exited = exitState.value;
51-
if (exited) {
52-
throw new Error(
53-
`tauri-webdriver exited during startup (code=${exited.code}, signal=${exited.signal}). ` +
52+
driver.once('error', (err) => {
53+
clearTimeout(timer);
54+
reject(new Error(`tauri-webdriver failed to spawn: ${(err as Error).message}`));
55+
});
56+
driver.once('exit', (code, signal) => {
57+
clearTimeout(timer);
58+
reject(
59+
new Error(
60+
`tauri-webdriver exited during startup (code=${code}, signal=${signal}). ` +
5461
`See ${path.relative(process.cwd(), stderrPath)} for driver output.`,
55-
);
56-
}
57-
try {
58-
const res = await fetch(STATUS_URL, { signal: AbortSignal.timeout(1_000) });
59-
if (res.ok) return;
60-
} catch {
61-
// not yet — keep polling
62-
}
63-
await delay(POLL_INTERVAL_MS);
64-
}
65-
throw new Error(
66-
`tauri-webdriver did not become ready on ${STATUS_URL} within ${READY_TIMEOUT_MS}ms. ` +
67-
`See ${path.relative(process.cwd(), stderrPath)} for driver output.`,
68-
);
69-
})();
62+
),
63+
);
64+
});
65+
});
7066

7167
try {
72-
await Promise.race([ready, spawnFailed]);
68+
await ready;
7369
} catch (err) {
7470
if (driver.exitCode === null && !driver.killed) driver.kill('SIGTERM');
7571
stdoutLog.end();

0 commit comments

Comments
 (0)