diff --git a/packages/playwright-test/src/cli.ts b/packages/playwright-test/src/cli.ts index 2d7cfeb4f3..bb3f665cbb 100644 --- a/packages/playwright-test/src/cli.ts +++ b/packages/playwright-test/src/cli.ts @@ -241,7 +241,7 @@ function restartWithExperimentalTsEsm(configFile: string | null): boolean { return false; if (!fileIsModule(configFile)) return false; - const NODE_OPTIONS = (process.env.NODE_OPTIONS || '') + ` --experimental-loader=${url.pathToFileURL(require.resolve('@playwright/test/lib/experimentalLoader')).toString()}`; + const NODE_OPTIONS = (process.env.NODE_OPTIONS || '') + experimentalLoaderOption(); const innerProcess = require('child_process').fork(require.resolve('playwright-core/cli'), process.argv.slice(2), { env: { ...process.env, @@ -257,4 +257,16 @@ function restartWithExperimentalTsEsm(configFile: string | null): boolean { return true; } +export function experimentalLoaderOption() { + return ` --experimental-loader=${url.pathToFileURL(require.resolve('@playwright/test/lib/experimentalLoader')).toString()}`; +} + +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; +} + const kTraceModes: TraceMode[] = ['on', 'off', 'on-first-retry', 'retain-on-failure']; diff --git a/packages/playwright-test/src/plugins/webServerPlugin.ts b/packages/playwright-test/src/plugins/webServerPlugin.ts index e867b5c8a2..4ce87a6de8 100644 --- a/packages/playwright-test/src/plugins/webServerPlugin.ts +++ b/packages/playwright-test/src/plugins/webServerPlugin.ts @@ -25,6 +25,7 @@ import { launchProcess } from 'playwright-core/lib/utils/processLauncher'; import type { FullConfig, Reporter } from '../../types/testReporter'; import type { TestRunnerPlugin } from '.'; import type { FullConfigInternal } from '../types'; +import { envWithoutExperimentalLoaderOptions } from '../cli'; export type WebServerPluginOptions = { @@ -91,7 +92,7 @@ export class WebServerPlugin implements TestRunnerPlugin { command: this._options.command, env: { ...DEFAULT_ENVIRONMENT_VARIABLES, - ...process.env, + ...envWithoutExperimentalLoaderOptions(), ...this._options.env, }, cwd: this._options.cwd, @@ -99,7 +100,7 @@ export class WebServerPlugin implements TestRunnerPlugin { shell: true, attemptToGracefullyClose: async () => {}, log: () => {}, - onExit: code => processExitedReject(new Error(`Process from config.webServer was not able to start. Exit code: ${code}`)), + onExit: code => processExitedReject(new Error(code ? `Process from config.webServer was not able to start. Exit code: ${code}` : 'Process from config.webServer exited early.')), tempDirectories: [], }); this._killProcess = kill; diff --git a/tests/playwright-test/loader.spec.ts b/tests/playwright-test/loader.spec.ts index 8d88ac8ec1..4757ba6100 100644 --- a/tests/playwright-test/loader.spec.ts +++ b/tests/playwright-test/loader.spec.ts @@ -418,3 +418,34 @@ test('should work with cross-imports - 2', async ({ runInlineTest }) => { expect(result.output).toContain('TEST-1'); expect(result.output).toContain('TEST-2'); }); + +test('should load web server w/o esm loader in ems module', async ({ runInlineTest, nodeVersion }) => { + // We only support experimental esm mode on Node 16+ + test.skip(nodeVersion.major < 16); + const result = await runInlineTest({ + 'playwright.config.ts': ` + //@no-header + export default { + webServer: { + command: 'node ws.js', + port: 9876, + timeout: 100, + }, + projects: [{name: 'foo'}] + }`, + 'package.json': `{ "type": "module" }`, + 'ws.js': ` + //@no-header + console.log('NODE_OPTIONS ' + process.env.NODE_OPTIONS); + setTimeout(() => {}, 100000); + `, + 'a.test.ts': ` + const { test } = pwt; + test('passes', () => {}); + ` + }, {}, { ...process.env, DEBUG: 'pw:webserver' }); + + expect(result.exitCode).toBe(1); + expect(result.passed).toBe(0); + expect(result.output).toContain('NODE_OPTIONS undefined'); +});