diff --git a/tests/config/commonFixtures.ts b/tests/config/commonFixtures.ts index 951b7763ab..1393004a71 100644 --- a/tests/config/commonFixtures.ts +++ b/tests/config/commonFixtures.ts @@ -204,8 +204,8 @@ export class TestChildProcess { throw new Error(`Process received signal: ${r.signal}`); } - async waitForOutput(substring: string) { - while (!stripAnsi(this.output).includes(substring)) + async waitForOutput(substring: string, count = 1) { + while (countTimes(stripAnsi(this.output), substring) < count) await new Promise(f => this._outputCallbacks.add(f)); } @@ -275,3 +275,15 @@ export const commonFixtures: Fixtures = { token.canceled = true; }, }; + +export function countTimes(s: string, sub: string): number { + let result = 0; + for (let index = 0; index !== -1;) { + index = s.indexOf(sub, index); + if (index !== -1) { + result++; + index += sub.length; + } + } + return result; +} diff --git a/tests/playwright-test/expect.spec.ts b/tests/playwright-test/expect.spec.ts index ad070efd4c..573b15cd7e 100644 --- a/tests/playwright-test/expect.spec.ts +++ b/tests/playwright-test/expect.spec.ts @@ -15,7 +15,7 @@ */ import path from 'path'; -import { test, expect } from './playwright-test-fixtures'; +import { test, expect, parseTestRunnerOutput } from './playwright-test-fixtures'; test('should be able to call expect.extend in config', async ({ runInlineTest }) => { const result = await runInlineTest({ @@ -588,10 +588,10 @@ test('should print pending operations for toHaveText', async ({ runInlineTest }) expect(output).toContain('waiting for locator(\'no-such-thing\')'); }); -test('should print expected/received on Ctrl+C', async ({ runInlineTest }) => { +test('should print expected/received on Ctrl+C', async ({ interactWithTestRunner }) => { test.skip(process.platform === 'win32', 'No sending SIGINT on Windows'); - const result = await runInlineTest({ + const testProcess = await interactWithTestRunner({ 'a.test.ts': ` import { test, expect } from '@playwright/test'; @@ -603,8 +603,13 @@ test('should print expected/received on Ctrl+C', async ({ runInlineTest }) => { await promise; }); `, - }, { workers: 1 }, {}, { sendSIGINTAfter: 1 }); - expect(result.exitCode).toBe(130); + }, { workers: 1 }); + await testProcess.waitForOutput('%%SEND-SIGINT%%'); + process.kill(testProcess.process.pid!, 'SIGINT'); + const { exitCode } = await testProcess.exited; + expect(exitCode).toBe(130); + + const result = parseTestRunnerOutput(testProcess.output); expect(result.passed).toBe(0); expect(result.interrupted).toBe(1); expect(result.output).toContain('Expected string: "Text 2"'); diff --git a/tests/playwright-test/playwright-test-fixtures.ts b/tests/playwright-test/playwright-test-fixtures.ts index cea41f88fb..aaaaec9a0b 100644 --- a/tests/playwright-test/playwright-test-fixtures.ts +++ b/tests/playwright-test/playwright-test-fixtures.ts @@ -26,8 +26,9 @@ import { serverFixtures } from '../config/serverFixtures'; import type { TestInfo } from './stable-test-runner'; import { expect } from './stable-test-runner'; import { test as base } from './stable-test-runner'; +export { countTimes } from '../config/commonFixtures'; -export type CliRunResult = { +type CliRunResult = { exitCode: number, output: string, }; @@ -92,13 +93,7 @@ const configFile = (baseDir: string, files: Files): string | undefined => { return undefined; }; -async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], baseDir: string, params: any, env: NodeJS.ProcessEnv, options: RunOptions, files: Files, mergeReports: (reportFolder: string, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise, useIntermediateMergeReport: boolean): Promise { - let reporter; - if (useIntermediateMergeReport) { - reporter = params.reporter; - params.reporter = 'blob'; - } - +function startPlaywrightTest(childProcess: CommonFixtures['childProcess'], baseDir: string, params: any, env: NodeJS.ProcessEnv, options: RunOptions): TestChildProcess { const paramList: string[] = []; for (const key of Object.keys(params)) { for (const value of Array.isArray(params[key]) ? params[key] : [params[key]]) { @@ -106,7 +101,6 @@ async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], b paramList.push(params[key] === true ? `${k}` : `${k}=${value}`); } } - const reportFile = path.join(baseDir, 'report.json'); const args = ['test']; args.push( '--workers=2', @@ -114,14 +108,27 @@ async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], b ); if (options.additionalArgs) args.push(...options.additionalArgs); + return childProcess({ + command: ['node', cliEntrypoint, ...args], + env: cleanEnv(env), + cwd: options.cwd ? path.resolve(baseDir, options.cwd) : baseDir, + }); +} - const cwd = options.cwd ? path.resolve(baseDir, options.cwd) : baseDir; - // eslint-disable-next-line prefer-const - let { exitCode, output } = await runPlaywrightCommand(childProcess, cwd, args, { +async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], baseDir: string, params: any, env: NodeJS.ProcessEnv, options: RunOptions, files: Files, mergeReports: (reportFolder: string, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise, useIntermediateMergeReport: boolean): Promise { + let reporter; + if (useIntermediateMergeReport) { + reporter = params.reporter; + params.reporter = 'blob'; + } + const reportFile = path.join(baseDir, 'report.json'); + const testProcess = startPlaywrightTest(childProcess, baseDir, params, { PW_TEST_REPORTER: path.join(__dirname, '../../packages/playwright-test/lib/reporters/json.js'), PLAYWRIGHT_JSON_OUTPUT_NAME: reportFile, ...env, - }, options.sendSIGINTAfter); + }, options); + const { exitCode } = await testProcess.exited; + let output = testProcess.output.toString(); if (useIntermediateMergeReport) { const additionalArgs = []; @@ -130,25 +137,14 @@ async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], b const config = configFile(baseDir, files); if (config) additionalArgs.push('--config', config); + const cwd = options.cwd ? path.resolve(baseDir, options.cwd) : baseDir; const mergeResult = await mergeReports('blob-report', env, { cwd, additionalArgs }); expect(mergeResult.exitCode).toBe(0); output = mergeResult.output; } - const summary = (re: RegExp) => { - let result = 0; - let match = re.exec(output); - while (match) { - result += (+match[1]); - match = re.exec(output); - } - return result; - }; - const passed = summary(/(\d+) passed/g); - const failed = summary(/(\d+) failed/g); - const flaky = summary(/(\d+) flaky/g); - const skipped = summary(/(\d+) skipped/g); - const interrupted = summary(/(\d+) interrupted/g); + const parsed = parseTestRunnerOutput(output); + let report; try { report = JSON.parse(fs.readFileSync(reportFile).toString()); @@ -171,66 +167,23 @@ async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], b if (report) visitSuites(report.suites); - const strippedOutput = stripAnsi(output); return { + ...parsed, exitCode, - output: strippedOutput, - outputLines: strippedOutput.split('\n').filter(line => line.startsWith('%%')).map(line => line.substring(2).trim()), rawOutput: output, - passed, - failed, - flaky, - skipped, - interrupted, report, results, }; } async function runPlaywrightListFiles(childProcess: CommonFixtures['childProcess'], baseDir: string, env: NodeJS.ProcessEnv): Promise<{ output: string, exitCode: number }> { - const reportFile = path.join(baseDir, 'report.json'); - // eslint-disable-next-line prefer-const - let { exitCode, output } = await runPlaywrightCommand(childProcess, baseDir, ['list-files'], { - PW_TEST_REPORTER: path.join(__dirname, '../../packages/playwright-test/lib/reporters/json.js'), - PLAYWRIGHT_JSON_OUTPUT_NAME: reportFile, - ...env, - }); - return { exitCode, output }; -} - -function watchPlaywrightTest(childProcess: CommonFixtures['childProcess'], baseDir: string, env: NodeJS.ProcessEnv, options: RunOptions): TestChildProcess { - const args = ['test', '--workers=2']; - if (options.additionalArgs) - args.push(...options.additionalArgs); - const cwd = options.cwd ? path.resolve(baseDir, options.cwd) : baseDir; - - const command = ['node', cliEntrypoint]; - command.push(...args); const testProcess = childProcess({ - command, - env: cleanEnv({ PWTEST_WATCH: '1', ...env }), - cwd, - }); - return testProcess; -} - -async function runPlaywrightCommand(childProcess: CommonFixtures['childProcess'], cwd: string, commandWithArguments: string[], env: NodeJS.ProcessEnv, sendSIGINTAfter?: number): Promise { - const command = ['node', cliEntrypoint]; - command.push(...commandWithArguments); - const testProcess = childProcess({ - command, + command: ['node', cliEntrypoint, 'list-files'], env: cleanEnv(env), - cwd, + cwd: baseDir, }); - let didSendSigint = false; - testProcess.onOutput = () => { - if (sendSIGINTAfter && !didSendSigint && countTimes(testProcess.output, '%%SEND-SIGINT%%') >= sendSIGINTAfter) { - didSendSigint = true; - process.kill(testProcess.process.pid!, 'SIGINT'); - } - }; const { exitCode } = await testProcess.exited; - return { exitCode, output: testProcess.output.toString() }; + return { exitCode, output: testProcess.output }; } export function cleanEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv { @@ -261,7 +214,6 @@ export function cleanEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv { } export type RunOptions = { - sendSIGINTAfter?: number; additionalArgs?: string[]; cwd?: string, }; @@ -271,6 +223,7 @@ type Fixtures = { runInlineTest: (files: Files, params?: Params, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise; runListFiles: (files: Files) => Promise<{ output: string, exitCode: number }>; runWatchTest: (files: Files, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise; + interactWithTestRunner: (files: Files, params?: Params, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise; runTSC: (files: Files) => Promise; mergeReports: (reportFolder: string, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise useIntermediateMergeReport: boolean; @@ -310,12 +263,16 @@ export const test = base await rimraf(cacheDir); }, - runWatchTest: async ({ childProcess }, use, testInfo: TestInfo) => { + runWatchTest: async ({ interactWithTestRunner }, use, testInfo: TestInfo) => { + await use((files, env, options) => interactWithTestRunner(files, {}, { ...env, PWTEST_WATCH: '1' }, options)); + }, + + interactWithTestRunner: async ({ childProcess }, use, testInfo: TestInfo) => { const cacheDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'playwright-test-cache-')); let testProcess: TestChildProcess | undefined; - await use(async (files: Files, env: NodeJS.ProcessEnv = {}, options: RunOptions = {}) => { + await use(async (files: Files, params: Params = {}, env: NodeJS.ProcessEnv = {}, options: RunOptions = {}) => { const baseDir = await writeFiles(testInfo, files, true); - testProcess = watchPlaywrightTest(childProcess, baseDir, { ...env, PWTEST_CACHE_DIR: cacheDir }, options); + testProcess = startPlaywrightTest(childProcess, baseDir, params, { ...env, PWTEST_CACHE_DIR: cacheDir }, options); return testProcess; }); await testProcess?.kill(); @@ -388,18 +345,6 @@ export function stripAnsi(str: string): string { return str.replace(asciiRegex, ''); } -export function countTimes(s: string, sub: string): number { - let result = 0; - for (let index = 0; index !== -1;) { - index = s.indexOf(sub, index); - if (index !== -1) { - result++; - index += sub.length; - } - } - return result; -} - export function createImage(width: number, height: number, r: number = 0, g: number = 0, b: number = 0, a: number = 255): Buffer { const image = new PNG({ width, height }); // Make both images red. @@ -446,3 +391,32 @@ export function expectTestHelper(result: RunResult) { } }; } + +export function parseTestRunnerOutput(output: string) { + const summary = (re: RegExp) => { + let result = 0; + let match = re.exec(output); + while (match) { + result += (+match[1]); + match = re.exec(output); + } + return result; + }; + const passed = summary(/(\d+) passed/g); + const failed = summary(/(\d+) failed/g); + const flaky = summary(/(\d+) flaky/g); + const skipped = summary(/(\d+) skipped/g); + const interrupted = summary(/(\d+) interrupted/g); + + const strippedOutput = stripAnsi(output); + return { + output: strippedOutput, + outputLines: strippedOutput.split('\n').filter(line => line.startsWith('%%')).map(line => line.substring(2).trim()), + rawOutput: output, + passed, + failed, + flaky, + skipped, + interrupted, + }; +} diff --git a/tests/playwright-test/playwright.spec.ts b/tests/playwright-test/playwright.spec.ts index 7d31237c48..154fa3f909 100644 --- a/tests/playwright-test/playwright.spec.ts +++ b/tests/playwright-test/playwright.spec.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { test, expect } from './playwright-test-fixtures'; +import { test, expect, parseTestRunnerOutput } from './playwright-test-fixtures'; import fs from 'fs'; import path from 'path'; import { spawnSync } from 'child_process'; @@ -431,10 +431,10 @@ test('should throw when using page in beforeAll', async ({ runInlineTest }) => { expect(result.output).toContain(`Error: "context" and "page" fixtures are not supported in "beforeAll"`); }); -test('should report click error on sigint', async ({ runInlineTest }) => { +test('should report click error on sigint', async ({ interactWithTestRunner }) => { test.skip(process.platform === 'win32', 'No sending SIGINT on Windows'); - const result = await runInlineTest({ + const testProcess = await interactWithTestRunner({ 'a.test.ts': ` import { test, expect } from '@playwright/test'; test('timedout', async ({ page }) => { @@ -445,9 +445,13 @@ test('should report click error on sigint', async ({ runInlineTest }) => { await promise; }); `, - }, { workers: 1 }, {}, { sendSIGINTAfter: 1 }); + }, { workers: 1 }); + await testProcess.waitForOutput('%%SEND-SIGINT%%'); + process.kill(testProcess.process.pid!, 'SIGINT'); + const { exitCode } = await testProcess.exited; + expect(exitCode).toBe(130); - expect(result.exitCode).toBe(130); + const result = parseTestRunnerOutput(testProcess.output); expect(result.passed).toBe(0); expect(result.failed).toBe(0); expect(result.interrupted).toBe(1); diff --git a/tests/playwright-test/runner.spec.ts b/tests/playwright-test/runner.spec.ts index db472523f6..f1717dd32f 100644 --- a/tests/playwright-test/runner.spec.ts +++ b/tests/playwright-test/runner.spec.ts @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +import fs from 'fs'; import path from 'path'; -import { test, expect } from './playwright-test-fixtures'; +import { test, expect, parseTestRunnerOutput } from './playwright-test-fixtures'; test('it should not allow multiple tests with the same name per suite', async ({ runInlineTest }) => { const result = await runInlineTest({ @@ -93,10 +95,10 @@ test('should continue with other tests after worker process suddenly exits', asy expect(result.output).toContain('Internal error: worker process exited unexpectedly'); }); -test('sigint should stop workers', async ({ runInlineTest }) => { +test('sigint should stop workers', async ({ interactWithTestRunner }) => { test.skip(process.platform === 'win32', 'No sending SIGINT on Windows'); - const result = await runInlineTest({ + const testProcess = await interactWithTestRunner({ 'a.spec.js': ` import { test, expect } from '@playwright/test'; test('interrupted1', async () => { @@ -117,8 +119,16 @@ test('sigint should stop workers', async ({ runInlineTest }) => { console.log('\\n%%skipped2'); }); `, - }, { 'workers': 2, 'reporter': 'line,json' }, {}, { sendSIGINTAfter: 2 }); - expect(result.exitCode).toBe(130); + }, { 'workers': 2, 'reporter': 'line,json' }, { + PW_TEST_REPORTER: path.join(__dirname, '../../packages/playwright-test/lib/reporters/json.js'), + PLAYWRIGHT_JSON_OUTPUT_NAME: 'report.json', + }); + await testProcess.waitForOutput('%%SEND-SIGINT%%', 2); + process.kill(testProcess.process.pid!, 'SIGINT'); + const { exitCode } = await testProcess.exited; + expect(exitCode).toBe(130); + + const result = parseTestRunnerOutput(testProcess.output); expect(result.passed).toBe(0); expect(result.failed).toBe(0); expect(result.skipped).toBe(2); @@ -130,11 +140,12 @@ test('sigint should stop workers', async ({ runInlineTest }) => { expect(result.output).toContain('Test was interrupted.'); expect(result.output).not.toContain('Test timeout of'); - const interrupted2 = result.report.suites[1].specs[0]; + const report = JSON.parse(fs.readFileSync(test.info().outputPath('report.json'), 'utf8')); + const interrupted2 = report.suites[1].specs[0]; expect(interrupted2.title).toBe('interrupted2'); expect(interrupted2.tests[0].results[0].workerIndex === 0 || interrupted2.tests[0].results[0].workerIndex === 1).toBe(true); - const skipped2 = result.report.suites[1].specs[1]; + const skipped2 = report.suites[1].specs[1]; expect(skipped2.title).toBe('skipped2'); expect(skipped2.tests[0].results[0].workerIndex).toBe(-1); }); @@ -169,10 +180,10 @@ test('should use the first occurring error when an unhandled exception was throw expect(result.report.suites[0].specs[0].tests[0].results[0].error!.message).toBe('first error'); }); -test('worker interrupt should report errors', async ({ runInlineTest }) => { +test('worker interrupt should report errors', async ({ interactWithTestRunner }) => { test.skip(process.platform === 'win32', 'No sending SIGINT on Windows'); - const result = await runInlineTest({ + const testProcess = await interactWithTestRunner({ 'a.spec.ts': ` import { test as base, expect } from '@playwright/test'; const test = base.extend({ @@ -187,8 +198,13 @@ test('worker interrupt should report errors', async ({ runInlineTest }) => { await throwOnTeardown; }); `, - }, {}, {}, { sendSIGINTAfter: 1 }); - expect(result.exitCode).toBe(130); + }); + await testProcess.waitForOutput('%%SEND-SIGINT%%'); + process.kill(testProcess.process.pid!, 'SIGINT'); + const { exitCode } = await testProcess.exited; + expect(exitCode).toBe(130); + + const result = parseTestRunnerOutput(testProcess.output); expect(result.passed).toBe(0); expect(result.failed).toBe(0); expect(result.interrupted).toBe(1); @@ -334,10 +350,10 @@ test('should not hang if test suites in worker are inconsistent with runner', as expect(result.report.suites[0].specs[1].tests[0].results[0].error!.message).toBe('Test(s) not found in the worker process. Make sure test titles do not change:\nproject-name > a.spec.js > Test 1 - bar\nproject-name > a.spec.js > Test 2 - baz'); }); -test('sigint should stop global setup', async ({ runInlineTest }) => { +test('sigint should stop global setup', async ({ interactWithTestRunner }) => { test.skip(process.platform === 'win32', 'No sending SIGINT on Windows'); - const result = await runInlineTest({ + const testProcess = await interactWithTestRunner({ 'playwright.config.ts': ` module.exports = { globalSetup: './globalSetup', @@ -360,18 +376,22 @@ test('sigint should stop global setup', async ({ runInlineTest }) => { import { test, expect } from '@playwright/test'; test('test', async () => { }); `, - }, { 'workers': 1 }, {}, { sendSIGINTAfter: 1 }); - expect(result.exitCode).toBe(130); + }, { 'workers': 1 }); + await testProcess.waitForOutput('%%SEND-SIGINT%%'); + process.kill(testProcess.process.pid!, 'SIGINT'); + const { exitCode } = await testProcess.exited; + expect(exitCode).toBe(130); + + const result = parseTestRunnerOutput(testProcess.output); expect(result.passed).toBe(0); - const output = result.output; - expect(output).toContain('Global setup'); - expect(output).not.toContain('Global teardown'); + expect(result.output).toContain('Global setup'); + expect(result.output).not.toContain('Global teardown'); }); -test('sigint should stop plugins', async ({ runInlineTest }) => { +test('sigint should stop plugins', async ({ interactWithTestRunner }) => { test.skip(process.platform === 'win32', 'No sending SIGINT on Windows'); - const result = await runInlineTest({ + const testProcess = await interactWithTestRunner({ 'playwright.config.ts': ` const _plugins = []; _plugins.push(() => ({ @@ -403,21 +423,25 @@ test('sigint should stop plugins', async ({ runInlineTest }) => { console.log('testing!'); }); `, - }, { 'workers': 1 }, {}, { sendSIGINTAfter: 1 }); - expect(result.exitCode).toBe(130); + }, { 'workers': 1 }); + await testProcess.waitForOutput('%%SEND-SIGINT%%'); + process.kill(testProcess.process.pid!, 'SIGINT'); + const { exitCode } = await testProcess.exited; + expect(exitCode).toBe(130); + + const result = parseTestRunnerOutput(testProcess.output); expect(result.passed).toBe(0); - const output = result.output; - expect(output).toContain('Plugin1 setup'); - expect(output).toContain('Plugin1 teardown'); - expect(output).not.toContain('Plugin2 setup'); - expect(output).not.toContain('Plugin2 teardown'); - expect(output).not.toContain('testing!'); + expect(result.output).toContain('Plugin1 setup'); + expect(result.output).toContain('Plugin1 teardown'); + expect(result.output).not.toContain('Plugin2 setup'); + expect(result.output).not.toContain('Plugin2 teardown'); + expect(result.output).not.toContain('testing!'); }); -test('sigint should stop plugins 2', async ({ runInlineTest }) => { +test('sigint should stop plugins 2', async ({ interactWithTestRunner }) => { test.skip(process.platform === 'win32', 'No sending SIGINT on Windows'); - const result = await runInlineTest({ + const testProcess = await interactWithTestRunner({ 'playwright.config.ts': ` const _plugins = []; _plugins.push(() => ({ @@ -447,15 +471,19 @@ test('sigint should stop plugins 2', async ({ runInlineTest }) => { console.log('testing!'); }); `, - }, { 'workers': 1 }, {}, { sendSIGINTAfter: 1 }); - expect(result.exitCode).toBe(130); + }, { 'workers': 1 }); + await testProcess.waitForOutput('%%SEND-SIGINT%%'); + process.kill(testProcess.process.pid!, 'SIGINT'); + const { exitCode } = await testProcess.exited; + expect(exitCode).toBe(130); + + const result = parseTestRunnerOutput(testProcess.output); expect(result.passed).toBe(0); - const output = result.output; - expect(output).toContain('Plugin1 setup'); - expect(output).toContain('Plugin2 setup'); - expect(output).toContain('Plugin1 teardown'); - expect(output).toContain('Plugin2 teardown'); - expect(output).not.toContain('testing!'); + expect(result.output).toContain('Plugin1 setup'); + expect(result.output).toContain('Plugin2 setup'); + expect(result.output).toContain('Plugin1 teardown'); + expect(result.output).toContain('Plugin2 teardown'); + expect(result.output).not.toContain('testing!'); }); test('should not crash with duplicate titles and .only', async ({ runInlineTest }) => { diff --git a/tests/playwright-test/web-server.spec.ts b/tests/playwright-test/web-server.spec.ts index 3e9bbae462..46150f3eef 100644 --- a/tests/playwright-test/web-server.spec.ts +++ b/tests/playwright-test/web-server.spec.ts @@ -16,7 +16,7 @@ import type http from 'http'; import path from 'path'; -import { test, expect } from './playwright-test-fixtures'; +import { test, expect, parseTestRunnerOutput } from './playwright-test-fixtures'; import { createHttpServer } from '../../packages/playwright-core/lib/utils/network'; const SIMPLE_SERVER_PATH = path.join(__dirname, 'assets', 'simple-server.js'); @@ -705,10 +705,10 @@ test('should be able to ignore "stderr"', async ({ runInlineTest }, { workerInde expect(result.output).not.toContain('error from server'); }); -test('should forward stdout when set to "pipe" before server is ready', async ({ runInlineTest }, { workerIndex }) => { +test('should forward stdout when set to "pipe" before server is ready', async ({ interactWithTestRunner }) => { test.skip(process.platform === 'win32', 'No sending SIGINT on Windows'); - const result = await runInlineTest({ + const testProcess = await interactWithTestRunner({ 'web-server.js': ` console.log('output from server'); console.log('\\n%%SEND-SIGINT%%'); @@ -728,7 +728,12 @@ test('should forward stdout when set to "pipe" before server is ready', async ({ }, }; `, - }, { workers: 1 }, {}, { sendSIGINTAfter: 1 }); + }, { workers: 1 }); + await testProcess.waitForOutput('%%SEND-SIGINT%%'); + process.kill(testProcess.process.pid!, 'SIGINT'); + await testProcess.exited; + + const result = parseTestRunnerOutput(testProcess.output); expect(result.passed).toBe(0); expect(result.output).toContain('[WebServer] output from server'); expect(result.output).not.toContain('Timed out waiting 3000ms');