fix: consider project suffix when computing id (#23270)
This commit is contained in:
parent
e0600f4799
commit
dce730c3be
|
|
@ -154,6 +154,10 @@ export class FullProjectInternal {
|
||||||
deps: FullProjectInternal[] = [];
|
deps: FullProjectInternal[] = [];
|
||||||
teardown: FullProjectInternal | undefined;
|
teardown: FullProjectInternal | undefined;
|
||||||
|
|
||||||
|
static from(config: FullProject): FullProjectInternal {
|
||||||
|
return (config as any)[projectInternalSymbol];
|
||||||
|
}
|
||||||
|
|
||||||
constructor(configDir: string, config: Config, fullConfig: FullConfigInternal, projectConfig: Project, configCLIOverrides: ConfigCLIOverrides, throwawayArtifactsPath: string) {
|
constructor(configDir: string, config: Config, fullConfig: FullConfigInternal, projectConfig: Project, configCLIOverrides: ConfigCLIOverrides, throwawayArtifactsPath: string) {
|
||||||
this.fullConfig = fullConfig;
|
this.fullConfig = fullConfig;
|
||||||
const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir);
|
const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import path from 'path';
|
||||||
import type { FullConfig, TestCase, Suite, TestResult, TestError, FullResult, TestStep, Location, Reporter } from '../../types/testReporter';
|
import type { FullConfig, TestCase, Suite, TestResult, TestError, FullResult, TestStep, Location, Reporter } from '../../types/testReporter';
|
||||||
import type { SuitePrivate } from '../../types/reporterPrivate';
|
import type { SuitePrivate } from '../../types/reporterPrivate';
|
||||||
import { monotonicTime } from 'playwright-core/lib/utils';
|
import { monotonicTime } from 'playwright-core/lib/utils';
|
||||||
import type { FullProject } from '../../types/test';
|
|
||||||
export type TestResultOutput = { chunk: string | Buffer, type: 'stdout' | 'stderr' };
|
export type TestResultOutput = { chunk: string | Buffer, type: 'stdout' | 'stderr' };
|
||||||
export const kOutputSymbol = Symbol('output');
|
export const kOutputSymbol = Symbol('output');
|
||||||
|
|
||||||
|
|
@ -498,23 +497,6 @@ function fitToWidth(line: string, width: number, prefix?: string): string {
|
||||||
return taken.reverse().join('');
|
return taken.reverse().join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function uniqueProjectIds(projects: FullProject[]): Map<FullProject, string> {
|
|
||||||
const usedNames = new Set<string>();
|
|
||||||
const result = new Map<FullProject, string>();
|
|
||||||
for (const p of projects) {
|
|
||||||
const name = p.name || '';
|
|
||||||
for (let i = 0; i < projects.length; ++i) {
|
|
||||||
const candidate = name + (i ? i : '');
|
|
||||||
if (usedNames.has(candidate))
|
|
||||||
continue;
|
|
||||||
result.set(p, candidate);
|
|
||||||
usedNames.add(candidate);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function belongsToNodeModules(file: string) {
|
function belongsToNodeModules(file: string) {
|
||||||
return file.includes(`${path.sep}node_modules${path.sep}`);
|
return file.includes(`${path.sep}node_modules${path.sep}`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import type { FullConfig, TestCase, Suite, TestResult, TestError, TestStep, FullResult, Location, Reporter, JSONReport, JSONReportSuite, JSONReportSpec, JSONReportTest, JSONReportTestResult, JSONReportTestStep, JSONReportError } from '../../types/testReporter';
|
import type { FullConfig, TestCase, Suite, TestResult, TestError, TestStep, FullResult, Location, Reporter, JSONReport, JSONReportSuite, JSONReportSpec, JSONReportTest, JSONReportTestResult, JSONReportTestStep, JSONReportError } from '../../types/testReporter';
|
||||||
import { formatError, prepareErrorStack, uniqueProjectIds } from './base';
|
import { formatError, prepareErrorStack } from './base';
|
||||||
import { MultiMap } from 'playwright-core/lib/utils';
|
import { MultiMap } from 'playwright-core/lib/utils';
|
||||||
import { assert } from 'playwright-core/lib/utils';
|
import { assert } from 'playwright-core/lib/utils';
|
||||||
import type { FullProject } from '../../types/test';
|
import { FullProjectInternal } from '../common/config';
|
||||||
|
|
||||||
export function toPosixPath(aPath: string): string {
|
export function toPosixPath(aPath: string): string {
|
||||||
return aPath.split(path.sep).join(path.posix.sep);
|
return aPath.split(path.sep).join(path.posix.sep);
|
||||||
|
|
@ -54,7 +54,6 @@ class JSONReporter implements Reporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _serializeReport(): JSONReport {
|
private _serializeReport(): JSONReport {
|
||||||
const projectIds = uniqueProjectIds(this.config.projects);
|
|
||||||
return {
|
return {
|
||||||
config: {
|
config: {
|
||||||
...removePrivateFields(this.config),
|
...removePrivateFields(this.config),
|
||||||
|
|
@ -65,7 +64,7 @@ class JSONReporter implements Reporter {
|
||||||
repeatEach: project.repeatEach,
|
repeatEach: project.repeatEach,
|
||||||
retries: project.retries,
|
retries: project.retries,
|
||||||
metadata: project.metadata,
|
metadata: project.metadata,
|
||||||
id: projectIds.get(project)!,
|
id: FullProjectInternal.from(project).id,
|
||||||
name: project.name,
|
name: project.name,
|
||||||
testDir: toPosixPath(project.testDir),
|
testDir: toPosixPath(project.testDir),
|
||||||
testIgnore: serializePatterns(project.testIgnore),
|
testIgnore: serializePatterns(project.testIgnore),
|
||||||
|
|
@ -74,15 +73,15 @@ class JSONReporter implements Reporter {
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
suites: this._mergeSuites(this.suite.suites, projectIds),
|
suites: this._mergeSuites(this.suite.suites),
|
||||||
errors: this._errors
|
errors: this._errors
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _mergeSuites(suites: Suite[], projectIds: Map<FullProject, string>): JSONReportSuite[] {
|
private _mergeSuites(suites: Suite[]): JSONReportSuite[] {
|
||||||
const fileSuites = new MultiMap<string, JSONReportSuite>();
|
const fileSuites = new MultiMap<string, JSONReportSuite>();
|
||||||
for (const projectSuite of suites) {
|
for (const projectSuite of suites) {
|
||||||
const projectId = projectIds.get(projectSuite.project()!)!;
|
const projectId = FullProjectInternal.from(projectSuite.project()!).id;
|
||||||
const projectName = projectSuite.project()!.name;
|
const projectName = projectSuite.project()!.name;
|
||||||
for (const fileSuite of projectSuite.suites) {
|
for (const fileSuite of projectSuite.suites) {
|
||||||
const file = fileSuite.location!.file;
|
const file = fileSuite.location!.file;
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import { createGuid } from 'playwright-core/lib/utils';
|
||||||
import { serializeRegexPatterns } from '../isomorphic/teleReceiver';
|
import { serializeRegexPatterns } from '../isomorphic/teleReceiver';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import type { FullProject } from '../../types/test';
|
import type { FullProject } from '../../types/test';
|
||||||
import { uniqueProjectIds } from './base';
|
|
||||||
|
|
||||||
export class TeleReporterEmitter implements Reporter {
|
export class TeleReporterEmitter implements Reporter {
|
||||||
private _messageSink: (message: any) => void;
|
private _messageSink: (message: any) => void;
|
||||||
|
|
@ -36,7 +35,7 @@ export class TeleReporterEmitter implements Reporter {
|
||||||
onBegin(config: FullConfig, suite: Suite) {
|
onBegin(config: FullConfig, suite: Suite) {
|
||||||
this._rootDir = config.rootDir;
|
this._rootDir = config.rootDir;
|
||||||
const projects: any[] = [];
|
const projects: any[] = [];
|
||||||
const projectIds = uniqueProjectIds(config.projects);
|
const projectIds = this._uniqueProjectIds(config.projects);
|
||||||
for (const projectSuite of suite.suites) {
|
for (const projectSuite of suite.suites) {
|
||||||
const report = this._serializeProject(projectSuite, projectIds);
|
const report = this._serializeProject(projectSuite, projectIds);
|
||||||
projects.push(report);
|
projects.push(report);
|
||||||
|
|
@ -139,6 +138,23 @@ export class TeleReporterEmitter implements Reporter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _uniqueProjectIds(projects: FullProject[]): Map<FullProject, string> {
|
||||||
|
const usedNames = new Set<string>();
|
||||||
|
const result = new Map<FullProject, string>();
|
||||||
|
for (const p of projects) {
|
||||||
|
const name = this._serializeProjectName(p.name);
|
||||||
|
for (let i = 0; i < projects.length; ++i) {
|
||||||
|
const candidate = name + (i ? i : '');
|
||||||
|
if (usedNames.has(candidate))
|
||||||
|
continue;
|
||||||
|
result.set(p, candidate);
|
||||||
|
usedNames.add(candidate);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private _serializeProject(suite: Suite, projectIds: Map<FullProject, string>): JsonProject {
|
private _serializeProject(suite: Suite, projectIds: Map<FullProject, string>): JsonProject {
|
||||||
const project = suite.project()!;
|
const project = suite.project()!;
|
||||||
const report: JsonProject = {
|
const report: JsonProject = {
|
||||||
|
|
|
||||||
|
|
@ -908,7 +908,6 @@ test('custom project suffix', async ({ runInlineTest, mergeReports }) => {
|
||||||
`,
|
`,
|
||||||
'playwright.config.ts': `
|
'playwright.config.ts': `
|
||||||
module.exports = {
|
module.exports = {
|
||||||
retries: 1,
|
|
||||||
reporter: 'blob',
|
reporter: 'blob',
|
||||||
projects: [
|
projects: [
|
||||||
{ name: 'foo' },
|
{ name: 'foo' },
|
||||||
|
|
@ -918,9 +917,7 @@ test('custom project suffix', async ({ runInlineTest, mergeReports }) => {
|
||||||
`,
|
`,
|
||||||
'a.test.js': `
|
'a.test.js': `
|
||||||
import { test, expect } from '@playwright/test';
|
import { test, expect } from '@playwright/test';
|
||||||
test('math 1', async ({}) => {
|
test('math 1', async ({}) => {});
|
||||||
expect(1 + 1).toBe(2);
|
|
||||||
});
|
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -930,3 +927,40 @@ test('custom project suffix', async ({ runInlineTest, mergeReports }) => {
|
||||||
expect(exitCode).toBe(0);
|
expect(exitCode).toBe(0);
|
||||||
expect(output).toContain(`projects: [ 'foo-suffix', 'bar-suffix' ]`);
|
expect(output).toContain(`projects: [ 'foo-suffix', 'bar-suffix' ]`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('same project different suffixes', async ({ runInlineTest, mergeReports }) => {
|
||||||
|
const files = {
|
||||||
|
'echo-reporter.js': `
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
class EchoReporter {
|
||||||
|
onBegin(config, suite) {
|
||||||
|
const projects = suite.suites.map(s => s.project().name);
|
||||||
|
projects.sort();
|
||||||
|
console.log('projects:', projects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = EchoReporter;
|
||||||
|
`,
|
||||||
|
'playwright.config.ts': `
|
||||||
|
module.exports = {
|
||||||
|
reporter: 'blob',
|
||||||
|
projects: [
|
||||||
|
{ name: 'foo' },
|
||||||
|
]
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'a.test.js': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
test('math 1', async ({}) => {});
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
|
||||||
|
await runInlineTest(files, undefined, { PWTEST_BLOB_SUFFIX: '-first' });
|
||||||
|
await runInlineTest(files, undefined, { PWTEST_BLOB_SUFFIX: '-second' });
|
||||||
|
|
||||||
|
const reportDir = test.info().outputPath('blob-report');
|
||||||
|
const { exitCode, output } = await mergeReports(reportDir, {}, { additionalArgs: ['--reporter', test.info().outputPath('echo-reporter.js')] });
|
||||||
|
expect(exitCode).toBe(0);
|
||||||
|
expect(output).toContain(`projects: [ 'foo-first', 'foo-second' ]`);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue