feat(trace-viewer): render wall time for each action (#9982)

This commit is contained in:
Pavel Feldman 2021-11-02 11:16:12 -08:00 committed by GitHub
parent ad4632935f
commit 6a30c90590
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 33 additions and 22 deletions

View file

@ -154,6 +154,7 @@ export class DispatcherConnection {
objectId: sdkObject?.guid,
pageId: sdkObject?.attribution?.page?.guid,
frameId: sdkObject?.attribution?.frame?.guid,
wallTime: Date.now(),
startTime: monotonicTime(),
endTime: 0,
type,
@ -228,6 +229,7 @@ export class DispatcherConnection {
objectId: sdkObject?.guid,
pageId: sdkObject?.attribution?.page?.guid,
frameId: sdkObject?.attribution?.frame?.guid,
wallTime: Date.now(),
startTime: monotonicTime(),
endTime: 0,
type: dispatcher._type,

View file

@ -18,6 +18,7 @@ import { Point, StackFrame, SerializedError } from './channels';
export type CallMetadata = {
id: string;
wallTime: number;
startTime: number;
endTime: number;
pauseStartTime?: number;

View file

@ -88,6 +88,7 @@ export function createInstrumentation(): Instrumentation {
export function internalCallMetadata(): CallMetadata {
return {
id: '',
wallTime: 0,
startTime: 0,
endTime: 0,
type: 'Internal',

View file

@ -440,6 +440,7 @@ class ContextRecorder extends EventEmitter {
objectId: frame.guid,
pageId: frame._page.guid,
frameId: frame.guid,
wallTime: Date.now(),
startTime: monotonicTime(),
endTime: 0,
type: 'Frame',

View file

@ -65,7 +65,7 @@
}
.action-duration {
margin-left: 4px;
margin: 0 4px;
color: var(--gray);
}

View file

@ -90,8 +90,8 @@ export const ActionList: React.FC<ActionListProps> = ({
<span>{metadata.apiName}</span>
{metadata.params.selector && <div className='action-selector' title={metadata.params.selector}>{metadata.params.selector}</div>}
{metadata.method === 'goto' && metadata.params.url && <div className='action-url' title={metadata.params.url}>{metadata.params.url}</div>}
<span className='action-duration'> {metadata.endTime ? msToString(metadata.endTime - metadata.startTime) : 'Timed Out'}</span>
</div>
<div className='action-duration' style={{ flex: 'none' }}>{metadata.endTime ? msToString(metadata.endTime - metadata.startTime) : 'Timed Out'}</div>
<div className='action-icons' onClick={() => setSelectedTab('console')}>
{!!errors && <div className='action-icon'><span className={'codicon codicon-error'}></span><span className="action-icon-value">{errors}</span></div>}
{!!warnings && <div className='action-icon'><span className={'codicon codicon-warning'}></span><span className="action-icon-value">{warnings}</span></div>}

View file

@ -54,10 +54,7 @@
overflow: hidden;
}
.call-duration {
color: var(--gray);
}
.call-line .datetime,
.call-line .string {
color: var(--orange);
}

View file

@ -32,12 +32,19 @@ export const CallTab: React.FunctionComponent<{
// Strip down the waitForEventInfo data, we never need it.
delete params.info;
const paramKeys = Object.keys(params);
const wallTime = new Date(action.metadata.wallTime).toLocaleString();
const duration = msToString(action.metadata.endTime - action.metadata.startTime);
return <div className='call-tab'>
<div className='call-error' key='error' hidden={!error}>
<div className='codicon codicon-issues'/>
{error}
</div>
<div className='call-line'>{action.metadata.apiName} <span className='call-duration'> {msToString(action.metadata.endTime - action.metadata.startTime)}</span></div>
<div className='call-line'>{action.metadata.apiName}</div>
{<>
<div className='call-section'>Time</div>
<div className='call-line'>wall time: <span className='datetime' title={wallTime}>{wallTime}</span></div>
<div className='call-line'>duration: <span className='datetime' title={duration}>{duration}</span></div>
</>}
{ !!paramKeys.length && <div className='call-section'>Parameters</div> }
{
!!paramKeys.length && paramKeys.map((name, index) => renderLine(action.metadata, name, params[name], 'param-' + index))

View file

@ -60,7 +60,7 @@ class LineReporter extends BaseReporter {
const title = `[${++this._current}/${this._total}] ${formatTestTitle(this.config, test)}`.substring(0, width);
process.stdout.write(`\u001B[1A\u001B[2K${title}\n`);
if (!this._omitFailures && !this.willRetry(test) && (test.outcome() === 'flaky' || test.outcome() === 'unexpected')) {
if (!this.willRetry(test) && (test.outcome() === 'flaky' || test.outcome() === 'unexpected')) {
process.stdout.write(`\u001B[1A\u001B[2K`);
console.log(formatFailure(this.config, test, {
index: ++this._failures

View file

@ -180,19 +180,19 @@ test('should show empty trace viewer', async ({ showTraceViewer }, testInfo) =>
test('should open simple trace viewer', async ({ showTraceViewer }) => {
const traceViewer = await showTraceViewer(traceFile);
await expect(traceViewer.actionTitles).toHaveText([
/browserContext.newPage— [\d.ms]+/,
/page.gotodata:text\/html,<html>Hello world<\/html>— [\d.ms]+/,
/page.setContent— [\d.ms]+/,
/expect.toHaveTextbutton— [\d.ms]+/,
/page.evaluate— [\d.ms]+/,
/page.click"Click"— [\d.ms]+/,
/page.waitForEvent— [\d.ms]+/,
/page.route— [\d.ms]+/,
/page.waitForNavigation— [\d.ms]+/,
/page.waitForTimeout— [\d.ms]+/,
/page.gotohttp:\/\/localhost:\d+\/frames\/frame.html— [\d.ms]+/,
/route.continue— [\d.ms]+/,
/page.setViewportSize— [\d.ms]+/,
/browserContext.newPage/,
/page.gotodata:text\/html,<html>Hello world<\/html>/,
/page.setContent/,
/expect.toHaveTextbutton/,
/page.evaluate/,
/page.click"Click"/,
/page.waitForEvent/,
/page.route/,
/page.waitForNavigation/,
/page.waitForTimeout/,
/page.gotohttp:\/\/localhost:\d+\/frames\/frame.html/,
/route.continue/,
/page.setViewportSize/,
]);
});
@ -235,7 +235,9 @@ test('should show params and return value', async ({ showTraceViewer, browserNam
const traceViewer = await showTraceViewer(traceFile);
await traceViewer.selectAction('page.evaluate');
await expect(traceViewer.callLines).toHaveText([
/page.evaluate — [\d.ms]+/,
/page.evaluate/,
/wall time: [0-9/:,APM ]+/,
/duration: [\d]+ms/,
'expression: "({↵ a↵ }) => {↵ console.log(\'Info\');↵ console.warn(\'Warning\');↵ con…"',
'isFunction: true',
'arg: {"a":"paramA","b":4}',