From bccd4c8906aa6466ff865644a177f35e45a1aff4 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Mon, 18 Oct 2021 21:14:01 -0800 Subject: [PATCH] feat(api): expose step location UI (#9605) --- .../src/web/htmlReport/htmlReport.css | 1 - .../src/web/htmlReport/htmlReport.tsx | 7 ++++--- packages/playwright-test/src/reporters/base.ts | 8 ++++---- packages/playwright-test/src/reporters/html.ts | 6 ++++-- packages/playwright-test/src/reporters/raw.ts | 18 ++++++++++-------- packages/playwright-test/src/workerRunner.ts | 5 +++-- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/packages/playwright-core/src/web/htmlReport/htmlReport.css b/packages/playwright-core/src/web/htmlReport/htmlReport.css index 511e09b1a2..ca747495e0 100644 --- a/packages/playwright-core/src/web/htmlReport/htmlReport.css +++ b/packages/playwright-core/src/web/htmlReport/htmlReport.css @@ -90,7 +90,6 @@ svg { } .chip-body > .tree-item { - max-width: 600px; line-height: 38px; } diff --git a/packages/playwright-core/src/web/htmlReport/htmlReport.tsx b/packages/playwright-core/src/web/htmlReport/htmlReport.tsx index 070a226cf8..6bc97920b9 100644 --- a/packages/playwright-core/src/web/htmlReport/htmlReport.tsx +++ b/packages/playwright-core/src/web/htmlReport/htmlReport.tsx @@ -217,10 +217,11 @@ const StepTreeItem: React.FC<{ {msToString(step.duration)} {statusIcon(step.error ? 'failed' : 'passed')} {step.title} - } loadChildren={step.steps.length + (step.error ? 1 : 0) ? () => { + {step.location && — {step.location.file}:{step.location.line}} + } loadChildren={step.steps.length + (step.snippet ? 1 : 0) ? () => { const children = step.steps.map((s, i) => ); - if (step.error) - children.unshift(); + if (step.snippet) + children.unshift(); return children; } : undefined} depth={depth}>; }; diff --git a/packages/playwright-test/src/reporters/base.ts b/packages/playwright-test/src/reporters/base.ts index 34b7334822..84b2e5e2a5 100644 --- a/packages/playwright-test/src/reporters/base.ts +++ b/packages/playwright-test/src/reporters/base.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { codeFrameColumns } from '@babel/code-frame'; +import { BabelCodeFrameOptions, codeFrameColumns } from '@babel/code-frame'; import colors from 'colors/safe'; import fs from 'fs'; import milliseconds from 'ms'; @@ -337,7 +337,7 @@ export function formatError(error: TestError, highlightCode: boolean, file?: str positionInFile = position; tokens.push(message); - const codeFrame = generateCodeFrame(highlightCode, file, position); + const codeFrame = generateCodeFrame({ highlightCode }, file, position); if (codeFrame) { tokens.push(''); tokens.push(codeFrame); @@ -365,7 +365,7 @@ function indent(lines: string, tab: string) { return lines.replace(/^(?=.+$)/gm, tab); } -function generateCodeFrame(highlightCode: boolean, file?: string, position?: PositionInFile): string | undefined { +export function generateCodeFrame(options: BabelCodeFrameOptions, file?: string, position?: PositionInFile): string | undefined { if (!position || !file) return; @@ -373,7 +373,7 @@ function generateCodeFrame(highlightCode: boolean, file?: string, position?: Pos const codeFrame = codeFrameColumns( source, { start: position }, - { highlightCode } + options ); return codeFrame; diff --git a/packages/playwright-test/src/reporters/html.ts b/packages/playwright-test/src/reporters/html.ts index fd320e359e..c82f78b921 100644 --- a/packages/playwright-test/src/reporters/html.ts +++ b/packages/playwright-test/src/reporters/html.ts @@ -90,7 +90,8 @@ export type TestStep = { title: string; startTime: string; duration: number; - log?: string[]; + location?: Location; + snippet?: string; error?: string; steps: TestStep[]; }; @@ -365,8 +366,9 @@ class HtmlBuilder { title: step.title, startTime: step.startTime, duration: step.duration, + snippet: step.snippet, steps: step.steps.map(s => this._createTestStep(s)), - log: step.log, + location: step.location, error: step.error }; } diff --git a/packages/playwright-test/src/reporters/raw.ts b/packages/playwright-test/src/reporters/raw.ts index be0cb49bb3..9c3b789509 100644 --- a/packages/playwright-test/src/reporters/raw.ts +++ b/packages/playwright-test/src/reporters/raw.ts @@ -20,7 +20,7 @@ import { FullProject } from '../types'; import { FullConfig, Location, Suite, TestCase, TestResult, TestStatus, TestStep } from '../../types/testReporter'; import { assert, calculateSha1 } from 'playwright-core/src/utils/utils'; import { sanitizeForFilePath } from '../util'; -import { formatResultFailure } from './base'; +import { formatResultFailure, generateCodeFrame } from './base'; import { toPosixPath, serializePatterns } from './json'; export type JsonLocation = Location; @@ -93,7 +93,8 @@ export type JsonTestStep = { duration: number; error?: JsonError; steps: JsonTestStep[]; - log?: string[]; + location?: Location; + snippet?: string; }; class RawReporter { @@ -159,18 +160,18 @@ class RawReporter { fileId, location, suites: suite.suites.map(s => this._serializeSuite(s)), - tests: suite.tests.map(t => this._serializeTest(t, fileId, location.file)), + tests: suite.tests.map(t => this._serializeTest(t, fileId)), }; } - private _serializeTest(test: TestCase, fileId: string, fileName: string): JsonTestCase { + private _serializeTest(test: TestCase, fileId: string): JsonTestCase { const [, projectName, , ...titles] = test.titlePath(); const testIdExpression = `project:${projectName}|path:${titles.join('>')}`; const testId = fileId + '-' + calculateSha1(testIdExpression); return { testId, title: test.title, - location: this._relativeLocation(test.location), + location: this._relativeLocation(test.location)!, expectedStatus: test.expectedStatus, timeout: test.timeout, annotations: test.annotations, @@ -202,8 +203,9 @@ class RawReporter { startTime: step.startTime.toISOString(), duration: step.duration, error: step.error?.message, + location: this._relativeLocation(step.location), steps: this._serializeSteps(test, step.steps), - log: step.data.log || undefined, + snippet: step.location ? generateCodeFrame({ highlightCode: true, linesBelow: 1, linesAbove: 1 }, step.location.file, step.location) : undefined }; }); } @@ -248,9 +250,9 @@ class RawReporter { }; } - private _relativeLocation(location: Location | undefined): Location { + private _relativeLocation(location: Location | undefined): Location | undefined { if (!location) - return { file: '', line: 0, column: 0 }; + return undefined; const file = toPosixPath(path.relative(this.config.rootDir, location.file)); return { file, diff --git a/packages/playwright-test/src/workerRunner.ts b/packages/playwright-test/src/workerRunner.ts index b63aa87575..bfc9d693ff 100644 --- a/packages/playwright-test/src/workerRunner.ts +++ b/packages/playwright-test/src/workerRunner.ts @@ -306,8 +306,9 @@ export class WorkerRunner extends EventEmitter { this.emit('stepEnd', payload); } }; - // Sanitize location that comes from userland. - const location = data.location ? { file: data.location.file, line: data.location.line, column: data.location.column } : undefined; + const hasLocation = data.location && !data.location.file.includes('@playwright'); + // Sanitize location that comes from user land, it might have extra properties. + const location = data.location && hasLocation ? { file: data.location.file, line: data.location.line, column: data.location.column } : undefined; const payload: StepBeginPayload = { testId, stepId,