mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: move from apiName to title in tracing (#36003)
This commit is contained in:
parent
3c888d59dd
commit
27ce0eb867
@ -47,7 +47,7 @@ import type * as har from '@trace/har';
|
|||||||
import type { FrameSnapshot } from '@trace/snapshot';
|
import type { FrameSnapshot } from '@trace/snapshot';
|
||||||
import type * as trace from '@trace/trace';
|
import type * as trace from '@trace/trace';
|
||||||
|
|
||||||
const version: trace.VERSION = 7;
|
const version: trace.VERSION = 8;
|
||||||
|
|
||||||
export type TracerOptions = {
|
export type TracerOptions = {
|
||||||
name?: string;
|
name?: string;
|
||||||
@ -230,7 +230,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
|||||||
type: 'before',
|
type: 'before',
|
||||||
callId: metadata.id,
|
callId: metadata.id,
|
||||||
startTime: metadata.startTime,
|
startTime: metadata.startTime,
|
||||||
apiName: name,
|
title: name,
|
||||||
class: 'Tracing',
|
class: 'Tracing',
|
||||||
method: 'tracingGroup',
|
method: 'tracingGroup',
|
||||||
params: { },
|
params: { },
|
||||||
@ -650,7 +650,10 @@ function createBeforeActionTraceEvent(metadata: CallMetadata, parentId?: string)
|
|||||||
type: 'before',
|
type: 'before',
|
||||||
callId: metadata.id,
|
callId: metadata.id,
|
||||||
startTime: metadata.startTime,
|
startTime: metadata.startTime,
|
||||||
apiName: metadata.apiName || metadata.type + '.' + metadata.method,
|
// This will disappear for action trace events, their titles will be
|
||||||
|
// built based on the protocol metainfo. If I don't do this now,
|
||||||
|
// trace ill get frame.click instead of page.click in trace viewer.
|
||||||
|
title: metadata.apiName,
|
||||||
class: metadata.type,
|
class: metadata.type,
|
||||||
method: metadata.method,
|
method: metadata.method,
|
||||||
params: metadata.params,
|
params: metadata.params,
|
||||||
|
@ -329,7 +329,7 @@ export class TestInfoImpl implements TestInfo {
|
|||||||
location: data.location,
|
location: data.location,
|
||||||
};
|
};
|
||||||
this._onStepBegin(payload);
|
this._onStepBegin(payload);
|
||||||
this._tracing.appendBeforeActionForStep(stepId, parentStep?.stepId, data.apiName || data.title, data.params, data.location ? [data.location] : []);
|
this._tracing.appendBeforeActionForStep(stepId, parentStep?.stepId, { title: data.title, params: data.params, stack: data.location ? [data.location] : [] });
|
||||||
return step;
|
return step;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +425,7 @@ export class TestInfoImpl implements TestInfo {
|
|||||||
this._stepMap.get(stepId)!.attachmentIndices.push(index);
|
this._stepMap.get(stepId)!.attachmentIndices.push(index);
|
||||||
} else {
|
} else {
|
||||||
const callId = `attach@${createGuid()}`;
|
const callId = `attach@${createGuid()}`;
|
||||||
this._tracing.appendBeforeActionForStep(callId, undefined, `Attach "${attachment.name}"`, undefined, []);
|
this._tracing.appendBeforeActionForStep(callId, undefined, { title: `Attach "${attachment.name}"`, stack: [] });
|
||||||
this._tracing.appendAfterActionForStep(callId, undefined, [attachment]);
|
this._tracing.appendAfterActionForStep(callId, undefined, [attachment]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ import type EventEmitter from 'events';
|
|||||||
|
|
||||||
export type Attachment = TestInfo['attachments'][0];
|
export type Attachment = TestInfo['attachments'][0];
|
||||||
export const testTraceEntryName = 'test.trace';
|
export const testTraceEntryName = 'test.trace';
|
||||||
const version: trace.VERSION = 7;
|
const version: trace.VERSION = 8;
|
||||||
let traceOrdinal = 0;
|
let traceOrdinal = 0;
|
||||||
|
|
||||||
type TraceFixtureValue = PlaywrightWorkerOptions['trace'] | undefined;
|
type TraceFixtureValue = PlaywrightWorkerOptions['trace'] | undefined;
|
||||||
@ -267,7 +267,7 @@ export class TestTracing {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
appendBeforeActionForStep(callId: string, parentId: string | undefined, apiName: string, params: Record<string, any> | undefined, stack: StackFrame[]) {
|
appendBeforeActionForStep(callId: string, parentId: string | undefined, options: { title: string, params?: Record<string, any>, stack: StackFrame[] }) {
|
||||||
this._appendTraceEvent({
|
this._appendTraceEvent({
|
||||||
type: 'before',
|
type: 'before',
|
||||||
callId,
|
callId,
|
||||||
@ -275,9 +275,9 @@ export class TestTracing {
|
|||||||
startTime: monotonicTime(),
|
startTime: monotonicTime(),
|
||||||
class: 'Test',
|
class: 'Test',
|
||||||
method: 'step',
|
method: 'step',
|
||||||
apiName,
|
title: options.title,
|
||||||
params: Object.fromEntries(Object.entries(params || {}).map(([name, value]) => [name, generatePreview(value)])),
|
params: Object.fromEntries(Object.entries(options.params || {}).map(([name, value]) => [name, generatePreview(value)])),
|
||||||
stack,
|
stack: options.stack,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import type * as traceV4 from './versions/traceV4';
|
|||||||
import type * as traceV5 from './versions/traceV5';
|
import type * as traceV5 from './versions/traceV5';
|
||||||
import type * as traceV6 from './versions/traceV6';
|
import type * as traceV6 from './versions/traceV6';
|
||||||
import type * as traceV7 from './versions/traceV7';
|
import type * as traceV7 from './versions/traceV7';
|
||||||
|
import type * as traceV8 from './versions/traceV8';
|
||||||
import type { ActionEntry, ContextEntry, PageEntry } from '../types/entries';
|
import type { ActionEntry, ContextEntry, PageEntry } from '../types/entries';
|
||||||
import type { SnapshotStorage } from './snapshotStorage';
|
import type { SnapshotStorage } from './snapshotStorage';
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ export class TraceVersionError extends Error {
|
|||||||
|
|
||||||
// 6 => 10/2023 ~1.40
|
// 6 => 10/2023 ~1.40
|
||||||
// 7 => 05/2024 ~1.45
|
// 7 => 05/2024 ~1.45
|
||||||
const latestVersion: trace.VERSION = 7;
|
const latestVersion: trace.VERSION = 8;
|
||||||
|
|
||||||
export class TraceModernizer {
|
export class TraceModernizer {
|
||||||
private _contextEntry: ContextEntry;
|
private _contextEntry: ContextEntry;
|
||||||
@ -409,4 +410,15 @@ export class TraceModernizer {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_modernize_7_to_8(events: traceV7.TraceEvent[]): traceV8.TraceEvent[] {
|
||||||
|
const result: traceV8.TraceEvent[] = [];
|
||||||
|
for (const event of events) {
|
||||||
|
result.push(event);
|
||||||
|
if (event.type !== 'before' || !event.apiName)
|
||||||
|
continue;
|
||||||
|
(event as traceV8.BeforeActionTraceEvent).title = event.apiName;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
260
packages/trace-viewer/src/sw/versions/traceV8.ts
Normal file
260
packages/trace-viewer/src/sw/versions/traceV8.ts
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
/**
|
||||||
|
* 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 type { Entry as ResourceSnapshot } from '@trace/har';
|
||||||
|
|
||||||
|
type Language = 'javascript' | 'python' | 'java' | 'csharp' | 'jsonl';
|
||||||
|
type Point = { x: number, y: number };
|
||||||
|
type Size = { width: number, height: number };
|
||||||
|
|
||||||
|
type StackFrame = {
|
||||||
|
file: string,
|
||||||
|
line: number,
|
||||||
|
column: number,
|
||||||
|
function?: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Binary = Buffer;
|
||||||
|
|
||||||
|
type SerializedValue = {
|
||||||
|
n?: number,
|
||||||
|
b?: boolean,
|
||||||
|
s?: string,
|
||||||
|
v?: 'null' | 'undefined' | 'NaN' | 'Infinity' | '-Infinity' | '-0',
|
||||||
|
d?: string,
|
||||||
|
u?: string,
|
||||||
|
bi?: string,
|
||||||
|
ta?: {
|
||||||
|
b: Binary,
|
||||||
|
k: 'i8' | 'ui8' | 'ui8c' | 'i16' | 'ui16' | 'i32' | 'ui32' | 'f32' | 'f64' | 'bi64' | 'bui64',
|
||||||
|
},
|
||||||
|
e?: {
|
||||||
|
m: string,
|
||||||
|
n: string,
|
||||||
|
s: string,
|
||||||
|
},
|
||||||
|
r?: {
|
||||||
|
p: string,
|
||||||
|
f: string,
|
||||||
|
},
|
||||||
|
a?: SerializedValue[],
|
||||||
|
o?: {
|
||||||
|
k: string,
|
||||||
|
v: SerializedValue,
|
||||||
|
}[],
|
||||||
|
h?: number,
|
||||||
|
id?: number,
|
||||||
|
ref?: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
type SerializedError = {
|
||||||
|
error?: {
|
||||||
|
message: string,
|
||||||
|
name: string,
|
||||||
|
stack?: string,
|
||||||
|
},
|
||||||
|
value?: SerializedValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Text node.
|
||||||
|
type TextNodeSnapshot = string;
|
||||||
|
// Subtree reference, "x snapshots ago, node #y". Could point to a text node.
|
||||||
|
// Only nodes that are not references are counted, starting from zero, using post-order traversal.
|
||||||
|
type SubtreeReferenceSnapshot = [ [number, number] ];
|
||||||
|
// Node name, and optional attributes and child nodes.
|
||||||
|
type NodeNameAttributesChildNodesSnapshot = [ string ] | [ string, Record<string, string>, ...NodeSnapshot[] ];
|
||||||
|
|
||||||
|
type NodeSnapshot =
|
||||||
|
TextNodeSnapshot |
|
||||||
|
SubtreeReferenceSnapshot |
|
||||||
|
NodeNameAttributesChildNodesSnapshot;
|
||||||
|
|
||||||
|
type ResourceOverride = {
|
||||||
|
url: string,
|
||||||
|
sha1?: string,
|
||||||
|
ref?: number
|
||||||
|
};
|
||||||
|
|
||||||
|
type FrameSnapshot = {
|
||||||
|
snapshotName?: string,
|
||||||
|
callId: string,
|
||||||
|
pageId: string,
|
||||||
|
frameId: string,
|
||||||
|
frameUrl: string,
|
||||||
|
timestamp: number,
|
||||||
|
wallTime?: number,
|
||||||
|
collectionTime: number,
|
||||||
|
doctype?: string,
|
||||||
|
html: NodeSnapshot,
|
||||||
|
resourceOverrides: ResourceOverride[],
|
||||||
|
viewport: { width: number, height: number },
|
||||||
|
isMainFrame: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
type BrowserContextEventOptions = {
|
||||||
|
baseURL?: string,
|
||||||
|
viewport?: Size,
|
||||||
|
deviceScaleFactor?: number,
|
||||||
|
isMobile?: boolean,
|
||||||
|
userAgent?: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ContextCreatedTraceEvent = {
|
||||||
|
version: number,
|
||||||
|
type: 'context-options',
|
||||||
|
origin: 'testRunner' | 'library',
|
||||||
|
browserName: string,
|
||||||
|
channel?: string,
|
||||||
|
platform: string,
|
||||||
|
wallTime: number,
|
||||||
|
monotonicTime: number,
|
||||||
|
title?: string,
|
||||||
|
options: BrowserContextEventOptions,
|
||||||
|
sdkLanguage?: Language,
|
||||||
|
testIdAttributeName?: string,
|
||||||
|
contextId?: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ScreencastFrameTraceEvent = {
|
||||||
|
type: 'screencast-frame',
|
||||||
|
pageId: string,
|
||||||
|
sha1: string,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
timestamp: number,
|
||||||
|
frameSwapWallTime?: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BeforeActionTraceEvent = {
|
||||||
|
type: 'before',
|
||||||
|
callId: string;
|
||||||
|
startTime: number;
|
||||||
|
title?: string;
|
||||||
|
class: string;
|
||||||
|
method: string;
|
||||||
|
params: Record<string, any>;
|
||||||
|
stepId?: string;
|
||||||
|
beforeSnapshot?: string;
|
||||||
|
stack?: StackFrame[];
|
||||||
|
pageId?: string;
|
||||||
|
parentId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InputActionTraceEvent = {
|
||||||
|
type: 'input',
|
||||||
|
callId: string;
|
||||||
|
inputSnapshot?: string;
|
||||||
|
point?: Point;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AfterActionTraceEventAttachment = {
|
||||||
|
name: string;
|
||||||
|
contentType: string;
|
||||||
|
path?: string;
|
||||||
|
sha1?: string;
|
||||||
|
base64?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AfterActionTraceEventAnnotation = {
|
||||||
|
type: string,
|
||||||
|
description?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AfterActionTraceEvent = {
|
||||||
|
type: 'after',
|
||||||
|
callId: string;
|
||||||
|
endTime: number;
|
||||||
|
afterSnapshot?: string;
|
||||||
|
error?: SerializedError['error'];
|
||||||
|
attachments?: AfterActionTraceEventAttachment[];
|
||||||
|
annotations?: AfterActionTraceEventAnnotation[];
|
||||||
|
result?: any;
|
||||||
|
point?: Point;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LogTraceEvent = {
|
||||||
|
type: 'log',
|
||||||
|
callId: string;
|
||||||
|
time: number;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EventTraceEvent = {
|
||||||
|
type: 'event',
|
||||||
|
time: number;
|
||||||
|
class: string;
|
||||||
|
method: string;
|
||||||
|
params: any;
|
||||||
|
pageId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ConsoleMessageTraceEvent = {
|
||||||
|
type: 'console';
|
||||||
|
time: number;
|
||||||
|
pageId?: string;
|
||||||
|
messageType: string,
|
||||||
|
text: string,
|
||||||
|
args?: { preview: string, value: any }[],
|
||||||
|
location: {
|
||||||
|
url: string,
|
||||||
|
lineNumber: number,
|
||||||
|
columnNumber: number,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ResourceSnapshotTraceEvent = {
|
||||||
|
type: 'resource-snapshot',
|
||||||
|
snapshot: ResourceSnapshot,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FrameSnapshotTraceEvent = {
|
||||||
|
type: 'frame-snapshot',
|
||||||
|
snapshot: FrameSnapshot,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ActionTraceEvent = {
|
||||||
|
type: 'action',
|
||||||
|
} & Omit<BeforeActionTraceEvent, 'type'>
|
||||||
|
& Omit<AfterActionTraceEvent, 'type'>
|
||||||
|
& Omit<InputActionTraceEvent, 'type'>;
|
||||||
|
|
||||||
|
export type StdioTraceEvent = {
|
||||||
|
type: 'stdout' | 'stderr';
|
||||||
|
timestamp: number;
|
||||||
|
text?: string;
|
||||||
|
base64?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ErrorTraceEvent = {
|
||||||
|
type: 'error';
|
||||||
|
message: string;
|
||||||
|
stack?: StackFrame[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TraceEvent =
|
||||||
|
ContextCreatedTraceEvent |
|
||||||
|
ScreencastFrameTraceEvent |
|
||||||
|
ActionTraceEvent |
|
||||||
|
BeforeActionTraceEvent |
|
||||||
|
InputActionTraceEvent |
|
||||||
|
AfterActionTraceEvent |
|
||||||
|
EventTraceEvent |
|
||||||
|
LogTraceEvent |
|
||||||
|
ConsoleMessageTraceEvent |
|
||||||
|
ResourceSnapshotTraceEvent |
|
||||||
|
FrameSnapshotTraceEvent |
|
||||||
|
StdioTraceEvent |
|
||||||
|
ErrorTraceEvent;
|
@ -128,9 +128,10 @@ export const renderAction = (
|
|||||||
time = 'Timed out';
|
time = 'Timed out';
|
||||||
else if (!isLive)
|
else if (!isLive)
|
||||||
time = '-';
|
time = '-';
|
||||||
|
const title = action.title ?? action.class.toLowerCase() + '.' + action.method;
|
||||||
return <>
|
return <>
|
||||||
<div className='action-title' title={action.apiName}>
|
<div className='action-title' title={title}>
|
||||||
<span>{action.apiName}</span>
|
<span>{title}</span>
|
||||||
{parameterString &&
|
{parameterString &&
|
||||||
(parameterString.type === 'locator' ? (
|
(parameterString.type === 'locator' ? (
|
||||||
<>
|
<>
|
||||||
|
@ -42,7 +42,7 @@ export const CallTab: React.FunctionComponent<{
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='call-tab'>
|
<div className='call-tab'>
|
||||||
<div className='call-line'>{action.apiName}</div>
|
<div className='call-line'>{action.title}</div>
|
||||||
<div className='call-section'>Time</div>
|
<div className='call-section'>Time</div>
|
||||||
<DateTimeCallLine name='start:' value={startTime} />
|
<DateTimeCallLine name='start:' value={startTime} />
|
||||||
<DateTimeCallLine name='duration:' value={renderDuration(action)} />
|
<DateTimeCallLine name='duration:' value={renderDuration(action)} />
|
||||||
|
@ -153,9 +153,9 @@ function indexModel(context: ContextEntry) {
|
|||||||
}
|
}
|
||||||
let lastNonRouteAction = undefined;
|
let lastNonRouteAction = undefined;
|
||||||
for (let i = context.actions.length - 1; i >= 0; i--) {
|
for (let i = context.actions.length - 1; i >= 0; i--) {
|
||||||
const action = context.actions[i] as any;
|
const action = context.actions[i] as ActionTraceEvent;
|
||||||
action[nextInContextSymbol] = lastNonRouteAction;
|
(action as any)[nextInContextSymbol] = lastNonRouteAction;
|
||||||
if (!action.apiName.includes('route.'))
|
if (action.class !== 'Route')
|
||||||
lastNonRouteAction = action;
|
lastNonRouteAction = action;
|
||||||
}
|
}
|
||||||
for (const event of context.events)
|
for (const event of context.events)
|
||||||
@ -249,7 +249,7 @@ function mergeActionsAndUpdateTimingSameTrace(contexts: ContextEntry[]): ActionT
|
|||||||
|
|
||||||
for (const context of libraryContexts) {
|
for (const context of libraryContexts) {
|
||||||
for (const action of context.actions) {
|
for (const action of context.actions) {
|
||||||
const key = matchByStepId ? action.stepId! : `${action.apiName}@${(action as any).wallTime}`;
|
const key = matchByStepId ? action.stepId! : `${action.title}@${(action as any).wallTime}`;
|
||||||
map.set(key, { ...action, context });
|
map.set(key, { ...action, context });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,7 +265,7 @@ function mergeActionsAndUpdateTimingSameTrace(contexts: ContextEntry[]): ActionT
|
|||||||
const nonPrimaryIdToPrimaryId = new Map<string, string>();
|
const nonPrimaryIdToPrimaryId = new Map<string, string>();
|
||||||
for (const context of testRunnerContexts) {
|
for (const context of testRunnerContexts) {
|
||||||
for (const action of context.actions) {
|
for (const action of context.actions) {
|
||||||
const key = matchByStepId ? action.callId : `${action.apiName}@${(action as any).wallTime}`;
|
const key = matchByStepId ? action.callId : `${action.title}@${(action as any).wallTime}`;
|
||||||
const existing = map.get(key);
|
const existing = map.get(key);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
nonPrimaryIdToPrimaryId.set(action.callId, existing.callId);
|
nonPrimaryIdToPrimaryId.set(action.callId, existing.callId);
|
||||||
@ -326,7 +326,7 @@ function monotonicTimeDeltaBetweenLibraryAndRunner(nonPrimaryContexts: ContextEn
|
|||||||
for (const action of context.actions) {
|
for (const action of context.actions) {
|
||||||
if (!action.startTime)
|
if (!action.startTime)
|
||||||
continue;
|
continue;
|
||||||
const key = matchByStepId ? action.callId! : `${action.apiName}@${(action as any).wallTime}`;
|
const key = matchByStepId ? action.callId! : `${action.title}@${(action as any).wallTime}`;
|
||||||
const libraryAction = libraryActions.get(key);
|
const libraryAction = libraryActions.get(key);
|
||||||
if (libraryAction)
|
if (libraryAction)
|
||||||
return action.startTime - libraryAction.startTime;
|
return action.startTime - libraryAction.startTime;
|
||||||
@ -436,6 +436,7 @@ const kRouteMethods = new Set([
|
|||||||
'browsercontext.unroute',
|
'browsercontext.unroute',
|
||||||
'browsercontext.unrouteall',
|
'browsercontext.unrouteall',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
{
|
{
|
||||||
// .NET adds async suffix.
|
// .NET adds async suffix.
|
||||||
for (const method of [...kRouteMethods])
|
for (const method of [...kRouteMethods])
|
||||||
@ -449,6 +450,3 @@ const kRouteMethods = new Set([
|
|||||||
])
|
])
|
||||||
kRouteMethods.add(method);
|
kRouteMethods.add(method);
|
||||||
}
|
}
|
||||||
export function isRouteAction(action: ActionTraceEventInContext) {
|
|
||||||
return action.class === 'Route' || kRouteMethods.has(action.apiName.toLowerCase());
|
|
||||||
}
|
|
||||||
|
@ -105,7 +105,7 @@ export const Workbench: React.FunctionComponent<{
|
|||||||
// Select the last non-after hooks item.
|
// Select the last non-after hooks item.
|
||||||
let index = model.actions.length - 1;
|
let index = model.actions.length - 1;
|
||||||
for (let i = 0; i < model.actions.length; ++i) {
|
for (let i = 0; i < model.actions.length; ++i) {
|
||||||
if (model.actions[i].apiName === 'After Hooks' && i) {
|
if (model.actions[i].title === 'After Hooks' && i) {
|
||||||
index = i - 1;
|
index = i - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ import type { Point, SerializedError, StackFrame } from '@protocol/channels';
|
|||||||
|
|
||||||
export type Size = { width: number, height: number };
|
export type Size = { width: number, height: number };
|
||||||
|
|
||||||
// Make sure you add _modernize_N_to_N1(event: any) to traceModel.ts.
|
// Make sure you add _modernize_N_to_N1(event: any) to traceModernizer.ts.
|
||||||
export type VERSION = 7;
|
export type VERSION = 8;
|
||||||
|
|
||||||
export type BrowserContextEventOptions = {
|
export type BrowserContextEventOptions = {
|
||||||
baseURL?: string,
|
baseURL?: string,
|
||||||
@ -61,7 +61,7 @@ export type BeforeActionTraceEvent = {
|
|||||||
type: 'before',
|
type: 'before',
|
||||||
callId: string;
|
callId: string;
|
||||||
startTime: number;
|
startTime: number;
|
||||||
apiName: string;
|
title?: string;
|
||||||
class: string;
|
class: string;
|
||||||
method: string;
|
method: string;
|
||||||
params: Record<string, any>;
|
params: Record<string, any>;
|
||||||
|
@ -151,13 +151,13 @@ export async function parseTraceRaw(file: string): Promise<{ events: any[], reso
|
|||||||
return {
|
return {
|
||||||
events,
|
events,
|
||||||
resources,
|
resources,
|
||||||
actions: actionObjects.map(a => a.apiName),
|
actions: actionObjects.map(a => a.title ?? a.class.toLowerCase() + '.' + a.method),
|
||||||
actionObjects,
|
actionObjects,
|
||||||
stacks,
|
stacks,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function parseTrace(file: string): Promise<{ resources: Map<string, Buffer>, events: (EventTraceEvent | ConsoleMessageTraceEvent)[], actions: ActionTraceEvent[], apiNames: string[], traceModel: TraceModel, model: MultiTraceModel, actionTree: string[], errors: string[] }> {
|
export async function parseTrace(file: string): Promise<{ resources: Map<string, Buffer>, events: (EventTraceEvent | ConsoleMessageTraceEvent)[], actions: ActionTraceEvent[], titles: string[], traceModel: TraceModel, model: MultiTraceModel, actionTree: string[], errors: string[] }> {
|
||||||
const backend = new TraceBackend(file);
|
const backend = new TraceBackend(file);
|
||||||
const traceModel = new TraceModel();
|
const traceModel = new TraceModel();
|
||||||
await traceModel.load(backend, () => {});
|
await traceModel.load(backend, () => {});
|
||||||
@ -165,13 +165,13 @@ export async function parseTrace(file: string): Promise<{ resources: Map<string,
|
|||||||
const { rootItem } = buildActionTree(model.actions);
|
const { rootItem } = buildActionTree(model.actions);
|
||||||
const actionTree: string[] = [];
|
const actionTree: string[] = [];
|
||||||
const visit = (actionItem: ActionTreeItem, indent: string) => {
|
const visit = (actionItem: ActionTreeItem, indent: string) => {
|
||||||
actionTree.push(`${indent}${actionItem.action?.apiName || actionItem.id}`);
|
actionTree.push(`${indent}${actionItem.action?.title || actionItem.id}`);
|
||||||
for (const child of actionItem.children)
|
for (const child of actionItem.children)
|
||||||
visit(child, indent + ' ');
|
visit(child, indent + ' ');
|
||||||
};
|
};
|
||||||
rootItem.children.forEach(a => visit(a, ''));
|
rootItem.children.forEach(a => visit(a, ''));
|
||||||
return {
|
return {
|
||||||
apiNames: model.actions.map(a => a.apiName),
|
titles: model.actions.map(a => a.title ?? a.class.toLowerCase() + '.' + a.method),
|
||||||
resources: backend.entries,
|
resources: backend.entries,
|
||||||
actions: model.actions,
|
actions: model.actions,
|
||||||
events: model.events,
|
events: model.events,
|
||||||
|
@ -64,7 +64,7 @@ test('should collect trace with resources, but no js', async ({ context, page, s
|
|||||||
expect(script.snapshot.response.content._sha1).toBe(undefined);
|
expect(script.snapshot.response.content._sha1).toBe(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should use the correct apiName for event driven callbacks', async ({ context, page, server }, testInfo) => {
|
test('should use the correct title for event driven callbacks', async ({ context, page, server }, testInfo) => {
|
||||||
await context.tracing.start();
|
await context.tracing.start();
|
||||||
// route.* calls should not be included in the trace
|
// route.* calls should not be included in the trace
|
||||||
await page.route('**/empty.html', route => route.continue());
|
await page.route('**/empty.html', route => route.continue());
|
||||||
@ -125,7 +125,7 @@ test('can call tracing.group/groupEnd at any time and auto-close', async ({ cont
|
|||||||
const { events } = await parseTraceRaw(testInfo.outputPath('trace.zip'));
|
const { events } = await parseTraceRaw(testInfo.outputPath('trace.zip'));
|
||||||
const groups = events.filter(e => e.method === 'tracingGroup');
|
const groups = events.filter(e => e.method === 'tracingGroup');
|
||||||
expect(groups).toHaveLength(1);
|
expect(groups).toHaveLength(1);
|
||||||
expect(groups[0].apiName).toBe('actual');
|
expect(groups[0].title).toBe('actual');
|
||||||
expect(events.some(e => e.type === 'after' && e.callId === groups[0].callId)).toBe(true);
|
expect(events.some(e => e.type === 'after' && e.callId === groups[0].callId)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ test('should not include buffers in the trace', async ({ context, page, server }
|
|||||||
await page.screenshot();
|
await page.screenshot();
|
||||||
await context.tracing.stop({ path: testInfo.outputPath('trace.zip') });
|
await context.tracing.stop({ path: testInfo.outputPath('trace.zip') });
|
||||||
const { actionObjects } = await parseTraceRaw(testInfo.outputPath('trace.zip'));
|
const { actionObjects } = await parseTraceRaw(testInfo.outputPath('trace.zip'));
|
||||||
const screenshotEvent = actionObjects.find(a => a.apiName === 'page.screenshot');
|
const screenshotEvent = actionObjects.find(a => a.title === 'page.screenshot');
|
||||||
expect(screenshotEvent.beforeSnapshot).toBeTruthy();
|
expect(screenshotEvent.beforeSnapshot).toBeTruthy();
|
||||||
expect(screenshotEvent.afterSnapshot).toBeTruthy();
|
expect(screenshotEvent.afterSnapshot).toBeTruthy();
|
||||||
expect(screenshotEvent.result).toEqual({
|
expect(screenshotEvent.result).toEqual({
|
||||||
@ -166,7 +166,7 @@ test('should include context API requests', async ({ browserName, context, page,
|
|||||||
await page.request.post(server.PREFIX + '/simple.json', { data: { foo: 'bar' } });
|
await page.request.post(server.PREFIX + '/simple.json', { data: { foo: 'bar' } });
|
||||||
await context.tracing.stop({ path: testInfo.outputPath('trace.zip') });
|
await context.tracing.stop({ path: testInfo.outputPath('trace.zip') });
|
||||||
const { events } = await parseTraceRaw(testInfo.outputPath('trace.zip'));
|
const { events } = await parseTraceRaw(testInfo.outputPath('trace.zip'));
|
||||||
const postEvent = events.find(e => e.apiName === 'apiRequestContext.post');
|
const postEvent = events.find(e => e.title === 'apiRequestContext.post');
|
||||||
expect(postEvent).toBeTruthy();
|
expect(postEvent).toBeTruthy();
|
||||||
const harEntry = events.find(e => e.type === 'resource-snapshot');
|
const harEntry = events.find(e => e.type === 'resource-snapshot');
|
||||||
expect(harEntry).toBeTruthy();
|
expect(harEntry).toBeTruthy();
|
||||||
@ -484,7 +484,7 @@ test('should include interrupted actions', async ({ context, page, server }, tes
|
|||||||
await context.close();
|
await context.close();
|
||||||
|
|
||||||
const { events } = await parseTraceRaw(testInfo.outputPath('trace.zip'));
|
const { events } = await parseTraceRaw(testInfo.outputPath('trace.zip'));
|
||||||
const clickEvent = events.find(e => e.apiName === 'page.click');
|
const clickEvent = events.find(e => e.title === 'page.click');
|
||||||
expect(clickEvent).toBeTruthy();
|
expect(clickEvent).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -605,7 +605,7 @@ test('should hide internal stack frames', async ({ context, page }, testInfo) =>
|
|||||||
await context.tracing.stop({ path: tracePath });
|
await context.tracing.stop({ path: tracePath });
|
||||||
|
|
||||||
const trace = await parseTraceRaw(tracePath);
|
const trace = await parseTraceRaw(tracePath);
|
||||||
const actions = trace.actionObjects.filter(a => !a.apiName.startsWith('tracing.'));
|
const actions = trace.actionObjects.filter(a => a.class !== 'Tracing');
|
||||||
expect(actions).toHaveLength(4);
|
expect(actions).toHaveLength(4);
|
||||||
for (const action of actions)
|
for (const action of actions)
|
||||||
expect(relativeStack(action, trace.stacks)).toEqual(['tracing.spec.ts']);
|
expect(relativeStack(action, trace.stacks)).toEqual(['tracing.spec.ts']);
|
||||||
@ -626,7 +626,7 @@ test('should hide internal stack frames in expect', async ({ context, page }, te
|
|||||||
await context.tracing.stop({ path: tracePath });
|
await context.tracing.stop({ path: tracePath });
|
||||||
|
|
||||||
const trace = await parseTraceRaw(tracePath);
|
const trace = await parseTraceRaw(tracePath);
|
||||||
const actions = trace.actionObjects.filter(a => !a.apiName.startsWith('tracing.'));
|
const actions = trace.actionObjects.filter(a => a.class !== 'Tracing');
|
||||||
expect(actions).toHaveLength(5);
|
expect(actions).toHaveLength(5);
|
||||||
for (const action of actions)
|
for (const action of actions)
|
||||||
expect(relativeStack(action, trace.stacks)).toEqual(['tracing.spec.ts']);
|
expect(relativeStack(action, trace.stacks)).toEqual(['tracing.spec.ts']);
|
||||||
@ -813,7 +813,7 @@ test('should not emit after w/o before', async ({ browserType, mode }, testInfo)
|
|||||||
return {
|
return {
|
||||||
type: e.type,
|
type: e.type,
|
||||||
callId: +e.callId.split('@')[1] - minCallId,
|
callId: +e.callId.split('@')[1] - minCallId,
|
||||||
apiName: e.apiName,
|
title: e.title,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -826,17 +826,17 @@ test('should not emit after w/o before', async ({ browserType, mode }, testInfo)
|
|||||||
{
|
{
|
||||||
type: 'before',
|
type: 'before',
|
||||||
callId: expect.any(Number),
|
callId: expect.any(Number),
|
||||||
apiName: 'page.evaluate'
|
title: 'page.evaluate'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'before',
|
type: 'before',
|
||||||
callId: expect.any(Number),
|
callId: expect.any(Number),
|
||||||
apiName: 'page.waitForEvent'
|
title: 'page.waitForEvent'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'after',
|
type: 'after',
|
||||||
callId: expect.any(Number),
|
callId: expect.any(Number),
|
||||||
apiName: undefined,
|
title: undefined,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
call1 = sanitized[0].callId;
|
call1 = sanitized[0].callId;
|
||||||
@ -852,12 +852,12 @@ test('should not emit after w/o before', async ({ browserType, mode }, testInfo)
|
|||||||
{
|
{
|
||||||
type: 'before',
|
type: 'before',
|
||||||
callId: expect.any(Number),
|
callId: expect.any(Number),
|
||||||
apiName: 'page.evaluateHandle'
|
title: 'page.evaluateHandle'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'after',
|
type: 'after',
|
||||||
callId: expect.any(Number),
|
callId: expect.any(Number),
|
||||||
apiName: undefined
|
title: undefined
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
call2before = sanitized[0].callId;
|
call2before = sanitized[0].callId;
|
||||||
|
@ -213,7 +213,7 @@ test('should record trace', async ({ runInlineTest }) => {
|
|||||||
expect(fs.existsSync(test.info().outputPath('test-results', 'a-pass', 'trace.zip'))).toBe(false);
|
expect(fs.existsSync(test.info().outputPath('test-results', 'a-pass', 'trace.zip'))).toBe(false);
|
||||||
|
|
||||||
const trace = await parseTrace(test.info().outputPath('test-results', 'a-fail', 'trace.zip'));
|
const trace = await parseTrace(test.info().outputPath('test-results', 'a-fail', 'trace.zip'));
|
||||||
expect(trace.apiNames).toEqual([
|
expect(trace.titles).toEqual([
|
||||||
'Before Hooks',
|
'Before Hooks',
|
||||||
'fixture: context',
|
'fixture: context',
|
||||||
'browser.newContext',
|
'browser.newContext',
|
||||||
|
@ -478,14 +478,14 @@ test('should reset tracing', async ({ runInlineTest }, testInfo) => {
|
|||||||
expect(result.passed).toBe(2);
|
expect(result.passed).toBe(2);
|
||||||
|
|
||||||
const trace1 = await parseTrace(traceFile1);
|
const trace1 = await parseTrace(traceFile1);
|
||||||
expect(trace1.apiNames).toEqual([
|
expect(trace1.titles).toEqual([
|
||||||
'page.setContent',
|
'page.setContent',
|
||||||
'page.click',
|
'page.click',
|
||||||
]);
|
]);
|
||||||
expect(trace1.traceModel.storage().snapshotsForTest().length).toBeGreaterThan(0);
|
expect(trace1.traceModel.storage().snapshotsForTest().length).toBeGreaterThan(0);
|
||||||
|
|
||||||
const trace2 = await parseTrace(traceFile2);
|
const trace2 = await parseTrace(traceFile2);
|
||||||
expect(trace2.apiNames).toEqual([
|
expect(trace2.titles).toEqual([
|
||||||
'page.setContent',
|
'page.setContent',
|
||||||
'page.fill',
|
'page.fill',
|
||||||
'locator.click',
|
'locator.click',
|
||||||
|
@ -465,7 +465,7 @@ test(`trace:retain-on-failure should create trace if context is closed before fa
|
|||||||
}, { trace: 'retain-on-failure' });
|
}, { trace: 'retain-on-failure' });
|
||||||
const tracePath = test.info().outputPath('test-results', 'a-passing-test', 'trace.zip');
|
const tracePath = test.info().outputPath('test-results', 'a-passing-test', 'trace.zip');
|
||||||
const trace = await parseTrace(tracePath);
|
const trace = await parseTrace(tracePath);
|
||||||
expect(trace.apiNames).toContain('page.goto');
|
expect(trace.titles).toContain('page.goto');
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -487,7 +487,7 @@ test(`trace:retain-on-failure should create trace if context is closed before fa
|
|||||||
}, { trace: 'retain-on-failure' });
|
}, { trace: 'retain-on-failure' });
|
||||||
const tracePath = test.info().outputPath('test-results', 'a-passing-test', 'trace.zip');
|
const tracePath = test.info().outputPath('test-results', 'a-passing-test', 'trace.zip');
|
||||||
const trace = await parseTrace(tracePath);
|
const trace = await parseTrace(tracePath);
|
||||||
expect(trace.apiNames).toContain('page.goto');
|
expect(trace.titles).toContain('page.goto');
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -507,7 +507,7 @@ test(`trace:retain-on-failure should create trace if request context is disposed
|
|||||||
}, { trace: 'retain-on-failure' });
|
}, { trace: 'retain-on-failure' });
|
||||||
const tracePath = test.info().outputPath('test-results', 'a-passing-test', 'trace.zip');
|
const tracePath = test.info().outputPath('test-results', 'a-passing-test', 'trace.zip');
|
||||||
const trace = await parseTrace(tracePath);
|
const trace = await parseTrace(tracePath);
|
||||||
expect(trace.apiNames).toContain('apiRequestContext.get');
|
expect(trace.titles).toContain('apiRequestContext.get');
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -528,7 +528,7 @@ test('should include attachments by default', async ({ runInlineTest, server },
|
|||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.passed).toBe(1);
|
expect(result.passed).toBe(1);
|
||||||
const trace = await parseTrace(testInfo.outputPath('test-results', 'a-pass', 'trace.zip'));
|
const trace = await parseTrace(testInfo.outputPath('test-results', 'a-pass', 'trace.zip'));
|
||||||
expect(trace.apiNames).toEqual([
|
expect(trace.titles).toEqual([
|
||||||
'Before Hooks',
|
'Before Hooks',
|
||||||
`attach "foo"`,
|
`attach "foo"`,
|
||||||
'After Hooks',
|
'After Hooks',
|
||||||
@ -558,7 +558,7 @@ test('should opt out of attachments', async ({ runInlineTest, server }, testInfo
|
|||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.passed).toBe(1);
|
expect(result.passed).toBe(1);
|
||||||
const trace = await parseTrace(testInfo.outputPath('test-results', 'a-pass', 'trace.zip'));
|
const trace = await parseTrace(testInfo.outputPath('test-results', 'a-pass', 'trace.zip'));
|
||||||
expect(trace.apiNames).toEqual([
|
expect(trace.titles).toEqual([
|
||||||
'Before Hooks',
|
'Before Hooks',
|
||||||
`attach "foo"`,
|
`attach "foo"`,
|
||||||
'After Hooks',
|
'After Hooks',
|
||||||
@ -729,7 +729,7 @@ test('should not throw when attachment is missing', async ({ runInlineTest }, te
|
|||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.passed).toBe(1);
|
expect(result.passed).toBe(1);
|
||||||
const trace = await parseTrace(testInfo.outputPath('test-results', 'a-passes', 'trace.zip'));
|
const trace = await parseTrace(testInfo.outputPath('test-results', 'a-passes', 'trace.zip'));
|
||||||
expect(trace.apiNames).toContain('Attach "screenshot"');
|
expect(trace.titles).toContain('Attach "screenshot"');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not throw when screenshot on failure fails', async ({ runInlineTest, server }, testInfo) => {
|
test('should not throw when screenshot on failure fails', async ({ runInlineTest, server }, testInfo) => {
|
||||||
@ -1102,7 +1102,7 @@ test('trace:retain-on-first-failure should create trace but only on first failur
|
|||||||
|
|
||||||
const tracePath = test.info().outputPath('test-results', 'a-fail', 'trace.zip');
|
const tracePath = test.info().outputPath('test-results', 'a-fail', 'trace.zip');
|
||||||
const trace = await parseTrace(tracePath);
|
const trace = await parseTrace(tracePath);
|
||||||
expect(trace.apiNames).toContain('page.goto');
|
expect(trace.titles).toContain('page.goto');
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1119,7 +1119,7 @@ test('trace:retain-on-first-failure should create trace if context is closed bef
|
|||||||
}, { trace: 'retain-on-first-failure' });
|
}, { trace: 'retain-on-first-failure' });
|
||||||
const tracePath = test.info().outputPath('test-results', 'a-fail', 'trace.zip');
|
const tracePath = test.info().outputPath('test-results', 'a-fail', 'trace.zip');
|
||||||
const trace = await parseTrace(tracePath);
|
const trace = await parseTrace(tracePath);
|
||||||
expect(trace.apiNames).toContain('page.goto');
|
expect(trace.titles).toContain('page.goto');
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1138,7 +1138,7 @@ test('trace:retain-on-first-failure should create trace if context is closed bef
|
|||||||
}, { trace: 'retain-on-first-failure' });
|
}, { trace: 'retain-on-first-failure' });
|
||||||
const tracePath = test.info().outputPath('test-results', 'a-fail', 'trace.zip');
|
const tracePath = test.info().outputPath('test-results', 'a-fail', 'trace.zip');
|
||||||
const trace = await parseTrace(tracePath);
|
const trace = await parseTrace(tracePath);
|
||||||
expect(trace.apiNames).toContain('page.goto');
|
expect(trace.titles).toContain('page.goto');
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1155,7 +1155,7 @@ test('trace:retain-on-first-failure should create trace if request context is di
|
|||||||
}, { trace: 'retain-on-first-failure' });
|
}, { trace: 'retain-on-first-failure' });
|
||||||
const tracePath = test.info().outputPath('test-results', 'a-fail', 'trace.zip');
|
const tracePath = test.info().outputPath('test-results', 'a-fail', 'trace.zip');
|
||||||
const trace = await parseTrace(tracePath);
|
const trace = await parseTrace(tracePath);
|
||||||
expect(trace.apiNames).toContain('apiRequestContext.get');
|
expect(trace.titles).toContain('apiRequestContext.get');
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1348,13 +1348,13 @@ test('should record trace snapshot for more obscure commands', async ({ runInlin
|
|||||||
const snapshots = trace.traceModel.storage();
|
const snapshots = trace.traceModel.storage();
|
||||||
const snapshotFrameOrPageId = snapshots.snapshotsForTest()[0];
|
const snapshotFrameOrPageId = snapshots.snapshotsForTest()[0];
|
||||||
|
|
||||||
const countAction = trace.actions.find(a => a.apiName === 'locator.count');
|
const countAction = trace.actions.find(a => a.title === 'locator.count');
|
||||||
expect(countAction.beforeSnapshot).toBeTruthy();
|
expect(countAction.beforeSnapshot).toBeTruthy();
|
||||||
expect(countAction.afterSnapshot).toBeTruthy();
|
expect(countAction.afterSnapshot).toBeTruthy();
|
||||||
expect(snapshots.snapshotByName(snapshotFrameOrPageId, countAction.beforeSnapshot)).toBeTruthy();
|
expect(snapshots.snapshotByName(snapshotFrameOrPageId, countAction.beforeSnapshot)).toBeTruthy();
|
||||||
expect(snapshots.snapshotByName(snapshotFrameOrPageId, countAction.afterSnapshot)).toBeTruthy();
|
expect(snapshots.snapshotByName(snapshotFrameOrPageId, countAction.afterSnapshot)).toBeTruthy();
|
||||||
|
|
||||||
const boundingBoxAction = trace.actions.find(a => a.apiName === 'locator.boundingBox');
|
const boundingBoxAction = trace.actions.find(a => a.title === 'locator.boundingBox');
|
||||||
expect(boundingBoxAction.beforeSnapshot).toBeTruthy();
|
expect(boundingBoxAction.beforeSnapshot).toBeTruthy();
|
||||||
expect(boundingBoxAction.afterSnapshot).toBeTruthy();
|
expect(boundingBoxAction.afterSnapshot).toBeTruthy();
|
||||||
expect(snapshots.snapshotByName(snapshotFrameOrPageId, boundingBoxAction.beforeSnapshot)).toBeTruthy();
|
expect(snapshots.snapshotByName(snapshotFrameOrPageId, boundingBoxAction.beforeSnapshot)).toBeTruthy();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user