mirror of
https://github.com/microsoft/playwright.git
synced 2025-01-07 03:39:48 +03:00
test: add a tracing bot that collects a trace for most contexts (#8316)
This commit is contained in:
parent
e5be2c9205
commit
7818f5fa0b
24
.github/workflows/tests_secondary.yml
vendored
24
.github/workflows/tests_secondary.yml
vendored
@ -187,6 +187,30 @@ jobs:
|
|||||||
name: mode-${{ matrix.mode }}-linux-test-results
|
name: mode-${{ matrix.mode }}-linux-test-results
|
||||||
path: test-results
|
path: test-results
|
||||||
|
|
||||||
|
tracing_linux:
|
||||||
|
name: "Tracing"
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
browser: [chromium, firefox, webkit]
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 12
|
||||||
|
- run: npm ci
|
||||||
|
env:
|
||||||
|
DEBUG: pw:install
|
||||||
|
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||||
|
- run: npm run build
|
||||||
|
- run: node lib/cli/cli install --with-deps ${{ matrix.browser }} chromium
|
||||||
|
- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test -- --project=${{ matrix.browser }}
|
||||||
|
env:
|
||||||
|
PWTEST_TRACE: 1
|
||||||
|
- run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json
|
||||||
|
if: always()
|
||||||
|
|
||||||
chrome_stable_linux:
|
chrome_stable_linux:
|
||||||
name: "Chrome Stable (Linux)"
|
name: "Chrome Stable (Linux)"
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
@ -50,7 +50,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
|
|||||||
};
|
};
|
||||||
|
|
||||||
readonly tracing: Tracing;
|
readonly tracing: Tracing;
|
||||||
|
private _closed = false;
|
||||||
readonly _backgroundPages = new Set<Page>();
|
readonly _backgroundPages = new Set<Page>();
|
||||||
readonly _serviceWorkers = new Set<Worker>();
|
readonly _serviceWorkers = new Set<Worker>();
|
||||||
readonly _isChromium: boolean;
|
readonly _isChromium: boolean;
|
||||||
@ -320,6 +320,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onClose() {
|
_onClose() {
|
||||||
|
this._closed = true;
|
||||||
if (this._browser)
|
if (this._browser)
|
||||||
this._browser._contexts.delete(this);
|
this._browser._contexts.delete(this);
|
||||||
this._browserType?._contexts?.delete(this);
|
this._browserType?._contexts?.delete(this);
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
import { contextTest as it, expect } from '../config/browserTest';
|
import { contextTest as it, expect } from '../config/browserTest';
|
||||||
|
|
||||||
|
it.skip(({ trace }) => !!trace);
|
||||||
|
|
||||||
it('should work', async function({page, server}) {
|
it('should work', async function({page, server}) {
|
||||||
await page.coverage.startJSCoverage();
|
await page.coverage.startJSCoverage();
|
||||||
await page.goto(server.PREFIX + '/jscoverage/simple.html', { waitUntil: 'load' });
|
await page.goto(server.PREFIX + '/jscoverage/simple.html', { waitUntil: 'load' });
|
||||||
|
@ -33,6 +33,7 @@ type BaseOptions = {
|
|||||||
browserName: BrowserName;
|
browserName: BrowserName;
|
||||||
channel: LaunchOptions['channel'];
|
channel: LaunchOptions['channel'];
|
||||||
video: boolean | undefined;
|
video: boolean | undefined;
|
||||||
|
trace: boolean | undefined;
|
||||||
headless: boolean | undefined;
|
headless: boolean | undefined;
|
||||||
};
|
};
|
||||||
type BaseFixtures = {
|
type BaseFixtures = {
|
||||||
@ -105,6 +106,7 @@ const baseFixtures: Fixtures<{}, BaseOptions & BaseFixtures> = {
|
|||||||
browserName: [ 'chromium' , { scope: 'worker' } ],
|
browserName: [ 'chromium' , { scope: 'worker' } ],
|
||||||
channel: [ undefined, { scope: 'worker' } ],
|
channel: [ undefined, { scope: 'worker' } ],
|
||||||
video: [ undefined, { scope: 'worker' } ],
|
video: [ undefined, { scope: 'worker' } ],
|
||||||
|
trace: [ undefined, { scope: 'worker' } ],
|
||||||
headless: [ undefined, { scope: 'worker' } ],
|
headless: [ undefined, { scope: 'worker' } ],
|
||||||
platform: [ process.platform as 'win32' | 'darwin' | 'linux', { scope: 'worker' } ],
|
platform: [ process.platform as 'win32' | 'darwin' | 'linux', { scope: 'worker' } ],
|
||||||
playwright: [ async ({ mode }, run, workerInfo) => {
|
playwright: [ async ({ mode }, run, workerInfo) => {
|
||||||
|
@ -24,7 +24,6 @@ import { RemoteServer, RemoteServerOptions } from './remoteServer';
|
|||||||
import { baseTest, CommonWorkerFixtures } from './baseTest';
|
import { baseTest, CommonWorkerFixtures } from './baseTest';
|
||||||
|
|
||||||
type PlaywrightWorkerOptions = {
|
type PlaywrightWorkerOptions = {
|
||||||
tracesDir: LaunchOptions['tracesDir'];
|
|
||||||
executablePath: LaunchOptions['executablePath'];
|
executablePath: LaunchOptions['executablePath'];
|
||||||
proxy: LaunchOptions['proxy'];
|
proxy: LaunchOptions['proxy'];
|
||||||
args: LaunchOptions['args'];
|
args: LaunchOptions['args'];
|
||||||
@ -50,7 +49,6 @@ type PlaywrightTestFixtures = {
|
|||||||
export type PlaywrightOptions = PlaywrightWorkerOptions & PlaywrightTestOptions;
|
export type PlaywrightOptions = PlaywrightWorkerOptions & PlaywrightTestOptions;
|
||||||
|
|
||||||
export const playwrightFixtures: Fixtures<PlaywrightTestOptions & PlaywrightTestFixtures, PlaywrightWorkerOptions & PlaywrightWorkerFixtures, {}, CommonWorkerFixtures> = {
|
export const playwrightFixtures: Fixtures<PlaywrightTestOptions & PlaywrightTestFixtures, PlaywrightWorkerOptions & PlaywrightWorkerFixtures, {}, CommonWorkerFixtures> = {
|
||||||
tracesDir: [ undefined, { scope: 'worker' } ],
|
|
||||||
executablePath: [ undefined, { scope: 'worker' } ],
|
executablePath: [ undefined, { scope: 'worker' } ],
|
||||||
proxy: [ undefined, { scope: 'worker' } ],
|
proxy: [ undefined, { scope: 'worker' } ],
|
||||||
args: [ undefined, { scope: 'worker' } ],
|
args: [ undefined, { scope: 'worker' } ],
|
||||||
@ -60,12 +58,11 @@ export const playwrightFixtures: Fixtures<PlaywrightTestOptions & PlaywrightTest
|
|||||||
await run(playwright[browserName]);
|
await run(playwright[browserName]);
|
||||||
}, { scope: 'worker' } ],
|
}, { scope: 'worker' } ],
|
||||||
|
|
||||||
browserOptions: [async ({ headless, channel, executablePath, tracesDir, proxy, args }, run) => {
|
browserOptions: [async ({ headless, channel, executablePath, proxy, args }, run) => {
|
||||||
await run({
|
await run({
|
||||||
headless,
|
headless,
|
||||||
channel,
|
channel,
|
||||||
executablePath,
|
executablePath,
|
||||||
tracesDir,
|
|
||||||
proxy,
|
proxy,
|
||||||
args,
|
args,
|
||||||
handleSIGINT: false,
|
handleSIGINT: false,
|
||||||
@ -125,7 +122,7 @@ export const playwrightFixtures: Fixtures<PlaywrightTestOptions & PlaywrightTest
|
|||||||
await remoteServer.close();
|
await remoteServer.close();
|
||||||
},
|
},
|
||||||
|
|
||||||
contextOptions: async ({ video, hasTouch, browserVersion }, run, testInfo) => {
|
contextOptions: async ({ video, hasTouch }, run, testInfo) => {
|
||||||
const debugName = path.relative(testInfo.project.outputDir, testInfo.outputDir).replace(/[\/\\]/g, '-');
|
const debugName = path.relative(testInfo.project.outputDir, testInfo.outputDir).replace(/[\/\\]/g, '-');
|
||||||
const contextOptions = {
|
const contextOptions = {
|
||||||
recordVideo: video ? { dir: testInfo.outputPath('') } : undefined,
|
recordVideo: video ? { dir: testInfo.outputPath('') } : undefined,
|
||||||
@ -135,10 +132,12 @@ export const playwrightFixtures: Fixtures<PlaywrightTestOptions & PlaywrightTest
|
|||||||
await run(contextOptions);
|
await run(contextOptions);
|
||||||
},
|
},
|
||||||
|
|
||||||
contextFactory: async ({ browser, contextOptions, video }, run, testInfo) => {
|
contextFactory: async ({ browser, contextOptions, trace }, run, testInfo) => {
|
||||||
const contexts: BrowserContext[] = [];
|
const contexts: BrowserContext[] = [];
|
||||||
await run(async options => {
|
await run(async options => {
|
||||||
const context = await browser.newContext({ ...contextOptions, ...options });
|
const context = await browser.newContext({ ...contextOptions, ...options });
|
||||||
|
if (trace)
|
||||||
|
await context.tracing.start({ screenshots: true, snapshots: true });
|
||||||
(context as any)._csi = {
|
(context as any)._csi = {
|
||||||
onApiCall: (name: string) => {
|
onApiCall: (name: string) => {
|
||||||
return (testInfo as any)._addStep('pw:api', name);
|
return (testInfo as any)._addStep('pw:api', name);
|
||||||
@ -149,6 +148,8 @@ export const playwrightFixtures: Fixtures<PlaywrightTestOptions & PlaywrightTest
|
|||||||
});
|
});
|
||||||
await Promise.all(contexts.map(async context => {
|
await Promise.all(contexts.map(async context => {
|
||||||
const videos = context.pages().map(p => p.video()).filter(Boolean);
|
const videos = context.pages().map(p => p.video()).filter(Boolean);
|
||||||
|
if (!(context as any)._closed && trace)
|
||||||
|
await context.tracing.stop({ path: testInfo.outputPath('trace.zip') });
|
||||||
await context.close();
|
await context.close();
|
||||||
for (const v of videos) {
|
for (const v of videos) {
|
||||||
const videoPath = await v.path().catch(() => null);
|
const videoPath = await v.path().catch(() => null);
|
||||||
|
@ -42,13 +42,14 @@ const mode = (process.env.PWTEST_MODE || 'default') as ('default' | 'driver' | '
|
|||||||
const headed = !!process.env.HEADFUL;
|
const headed = !!process.env.HEADFUL;
|
||||||
const channel = process.env.PWTEST_CHANNEL as any;
|
const channel = process.env.PWTEST_CHANNEL as any;
|
||||||
const video = !!process.env.PWTEST_VIDEO;
|
const video = !!process.env.PWTEST_VIDEO;
|
||||||
|
const trace = !!process.env.PWTEST_TRACE;
|
||||||
|
|
||||||
const outputDir = path.join(__dirname, '..', '..', 'test-results');
|
const outputDir = path.join(__dirname, '..', '..', 'test-results');
|
||||||
const testDir = path.join(__dirname, '..');
|
const testDir = path.join(__dirname, '..');
|
||||||
const config: Config<CommonOptions & PlaywrightOptions> = {
|
const config: Config<CommonOptions & PlaywrightOptions> = {
|
||||||
testDir,
|
testDir,
|
||||||
outputDir,
|
outputDir,
|
||||||
timeout: video || process.env.PWTRACE ? 60000 : 30000,
|
timeout: video ? 60000 : 30000,
|
||||||
globalTimeout: 5400000,
|
globalTimeout: 5400000,
|
||||||
workers: process.env.CI ? 1 : undefined,
|
workers: process.env.CI ? 1 : undefined,
|
||||||
forbidOnly: !!process.env.CI,
|
forbidOnly: !!process.env.CI,
|
||||||
@ -79,7 +80,7 @@ for (const browserName of browserNames) {
|
|||||||
channel,
|
channel,
|
||||||
video,
|
video,
|
||||||
executablePath,
|
executablePath,
|
||||||
tracesDir: process.env.PWTRACE ? path.join(outputDir, 'trace') : undefined,
|
trace,
|
||||||
coverageName: browserName,
|
coverageName: browserName,
|
||||||
},
|
},
|
||||||
define: { test: pageTest, fixtures: pageFixtures },
|
define: { test: pageTest, fixtures: pageFixtures },
|
||||||
@ -91,6 +92,7 @@ for (const browserName of browserNames) {
|
|||||||
channel,
|
channel,
|
||||||
mode,
|
mode,
|
||||||
video: !!video,
|
video: !!video,
|
||||||
|
trace: !!trace,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ export class RemoteServer {
|
|||||||
args: browserOptions.args,
|
args: browserOptions.args,
|
||||||
headless: browserOptions.headless,
|
headless: browserOptions.headless,
|
||||||
channel: browserOptions.channel,
|
channel: browserOptions.channel,
|
||||||
tracesDir: browserOptions.tracesDir,
|
|
||||||
handleSIGINT: true,
|
handleSIGINT: true,
|
||||||
handleSIGTERM: true,
|
handleSIGTERM: true,
|
||||||
handleSIGHUP: true,
|
handleSIGHUP: true,
|
||||||
|
@ -66,7 +66,7 @@ it('should dismiss the confirm prompt', async ({page}) => {
|
|||||||
expect(result).toBe(false);
|
expect(result).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to close context with open alert', async ({page}) => {
|
it('should be able to close context with open alert', async ({page, trace}) => {
|
||||||
const alertPromise = page.waitForEvent('dialog');
|
const alertPromise = page.waitForEvent('dialog');
|
||||||
await page.evaluate(() => {
|
await page.evaluate(() => {
|
||||||
setTimeout(() => alert('hello'), 0);
|
setTimeout(() => alert('hello'), 0);
|
||||||
|
@ -18,6 +18,8 @@ import { expect, contextTest as test, browserTest } from './config/browserTest';
|
|||||||
import yauzl from 'yauzl';
|
import yauzl from 'yauzl';
|
||||||
import jpeg from 'jpeg-js';
|
import jpeg from 'jpeg-js';
|
||||||
|
|
||||||
|
test.skip(({ trace }) => !!trace);
|
||||||
|
|
||||||
test('should collect trace with resources, but no js', async ({ context, page, server }, testInfo) => {
|
test('should collect trace with resources, but no js', async ({ context, page, server }, testInfo) => {
|
||||||
await context.tracing.start({ screenshots: true, snapshots: true });
|
await context.tracing.start({ screenshots: true, snapshots: true });
|
||||||
await page.goto(server.PREFIX + '/frames/frame.html');
|
await page.goto(server.PREFIX + '/frames/frame.html');
|
||||||
|
Loading…
Reference in New Issue
Block a user