chore: allow web server w/o waiting (#24609)
This commit is contained in:
parent
b3ce913551
commit
8fde110c61
|
@ -584,8 +584,8 @@ export default defineConfig({
|
|||
* since: v1.10
|
||||
- type: ?<[Object]|[Array]<[Object]>>
|
||||
- `command` <[string]> Shell command to start. For example `npm run start`..
|
||||
- `port` ?<[int]> The port that your http server is expected to appear on. It does wait until it accepts connections. Exactly one of `port` or `url` is required.
|
||||
- `url` ?<[string]> The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is checked. Exactly one of `port` or `url` is required.
|
||||
- `port` ?<[int]> The port that your http server is expected to appear on. It does wait until it accepts connections. Either `port` or `url` should be specified.
|
||||
- `url` ?<[string]> The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is checked. Either `port` or `url` should be specified.
|
||||
- `ignoreHTTPSErrors` ?<[boolean]> Whether to ignore HTTPS errors when fetching the `url`. Defaults to `false`.
|
||||
- `timeout` ?<[int]> How long to wait for the process to start up and be available in milliseconds. Defaults to 60000.
|
||||
- `reuseExistingServer` ?<[boolean]> If true, it will re-use an existing server on the `port` or `url` when available. If no server is running on that `port` or `url`, it will run the command to start a new server. If `false`, it will throw if an existing process is listening on the `port` or `url`. This should be commonly set to `!process.env.CI` to allow the local dev server when running tests locally.
|
||||
|
|
|
@ -28,7 +28,7 @@ import type { ReporterV2 } from '../reporters/reporterV2';
|
|||
|
||||
export type WebServerPluginOptions = {
|
||||
command: string;
|
||||
url: string;
|
||||
url?: string;
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
timeout?: number;
|
||||
reuseExistingServer?: boolean;
|
||||
|
@ -45,7 +45,7 @@ const DEFAULT_ENVIRONMENT_VARIABLES = {
|
|||
const debugWebServer = debug('pw:webserver');
|
||||
|
||||
export class WebServerPlugin implements TestRunnerPlugin {
|
||||
private _isAvailable?: () => Promise<boolean>;
|
||||
private _isAvailableCallback?: () => Promise<boolean>;
|
||||
private _killProcess?: () => Promise<void>;
|
||||
private _processExitedPromise!: Promise<any>;
|
||||
private _options: WebServerPluginOptions;
|
||||
|
@ -60,7 +60,7 @@ export class WebServerPlugin implements TestRunnerPlugin {
|
|||
|
||||
public async setup(config: FullConfig, configDir: string, reporter: ReporterV2) {
|
||||
this._reporter = reporter;
|
||||
this._isAvailable = getIsAvailableFunction(this._options.url, this._checkPortOnly, !!this._options.ignoreHTTPSErrors, this._reporter.onStdErr?.bind(this._reporter));
|
||||
this._isAvailableCallback = this._options.url ? getIsAvailableFunction(this._options.url, this._checkPortOnly, !!this._options.ignoreHTTPSErrors, this._reporter.onStdErr?.bind(this._reporter)) : undefined;
|
||||
this._options.cwd = this._options.cwd ? path.resolve(configDir, this._options.cwd) : configDir;
|
||||
try {
|
||||
await this._startProcess();
|
||||
|
@ -79,12 +79,12 @@ export class WebServerPlugin implements TestRunnerPlugin {
|
|||
let processExitedReject = (error: Error) => { };
|
||||
this._processExitedPromise = new Promise((_, reject) => processExitedReject = reject);
|
||||
|
||||
const isAlreadyAvailable = await this._isAvailable!();
|
||||
const isAlreadyAvailable = await this._isAvailableCallback?.();
|
||||
if (isAlreadyAvailable) {
|
||||
debugWebServer(`WebServer is already available`);
|
||||
if (this._options.reuseExistingServer)
|
||||
return;
|
||||
const port = new URL(this._options.url);
|
||||
const port = new URL(this._options.url!).port;
|
||||
throw new Error(`${this._options.url ?? `http://localhost${port ? ':' + port : ''}`} is already used, make sure that nothing is running on the port/url or set reuseExistingServer:true in config.webServer.`);
|
||||
}
|
||||
|
||||
|
@ -121,21 +121,21 @@ export class WebServerPlugin implements TestRunnerPlugin {
|
|||
}
|
||||
|
||||
private async _waitForProcess() {
|
||||
if (!this._isAvailableCallback) {
|
||||
this._processExitedPromise.catch(() => {});
|
||||
return;
|
||||
}
|
||||
debugWebServer(`Waiting for availability...`);
|
||||
await this._waitForAvailability();
|
||||
debugWebServer(`WebServer available`);
|
||||
}
|
||||
|
||||
private async _waitForAvailability() {
|
||||
const launchTimeout = this._options.timeout || 60 * 1000;
|
||||
const cancellationToken = { canceled: false };
|
||||
const { timedOut } = (await Promise.race([
|
||||
raceAgainstDeadline(() => waitFor(this._isAvailable!, cancellationToken), monotonicTime() + launchTimeout),
|
||||
raceAgainstDeadline(() => waitFor(this._isAvailableCallback!, cancellationToken), monotonicTime() + launchTimeout),
|
||||
this._processExitedPromise,
|
||||
]));
|
||||
cancellationToken.canceled = true;
|
||||
if (timedOut)
|
||||
throw new Error(`Timed out waiting ${launchTimeout}ms from config.webServer.`);
|
||||
debugWebServer(`WebServer available`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,15 +214,17 @@ export const webServerPluginsForConfig = (config: FullConfigInternal): TestRunne
|
|||
const shouldSetBaseUrl = !!config.config.webServer;
|
||||
const webServerPlugins = [];
|
||||
for (const webServerConfig of config.webServers) {
|
||||
if ((!webServerConfig.port && !webServerConfig.url) || (webServerConfig.port && webServerConfig.url))
|
||||
throw new Error(`Exactly one of 'port' or 'url' is required in config.webServer.`);
|
||||
if (webServerConfig.port && webServerConfig.url)
|
||||
throw new Error(`Either 'port' or 'url' should be specified in config.webServer.`);
|
||||
|
||||
const url = webServerConfig.url || `http://localhost:${webServerConfig.port}`;
|
||||
|
||||
// We only set base url when only the port is given. That's a legacy mode we have regrets about.
|
||||
if (shouldSetBaseUrl && !webServerConfig.url)
|
||||
process.env.PLAYWRIGHT_TEST_BASE_URL = url;
|
||||
let url: string | undefined;
|
||||
if (webServerConfig.port || webServerConfig.url) {
|
||||
url = webServerConfig.url || `http://localhost:${webServerConfig.port}`;
|
||||
|
||||
// We only set base url when only the port is given. That's a legacy mode we have regrets about.
|
||||
if (shouldSetBaseUrl && !webServerConfig.url)
|
||||
process.env.PLAYWRIGHT_TEST_BASE_URL = url;
|
||||
}
|
||||
webServerPlugins.push(new WebServerPlugin({ ...webServerConfig, url }, webServerConfig.port !== undefined));
|
||||
}
|
||||
|
||||
|
|
|
@ -6735,15 +6735,15 @@ interface TestConfigWebServer {
|
|||
command: string;
|
||||
|
||||
/**
|
||||
* The port that your http server is expected to appear on. It does wait until it accepts connections. Exactly one of
|
||||
* `port` or `url` is required.
|
||||
* The port that your http server is expected to appear on. It does wait until it accepts connections. Either `port`
|
||||
* or `url` should be specified.
|
||||
*/
|
||||
port?: number;
|
||||
|
||||
/**
|
||||
* The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the
|
||||
* server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is
|
||||
* checked. Exactly one of `port` or `url` is required.
|
||||
* checked. Either `port` or `url` should be specified.
|
||||
*/
|
||||
url?: string;
|
||||
|
||||
|
|
Loading…
Reference in New Issue