feat(test): more information about timing out fixtures (#13546)
- Always show a fixture that was running during timeout. - Give custom titles to built-in fixtures. - Specify setup/teardown fixture phase in the message. - Split connect vs launch browser fixtures for better naming. Example timeout message: ```log Timeout of 2000ms exceeded while running fixture "built-in playwright configuration" teardown. ```
This commit is contained in:
parent
e2fff31848
commit
166675b9c1
|
|
@ -31,6 +31,7 @@ type FixtureRegistration = {
|
||||||
fn: Function | any; // Either a fixture function, or a fixture value.
|
fn: Function | any; // Either a fixture function, or a fixture value.
|
||||||
auto: boolean;
|
auto: boolean;
|
||||||
option: boolean;
|
option: boolean;
|
||||||
|
customTitle?: string;
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
deps: string[]; // Names of the dependencies, ({ foo, bar }) => {...}
|
deps: string[]; // Names of the dependencies, ({ foo, bar }) => {...}
|
||||||
id: string; // Unique id, to differentiate between fixtures with the same name.
|
id: string; // Unique id, to differentiate between fixtures with the same name.
|
||||||
|
|
@ -54,7 +55,7 @@ class Fixture {
|
||||||
this.usages = new Set();
|
this.usages = new Set();
|
||||||
this.value = null;
|
this.value = null;
|
||||||
this._runnableDescription = {
|
this._runnableDescription = {
|
||||||
fixture: this.registration.name,
|
title: `fixture "${this.registration.customTitle || this.registration.name}" setup`,
|
||||||
location: registration.location,
|
location: registration.location,
|
||||||
slot: this.registration.timeout === undefined ? undefined : {
|
slot: this.registration.timeout === undefined ? undefined : {
|
||||||
timeout: this.registration.timeout,
|
timeout: this.registration.timeout,
|
||||||
|
|
@ -117,6 +118,7 @@ class Fixture {
|
||||||
this.usages.clear();
|
this.usages.clear();
|
||||||
if (this._useFuncFinished) {
|
if (this._useFuncFinished) {
|
||||||
debugTest(`teardown ${this.registration.name}`);
|
debugTest(`teardown ${this.registration.name}`);
|
||||||
|
this._runnableDescription.title = `fixture "${this.registration.customTitle || this.registration.name}" teardown`;
|
||||||
timeoutManager.setCurrentFixture(this._runnableDescription);
|
timeoutManager.setCurrentFixture(this._runnableDescription);
|
||||||
this._useFuncFinished.resolve();
|
this._useFuncFinished.resolve();
|
||||||
await this._selfTeardownComplete;
|
await this._selfTeardownComplete;
|
||||||
|
|
@ -147,13 +149,14 @@ export class FixturePool {
|
||||||
for (const entry of Object.entries(fixtures)) {
|
for (const entry of Object.entries(fixtures)) {
|
||||||
const name = entry[0];
|
const name = entry[0];
|
||||||
let value = entry[1];
|
let value = entry[1];
|
||||||
let options: { auto: boolean, scope: FixtureScope, option: boolean, timeout: number | undefined } | undefined;
|
let options: { auto: boolean, scope: FixtureScope, option: boolean, timeout: number | undefined, customTitle: string | undefined } | undefined;
|
||||||
if (isFixtureTuple(value)) {
|
if (isFixtureTuple(value)) {
|
||||||
options = {
|
options = {
|
||||||
auto: !!value[1].auto,
|
auto: !!value[1].auto,
|
||||||
scope: value[1].scope || 'test',
|
scope: value[1].scope || 'test',
|
||||||
option: !!value[1].option,
|
option: !!value[1].option,
|
||||||
timeout: value[1].timeout,
|
timeout: value[1].timeout,
|
||||||
|
customTitle: (value[1] as any)._title,
|
||||||
};
|
};
|
||||||
value = value[0];
|
value = value[0];
|
||||||
}
|
}
|
||||||
|
|
@ -166,9 +169,9 @@ export class FixturePool {
|
||||||
if (previous.auto !== options.auto)
|
if (previous.auto !== options.auto)
|
||||||
throw errorWithLocations(`Fixture "${name}" has already been registered as a { auto: '${previous.scope}' } fixture.`, { location, name }, previous);
|
throw errorWithLocations(`Fixture "${name}" has already been registered as a { auto: '${previous.scope}' } fixture.`, { location, name }, previous);
|
||||||
} else if (previous) {
|
} else if (previous) {
|
||||||
options = { auto: previous.auto, scope: previous.scope, option: previous.option, timeout: previous.timeout };
|
options = { auto: previous.auto, scope: previous.scope, option: previous.option, timeout: previous.timeout, customTitle: previous.customTitle };
|
||||||
} else if (!options) {
|
} else if (!options) {
|
||||||
options = { auto: false, scope: 'test', option: false, timeout: undefined };
|
options = { auto: false, scope: 'test', option: false, timeout: undefined, customTitle: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.scope !== 'test' && options.scope !== 'worker')
|
if (options.scope !== 'test' && options.scope !== 'worker')
|
||||||
|
|
@ -177,7 +180,7 @@ export class FixturePool {
|
||||||
throw errorWithLocations(`Cannot use({ ${name} }) in a describe group, because it forces a new worker.\nMake it top-level in the test file or put in the configuration file.`, { location, name });
|
throw errorWithLocations(`Cannot use({ ${name} }) in a describe group, because it forces a new worker.\nMake it top-level in the test file or put in the configuration file.`, { location, name });
|
||||||
|
|
||||||
const deps = fixtureParameterNames(fn, location);
|
const deps = fixtureParameterNames(fn, location);
|
||||||
const registration: FixtureRegistration = { id: '', name, location, scope: options.scope, fn, auto: options.auto, option: options.option, timeout: options.timeout, deps, super: previous };
|
const registration: FixtureRegistration = { id: '', name, location, scope: options.scope, fn, auto: options.auto, option: options.option, timeout: options.timeout, customTitle: options.customTitle, deps, super: previous };
|
||||||
registrationId(registration);
|
registrationId(registration);
|
||||||
this.registrations.set(name, registration);
|
this.registrations.set(name, registration);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import type { LaunchOptions, BrowserContextOptions, Page, BrowserContext, Video, APIRequestContext, Tracing } from 'playwright-core';
|
import type { LaunchOptions, BrowserContextOptions, Page, Browser, BrowserContext, Video, APIRequestContext, Tracing } from 'playwright-core';
|
||||||
import type { TestType, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo } from '../types/test';
|
import type { TestType, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo } from '../types/test';
|
||||||
import { rootTestType } from './testType';
|
import { rootTestType } from './testType';
|
||||||
import { createGuid, debugMode } from 'playwright-core/lib/utils';
|
import { createGuid, debugMode } from 'playwright-core/lib/utils';
|
||||||
|
|
@ -44,6 +44,7 @@ type TestFixtures = PlaywrightTestArgs & PlaywrightTestOptions & {
|
||||||
_contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
|
_contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
|
||||||
};
|
};
|
||||||
type WorkerFixtures = PlaywrightWorkerArgs & PlaywrightWorkerOptions & {
|
type WorkerFixtures = PlaywrightWorkerArgs & PlaywrightWorkerOptions & {
|
||||||
|
_connectedBrowser: Browser | undefined,
|
||||||
_browserOptions: LaunchOptions;
|
_browserOptions: LaunchOptions;
|
||||||
_artifactsDir: () => string;
|
_artifactsDir: () => string;
|
||||||
_snapshotSuffix: string;
|
_snapshotSuffix: string;
|
||||||
|
|
@ -86,12 +87,12 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
||||||
});
|
});
|
||||||
if (dir)
|
if (dir)
|
||||||
await removeFolders([dir]);
|
await removeFolders([dir]);
|
||||||
}, { scope: 'worker' }],
|
}, { scope: 'worker', _title: 'built-in playwright configuration' } as any],
|
||||||
|
|
||||||
_browserOptions: [async ({ playwright, headless, channel, launchOptions }, use) => {
|
_browserOptions: [async ({ playwright, headless, channel, launchOptions }, use) => {
|
||||||
const options: LaunchOptions = {
|
const options: LaunchOptions = {
|
||||||
handleSIGINT: false,
|
handleSIGINT: false,
|
||||||
timeout: 30000, // 30 seconds
|
timeout: 0,
|
||||||
...launchOptions,
|
...launchOptions,
|
||||||
};
|
};
|
||||||
if (headless !== undefined)
|
if (headless !== undefined)
|
||||||
|
|
@ -106,27 +107,37 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
||||||
(browserType as any)._defaultLaunchOptions = undefined;
|
(browserType as any)._defaultLaunchOptions = undefined;
|
||||||
}, { scope: 'worker', auto: true }],
|
}, { scope: 'worker', auto: true }],
|
||||||
|
|
||||||
browser: [async ({ playwright, browserName, channel, headless, connectOptions }, use) => {
|
_connectedBrowser: [async ({ playwright, browserName, channel, headless, connectOptions }, use) => {
|
||||||
|
if (!connectOptions) {
|
||||||
|
await use(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!['chromium', 'firefox', 'webkit'].includes(browserName))
|
if (!['chromium', 'firefox', 'webkit'].includes(browserName))
|
||||||
throw new Error(`Unexpected browserName "${browserName}", must be one of "chromium", "firefox" or "webkit"`);
|
throw new Error(`Unexpected browserName "${browserName}", must be one of "chromium", "firefox" or "webkit"`);
|
||||||
if (connectOptions) {
|
const browser = await playwright[browserName].connect(connectOptions.wsEndpoint, {
|
||||||
const browser = await playwright[browserName].connect(connectOptions.wsEndpoint, {
|
headers: {
|
||||||
headers: {
|
'x-playwright-browser': channel || browserName,
|
||||||
'x-playwright-browser': channel || browserName,
|
'x-playwright-headless': headless ? '1' : '0',
|
||||||
'x-playwright-headless': headless ? '1' : '0',
|
...connectOptions.headers,
|
||||||
...connectOptions.headers,
|
},
|
||||||
},
|
timeout: connectOptions.timeout ?? 3 * 60 * 1000, // 3 minutes
|
||||||
timeout: connectOptions.timeout ?? 3 * 60 * 1000, // 3 minutes
|
});
|
||||||
});
|
await use(browser);
|
||||||
await use(browser);
|
await browser.close();
|
||||||
await browser.close();
|
}, { scope: 'worker', timeout: 0, _title: 'remote connection' } as any],
|
||||||
|
|
||||||
|
browser: [async ({ playwright, browserName, _connectedBrowser }, use) => {
|
||||||
|
if (_connectedBrowser) {
|
||||||
|
await use(_connectedBrowser);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!['chromium', 'firefox', 'webkit'].includes(browserName))
|
||||||
|
throw new Error(`Unexpected browserName "${browserName}", must be one of "chromium", "firefox" or "webkit"`);
|
||||||
const browser = await playwright[browserName].launch();
|
const browser = await playwright[browserName].launch();
|
||||||
await use(browser);
|
await use(browser);
|
||||||
await browser.close();
|
await browser.close();
|
||||||
}, { scope: 'worker', timeout: 0 } ],
|
}, { scope: 'worker' } ],
|
||||||
|
|
||||||
acceptDownloads: [ undefined, { option: true } ],
|
acceptDownloads: [ undefined, { option: true } ],
|
||||||
bypassCSP: [ undefined, { option: true } ],
|
bypassCSP: [ undefined, { option: true } ],
|
||||||
|
|
@ -422,9 +433,9 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
||||||
else
|
else
|
||||||
await fs.promises.unlink(file).catch(() => {});
|
await fs.promises.unlink(file).catch(() => {});
|
||||||
}));
|
}));
|
||||||
}, { auto: true }],
|
}, { auto: true, _title: 'built-in playwright configuration' } as any],
|
||||||
|
|
||||||
_contextFactory: async ({ browser, video, _artifactsDir }, use, testInfo) => {
|
_contextFactory: [async ({ browser, video, _artifactsDir }, use, testInfo) => {
|
||||||
let videoMode = typeof video === 'string' ? video : video.mode;
|
let videoMode = typeof video === 'string' ? video : video.mode;
|
||||||
if (videoMode === 'retry-with-video')
|
if (videoMode === 'retry-with-video')
|
||||||
videoMode = 'on-first-retry';
|
videoMode = 'on-first-retry';
|
||||||
|
|
@ -476,7 +487,7 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
||||||
|
|
||||||
if (prependToError)
|
if (prependToError)
|
||||||
testInfo.errors.push({ message: prependToError });
|
testInfo.errors.push({ message: prependToError });
|
||||||
},
|
}, { scope: 'test', _title: 'context' } as any],
|
||||||
|
|
||||||
context: async ({ _contextFactory }, use) => {
|
context: async ({ _contextFactory }, use) => {
|
||||||
await use(await _contextFactory());
|
await use(await _contextFactory());
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ type RunnableDescription = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FixtureDescription = {
|
export type FixtureDescription = {
|
||||||
fixture: string;
|
title: string;
|
||||||
location?: Location;
|
location?: Location;
|
||||||
slot?: TimeSlot; // Falls back to current runnable slot.
|
slot?: TimeSlot; // Falls back to current runnable slot.
|
||||||
};
|
};
|
||||||
|
|
@ -123,7 +123,9 @@ export class TimeoutManager {
|
||||||
}
|
}
|
||||||
const fixtureWithSlot = this._fixture?.slot ? this._fixture : undefined;
|
const fixtureWithSlot = this._fixture?.slot ? this._fixture : undefined;
|
||||||
if (fixtureWithSlot)
|
if (fixtureWithSlot)
|
||||||
suffix = ` in fixture "${fixtureWithSlot.fixture}"`;
|
suffix = ` by ${fixtureWithSlot.title}`;
|
||||||
|
else if (this._fixture)
|
||||||
|
suffix = ` while running ${this._fixture.title}`;
|
||||||
const message = colors.red(`Timeout of ${this._currentSlot().timeout}ms exceeded${suffix}.`);
|
const message = colors.red(`Timeout of ${this._currentSlot().timeout}ms exceeded${suffix}.`);
|
||||||
const location = (fixtureWithSlot || this._runnable).location;
|
const location = (fixtureWithSlot || this._runnable).location;
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -471,10 +471,10 @@ test('should not report fixture teardown timeout twice', async ({ runInlineTest
|
||||||
}, { reporter: 'list', timeout: 1000 });
|
}, { reporter: 'list', timeout: 1000 });
|
||||||
expect(result.exitCode).toBe(1);
|
expect(result.exitCode).toBe(1);
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
expect(result.output).toContain('in fixtures teardown');
|
expect(result.output).toContain('Timeout of 1000ms exceeded while running fixture "fixture" teardown.');
|
||||||
expect(stripAnsi(result.output)).not.toContain('pwt.test.extend'); // Should not point to the location.
|
expect(stripAnsi(result.output)).not.toContain('pwt.test.extend'); // Should not point to the location.
|
||||||
// TODO: this should be "1" actually.
|
// TODO: this should be "not.toContain" actually.
|
||||||
expect(countTimes(result.output, 'in fixtures teardown')).not.toBe(1);
|
expect(result.output).toContain('in fixtures teardown');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle fixture teardown error after test timeout and continue', async ({ runInlineTest }) => {
|
test('should handle fixture teardown error after test timeout and continue', async ({ runInlineTest }) => {
|
||||||
|
|
@ -529,6 +529,6 @@ test('should report worker fixture teardown with debug info', async ({ runInline
|
||||||
'a.spec.ts:12:9 › good18',
|
'a.spec.ts:12:9 › good18',
|
||||||
'a.spec.ts:12:9 › good19',
|
'a.spec.ts:12:9 › good19',
|
||||||
'',
|
'',
|
||||||
'Timeout of 1000ms exceeded in fixtures teardown.',
|
'Timeout of 1000ms exceeded while running fixture "fixture" teardown.',
|
||||||
].join('\n'));
|
].join('\n'));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
97
tests/playwright-test/playwright.connect.spec.ts
Normal file
97
tests/playwright-test/playwright.connect.spec.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { test, expect } from './playwright-test-fixtures';
|
||||||
|
|
||||||
|
test('should work with connectOptions', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'playwright.config.js': `
|
||||||
|
module.exports = {
|
||||||
|
globalSetup: './global-setup',
|
||||||
|
use: {
|
||||||
|
connectOptions: {
|
||||||
|
wsEndpoint: process.env.CONNECT_WS_ENDPOINT,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'global-setup.ts': `
|
||||||
|
module.exports = async () => {
|
||||||
|
const server = await pwt.chromium.launchServer();
|
||||||
|
process.env.CONNECT_WS_ENDPOINT = server.wsEndpoint();
|
||||||
|
return () => server.close();
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'a.test.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test.use({ locale: 'fr-CH' });
|
||||||
|
test('pass', async ({ page }) => {
|
||||||
|
await page.setContent('<div>PASS</div>');
|
||||||
|
await expect(page.locator('div')).toHaveText('PASS');
|
||||||
|
expect(await page.evaluate(() => navigator.language)).toBe('fr-CH');
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should throw with bad connectOptions', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'playwright.config.js': `
|
||||||
|
module.exports = {
|
||||||
|
use: {
|
||||||
|
connectOptions: {
|
||||||
|
wsEndpoint: 'http://does-not-exist-bad-domain.oh-no-should-not-work',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'a.test.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('pass', async ({ page }) => {
|
||||||
|
await page.setContent('<div>PASS</div>');
|
||||||
|
await expect(page.locator('div')).toHaveText('PASS');
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
expect(result.passed).toBe(0);
|
||||||
|
expect(result.output).toContain('browserType.connect:');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should respect connectOptions.timeout', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'playwright.config.js': `
|
||||||
|
module.exports = {
|
||||||
|
use: {
|
||||||
|
connectOptions: {
|
||||||
|
wsEndpoint: 'wss://locahost:5678',
|
||||||
|
timeout: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'a.test.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
test('pass', async ({ page }) => {
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
expect(result.passed).toBe(0);
|
||||||
|
expect(result.output).toContain('browserType.connect: Timeout 1ms exceeded.');
|
||||||
|
});
|
||||||
|
|
@ -563,83 +563,3 @@ test('should work with video.path() throwing', async ({ runInlineTest }, testInf
|
||||||
const video = fs.readdirSync(dir).find(file => file.endsWith('webm'));
|
const video = fs.readdirSync(dir).find(file => file.endsWith('webm'));
|
||||||
expect(video).toBeTruthy();
|
expect(video).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should work with connectOptions', async ({ runInlineTest }) => {
|
|
||||||
const result = await runInlineTest({
|
|
||||||
'playwright.config.js': `
|
|
||||||
module.exports = {
|
|
||||||
globalSetup: './global-setup',
|
|
||||||
use: {
|
|
||||||
connectOptions: {
|
|
||||||
wsEndpoint: process.env.CONNECT_WS_ENDPOINT,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
`,
|
|
||||||
'global-setup.ts': `
|
|
||||||
module.exports = async () => {
|
|
||||||
const server = await pwt.chromium.launchServer();
|
|
||||||
process.env.CONNECT_WS_ENDPOINT = server.wsEndpoint();
|
|
||||||
return () => server.close();
|
|
||||||
};
|
|
||||||
`,
|
|
||||||
'a.test.ts': `
|
|
||||||
const { test } = pwt;
|
|
||||||
test.use({ locale: 'fr-CH' });
|
|
||||||
test('pass', async ({ page }) => {
|
|
||||||
await page.setContent('<div>PASS</div>');
|
|
||||||
await expect(page.locator('div')).toHaveText('PASS');
|
|
||||||
expect(await page.evaluate(() => navigator.language)).toBe('fr-CH');
|
|
||||||
});
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
expect(result.exitCode).toBe(0);
|
|
||||||
expect(result.passed).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should throw with bad connectOptions', async ({ runInlineTest }) => {
|
|
||||||
const result = await runInlineTest({
|
|
||||||
'playwright.config.js': `
|
|
||||||
module.exports = {
|
|
||||||
use: {
|
|
||||||
connectOptions: {
|
|
||||||
wsEndpoint: 'http://does-not-exist-bad-domain.oh-no-should-not-work',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
`,
|
|
||||||
'a.test.ts': `
|
|
||||||
const { test } = pwt;
|
|
||||||
test('pass', async ({ page }) => {
|
|
||||||
await page.setContent('<div>PASS</div>');
|
|
||||||
await expect(page.locator('div')).toHaveText('PASS');
|
|
||||||
});
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
expect(result.exitCode).toBe(1);
|
|
||||||
expect(result.passed).toBe(0);
|
|
||||||
expect(result.output).toContain('browserType.connect:');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should respect connectOptions.timeout', async ({ runInlineTest }) => {
|
|
||||||
const result = await runInlineTest({
|
|
||||||
'playwright.config.js': `
|
|
||||||
module.exports = {
|
|
||||||
use: {
|
|
||||||
connectOptions: {
|
|
||||||
wsEndpoint: 'wss://locahost:5678',
|
|
||||||
timeout: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
`,
|
|
||||||
'a.test.ts': `
|
|
||||||
const { test } = pwt;
|
|
||||||
test('pass', async ({ page }) => {
|
|
||||||
});
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
expect(result.exitCode).toBe(1);
|
|
||||||
expect(result.passed).toBe(0);
|
|
||||||
expect(result.output).toContain('browserType.connect: Timeout 1ms exceeded.');
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ test('should respect fixture timeout', async ({ runInlineTest }) => {
|
||||||
slowSetup: [async ({}, use) => {
|
slowSetup: [async ({}, use) => {
|
||||||
await new Promise(f => setTimeout(f, 2000));
|
await new Promise(f => setTimeout(f, 2000));
|
||||||
await use('hey');
|
await use('hey');
|
||||||
}, { timeout: 500 }],
|
}, { timeout: 500, _title: 'custom title' }],
|
||||||
slowTeardown: [async ({}, use) => {
|
slowTeardown: [async ({}, use) => {
|
||||||
await use('hey');
|
await use('hey');
|
||||||
await new Promise(f => setTimeout(f, 2000));
|
await new Promise(f => setTimeout(f, 2000));
|
||||||
|
|
@ -196,8 +196,8 @@ test('should respect fixture timeout', async ({ runInlineTest }) => {
|
||||||
expect(result.exitCode).toBe(1);
|
expect(result.exitCode).toBe(1);
|
||||||
expect(result.passed).toBe(1);
|
expect(result.passed).toBe(1);
|
||||||
expect(result.failed).toBe(2);
|
expect(result.failed).toBe(2);
|
||||||
expect(result.output).toContain('Timeout of 500ms exceeded in fixture "slowSetup"');
|
expect(result.output).toContain('Timeout of 500ms exceeded by fixture "custom title" setup.');
|
||||||
expect(result.output).toContain('Timeout of 400ms exceeded in fixture "slowTeardown"');
|
expect(result.output).toContain('Timeout of 400ms exceeded by fixture "slowTeardown" teardown.');
|
||||||
expect(stripAnsi(result.output)).toContain('> 5 | const test = pwt.test.extend({');
|
expect(stripAnsi(result.output)).toContain('> 5 | const test = pwt.test.extend({');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -222,7 +222,7 @@ test('should respect test.setTimeout in the worker fixture', async ({ runInlineT
|
||||||
slowTeardown: [async ({}, use) => {
|
slowTeardown: [async ({}, use) => {
|
||||||
await use('hey');
|
await use('hey');
|
||||||
await new Promise(f => setTimeout(f, 2000));
|
await new Promise(f => setTimeout(f, 2000));
|
||||||
}, { scope: 'worker', timeout: 400 }],
|
}, { scope: 'worker', timeout: 400, _title: 'custom title' }],
|
||||||
});
|
});
|
||||||
test('test ok', async ({ fixture, noTimeout }) => {
|
test('test ok', async ({ fixture, noTimeout }) => {
|
||||||
await new Promise(f => setTimeout(f, 1000));
|
await new Promise(f => setTimeout(f, 1000));
|
||||||
|
|
@ -236,8 +236,8 @@ test('should respect test.setTimeout in the worker fixture', async ({ runInlineT
|
||||||
expect(result.exitCode).toBe(1);
|
expect(result.exitCode).toBe(1);
|
||||||
expect(result.passed).toBe(2);
|
expect(result.passed).toBe(2);
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
expect(result.output).toContain('Timeout of 500ms exceeded in fixture "slowSetup"');
|
expect(result.output).toContain('Timeout of 500ms exceeded by fixture "slowSetup" setup.');
|
||||||
expect(result.output).toContain('Timeout of 400ms exceeded in fixture "slowTeardown"');
|
expect(result.output).toContain('Timeout of 400ms exceeded by fixture "custom title" teardown.');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('fixture time in beforeAll hook should not affect test', async ({ runInlineTest }) => {
|
test('fixture time in beforeAll hook should not affect test', async ({ runInlineTest }) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue