chore: make console stream live in ui mode (#26562)
This commit is contained in:
parent
32a309ccb8
commit
f83d81956d
|
|
@ -33,10 +33,15 @@ export class Tracing extends ChannelOwner<channels.TracingChannel> implements ap
|
||||||
super(parent, type, guid, initializer);
|
super(parent, type, guid, initializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(options: { name?: string, title?: string, snapshots?: boolean, screenshots?: boolean, sources?: boolean } = {}) {
|
async start(options: { name?: string, title?: string, snapshots?: boolean, screenshots?: boolean, sources?: boolean, _live?: boolean } = {}) {
|
||||||
this._includeSources = !!options.sources;
|
this._includeSources = !!options.sources;
|
||||||
const traceName = await this._wrapApiCall(async () => {
|
const traceName = await this._wrapApiCall(async () => {
|
||||||
await this._channel.tracingStart(options);
|
await this._channel.tracingStart({
|
||||||
|
name: options.name,
|
||||||
|
snapshots: options.snapshots,
|
||||||
|
screenshots: options.screenshots,
|
||||||
|
live: options._live,
|
||||||
|
});
|
||||||
const response = await this._channel.tracingStartChunk({ name: options.name, title: options.title });
|
const response = await this._channel.tracingStartChunk({ name: options.name, title: options.title });
|
||||||
return response.traceName;
|
return response.traceName;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2130,7 +2130,7 @@ scheme.TracingTracingStartParams = tObject({
|
||||||
name: tOptional(tString),
|
name: tOptional(tString),
|
||||||
snapshots: tOptional(tBoolean),
|
snapshots: tOptional(tBoolean),
|
||||||
screenshots: tOptional(tBoolean),
|
screenshots: tOptional(tBoolean),
|
||||||
sources: tOptional(tBoolean),
|
live: tOptional(tBoolean),
|
||||||
});
|
});
|
||||||
scheme.TracingTracingStartResult = tOptional(tObject({}));
|
scheme.TracingTracingStartResult = tOptional(tObject({}));
|
||||||
scheme.TracingTracingStartChunkParams = tObject({
|
scheme.TracingTracingStartChunkParams = tObject({
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ export type TracerOptions = {
|
||||||
name?: string;
|
name?: string;
|
||||||
snapshots?: boolean;
|
snapshots?: boolean;
|
||||||
screenshots?: boolean;
|
screenshots?: boolean;
|
||||||
|
live?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type RecordingState = {
|
type RecordingState = {
|
||||||
|
|
@ -455,8 +456,8 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
||||||
|
|
||||||
private _appendTraceEvent(event: trace.TraceEvent) {
|
private _appendTraceEvent(event: trace.TraceEvent) {
|
||||||
const visited = visitTraceEvent(event, this._state!.traceSha1s);
|
const visited = visitTraceEvent(event, this._state!.traceSha1s);
|
||||||
// Do not flush events, they are too noisy.
|
// Do not flush (console) events, they are too noisy, unless we are in ui mode (live).
|
||||||
const flush = event.type !== 'event' && event.type !== 'object';
|
const flush = this._state!.options.live || (event.type !== 'event' && event.type !== 'object');
|
||||||
this._fs.appendFile(this._state!.traceFile, JSON.stringify(visited) + '\n', flush);
|
this._fs.appendFile(this._state!.traceFile, JSON.stringify(visited) + '\n', flush);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -526,7 +526,7 @@ class ArtifactsRecorder {
|
||||||
private _traceMode: TraceMode;
|
private _traceMode: TraceMode;
|
||||||
private _captureTrace = false;
|
private _captureTrace = false;
|
||||||
private _screenshotOptions: { mode: ScreenshotMode } & Pick<playwrightLibrary.PageScreenshotOptions, 'fullPage' | 'omitBackground'> | undefined;
|
private _screenshotOptions: { mode: ScreenshotMode } & Pick<playwrightLibrary.PageScreenshotOptions, 'fullPage' | 'omitBackground'> | undefined;
|
||||||
private _traceOptions: { screenshots: boolean, snapshots: boolean, sources: boolean, attachments: boolean, mode?: TraceMode };
|
private _traceOptions: { screenshots: boolean, snapshots: boolean, sources: boolean, attachments: boolean, _live: boolean, mode?: TraceMode };
|
||||||
private _temporaryTraceFiles: string[] = [];
|
private _temporaryTraceFiles: string[] = [];
|
||||||
private _temporaryScreenshots: string[] = [];
|
private _temporaryScreenshots: string[] = [];
|
||||||
private _reusedContexts = new Set<BrowserContext>();
|
private _reusedContexts = new Set<BrowserContext>();
|
||||||
|
|
@ -541,7 +541,7 @@ class ArtifactsRecorder {
|
||||||
this._screenshotMode = normalizeScreenshotMode(screenshot);
|
this._screenshotMode = normalizeScreenshotMode(screenshot);
|
||||||
this._screenshotOptions = typeof screenshot === 'string' ? undefined : screenshot;
|
this._screenshotOptions = typeof screenshot === 'string' ? undefined : screenshot;
|
||||||
this._traceMode = normalizeTraceMode(trace);
|
this._traceMode = normalizeTraceMode(trace);
|
||||||
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true, attachments: true };
|
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true, attachments: true, _live: false };
|
||||||
this._traceOptions = typeof trace === 'string' ? defaultTraceOptions : { ...defaultTraceOptions, ...trace, mode: undefined };
|
this._traceOptions = typeof trace === 'string' ? defaultTraceOptions : { ...defaultTraceOptions, ...trace, mode: undefined };
|
||||||
this._screenshottedSymbol = Symbol('screenshotted');
|
this._screenshottedSymbol = Symbol('screenshotted');
|
||||||
this._startedCollectingArtifacts = Symbol('startedCollectingArtifacts');
|
this._startedCollectingArtifacts = Symbol('startedCollectingArtifacts');
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ class UIMode {
|
||||||
p.project.repeatEach = 1;
|
p.project.repeatEach = 1;
|
||||||
}
|
}
|
||||||
config.configCLIOverrides.use = config.configCLIOverrides.use || {};
|
config.configCLIOverrides.use = config.configCLIOverrides.use || {};
|
||||||
config.configCLIOverrides.use.trace = { mode: 'on', sources: false };
|
config.configCLIOverrides.use.trace = { mode: 'on', sources: false, _live: true };
|
||||||
|
|
||||||
this._originalStdoutWrite = process.stdout.write;
|
this._originalStdoutWrite = process.stdout.write;
|
||||||
this._originalStderrWrite = process.stderr.write;
|
this._originalStderrWrite = process.stderr.write;
|
||||||
|
|
|
||||||
|
|
@ -3803,13 +3803,13 @@ export type TracingTracingStartParams = {
|
||||||
name?: string,
|
name?: string,
|
||||||
snapshots?: boolean,
|
snapshots?: boolean,
|
||||||
screenshots?: boolean,
|
screenshots?: boolean,
|
||||||
sources?: boolean,
|
live?: boolean,
|
||||||
};
|
};
|
||||||
export type TracingTracingStartOptions = {
|
export type TracingTracingStartOptions = {
|
||||||
name?: string,
|
name?: string,
|
||||||
snapshots?: boolean,
|
snapshots?: boolean,
|
||||||
screenshots?: boolean,
|
screenshots?: boolean,
|
||||||
sources?: boolean,
|
live?: boolean,
|
||||||
};
|
};
|
||||||
export type TracingTracingStartResult = void;
|
export type TracingTracingStartResult = void;
|
||||||
export type TracingTracingStartChunkParams = {
|
export type TracingTracingStartChunkParams = {
|
||||||
|
|
|
||||||
|
|
@ -3014,7 +3014,7 @@ Tracing:
|
||||||
name: string?
|
name: string?
|
||||||
snapshots: boolean?
|
snapshots: boolean?
|
||||||
screenshots: boolean?
|
screenshots: boolean?
|
||||||
sources: boolean?
|
live: boolean?
|
||||||
|
|
||||||
tracingStartChunk:
|
tracingStartChunk:
|
||||||
parameters:
|
parameters:
|
||||||
|
|
|
||||||
|
|
@ -200,10 +200,14 @@ function format(args: { preview: string, value: any }[]): JSX.Element[] {
|
||||||
function parseCSSStyle(cssFormat: string): Record<string, string | number> {
|
function parseCSSStyle(cssFormat: string): Record<string, string | number> {
|
||||||
try {
|
try {
|
||||||
const styleObject: Record<string, string | number> = {};
|
const styleObject: Record<string, string | number> = {};
|
||||||
const cssText = cssFormat.replace(/;$/, '').replace(/: /g, ':').replace(/; /g, ';');
|
const cssProperties = cssFormat.split(';');
|
||||||
const cssProperties = cssText.split(';');
|
for (const token of cssProperties) {
|
||||||
for (const property of cssProperties) {
|
const property = token.trim();
|
||||||
const [key, value] = property.split(':');
|
if (!property)
|
||||||
|
continue;
|
||||||
|
let [key, value] = property.split(':');
|
||||||
|
key = key.trim();
|
||||||
|
value = value.trim();
|
||||||
if (!supportProperty(key))
|
if (!supportProperty(key))
|
||||||
continue;
|
continue;
|
||||||
// cssProperties are background-color, JSDom ones are backgroundColor
|
// cssProperties are background-color, JSDom ones are backgroundColor
|
||||||
|
|
|
||||||
|
|
@ -151,3 +151,28 @@ test('should format console messages in page', async ({ runUITest }, testInfo) =
|
||||||
await expect(link).toHaveCSS('color', 'rgb(0, 0, 255)');
|
await expect(link).toHaveCSS('color', 'rgb(0, 0, 255)');
|
||||||
await expect(link).toHaveCSS('text-decoration', 'none solid rgb(0, 0, 255)');
|
await expect(link).toHaveCSS('text-decoration', 'none solid rgb(0, 0, 255)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should stream console messages live', async ({ runUITest }, testInfo) => {
|
||||||
|
const { page } = await runUITest({
|
||||||
|
'a.spec.ts': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
test('print', async ({ page }) => {
|
||||||
|
await page.setContent('<button>Click me</button>');
|
||||||
|
const button = page.getByRole('button', { name: 'Click me' });
|
||||||
|
await button.evaluate(node => node.addEventListener('click', () => {
|
||||||
|
setTimeout(() => { console.log('I was clicked'); }, 1000);
|
||||||
|
}));
|
||||||
|
await button.click();
|
||||||
|
await page.locator('#not-there').waitFor();
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
await page.getByTitle('Run all').click();
|
||||||
|
await page.getByText('Console').click();
|
||||||
|
await page.getByText('print').click();
|
||||||
|
|
||||||
|
await expect(page.locator('.console-tab .console-line-message')).toHaveText([
|
||||||
|
'I was clicked',
|
||||||
|
]);
|
||||||
|
await page.getByTitle('Stop').click();
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue