feat(plugins): add webServer implementation (#13779)
This commit is contained in:
parent
45972a0b6a
commit
f486ce8c06
|
|
@ -19,6 +19,7 @@
|
||||||
"./lib/cli": "./lib/cli.js",
|
"./lib/cli": "./lib/cli.js",
|
||||||
"./lib/experimentalLoader": "./lib/experimentalLoader.js",
|
"./lib/experimentalLoader": "./lib/experimentalLoader.js",
|
||||||
"./lib/mount": "./lib/mount.js",
|
"./lib/mount": "./lib/mount.js",
|
||||||
|
"./lib/plugins": "./lib/plugins/index.js",
|
||||||
"./lib/plugins/vitePlugin": "./lib/plugins/vitePlugin.js",
|
"./lib/plugins/vitePlugin": "./lib/plugins/vitePlugin.js",
|
||||||
"./reporter": "./reporter.js"
|
"./reporter": "./reporter.js"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,4 @@
|
||||||
matchers/
|
matchers/
|
||||||
reporters/
|
reporters/
|
||||||
third_party/
|
third_party/
|
||||||
|
plugins/webServerPlugin.ts
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import type { Reporter } from '../types/testReporter';
|
||||||
import { builtInReporters } from './runner';
|
import { builtInReporters } from './runner';
|
||||||
import { isRegExp } from 'playwright-core/lib/utils';
|
import { isRegExp } from 'playwright-core/lib/utils';
|
||||||
import { serializeError } from './util';
|
import { serializeError } from './util';
|
||||||
|
import { _legacyWebServer } from './plugins/webServerPlugin';
|
||||||
|
|
||||||
// To allow multiple loaders in the same process without clearing require cache,
|
// To allow multiple loaders in the same process without clearing require cache,
|
||||||
// we make these maps global.
|
// we make these maps global.
|
||||||
|
|
@ -76,6 +77,11 @@ export class Loader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _processConfigObject(config: Config, configDir: string) {
|
private _processConfigObject(config: Config, configDir: string) {
|
||||||
|
if (config.webServer) {
|
||||||
|
config.plugins = config.plugins || [];
|
||||||
|
config.plugins.push(_legacyWebServer(config.webServer));
|
||||||
|
}
|
||||||
|
|
||||||
for (const plugin of config.plugins || [])
|
for (const plugin of config.plugins || [])
|
||||||
plugin.configure?.(config, configDir);
|
plugin.configure?.(config, configDir);
|
||||||
|
|
||||||
|
|
|
||||||
16
packages/playwright-test/src/plugins/index.ts
Normal file
16
packages/playwright-test/src/plugins/index.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
export { webServer } from './webServerPlugin';
|
||||||
|
|
@ -13,15 +13,33 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import https from 'https';
|
import https from 'https';
|
||||||
|
import path from 'path';
|
||||||
import net from 'net';
|
import net from 'net';
|
||||||
|
|
||||||
import { debug } from 'playwright-core/lib/utilsBundle';
|
import { debug } from 'playwright-core/lib/utilsBundle';
|
||||||
import { raceAgainstTimeout } from 'playwright-core/lib/utils/timeoutRunner';
|
import { raceAgainstTimeout } from 'playwright-core/lib/utils/timeoutRunner';
|
||||||
import type { FullConfig } from './types';
|
|
||||||
import { launchProcess } from 'playwright-core/lib/utils/processLauncher';
|
import { launchProcess } from 'playwright-core/lib/utils/processLauncher';
|
||||||
import type { Reporter } from '../types/testReporter';
|
|
||||||
|
import type { PlaywrightTestConfig, TestPlugin } from '../types';
|
||||||
|
import type { Reporter } from '../../types/testReporter';
|
||||||
|
|
||||||
|
export type WebServerPluginOptions = {
|
||||||
|
command: string;
|
||||||
|
url: string;
|
||||||
|
ignoreHTTPSErrors?: boolean;
|
||||||
|
timeout?: number;
|
||||||
|
reuseExistingServer?: boolean;
|
||||||
|
cwd?: string;
|
||||||
|
env?: { [key: string]: string; };
|
||||||
|
};
|
||||||
|
|
||||||
|
interface InternalWebServerConfigOptions extends Omit<WebServerPluginOptions, 'url'> {
|
||||||
|
setBaseURL: boolean;
|
||||||
|
url?: string;
|
||||||
|
port?: number;
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_ENVIRONMENT_VARIABLES = {
|
const DEFAULT_ENVIRONMENT_VARIABLES = {
|
||||||
'BROWSER': 'none', // Disable that create-react-app will open the page in the browser
|
'BROWSER': 'none', // Disable that create-react-app will open the page in the browser
|
||||||
|
|
@ -29,29 +47,47 @@ const DEFAULT_ENVIRONMENT_VARIABLES = {
|
||||||
|
|
||||||
const debugWebServer = debug('pw:webserver');
|
const debugWebServer = debug('pw:webserver');
|
||||||
|
|
||||||
type WebServerConfig = NonNullable<FullConfig['webServer']>;
|
export class InternalWebServerPlugin implements TestPlugin {
|
||||||
|
|
||||||
export class WebServer {
|
|
||||||
private _isAvailable: () => Promise<boolean>;
|
private _isAvailable: () => Promise<boolean>;
|
||||||
private _killProcess?: () => Promise<void>;
|
private _killProcess?: () => Promise<void>;
|
||||||
private _processExitedPromise!: Promise<any>;
|
private _processExitedPromise!: Promise<any>;
|
||||||
|
private _config: InternalWebServerConfigOptions;
|
||||||
|
private _reporter: Reporter;
|
||||||
|
|
||||||
constructor(private readonly config: WebServerConfig, private readonly reporter: Reporter) {
|
constructor(config: InternalWebServerConfigOptions, reporter: Reporter) {
|
||||||
this._isAvailable = getIsAvailableFunction(config, reporter.onStdErr?.bind(reporter));
|
this._reporter = reporter;
|
||||||
|
this._config = { ...config };
|
||||||
|
this._config.setBaseURL = this._config.setBaseURL ?? true;
|
||||||
|
this._isAvailable = getIsAvailableFunction(config, this._reporter.onStdErr?.bind(this._reporter));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async create(config: WebServerConfig, reporter: Reporter): Promise<WebServer> {
|
get name() {
|
||||||
const webServer = new WebServer(config, reporter);
|
const target = this._config.url || `http://localhost:${this._config.port}`;
|
||||||
|
return `playwright-webserver-plugin [${target}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async configure(config: PlaywrightTestConfig, configDir: string) {
|
||||||
|
this._config.cwd = this._config.cwd ? path.resolve(configDir, this._config.cwd) : configDir;
|
||||||
|
if (this._config.setBaseURL && this._config.port !== undefined && !config.use?.baseURL) {
|
||||||
|
config.use = (config.use || {});
|
||||||
|
config.use.baseURL = `http://localhost:${this._config.port}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setup() {
|
||||||
try {
|
try {
|
||||||
await webServer._startProcess();
|
await this._startProcess();
|
||||||
await webServer._waitForProcess();
|
await this._waitForProcess();
|
||||||
return webServer;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await webServer.kill();
|
await this.teardown();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async teardown() {
|
||||||
|
await this._killProcess?.();
|
||||||
|
}
|
||||||
|
|
||||||
private async _startProcess(): Promise<void> {
|
private async _startProcess(): Promise<void> {
|
||||||
let processExitedReject = (error: Error) => { };
|
let processExitedReject = (error: Error) => { };
|
||||||
this._processExitedPromise = new Promise((_, reject) => processExitedReject = reject);
|
this._processExitedPromise = new Promise((_, reject) => processExitedReject = reject);
|
||||||
|
|
@ -59,20 +95,20 @@ export class WebServer {
|
||||||
const isAlreadyAvailable = await this._isAvailable();
|
const isAlreadyAvailable = await this._isAvailable();
|
||||||
if (isAlreadyAvailable) {
|
if (isAlreadyAvailable) {
|
||||||
debugWebServer(`WebServer is already available`);
|
debugWebServer(`WebServer is already available`);
|
||||||
if (this.config.reuseExistingServer)
|
if (this._config.reuseExistingServer)
|
||||||
return;
|
return;
|
||||||
throw new Error(`${this.config.url ?? `http://localhost:${this.config.port}`} is already used, make sure that nothing is running on the port/url or set reuseExistingServer:true in config.webServer.`);
|
throw new Error(`${this._config.url ?? `http://localhost:${this._config.port}`} is already used, make sure that nothing is running on the port/url or set reuseExistingServer:true in config.webServer.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
debugWebServer(`Starting WebServer process ${this.config.command}...`);
|
debugWebServer(`Starting WebServer process ${this._config.command}...`);
|
||||||
const { launchedProcess, kill } = await launchProcess({
|
const { launchedProcess, kill } = await launchProcess({
|
||||||
command: this.config.command,
|
command: this._config.command,
|
||||||
env: {
|
env: {
|
||||||
...DEFAULT_ENVIRONMENT_VARIABLES,
|
...DEFAULT_ENVIRONMENT_VARIABLES,
|
||||||
...process.env,
|
...process.env,
|
||||||
...this.config.env,
|
...this._config.env,
|
||||||
},
|
},
|
||||||
cwd: this.config.cwd,
|
cwd: this._config.cwd,
|
||||||
stdio: 'stdin',
|
stdio: 'stdin',
|
||||||
shell: true,
|
shell: true,
|
||||||
attemptToGracefullyClose: async () => {},
|
attemptToGracefullyClose: async () => {},
|
||||||
|
|
@ -84,10 +120,10 @@ export class WebServer {
|
||||||
|
|
||||||
debugWebServer(`Process started`);
|
debugWebServer(`Process started`);
|
||||||
|
|
||||||
launchedProcess.stderr!.on('data', line => this.reporter.onStdErr?.('[WebServer] ' + line.toString()));
|
launchedProcess.stderr!.on('data', line => this._reporter.onStdErr?.('[WebServer] ' + line.toString()));
|
||||||
launchedProcess.stdout!.on('data', line => {
|
launchedProcess.stdout!.on('data', line => {
|
||||||
if (debugWebServer.enabled)
|
if (debugWebServer.enabled)
|
||||||
this.reporter.onStdOut?.('[WebServer] ' + line.toString());
|
this._reporter.onStdOut?.('[WebServer] ' + line.toString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,12 +131,10 @@ export class WebServer {
|
||||||
debugWebServer(`Waiting for availability...`);
|
debugWebServer(`Waiting for availability...`);
|
||||||
await this._waitForAvailability();
|
await this._waitForAvailability();
|
||||||
debugWebServer(`WebServer available`);
|
debugWebServer(`WebServer available`);
|
||||||
if (this.config.port !== undefined)
|
|
||||||
process.env.PLAYWRIGHT_TEST_BASE_URL = `http://localhost:${this.config.port}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _waitForAvailability() {
|
private async _waitForAvailability() {
|
||||||
const launchTimeout = this.config.timeout || 60 * 1000;
|
const launchTimeout = this._config.timeout || 60 * 1000;
|
||||||
const cancellationToken = { canceled: false };
|
const cancellationToken = { canceled: false };
|
||||||
const { timedOut } = (await Promise.race([
|
const { timedOut } = (await Promise.race([
|
||||||
raceAgainstTimeout(() => waitFor(this._isAvailable, cancellationToken), launchTimeout),
|
raceAgainstTimeout(() => waitFor(this._isAvailable, cancellationToken), launchTimeout),
|
||||||
|
|
@ -110,9 +144,6 @@ export class WebServer {
|
||||||
if (timedOut)
|
if (timedOut)
|
||||||
throw new Error(`Timed out waiting ${launchTimeout}ms from config.webServer.`);
|
throw new Error(`Timed out waiting ${launchTimeout}ms from config.webServer.`);
|
||||||
}
|
}
|
||||||
public async kill() {
|
|
||||||
await this._killProcess?.();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function isPortUsed(port: number): Promise<boolean> {
|
async function isPortUsed(port: number): Promise<boolean> {
|
||||||
|
|
@ -173,7 +204,7 @@ async function waitFor(waitFn: () => Promise<boolean>, cancellationToken: { canc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIsAvailableFunction({ url, port, ignoreHTTPSErrors }: Pick<WebServerConfig, 'port' | 'url' | 'ignoreHTTPSErrors'>, onStdErr: Reporter['onStdErr']) {
|
function getIsAvailableFunction({ url, port, ignoreHTTPSErrors }: Pick<InternalWebServerConfigOptions, 'port' | 'url' | 'ignoreHTTPSErrors'>, onStdErr: Reporter['onStdErr']) {
|
||||||
if (url !== undefined && port === undefined) {
|
if (url !== undefined && port === undefined) {
|
||||||
const urlObject = new URL(url);
|
const urlObject = new URL(url);
|
||||||
return () => isURLAvailable(urlObject, ignoreHTTPSErrors, onStdErr);
|
return () => isURLAvailable(urlObject, ignoreHTTPSErrors, onStdErr);
|
||||||
|
|
@ -183,3 +214,13 @@ function getIsAvailableFunction({ url, port, ignoreHTTPSErrors }: Pick<WebServer
|
||||||
throw new Error(`Exactly one of 'port' or 'url' is required in config.webServer.`);
|
throw new Error(`Exactly one of 'port' or 'url' is required in config.webServer.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const webServer = (config: WebServerPluginOptions): TestPlugin => {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
return new InternalWebServerPlugin({ ...config, setBaseURL: false }, { onStdOut: d => console.log(d.toString()), onStdErr: d => console.error(d.toString()) });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const _legacyWebServer = (config: Omit<InternalWebServerConfigOptions, 'setBaseURL'>): TestPlugin => {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
return new InternalWebServerPlugin({ ...config, setBaseURL: true }, { onStdOut: d => console.log(d.toString()), onStdErr: d => console.error(d.toString()) });
|
||||||
|
};
|
||||||
|
|
@ -40,7 +40,6 @@ import HtmlReporter from './reporters/html';
|
||||||
import type { ProjectImpl } from './project';
|
import type { ProjectImpl } from './project';
|
||||||
import type { Config } from './types';
|
import type { Config } from './types';
|
||||||
import type { FullConfigInternal } from './types';
|
import type { FullConfigInternal } from './types';
|
||||||
import { WebServer } from './webServer';
|
|
||||||
import { raceAgainstTimeout } from 'playwright-core/lib/utils/timeoutRunner';
|
import { raceAgainstTimeout } from 'playwright-core/lib/utils/timeoutRunner';
|
||||||
import { SigIntWatcher } from './sigIntWatcher';
|
import { SigIntWatcher } from './sigIntWatcher';
|
||||||
import { GlobalInfoImpl } from './globalInfo';
|
import { GlobalInfoImpl } from './globalInfo';
|
||||||
|
|
@ -414,7 +413,6 @@ export class Runner {
|
||||||
const result: FullResult = { status: 'passed' };
|
const result: FullResult = { status: 'passed' };
|
||||||
const pluginTeardowns: (() => Promise<void>)[] = [];
|
const pluginTeardowns: (() => Promise<void>)[] = [];
|
||||||
let globalSetupResult: any;
|
let globalSetupResult: any;
|
||||||
let webServer: WebServer | undefined;
|
|
||||||
|
|
||||||
const tearDown = async () => {
|
const tearDown = async () => {
|
||||||
// Reverse to setup.
|
// Reverse to setup.
|
||||||
|
|
@ -428,10 +426,6 @@ export class Runner {
|
||||||
await (await this._loader.loadGlobalHook(config.globalTeardown, 'globalTeardown'))(this._loader.fullConfig());
|
await (await this._loader.loadGlobalHook(config.globalTeardown, 'globalTeardown'))(this._loader.fullConfig());
|
||||||
}, result);
|
}, result);
|
||||||
|
|
||||||
await this._runAndReportError(async () => {
|
|
||||||
await webServer?.kill();
|
|
||||||
}, result);
|
|
||||||
|
|
||||||
for (const teardown of pluginTeardowns) {
|
for (const teardown of pluginTeardowns) {
|
||||||
await this._runAndReportError(async () => {
|
await this._runAndReportError(async () => {
|
||||||
await teardown();
|
await teardown();
|
||||||
|
|
@ -448,9 +442,6 @@ export class Runner {
|
||||||
pluginTeardowns.unshift(plugin.teardown);
|
pluginTeardowns.unshift(plugin.teardown);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then do legacy web server.
|
|
||||||
webServer = config.webServer ? await WebServer.create(config.webServer, this._reporter) : undefined;
|
|
||||||
|
|
||||||
// The do global setup.
|
// The do global setup.
|
||||||
if (config.globalSetup)
|
if (config.globalSetup)
|
||||||
globalSetupResult = await (await this._loader.loadGlobalHook(config.globalSetup, 'globalSetup'))(this._loader.fullConfig(), this._globalInfo);
|
globalSetupResult = await (await this._loader.loadGlobalHook(config.globalSetup, 'globalSetup'))(this._loader.fullConfig(), this._globalInfo);
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,8 @@ setTimeout(() => {
|
||||||
server.setRoute('/env-FOO', (message, response) => {
|
server.setRoute('/env-FOO', (message, response) => {
|
||||||
response.end(process.env.FOO);
|
response.end(process.env.FOO);
|
||||||
});
|
});
|
||||||
|
server.setRoute('/port', (_, response) => {
|
||||||
|
response.end('' + server.PORT);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}, process.argv[3] ? +process.argv[3] : 0);
|
}, process.argv[3] ? +process.argv[3] : 0);
|
||||||
|
|
|
||||||
|
|
@ -426,3 +426,131 @@ test(`should suport self signed certificate`, async ({ runInlineTest, httpsServe
|
||||||
});
|
});
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should create multiple servers', async ({ runInlineTest }, { workerIndex }) => {
|
||||||
|
const port = workerIndex + 10500;
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'test.spec.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('connect to the server', async ({page}) => {
|
||||||
|
await page.goto('http://localhost:${port}/port');
|
||||||
|
await page.locator('text=${port}');
|
||||||
|
|
||||||
|
await page.goto('http://localhost:${port + 1}/port');
|
||||||
|
await page.locator('text=${port + 1}');
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'playwright.config.ts': `
|
||||||
|
import { webServer } from '@playwright/test/lib/plugins';
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
webServer({
|
||||||
|
command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${port}',
|
||||||
|
url: 'http://localhost:${port}/port',
|
||||||
|
}),
|
||||||
|
webServer({
|
||||||
|
command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${port + 1}',
|
||||||
|
url: 'http://localhost:${port + 1}/port',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
globalSetup: 'globalSetup.ts',
|
||||||
|
globalTeardown: 'globalTeardown.ts',
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'globalSetup.ts': `
|
||||||
|
module.exports = async () => {
|
||||||
|
const http = require("http");
|
||||||
|
const response = await new Promise(resolve => {
|
||||||
|
const request = http.request("http://localhost:${port}/hello", resolve);
|
||||||
|
request.end();
|
||||||
|
})
|
||||||
|
console.log('globalSetup-status-'+response.statusCode)
|
||||||
|
return async () => {
|
||||||
|
const response = await new Promise(resolve => {
|
||||||
|
const request = http.request("http://localhost:${port}/hello", resolve);
|
||||||
|
request.end();
|
||||||
|
})
|
||||||
|
console.log('globalSetup-teardown-status-'+response.statusCode)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'globalTeardown.ts': `
|
||||||
|
module.exports = async () => {
|
||||||
|
const http = require("http");
|
||||||
|
const response = await new Promise(resolve => {
|
||||||
|
const request = http.request("http://localhost:${port}/hello", resolve);
|
||||||
|
request.end();
|
||||||
|
})
|
||||||
|
console.log('globalTeardown-status-'+response.statusCode)
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
}, undefined, { DEBUG: 'pw:webserver' });
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
expect(result.output).toContain('[WebServer] listening');
|
||||||
|
expect(result.output).toContain('[WebServer] error from server');
|
||||||
|
expect(result.output).toContain('passed');
|
||||||
|
|
||||||
|
const expectedLogMessages = ['globalSetup-status-200', 'globalSetup-teardown-status', 'globalTeardown-status-200'];
|
||||||
|
const actualLogMessages = expectedLogMessages.map(log => ({
|
||||||
|
log,
|
||||||
|
index: result.output.indexOf(log),
|
||||||
|
})).sort((a, b) => a.index - b.index).filter(l => l.index !== -1).map(l => l.log);
|
||||||
|
expect(actualLogMessages).toStrictEqual(expectedLogMessages);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('baseURL with plugins', () => {
|
||||||
|
test('plugins do not set it', async ({ runInlineTest }, { workerIndex }) => {
|
||||||
|
const port = workerIndex + 10500;
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'test.spec.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('connect to the server', async ({baseURL, page}) => {
|
||||||
|
expect(baseURL).toBeUndefined();
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'playwright.config.ts': `
|
||||||
|
import { webServer } from '@playwright/test/lib/plugins';
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
webServer({
|
||||||
|
command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${port}',
|
||||||
|
url: 'http://localhost:${port}/port',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
}, undefined, { DEBUG: 'pw:webserver' });
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('legacy config sets it alongside plugin', async ({ runInlineTest }, { workerIndex }) => {
|
||||||
|
const port = workerIndex + 10500;
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'test.spec.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('connect to the server', async ({baseURL, page}) => {
|
||||||
|
expect(baseURL).toBe('http://localhost:${port}');
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'playwright.config.ts': `
|
||||||
|
import { webServer } from '@playwright/test/lib/plugins';
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
webServer({
|
||||||
|
command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${port + 1}',
|
||||||
|
url: 'http://localhost:${port + 1}/port'
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
webServer: {
|
||||||
|
command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${port}',
|
||||||
|
port: ${port},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
}, undefined, { DEBUG: 'pw:webserver' });
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue