|
1 | 1 | import { execFileSync } from 'node:child_process' |
2 | | -import { chmodSync, mkdtempSync, readdirSync, writeFileSync } from 'node:fs' |
| 2 | +import { chmodSync, mkdtempSync, readdirSync, readFileSync, writeFileSync } from 'node:fs' |
3 | 3 | import { tmpdir } from 'node:os' |
4 | 4 | import { join } from 'node:path' |
5 | 5 | import { type ElectronApplication, expect, type Page, test } from '@playwright/test' |
@@ -31,8 +31,32 @@ const STUBBORN = "trap '' HUP INT TERM" |
31 | 31 | const sim = new FixtureSim() |
32 | 32 | /** The app's own log output for the current test, attached when it fails. */ |
33 | 33 | const appOutput: string[] = [] |
34 | | -/** Each scenario's outcome, written to `TERMINAL_CANCEL_REPORT_PATH` when the suite ends. */ |
35 | | -const report: Array<{ name: string; status: string; durationMs: number }> = [] |
| 34 | +interface ReportCheck { |
| 35 | + name: string |
| 36 | + status: string |
| 37 | + durationMs: number |
| 38 | + retry: number |
| 39 | +} |
| 40 | + |
| 41 | +/** |
| 42 | + * Adds a scenario's outcome to the report at `TERMINAL_CANCEL_REPORT_PATH` as soon as it is known. |
| 43 | + * Playwright replaces the worker after a failure, so the file, not the worker's memory, holds what |
| 44 | + * came before: a failure and its retry both stay in it. |
| 45 | + */ |
| 46 | +function reportCheck(check: ReportCheck): void { |
| 47 | + const reportPath = process.env.TERMINAL_CANCEL_REPORT_PATH |
| 48 | + if (!reportPath) return |
| 49 | + let checks: ReportCheck[] = [] |
| 50 | + try { |
| 51 | + checks = (JSON.parse(readFileSync(reportPath, 'utf8')) as { checks: ReportCheck[] }).checks |
| 52 | + } catch { |
| 53 | + // The first check of the run. |
| 54 | + } |
| 55 | + writeFileSync( |
| 56 | + reportPath, |
| 57 | + JSON.stringify({ suite: 'terminal-cancel', checks: [...checks, check] }, null, 2) |
| 58 | + ) |
| 59 | +} |
36 | 60 |
|
37 | 61 | /** The shells, sleeps and tmux processes running, for a failure about who started what. */ |
38 | 62 | function processes(): string { |
@@ -266,10 +290,11 @@ test.describe('terminal cancel', () => { |
266 | 290 |
|
267 | 291 | test.afterEach(async () => { |
268 | 292 | const testInfo = test.info() |
269 | | - report.push({ |
| 293 | + reportCheck({ |
270 | 294 | name: testInfo.title, |
271 | 295 | status: testInfo.status ?? 'unknown', |
272 | 296 | durationMs: testInfo.duration, |
| 297 | + retry: testInfo.retry, |
273 | 298 | }) |
274 | 299 | if (testInfo.status !== testInfo.expectedStatus) { |
275 | 300 | // What each call came back with, and the panes tmux held, explain most failures. |
@@ -315,13 +340,6 @@ test.describe('terminal cancel', () => { |
315 | 340 |
|
316 | 341 | test.afterAll(async () => { |
317 | 342 | await sim.stop() |
318 | | - const reportPath = process.env.TERMINAL_CANCEL_REPORT_PATH |
319 | | - if (reportPath) { |
320 | | - writeFileSync( |
321 | | - reportPath, |
322 | | - JSON.stringify({ suite: 'terminal-cancel', checks: report }, null, 2) |
323 | | - ) |
324 | | - } |
325 | 343 | }) |
326 | 344 |
|
327 | 345 | async function start( |
|
0 commit comments