mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore(tracing): expose tracing api (#6523)
This commit is contained in:
parent
460cc31941
commit
21cb726b7d
@ -975,6 +975,9 @@ The file path to save the storage state to. If [`option: path`] is a relative pa
|
|||||||
current working directory. If no path is provided, storage
|
current working directory. If no path is provided, storage
|
||||||
state is still returned, but won't be saved to the disk.
|
state is still returned, but won't be saved to the disk.
|
||||||
|
|
||||||
|
## property: BrowserContext.tracing
|
||||||
|
- type: <[Tracing]>
|
||||||
|
|
||||||
## async method: BrowserContext.unroute
|
## async method: BrowserContext.unroute
|
||||||
|
|
||||||
Removes a route created with [`method: BrowserContext.route`]. When [`param: handler`] is not specified, removes all
|
Removes a route created with [`method: BrowserContext.route`]. When [`param: handler`] is not specified, removes all
|
||||||
|
|||||||
72
docs/src/api/class-tracing.md
Normal file
72
docs/src/api/class-tracing.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# class: Tracing
|
||||||
|
|
||||||
|
Tracing object for collecting test traces that can be opened using
|
||||||
|
Playwright CLI.
|
||||||
|
|
||||||
|
## async method: Tracing.export
|
||||||
|
|
||||||
|
Export trace into the file with the given name. Should be called after the
|
||||||
|
tracing has stopped.
|
||||||
|
|
||||||
|
### param: Tracing.export.path
|
||||||
|
- `path` <[path]>
|
||||||
|
|
||||||
|
File to save the trace into.
|
||||||
|
|
||||||
|
## async method: Tracing.start
|
||||||
|
|
||||||
|
Start tracing.
|
||||||
|
|
||||||
|
```js
|
||||||
|
await context.tracing.start({ name: 'trace', screenshots: true, snapshots: true });
|
||||||
|
const page = await context.newPage();
|
||||||
|
await page.goto('https://playwright.dev');
|
||||||
|
await context.tracing.stop();
|
||||||
|
await context.tracing.export('trace.zip');
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
context.tracing.start(page, new Tracing.StartOptions()
|
||||||
|
.setName("trace")
|
||||||
|
.setScreenshots(true)
|
||||||
|
.setSnapshots(true);
|
||||||
|
Page page = context.newPage();
|
||||||
|
page.goto('https://playwright.dev');
|
||||||
|
context.tracing.stop();
|
||||||
|
context.tracing.export(Paths.get("trace.zip")))
|
||||||
|
```
|
||||||
|
|
||||||
|
```python async
|
||||||
|
await context.tracing.start(name="trace" screenshots=True snapshots=True)
|
||||||
|
await page.goto("https://playwright.dev")
|
||||||
|
await context.tracing.stop()
|
||||||
|
await context.tracing.export("trace.zip")
|
||||||
|
```
|
||||||
|
|
||||||
|
```python sync
|
||||||
|
context.tracing.start(name="trace" screenshots=True snapshots=True)
|
||||||
|
page.goto("https://playwright.dev")
|
||||||
|
context.tracing.stop()
|
||||||
|
context.tracing.export("trace.zip")
|
||||||
|
```
|
||||||
|
|
||||||
|
### option: Tracing.start.name
|
||||||
|
- `name` <[string]>
|
||||||
|
|
||||||
|
If specified, the trace is going to be saved into the file with the
|
||||||
|
given name.
|
||||||
|
|
||||||
|
### option: Tracing.start.screenshots
|
||||||
|
- `screenshots` <[boolean]>
|
||||||
|
|
||||||
|
Whether to capture screenshots during tracing. Screenshots are used to build
|
||||||
|
a timeline preview.
|
||||||
|
|
||||||
|
### option: Tracing.start.snapshots
|
||||||
|
- `snapshots` <[boolean]>
|
||||||
|
|
||||||
|
Whether to capture DOM snapshot on every action.
|
||||||
|
|
||||||
|
## async method: Tracing.stop
|
||||||
|
|
||||||
|
Stop tracing.
|
||||||
@ -159,13 +159,18 @@ commandWithOpenOptions('pdf <url> <filename>', 'save page as pdf',
|
|||||||
console.log(' $ pdf https://example.com example.pdf');
|
console.log(' $ pdf https://example.com example.pdf');
|
||||||
});
|
});
|
||||||
|
|
||||||
if (process.env.PWTRACE) {
|
program
|
||||||
program
|
|
||||||
.command('show-trace [trace]')
|
.command('show-trace [trace]')
|
||||||
.option('--resources <dir>', 'load resources from shared folder')
|
.option('-b, --browser <browserType>', 'browser to use, one of cr, chromium, ff, firefox, wk, webkit', 'chromium')
|
||||||
.description('Show trace viewer')
|
.description('Show trace viewer')
|
||||||
.action(function(trace, command) {
|
.action(function(trace, command) {
|
||||||
showTraceViewer(trace, command.resources).catch(logErrorAndExit);
|
if (command.browser === 'cr')
|
||||||
|
command.browser = 'chromium';
|
||||||
|
if (command.browser === 'ff')
|
||||||
|
command.browser = 'firefox';
|
||||||
|
if (command.browser === 'wk')
|
||||||
|
command.browser = 'webkit';
|
||||||
|
showTraceViewer(trace, command.browser).catch(logErrorAndExit);
|
||||||
}).on('--help', function() {
|
}).on('--help', function() {
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('Examples:');
|
console.log('Examples:');
|
||||||
@ -173,7 +178,6 @@ if (process.env.PWTRACE) {
|
|||||||
console.log(' $ show-trace --resources=resources trace/file.trace');
|
console.log(' $ show-trace --resources=resources trace/file.trace');
|
||||||
console.log(' $ show-trace trace/directory');
|
console.log(' $ show-trace trace/directory');
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (process.argv[2] === 'run-driver')
|
if (process.argv[2] === 'run-driver')
|
||||||
runDriver();
|
runDriver();
|
||||||
|
|||||||
@ -35,6 +35,7 @@ export { JSHandle } from './jsHandle';
|
|||||||
export { Request, Response, Route, WebSocket } from './network';
|
export { Request, Response, Route, WebSocket } from './network';
|
||||||
export { Page } from './page';
|
export { Page } from './page';
|
||||||
export { Selectors } from './selectors';
|
export { Selectors } from './selectors';
|
||||||
|
export { Tracing } from './tracing';
|
||||||
export { Video } from './video';
|
export { Video } from './video';
|
||||||
export { Worker } from './worker';
|
export { Worker } from './worker';
|
||||||
export { CDPSession } from './cdpSession';
|
export { CDPSession } from './cdpSession';
|
||||||
|
|||||||
@ -50,7 +50,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
|
|||||||
sdkLanguage: 'javascript'
|
sdkLanguage: 'javascript'
|
||||||
};
|
};
|
||||||
|
|
||||||
readonly _tracing: Tracing;
|
readonly tracing: Tracing;
|
||||||
|
|
||||||
readonly _backgroundPages = new Set<Page>();
|
readonly _backgroundPages = new Set<Page>();
|
||||||
readonly _serviceWorkers = new Set<Worker>();
|
readonly _serviceWorkers = new Set<Worker>();
|
||||||
@ -69,7 +69,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
|
|||||||
if (parent instanceof Browser)
|
if (parent instanceof Browser)
|
||||||
this._browser = parent;
|
this._browser = parent;
|
||||||
this._isChromium = this._browser?._name === 'chromium';
|
this._isChromium = this._browser?._name === 'chromium';
|
||||||
this._tracing = new Tracing(this);
|
this.tracing = new Tracing(this);
|
||||||
|
|
||||||
this._channel.on('bindingCall', ({binding}) => this._onBinding(BindingCall.from(binding)));
|
this._channel.on('bindingCall', ({binding}) => this._onBinding(BindingCall.from(binding)));
|
||||||
this._channel.on('close', () => this._onClose());
|
this._channel.on('close', () => this._onClose());
|
||||||
|
|||||||
@ -14,18 +14,19 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import * as api from '../../types/types';
|
||||||
import * as channels from '../protocol/channels';
|
import * as channels from '../protocol/channels';
|
||||||
import { Artifact } from './artifact';
|
import { Artifact } from './artifact';
|
||||||
import { BrowserContext } from './browserContext';
|
import { BrowserContext } from './browserContext';
|
||||||
|
|
||||||
export class Tracing {
|
export class Tracing implements api.Tracing {
|
||||||
private _context: BrowserContext;
|
private _context: BrowserContext;
|
||||||
|
|
||||||
constructor(channel: BrowserContext) {
|
constructor(channel: BrowserContext) {
|
||||||
this._context = channel;
|
this._context = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(options: { snapshots?: boolean, screenshots?: boolean } = {}) {
|
async start(options: { name?: string, snapshots?: boolean, screenshots?: boolean } = {}) {
|
||||||
await this._context._wrapApiCall('tracing.start', async (channel: channels.BrowserContextChannel) => {
|
await this._context._wrapApiCall('tracing.start', async (channel: channels.BrowserContextChannel) => {
|
||||||
return await channel.tracingStart(options);
|
return await channel.tracingStart(options);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -226,7 +226,7 @@ export type BrowserTypeLaunchParams = {
|
|||||||
password?: string,
|
password?: string,
|
||||||
},
|
},
|
||||||
downloadsPath?: string,
|
downloadsPath?: string,
|
||||||
_traceDir?: string,
|
traceDir?: string,
|
||||||
chromiumSandbox?: boolean,
|
chromiumSandbox?: boolean,
|
||||||
firefoxUserPrefs?: any,
|
firefoxUserPrefs?: any,
|
||||||
slowMo?: number,
|
slowMo?: number,
|
||||||
@ -251,7 +251,7 @@ export type BrowserTypeLaunchOptions = {
|
|||||||
password?: string,
|
password?: string,
|
||||||
},
|
},
|
||||||
downloadsPath?: string,
|
downloadsPath?: string,
|
||||||
_traceDir?: string,
|
traceDir?: string,
|
||||||
chromiumSandbox?: boolean,
|
chromiumSandbox?: boolean,
|
||||||
firefoxUserPrefs?: any,
|
firefoxUserPrefs?: any,
|
||||||
slowMo?: number,
|
slowMo?: number,
|
||||||
@ -279,7 +279,7 @@ export type BrowserTypeLaunchPersistentContextParams = {
|
|||||||
password?: string,
|
password?: string,
|
||||||
},
|
},
|
||||||
downloadsPath?: string,
|
downloadsPath?: string,
|
||||||
_traceDir?: string,
|
traceDir?: string,
|
||||||
chromiumSandbox?: boolean,
|
chromiumSandbox?: boolean,
|
||||||
sdkLanguage: string,
|
sdkLanguage: string,
|
||||||
noDefaultViewport?: boolean,
|
noDefaultViewport?: boolean,
|
||||||
@ -349,7 +349,7 @@ export type BrowserTypeLaunchPersistentContextOptions = {
|
|||||||
password?: string,
|
password?: string,
|
||||||
},
|
},
|
||||||
downloadsPath?: string,
|
downloadsPath?: string,
|
||||||
_traceDir?: string,
|
traceDir?: string,
|
||||||
chromiumSandbox?: boolean,
|
chromiumSandbox?: boolean,
|
||||||
noDefaultViewport?: boolean,
|
noDefaultViewport?: boolean,
|
||||||
viewport?: {
|
viewport?: {
|
||||||
|
|||||||
@ -260,7 +260,7 @@ LaunchOptions:
|
|||||||
username: string?
|
username: string?
|
||||||
password: string?
|
password: string?
|
||||||
downloadsPath: string?
|
downloadsPath: string?
|
||||||
_traceDir: string?
|
traceDir: string?
|
||||||
chromiumSandbox: boolean?
|
chromiumSandbox: boolean?
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -172,7 +172,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||||||
password: tOptional(tString),
|
password: tOptional(tString),
|
||||||
})),
|
})),
|
||||||
downloadsPath: tOptional(tString),
|
downloadsPath: tOptional(tString),
|
||||||
_traceDir: tOptional(tString),
|
traceDir: tOptional(tString),
|
||||||
chromiumSandbox: tOptional(tBoolean),
|
chromiumSandbox: tOptional(tBoolean),
|
||||||
firefoxUserPrefs: tOptional(tAny),
|
firefoxUserPrefs: tOptional(tAny),
|
||||||
slowMo: tOptional(tNumber),
|
slowMo: tOptional(tNumber),
|
||||||
@ -197,7 +197,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||||||
password: tOptional(tString),
|
password: tOptional(tString),
|
||||||
})),
|
})),
|
||||||
downloadsPath: tOptional(tString),
|
downloadsPath: tOptional(tString),
|
||||||
_traceDir: tOptional(tString),
|
traceDir: tOptional(tString),
|
||||||
chromiumSandbox: tOptional(tBoolean),
|
chromiumSandbox: tOptional(tBoolean),
|
||||||
sdkLanguage: tString,
|
sdkLanguage: tString,
|
||||||
noDefaultViewport: tOptional(tBoolean),
|
noDefaultViewport: tOptional(tBoolean),
|
||||||
|
|||||||
@ -115,7 +115,7 @@ export abstract class BrowserType extends SdkObject {
|
|||||||
protocolLogger,
|
protocolLogger,
|
||||||
browserLogsCollector,
|
browserLogsCollector,
|
||||||
wsEndpoint: options.useWebSocket ? (transport as WebSocketTransport).wsEndpoint : undefined,
|
wsEndpoint: options.useWebSocket ? (transport as WebSocketTransport).wsEndpoint : undefined,
|
||||||
traceDir: options._traceDir,
|
traceDir: options.traceDir,
|
||||||
};
|
};
|
||||||
if (persistent)
|
if (persistent)
|
||||||
validateBrowserContextOptions(persistent, browserOptions);
|
validateBrowserContextOptions(persistent, browserOptions);
|
||||||
|
|||||||
@ -243,24 +243,11 @@ function rootScript() {
|
|||||||
pointElement.style.margin = '-10px 0 0 -10px';
|
pointElement.style.margin = '-10px 0 0 -10px';
|
||||||
pointElement.style.zIndex = '2147483647';
|
pointElement.style.zIndex = '2147483647';
|
||||||
|
|
||||||
let current = document.createElement('iframe');
|
const iframe = document.createElement('iframe');
|
||||||
document.body.appendChild(current);
|
document.body.appendChild(iframe);
|
||||||
let next = document.createElement('iframe');
|
|
||||||
document.body.appendChild(next);
|
|
||||||
next.style.visibility = 'hidden';
|
|
||||||
const onload = () => {
|
|
||||||
const temp = current;
|
|
||||||
current = next;
|
|
||||||
next = temp;
|
|
||||||
current.style.visibility = 'visible';
|
|
||||||
next.style.visibility = 'hidden';
|
|
||||||
};
|
|
||||||
current.onload = onload;
|
|
||||||
next.onload = onload;
|
|
||||||
|
|
||||||
(window as any).showSnapshot = async (url: string, options: { point?: Point } = {}) => {
|
(window as any).showSnapshot = async (url: string, options: { point?: Point } = {}) => {
|
||||||
await showPromise;
|
await showPromise;
|
||||||
next.src = url;
|
iframe.src = url;
|
||||||
if (options.point) {
|
if (options.point) {
|
||||||
pointElement.style.left = options.point.x + 'px';
|
pointElement.style.left = options.point.x + 'px';
|
||||||
pointElement.style.top = options.point.y + 'px';
|
pointElement.style.top = options.point.y + 'px';
|
||||||
|
|||||||
@ -31,10 +31,11 @@ const fsReadFileAsync = util.promisify(fs.readFile.bind(fs));
|
|||||||
|
|
||||||
class TraceViewer {
|
class TraceViewer {
|
||||||
private _server: HttpServer;
|
private _server: HttpServer;
|
||||||
|
private _browserName: string;
|
||||||
|
|
||||||
constructor(traceDir: string, resourcesDir?: string) {
|
constructor(traceDir: string, browserName: string) {
|
||||||
if (!resourcesDir)
|
this._browserName = browserName;
|
||||||
resourcesDir = path.join(traceDir, 'resources');
|
const resourcesDir = path.join(traceDir, 'resources');
|
||||||
|
|
||||||
// Served by TraceServer
|
// Served by TraceServer
|
||||||
// - "/tracemodel" - json with trace model.
|
// - "/tracemodel" - json with trace model.
|
||||||
@ -124,7 +125,7 @@ class TraceViewer {
|
|||||||
];
|
];
|
||||||
if (isUnderTest())
|
if (isUnderTest())
|
||||||
args.push(`--remote-debugging-port=0`);
|
args.push(`--remote-debugging-port=0`);
|
||||||
const context = await traceViewerPlaywright.chromium.launchPersistentContext(internalCallMetadata(), '', {
|
const context = await traceViewerPlaywright[this._browserName as 'chromium'].launchPersistentContext(internalCallMetadata(), '', {
|
||||||
// TODO: store language in the trace.
|
// TODO: store language in the trace.
|
||||||
sdkLanguage: 'javascript',
|
sdkLanguage: 'javascript',
|
||||||
args,
|
args,
|
||||||
@ -144,7 +145,7 @@ class TraceViewer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function showTraceViewer(traceDir: string, resourcesDir?: string) {
|
export async function showTraceViewer(traceDir: string, browserName: string) {
|
||||||
const traceViewer = new TraceViewer(traceDir, resourcesDir);
|
const traceViewer = new TraceViewer(traceDir, browserName);
|
||||||
await traceViewer.show();
|
await traceViewer.show();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -272,7 +272,7 @@ type LaunchOptionsBase = {
|
|||||||
chromiumSandbox?: boolean,
|
chromiumSandbox?: boolean,
|
||||||
slowMo?: number,
|
slowMo?: number,
|
||||||
useWebSocket?: boolean,
|
useWebSocket?: boolean,
|
||||||
_traceDir?: string,
|
traceDir?: string,
|
||||||
};
|
};
|
||||||
export type LaunchOptions = LaunchOptionsBase & {
|
export type LaunchOptions = LaunchOptionsBase & {
|
||||||
firefoxUserPrefs?: { [key: string]: string | number | boolean },
|
firefoxUserPrefs?: { [key: string]: string | number | boolean },
|
||||||
|
|||||||
@ -56,7 +56,7 @@ class PlaywrightEnv {
|
|||||||
async beforeAll(args: CommonArgs & PlaywrightEnvOptions, workerInfo: folio.WorkerInfo): Promise<PlaywrightWorkerArgs> {
|
async beforeAll(args: CommonArgs & PlaywrightEnvOptions, workerInfo: folio.WorkerInfo): Promise<PlaywrightWorkerArgs> {
|
||||||
this._browserType = args.playwright[args.browserName];
|
this._browserType = args.playwright[args.browserName];
|
||||||
this._browserOptions = {
|
this._browserOptions = {
|
||||||
_traceDir: args.traceDir,
|
traceDir: args.traceDir,
|
||||||
channel: args.browserChannel,
|
channel: args.browserChannel,
|
||||||
headless: !args.headful,
|
headless: !args.headful,
|
||||||
handleSIGINT: false,
|
handleSIGINT: false,
|
||||||
|
|||||||
@ -41,7 +41,7 @@ class PageEnv {
|
|||||||
async beforeAll(args: AllOptions & CommonArgs, workerInfo: folio.WorkerInfo) {
|
async beforeAll(args: AllOptions & CommonArgs, workerInfo: folio.WorkerInfo) {
|
||||||
this._browser = await args.playwright[args.browserName].launch({
|
this._browser = await args.playwright[args.browserName].launch({
|
||||||
...args.launchOptions,
|
...args.launchOptions,
|
||||||
_traceDir: args.traceDir,
|
traceDir: args.traceDir,
|
||||||
channel: args.browserChannel,
|
channel: args.browserChannel,
|
||||||
headless: !args.headful,
|
headless: !args.headful,
|
||||||
handleSIGINT: false,
|
handleSIGINT: false,
|
||||||
|
|||||||
@ -132,9 +132,9 @@ it.describe('snapshots', () => {
|
|||||||
await previewPage.evaluate(snapshotId => {
|
await previewPage.evaluate(snapshotId => {
|
||||||
(window as any).showSnapshot(snapshotId);
|
(window as any).showSnapshot(snapshotId);
|
||||||
}, `${snapshot.snapshot().pageId}?name=snapshot${counter}`);
|
}, `${snapshot.snapshot().pageId}?name=snapshot${counter}`);
|
||||||
while (previewPage.frames().length < 4)
|
while (previewPage.frames().length < 3)
|
||||||
await new Promise(f => previewPage.once('frameattached', f));
|
await new Promise(f => previewPage.once('frameattached', f));
|
||||||
const button = await previewPage.frames()[3].waitForSelector('button');
|
const button = await previewPage.frames()[2].waitForSelector('button');
|
||||||
expect(await button.textContent()).toBe('Hello iframe');
|
expect(await button.textContent()).toBe('Hello iframe');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -29,13 +29,13 @@ test.beforeEach(async ({ browserName, headful }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should collect trace', async ({ context, page, server, browserName }, testInfo) => {
|
test('should collect trace', async ({ context, page, server, browserName }, testInfo) => {
|
||||||
await (context as any)._tracing.start({ name: 'test', screenshots: true, snapshots: true });
|
await (context as any).tracing.start({ name: 'test', screenshots: true, snapshots: true });
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
await page.setContent('<button>Click</button>');
|
await page.setContent('<button>Click</button>');
|
||||||
await page.click('"Click"');
|
await page.click('"Click"');
|
||||||
await page.close();
|
await page.close();
|
||||||
await (context as any)._tracing.stop();
|
await (context as any).tracing.stop();
|
||||||
await (context as any)._tracing.export(testInfo.outputPath('trace.zip'));
|
await (context as any).tracing.export(testInfo.outputPath('trace.zip'));
|
||||||
|
|
||||||
const { events } = await parseTrace(testInfo.outputPath('trace.zip'));
|
const { events } = await parseTrace(testInfo.outputPath('trace.zip'));
|
||||||
expect(events[0].type).toBe('context-metadata');
|
expect(events[0].type).toBe('context-metadata');
|
||||||
@ -51,13 +51,13 @@ test('should collect trace', async ({ context, page, server, browserName }, test
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should collect trace', async ({ context, page, server }, testInfo) => {
|
test('should collect trace', async ({ context, page, server }, testInfo) => {
|
||||||
await (context as any)._tracing.start({ name: 'test' });
|
await (context as any).tracing.start({ name: 'test' });
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
await page.setContent('<button>Click</button>');
|
await page.setContent('<button>Click</button>');
|
||||||
await page.click('"Click"');
|
await page.click('"Click"');
|
||||||
await page.close();
|
await page.close();
|
||||||
await (context as any)._tracing.stop();
|
await (context as any).tracing.stop();
|
||||||
await (context as any)._tracing.export(testInfo.outputPath('trace.zip'));
|
await (context as any).tracing.export(testInfo.outputPath('trace.zip'));
|
||||||
|
|
||||||
const { events } = await parseTrace(testInfo.outputPath('trace.zip'));
|
const { events } = await parseTrace(testInfo.outputPath('trace.zip'));
|
||||||
expect(events.some(e => e.type === 'frame-snapshot')).toBeFalsy();
|
expect(events.some(e => e.type === 'frame-snapshot')).toBeFalsy();
|
||||||
@ -65,18 +65,18 @@ test('should collect trace', async ({ context, page, server }, testInfo) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should collect two traces', async ({ context, page, server }, testInfo) => {
|
test('should collect two traces', async ({ context, page, server }, testInfo) => {
|
||||||
await (context as any)._tracing.start({ name: 'test1', screenshots: true, snapshots: true });
|
await (context as any).tracing.start({ name: 'test1', screenshots: true, snapshots: true });
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
await page.setContent('<button>Click</button>');
|
await page.setContent('<button>Click</button>');
|
||||||
await page.click('"Click"');
|
await page.click('"Click"');
|
||||||
await (context as any)._tracing.stop();
|
await (context as any).tracing.stop();
|
||||||
await (context as any)._tracing.export(testInfo.outputPath('trace1.zip'));
|
await (context as any).tracing.export(testInfo.outputPath('trace1.zip'));
|
||||||
|
|
||||||
await (context as any)._tracing.start({ name: 'test2', screenshots: true, snapshots: true });
|
await (context as any).tracing.start({ name: 'test2', screenshots: true, snapshots: true });
|
||||||
await page.dblclick('"Click"');
|
await page.dblclick('"Click"');
|
||||||
await page.close();
|
await page.close();
|
||||||
await (context as any)._tracing.stop();
|
await (context as any).tracing.stop();
|
||||||
await (context as any)._tracing.export(testInfo.outputPath('trace2.zip'));
|
await (context as any).tracing.export(testInfo.outputPath('trace2.zip'));
|
||||||
|
|
||||||
{
|
{
|
||||||
const { events } = await parseTrace(testInfo.outputPath('trace1.zip'));
|
const { events } = await parseTrace(testInfo.outputPath('trace1.zip'));
|
||||||
@ -127,15 +127,15 @@ for (const params of [
|
|||||||
const previewHeight = params.height * scale;
|
const previewHeight = params.height * scale;
|
||||||
|
|
||||||
const context = await contextFactory({ viewport: { width: params.width, height: params.height }});
|
const context = await contextFactory({ viewport: { width: params.width, height: params.height }});
|
||||||
await (context as any)._tracing.start({ name: 'test', screenshots: true, snapshots: true });
|
await (context as any).tracing.start({ name: 'test', screenshots: true, snapshots: true });
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
// Make sure we have a chance to paint.
|
// Make sure we have a chance to paint.
|
||||||
for (let i = 0; i < 10; ++i) {
|
for (let i = 0; i < 10; ++i) {
|
||||||
await page.setContent('<body style="box-sizing: border-box; width: 100%; height: 100%; margin:0; background: red; border: 50px solid blue"></body>');
|
await page.setContent('<body style="box-sizing: border-box; width: 100%; height: 100%; margin:0; background: red; border: 50px solid blue"></body>');
|
||||||
await page.evaluate(() => new Promise(requestAnimationFrame));
|
await page.evaluate(() => new Promise(requestAnimationFrame));
|
||||||
}
|
}
|
||||||
await (context as any)._tracing.stop();
|
await (context as any).tracing.stop();
|
||||||
await (context as any)._tracing.export(testInfo.outputPath('trace.zip'));
|
await (context as any).tracing.export(testInfo.outputPath('trace.zip'));
|
||||||
|
|
||||||
const { events, resources } = await parseTrace(testInfo.outputPath('trace.zip'));
|
const { events, resources } = await parseTrace(testInfo.outputPath('trace.zip'));
|
||||||
const frames = events.filter(e => e.type === 'screencast-frame');
|
const frames = events.filter(e => e.type === 'screencast-frame');
|
||||||
|
|||||||
48
types/types.d.ts
vendored
48
types/types.d.ts
vendored
@ -5455,6 +5455,8 @@ export interface BrowserContext {
|
|||||||
}>;
|
}>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
tracing: Tracing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a route created with
|
* Removes a route created with
|
||||||
* [browserContext.route(url, handler)](https://playwright.dev/docs/api/class-browsercontext#browsercontextrouteurl-handler).
|
* [browserContext.route(url, handler)](https://playwright.dev/docs/api/class-browsercontext#browsercontextrouteurl-handler).
|
||||||
@ -10264,6 +10266,52 @@ export interface Touchscreen {
|
|||||||
tap(x: number, y: number): Promise<void>;
|
tap(x: number, y: number): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracing object for collecting test traces that can be opened using Playwright CLI.
|
||||||
|
*/
|
||||||
|
export interface Tracing {
|
||||||
|
/**
|
||||||
|
* Export trace into the file with the given name. Should be called after the tracing has stopped.
|
||||||
|
* @param path File to save the trace into.
|
||||||
|
*/
|
||||||
|
export(path: string): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start tracing.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* await context.tracing.start({ name: 'trace', screenshots: true, snapshots: true });
|
||||||
|
* const page = await context.newPage();
|
||||||
|
* await page.goto('https://playwright.dev');
|
||||||
|
* await context.tracing.stop();
|
||||||
|
* await context.tracing.export('trace.zip');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
start(options?: {
|
||||||
|
/**
|
||||||
|
* If specified, the trace is going to be saved into the file with the given name.
|
||||||
|
*/
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to capture screenshots during tracing. Screenshots are used to build a timeline preview.
|
||||||
|
*/
|
||||||
|
screenshots?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to capture DOM snapshot on every action.
|
||||||
|
*/
|
||||||
|
snapshots?: boolean;
|
||||||
|
}): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop tracing.
|
||||||
|
*/
|
||||||
|
stop(): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When browser context is created with the `recordVideo` option, each page has a video object associated with it.
|
* When browser context is created with the `recordVideo` option, each page has a video object associated with it.
|
||||||
*
|
*
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user