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,