Revert "chore: allow calling spawnSync on Node.js file inside test" (#24611)

Reverts microsoft/playwright#24539
This commit is contained in:
Pavel Feldman 2023-08-04 09:01:38 -07:00 committed by GitHub
parent 6731f5b6d5
commit b3ce913551
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 17 additions and 111 deletions

View File

@ -21,7 +21,7 @@ import fs from 'fs';
import path from 'path';
import { Runner } from './runner/runner';
import { stopProfiling, startProfiling, gracefullyProcessExitDoNotHang } from 'playwright-core/lib/utils';
import { execArgvWithoutExperimentalLoaderOptions, execArgvWithExperimentalLoaderOptions, fileIsModule, serializeError } from './util';
import { experimentalLoaderOption, fileIsModule, serializeError } from './util';
import { showHTMLReport } from './reporters/html';
import { createMergedReport } from './reporters/merge';
import { ConfigLoader, resolveConfigFile } from './common/configLoader';
@ -275,19 +275,17 @@ function restartWithExperimentalTsEsm(configFile: string | null): boolean {
return false;
if (process.env.PW_DISABLE_TS_ESM)
return false;
if (process.env.PW_TS_ESM_ON) {
// clear execArgv after restart, so that childProcess.fork in user code does not inherit our loader.
process.execArgv = execArgvWithoutExperimentalLoaderOptions();
if (process.env.PW_TS_ESM_ON)
return false;
}
if (!fileIsModule(configFile))
return false;
const innerProcess = (require('child_process') as typeof import('child_process')).fork(require.resolve('./cli'), process.argv.slice(2), {
const NODE_OPTIONS = (process.env.NODE_OPTIONS || '') + experimentalLoaderOption();
const innerProcess = require('child_process').fork(require.resolve('./cli'), process.argv.slice(2), {
env: {
...process.env,
NODE_OPTIONS,
PW_TS_ESM_ON: '1',
},
execArgv: execArgvWithExperimentalLoaderOptions(),
}
});
innerProcess.on('close', (code: number | null) => {

View File

@ -18,7 +18,7 @@ import type { WriteStream } from 'tty';
import type { EnvProducedPayload, ProcessInitParams, TtyParams } from './ipc';
import { startProfiling, stopProfiling } from 'playwright-core/lib/utils';
import type { TestInfoError } from '../../types/test';
import { execArgvWithoutExperimentalLoaderOptions, serializeError } from '../util';
import { serializeError } from '../util';
export type ProtocolRequest = {
id: number;
@ -51,9 +51,6 @@ process.on('disconnect', gracefullyCloseAndExit);
process.on('SIGINT', () => {});
process.on('SIGTERM', () => {});
// Clear execArgv immediately, so that the user-code does not inherit our loader.
process.execArgv = execArgvWithoutExperimentalLoaderOptions();
let processRunner: ProcessRunner;
let processName: string;
const startingEnv = { ...process.env };

View File

@ -22,6 +22,7 @@ import { raceAgainstDeadline, launchProcess, httpRequest, monotonicTime } from '
import type { FullConfig } from '../../types/testReporter';
import type { TestRunnerPlugin } from '.';
import type { FullConfigInternal } from '../common/config';
import { envWithoutExperimentalLoaderOptions } from '../util';
import type { ReporterV2 } from '../reporters/reporterV2';
@ -92,6 +93,7 @@ export class WebServerPlugin implements TestRunnerPlugin {
command: this._options.command,
env: {
...DEFAULT_ENVIRONMENT_VARIABLES,
...envWithoutExperimentalLoaderOptions(),
...this._options.env,
},
cwd: this._options.cwd,

View File

@ -19,7 +19,6 @@ import { EventEmitter } from 'events';
import { debug } from 'playwright-core/lib/utilsBundle';
import type { EnvProducedPayload, ProcessInitParams } from '../common/ipc';
import type { ProtocolResponse } from '../common/process';
import { execArgvWithExperimentalLoaderOptions } from '../util';
export type ProcessExitData = {
unexpectedly: boolean;
@ -51,7 +50,6 @@ export class ProcessHost extends EventEmitter {
detached: false,
env: { ...process.env, ...this._extraEnv },
stdio: inheritStdio ? ['ignore', 'inherit', 'inherit', 'ipc'] : ['ignore', 'ignore', process.env.PW_RUNNER_DEBUG ? 'inherit' : 'ignore', 'ipc'],
...(process.env.PW_TS_ESM_ON ? { execArgv: execArgvWithExperimentalLoaderOptions() } : {}),
});
this.process.on('exit', (code, signal) => {
this.didExit = true;

View File

@ -303,20 +303,16 @@ function folderIsModule(folder: string): boolean {
return require(packageJsonPath).type === 'module';
}
const kExperimentalLoaderOptions = [
'--no-warnings',
`--experimental-loader=${url.pathToFileURL(require.resolve('@playwright/test/lib/transform/esmLoader')).toString()}`,
];
export function execArgvWithExperimentalLoaderOptions() {
return [
...process.execArgv,
...kExperimentalLoaderOptions,
];
export function experimentalLoaderOption() {
return ` --no-warnings --experimental-loader=${url.pathToFileURL(require.resolve('@playwright/test/lib/transform/esmLoader')).toString()}`;
}
export function execArgvWithoutExperimentalLoaderOptions() {
return process.execArgv.filter(arg => !kExperimentalLoaderOptions.includes(arg));
export function envWithoutExperimentalLoaderOptions(): NodeJS.ProcessEnv {
const substring = experimentalLoaderOption();
const result = { ...process.env };
if (result.NODE_OPTIONS)
result.NODE_OPTIONS = result.NODE_OPTIONS.replace(substring, '').trim() || undefined;
return result;
}
// This follows the --moduleResolution=bundler strategy from tsc.

View File

@ -547,88 +547,3 @@ test('should disallow ESM when config is cjs', async ({ runInlineTest }) => {
expect(result.exitCode).toBe(1);
expect(result.output).toContain('Unknown file extension ".ts"');
});
test('should be able to use use execSync with a Node.js file inside a spec', async ({ runInlineTest }) => {
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/24516' });
const result = await runInlineTest({
'global-setup.ts': `
import { execSync, spawnSync, fork } from 'child_process';
console.log('%%global-setup import level');
console.log('%%execSync: ' + execSync('node hello.js').toString());
console.log('%%spawnSync: ' + spawnSync('node', ['hello.js']).stdout.toString());
export default async () => {
console.log('%%global-setup export level');
console.log('%%execSync: ' + execSync('node hello.js').toString());
console.log('%%spawnSync: ' + spawnSync('node', ['hello.js']).stdout.toString());
const child = fork('hellofork.js');
child.on('message', (m) => console.log('%%fork: ' + m));
await new Promise((resolve) => child.on('exit', (code) => resolve(code)));
}
`,
'global-teardown.ts': `
import { execSync, spawnSync, fork } from 'child_process';
console.log('%%global-teardown import level');
console.log('%%execSync: ' + execSync('node hello.js').toString());
console.log('%%spawnSync: ' + spawnSync('node', ['hello.js']).stdout.toString());
export default async () => {
console.log('%%global-teardown export level');
console.log('%%execSync: ' + execSync('node hello.js').toString());
console.log('%%spawnSync: ' + spawnSync('node', ['hello.js']).stdout.toString());
const child = fork('hellofork.js');
child.on('message', (m) => console.log('%%fork: ' + m));
await new Promise((resolve) => child.on('exit', (code) => resolve(code)));
}
`,
'package.json': `{ "type": "module" }`,
'playwright.config.ts': `export default {
projects: [{name: 'foo'}],
globalSetup: './global-setup.ts',
globalTeardown: './global-teardown.ts',
};`,
'hello.js': `console.log('hello from hello.js');`,
'hellofork.js': `process.send('hello from hellofork.js');`,
'a.test.ts': `
import { test, expect } from '@playwright/test';
import { execSync, spawnSync, fork } from 'child_process';
console.log('%%inside test file');
console.log('%%execSync: ' + execSync('node hello.js').toString());
console.log('%%spawnSync: ' + spawnSync('node', ['hello.js']).stdout.toString());
test('check project name', async ({}) => {
console.log('%%inside test');
console.log('%%execSync: ' + execSync('node hello.js').toString());
console.log('%%spawnSync: ' + spawnSync('node', ['hello.js']).stdout.toString());
const child = fork('hellofork.js');
child.on('message', (m) => console.log('%%fork: ' + m));
await new Promise((resolve) => child.on('exit', (code) => resolve(code)));
});
`,
});
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1);
expect(result.outputLines).toEqual([
'global-setup import level',
'execSync: hello from hello.js',
'spawnSync: hello from hello.js',
'global-teardown import level',
'execSync: hello from hello.js',
'spawnSync: hello from hello.js',
'global-setup export level',
'execSync: hello from hello.js',
'spawnSync: hello from hello.js',
'fork: hello from hellofork.js',
'inside test file',
'execSync: hello from hello.js',
'spawnSync: hello from hello.js',
'inside test file',
'execSync: hello from hello.js',
'spawnSync: hello from hello.js',
'inside test',
'execSync: hello from hello.js',
'spawnSync: hello from hello.js',
'fork: hello from hellofork.js',
'global-teardown export level',
'execSync: hello from hello.js',
'spawnSync: hello from hello.js',
'fork: hello from hellofork.js',
]);
});