feat: support name option in tracing.startChunk() (#21692)
This commit is contained in:
parent
bde2e90973
commit
40a6eff8f2
|
|
@ -267,6 +267,13 @@ await context.Tracing.StopChunkAsync(new()
|
||||||
|
|
||||||
Trace name to be shown in the Trace Viewer.
|
Trace name to be shown in the Trace Viewer.
|
||||||
|
|
||||||
|
### option: Tracing.startChunk.name
|
||||||
|
* since: v1.32
|
||||||
|
- `name` <[string]>
|
||||||
|
|
||||||
|
If specified, the trace is going to be saved into the file with the
|
||||||
|
given name inside the [`option: tracesDir`] folder specified in [`method: BrowserType.launch`].
|
||||||
|
|
||||||
## async method: Tracing.stop
|
## async method: Tracing.stop
|
||||||
* since: v1.12
|
* since: v1.12
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,13 @@ export class Tracing extends ChannelOwner<channels.TracingChannel> implements ap
|
||||||
this._includeSources = !!options.sources;
|
this._includeSources = !!options.sources;
|
||||||
await this._wrapApiCall(async () => {
|
await this._wrapApiCall(async () => {
|
||||||
await this._channel.tracingStart(options);
|
await this._channel.tracingStart(options);
|
||||||
await this._channel.tracingStartChunk({ title: options.title });
|
await this._channel.tracingStartChunk({ name: options.name, title: options.title });
|
||||||
});
|
});
|
||||||
this._metadataCollector = [];
|
this._metadataCollector = [];
|
||||||
this._connection.startCollectingCallMetadata(this._metadataCollector);
|
this._connection.startCollectingCallMetadata(this._metadataCollector);
|
||||||
}
|
}
|
||||||
|
|
||||||
async startChunk(options: { title?: string } = {}) {
|
async startChunk(options: { name?: string, title?: string } = {}) {
|
||||||
await this._channel.tracingStartChunk(options);
|
await this._channel.tracingStartChunk(options);
|
||||||
this._metadataCollector = [];
|
this._metadataCollector = [];
|
||||||
this._connection.startCollectingCallMetadata(this._metadataCollector);
|
this._connection.startCollectingCallMetadata(this._metadataCollector);
|
||||||
|
|
|
||||||
|
|
@ -2092,6 +2092,7 @@ scheme.TracingTracingStartParams = tObject({
|
||||||
});
|
});
|
||||||
scheme.TracingTracingStartResult = tOptional(tObject({}));
|
scheme.TracingTracingStartResult = tOptional(tObject({}));
|
||||||
scheme.TracingTracingStartChunkParams = tObject({
|
scheme.TracingTracingStartChunkParams = tObject({
|
||||||
|
name: tOptional(tString),
|
||||||
title: tOptional(tString),
|
title: tOptional(tString),
|
||||||
});
|
});
|
||||||
scheme.TracingTracingStartChunkResult = tOptional(tObject({}));
|
scheme.TracingTracingStartChunkResult = tOptional(tObject({}));
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,8 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
||||||
const o = this._state.options;
|
const o = this._state.options;
|
||||||
if (!o.screenshots !== !options.screenshots || !o.snapshots !== !options.snapshots)
|
if (!o.screenshots !== !options.screenshots || !o.snapshots !== !options.snapshots)
|
||||||
throw new Error('Tracing has been already started with different options');
|
throw new Error('Tracing has been already started with different options');
|
||||||
|
if (options.name && options.name !== this._state.traceName)
|
||||||
|
await this._changeTraceName(this._state, options.name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: passing the same name for two contexts makes them write into a single file
|
// TODO: passing the same name for two contexts makes them write into a single file
|
||||||
|
|
@ -143,7 +145,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
||||||
this._harTracer.start();
|
this._harTracer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
async startChunk(options: { title?: string } = {}) {
|
async startChunk(options: { name?: string, title?: string } = {}) {
|
||||||
if (this._state && this._state.recording)
|
if (this._state && this._state.recording)
|
||||||
await this.stopChunk({ mode: 'discard' });
|
await this.stopChunk({ mode: 'discard' });
|
||||||
|
|
||||||
|
|
@ -158,6 +160,8 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
||||||
state.traceFile = path.join(state.tracesDir, `${state.traceName}${suffix}.trace`);
|
state.traceFile = path.join(state.tracesDir, `${state.traceName}${suffix}.trace`);
|
||||||
state.recording = true;
|
state.recording = true;
|
||||||
|
|
||||||
|
if (options.name && options.name !== this._state.traceName)
|
||||||
|
this._changeTraceName(this._state, options.name);
|
||||||
this._appendTraceOperation(async () => {
|
this._appendTraceOperation(async () => {
|
||||||
await mkdirIfNeeded(state.traceFile);
|
await mkdirIfNeeded(state.traceFile);
|
||||||
await fs.promises.appendFile(state.traceFile, JSON.stringify({ ...this._contextCreatedEvent, title: options.title, wallTime: Date.now() }) + '\n');
|
await fs.promises.appendFile(state.traceFile, JSON.stringify({ ...this._contextCreatedEvent, title: options.title, wallTime: Date.now() }) + '\n');
|
||||||
|
|
@ -188,6 +192,16 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
||||||
page.setScreencastOptions(null);
|
page.setScreencastOptions(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _changeTraceName(state: RecordingState, name: string) {
|
||||||
|
await this._appendTraceOperation(async () => {
|
||||||
|
const oldNetworkFile = state.networkFile;
|
||||||
|
state.traceFile = path.join(state.tracesDir, name + '.trace');
|
||||||
|
state.networkFile = path.join(state.tracesDir, name + '.network');
|
||||||
|
// Network file survives across chunks, so make a copy with the new name.
|
||||||
|
await fs.promises.copyFile(oldNetworkFile, state.networkFile);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async stop() {
|
async stop() {
|
||||||
if (!this._state)
|
if (!this._state)
|
||||||
return;
|
return;
|
||||||
|
|
@ -257,7 +271,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
||||||
if (params.mode === 'discard')
|
if (params.mode === 'discard')
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
// Har files are live, make a snapshot before returning the resulting entries.
|
// Network file survives across chunks, make a snapshot before returning the resulting entries.
|
||||||
const networkFile = path.join(state.networkFile, '..', createGuid());
|
const networkFile = path.join(state.networkFile, '..', createGuid());
|
||||||
await fs.promises.copyFile(state.networkFile, networkFile);
|
await fs.promises.copyFile(state.networkFile, networkFile);
|
||||||
|
|
||||||
|
|
|
||||||
7
packages/playwright-core/types/types.d.ts
vendored
7
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -18262,6 +18262,13 @@ export interface Tracing {
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
startChunk(options?: {
|
startChunk(options?: {
|
||||||
|
/**
|
||||||
|
* If specified, the trace is going to be saved into the file with the given name inside the `tracesDir` folder
|
||||||
|
* specified in
|
||||||
|
* [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browser-type-launch).
|
||||||
|
*/
|
||||||
|
name?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trace name to be shown in the Trace Viewer.
|
* Trace name to be shown in the Trace Viewer.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -3749,9 +3749,11 @@ export type TracingTracingStartOptions = {
|
||||||
};
|
};
|
||||||
export type TracingTracingStartResult = void;
|
export type TracingTracingStartResult = void;
|
||||||
export type TracingTracingStartChunkParams = {
|
export type TracingTracingStartChunkParams = {
|
||||||
|
name?: string,
|
||||||
title?: string,
|
title?: string,
|
||||||
};
|
};
|
||||||
export type TracingTracingStartChunkOptions = {
|
export type TracingTracingStartChunkOptions = {
|
||||||
|
name?: string,
|
||||||
title?: string,
|
title?: string,
|
||||||
};
|
};
|
||||||
export type TracingTracingStartChunkResult = void;
|
export type TracingTracingStartChunkResult = void;
|
||||||
|
|
|
||||||
|
|
@ -2925,6 +2925,7 @@ Tracing:
|
||||||
|
|
||||||
tracingStartChunk:
|
tracingStartChunk:
|
||||||
parameters:
|
parameters:
|
||||||
|
name: string?
|
||||||
title: string?
|
title: string?
|
||||||
|
|
||||||
tracingStopChunk:
|
tracingStopChunk:
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,58 @@ test('should collect two traces', async ({ context, page, server }, testInfo) =>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should respect tracesDir and name', async ({ browserType, server }, testInfo) => {
|
||||||
|
const tracesDir = testInfo.outputPath('traces');
|
||||||
|
const browser = await browserType.launch({ tracesDir });
|
||||||
|
const context = await browser.newContext();
|
||||||
|
const page = await context.newPage();
|
||||||
|
|
||||||
|
await context.tracing.start({ name: 'name1', snapshots: true });
|
||||||
|
await page.goto(server.PREFIX + '/one-style.html');
|
||||||
|
await context.tracing.stopChunk({ path: testInfo.outputPath('trace1.zip') });
|
||||||
|
expect(fs.existsSync(path.join(tracesDir, 'name1.trace'))).toBe(true);
|
||||||
|
expect(fs.existsSync(path.join(tracesDir, 'name1.network'))).toBe(true);
|
||||||
|
|
||||||
|
await context.tracing.startChunk({ name: 'name2' });
|
||||||
|
await page.goto(server.PREFIX + '/har.html');
|
||||||
|
await context.tracing.stop({ path: testInfo.outputPath('trace2.zip') });
|
||||||
|
expect(fs.existsSync(path.join(tracesDir, 'name2.trace'))).toBe(true);
|
||||||
|
expect(fs.existsSync(path.join(tracesDir, 'name2.network'))).toBe(true);
|
||||||
|
|
||||||
|
await browser.close();
|
||||||
|
|
||||||
|
function resourceNames(resources: Map<string, Buffer>) {
|
||||||
|
return [...resources.keys()].map(file => {
|
||||||
|
return file.replace(/^resources\/.*\.(html|css)$/, 'resources/XXX.$1');
|
||||||
|
}).sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const { resources, actions } = await parseTrace(testInfo.outputPath('trace1.zip'));
|
||||||
|
expect(actions).toEqual(['page.goto']);
|
||||||
|
expect(resourceNames(resources)).toEqual([
|
||||||
|
'resources/XXX.css',
|
||||||
|
'resources/XXX.html',
|
||||||
|
'trace.network',
|
||||||
|
'trace.stacks',
|
||||||
|
'trace.trace',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const { resources, actions } = await parseTrace(testInfo.outputPath('trace2.zip'));
|
||||||
|
expect(actions).toEqual(['page.goto']);
|
||||||
|
expect(resourceNames(resources)).toEqual([
|
||||||
|
'resources/XXX.css',
|
||||||
|
'resources/XXX.html',
|
||||||
|
'resources/XXX.html',
|
||||||
|
'trace.network',
|
||||||
|
'trace.stacks',
|
||||||
|
'trace.trace',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('should not include trace resources from the provious chunks', async ({ context, page, server, browserName }, testInfo) => {
|
test('should not include trace resources from the provious chunks', async ({ context, page, server, browserName }, testInfo) => {
|
||||||
test.skip(browserName !== 'chromium', 'The number of screenshots is flaky in non-Chromium');
|
test.skip(browserName !== 'chromium', 'The number of screenshots is flaky in non-Chromium');
|
||||||
await context.tracing.start({ screenshots: true, snapshots: true, sources: true });
|
await context.tracing.start({ screenshots: true, snapshots: true, sources: true });
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue