diff --git a/packages/playwright-test/src/isomorphic/teleReceiver.ts b/packages/playwright-test/src/isomorphic/teleReceiver.ts index 4402bfb8eb..f3e86b9d7a 100644 --- a/packages/playwright-test/src/isomorphic/teleReceiver.ts +++ b/packages/playwright-test/src/isomorphic/teleReceiver.ts @@ -104,11 +104,14 @@ export type JsonTestStepEnd = { export class TeleReporterReceiver { private _rootSuite: TeleSuite; + private _pathSeparator: string; private _reporter: Reporter; private _tests = new Map(); + private _rootDir!: string; - constructor(reporter: Reporter) { + constructor(pathSeparator: string, reporter: Reporter) { this._rootSuite = new TeleSuite('', 'root'); + this._pathSeparator = pathSeparator; this._reporter = reporter; } @@ -149,6 +152,7 @@ export class TeleReporterReceiver { } private _onBegin(config: JsonConfig, projects: JsonProject[]) { + this._rootDir = config.rootDir; const removeMissing = config.listOnly; for (const project of projects) { let projectSuite = this._rootSuite.suites.find(suite => suite.project()!.id === project.id); @@ -191,7 +195,7 @@ export class TeleReporterReceiver { titlePath: () => [], title: payload.title, category: payload.category, - location: payload.location, + location: this._absoluteLocation(payload.location), startTime: new Date(payload.startTime), duration: 0, steps: [], @@ -245,17 +249,17 @@ export class TeleReporterReceiver { id: project.id, metadata: project.metadata, name: project.name, - outputDir: project.outputDir, + outputDir: this._absolutePath(project.outputDir), repeatEach: project.repeatEach, retries: project.retries, - testDir: project.testDir, + testDir: this._absolutePath(project.testDir), testIgnore: parseRegexPatterns(project.testIgnore), testMatch: parseRegexPatterns(project.testMatch), timeout: project.timeout, grep: parseRegexPatterns(project.grep) as RegExp[], grepInvert: parseRegexPatterns(project.grepInvert) as RegExp[], dependencies: project.dependencies, - snapshotDir: project.snapshotDir, + snapshotDir: this._absolutePath(project.snapshotDir), use: {}, }; } @@ -268,7 +272,7 @@ export class TeleReporterReceiver { targetSuite.parent = parent; parent.suites.push(targetSuite); } - targetSuite.location = jsonSuite.location; + targetSuite.location = this._absoluteLocation(jsonSuite.location); targetSuite._fileId = jsonSuite.fileId; targetSuite._parallelMode = jsonSuite.parallelMode; this._mergeSuitesInto(jsonSuite.suites, targetSuite, removeMissing); @@ -284,7 +288,7 @@ export class TeleReporterReceiver { for (const jsonTest of jsonTests) { let targetTest = parent.tests.find(s => s.title === jsonTest.title); if (!targetTest) { - targetTest = new TeleTestCase(jsonTest.testId, jsonTest.title, jsonTest.location); + targetTest = new TeleTestCase(jsonTest.testId, jsonTest.title, this._absoluteLocation(jsonTest.location)); targetTest.parent = parent; parent.tests.push(targetTest); this._tests.set(targetTest.id, targetTest); @@ -301,11 +305,31 @@ export class TeleReporterReceiver { test.id = payload.testId; test.expectedStatus = payload.expectedStatus; test.timeout = payload.timeout; - test.location = payload.location; + test.location = this._absoluteLocation(payload.location); test.annotations = payload.annotations; test.retries = payload.retries; return test; } + + private _absoluteLocation(location: Location): Location; + private _absoluteLocation(location?: Location): Location | undefined; + private _absoluteLocation(location: Location | undefined): Location | undefined { + if (!location) + return location; + return { + ...location, + file: this._absolutePath(location.file), + }; + } + + private _absolutePath(relativePath: string): string; + private _absolutePath(relativePath?: string): string | undefined; + private _absolutePath(relativePath?: string): string | undefined { + if (!relativePath) + return relativePath; + return this._rootDir + this._pathSeparator + relativePath; + } + } export class TeleSuite implements SuitePrivate { diff --git a/packages/playwright-test/src/reporters/teleEmitter.ts b/packages/playwright-test/src/reporters/teleEmitter.ts index 63cf1f5398..657eb1d93f 100644 --- a/packages/playwright-test/src/reporters/teleEmitter.ts +++ b/packages/playwright-test/src/reporters/teleEmitter.ts @@ -14,22 +14,25 @@ * limitations under the License. */ -import type { FullConfig, FullResult, Reporter, TestError, TestResult, TestStep } from '../../types/testReporter'; +import type { FullConfig, FullResult, Reporter, TestError, TestResult, TestStep, Location } from '../../types/testReporter'; import type { Suite, TestCase } from '../common/test'; import type { JsonConfig, JsonProject, JsonSuite, JsonTestCase, JsonTestResultEnd, JsonTestResultStart, JsonTestStepEnd, JsonTestStepStart } from '../isomorphic/teleReceiver'; import type { SuitePrivate } from '../../types/reporterPrivate'; import type { FullConfigInternal, FullProjectInternal } from '../common/types'; import { createGuid } from 'playwright-core/lib/utils'; import { serializeRegexPatterns } from '../isomorphic/teleReceiver'; +import path from 'path'; export class TeleReporterEmitter implements Reporter { private _messageSink: (message: any) => void; + private _rootDir!: string; constructor(messageSink: (message: any) => void) { this._messageSink = messageSink; } onBegin(config: FullConfig, suite: Suite) { + this._rootDir = config.rootDir; const projects: any[] = []; for (const projectSuite of suite.suites) { const report = this._serializeProject(projectSuite); @@ -113,7 +116,7 @@ export class TeleReporterEmitter implements Reporter { private _serializeConfig(config: FullConfig): JsonConfig { return { rootDir: config.rootDir, - configFile: config.configFile, + configFile: this._relativePath(config.configFile), listOnly: (config as FullConfigInternal)._internal.listOnly, }; } @@ -124,10 +127,10 @@ export class TeleReporterEmitter implements Reporter { id: (project as FullProjectInternal)._internal.id, metadata: project.metadata, name: project.name, - outputDir: project.outputDir, + outputDir: this._relativePath(project.outputDir), repeatEach: project.repeatEach, retries: project.retries, - testDir: project.testDir, + testDir: this._relativePath(project.testDir), testIgnore: serializeRegexPatterns(project.testIgnore), testMatch: serializeRegexPatterns(project.testMatch), timeout: project.timeout, @@ -137,7 +140,7 @@ export class TeleReporterEmitter implements Reporter { grep: serializeRegexPatterns(project.grep), grepInvert: serializeRegexPatterns(project.grepInvert || []), dependencies: project.dependencies, - snapshotDir: project.snapshotDir, + snapshotDir: this._relativePath(project.snapshotDir), }; return report; } @@ -148,7 +151,7 @@ export class TeleReporterEmitter implements Reporter { title: suite.title, fileId: (suite as SuitePrivate)._fileId, parallelMode: (suite as SuitePrivate)._parallelMode, - location: suite.location, + location: this._relativeLocation(suite.location), suites: suite.suites.map(s => this._serializeSuite(s)), tests: suite.tests.map(t => this._serializeTest(t)), }; @@ -159,7 +162,7 @@ export class TeleReporterEmitter implements Reporter { return { testId: test.id, title: test.title, - location: test.location, + location: this._relativeLocation(test.location), expectedStatus: test.expectedStatus, timeout: test.timeout, annotations: test.annotations, @@ -193,7 +196,7 @@ export class TeleReporterEmitter implements Reporter { title: step.title, category: step.category, startTime: step.startTime.toISOString(), - location: step.location, + location: this._relativeLocation(step.location), }; } @@ -204,6 +207,25 @@ export class TeleReporterEmitter implements Reporter { error: step.error, }; } + + private _relativeLocation(location: Location): Location; + private _relativeLocation(location?: Location): Location | undefined; + private _relativeLocation(location: Location | undefined): Location | undefined { + if (!location) + return location; + return { + ...location, + file: this._relativePath(location.file), + }; + } + + private _relativePath(absolutePath: string): string; + private _relativePath(absolutePath?: string): string | undefined; + private _relativePath(absolutePath?: string): string | undefined { + if (!absolutePath) + return absolutePath; + return path.relative(this._rootDir, absolutePath); + } } const idSymbol = Symbol('id'); diff --git a/packages/trace-viewer/src/ui/watchMode.tsx b/packages/trace-viewer/src/ui/watchMode.tsx index cebd052e30..99af9f47a0 100644 --- a/packages/trace-viewer/src/ui/watchMode.tsx +++ b/packages/trace-viewer/src/ui/watchMode.tsx @@ -549,7 +549,7 @@ const refreshRootSuite = (eraseResults: boolean): Promise => { skipped: 0, }; let config: FullConfig; - receiver = new TeleReporterReceiver({ + receiver = new TeleReporterReceiver(pathSeparator, { onBegin: (c: FullConfig, suite: Suite) => { if (!rootSuite) rootSuite = suite;