chore: inject string pool into the tele receiver (#29781)
This commit is contained in:
parent
d5d4f591f3
commit
68284b0505
|
|
@ -18,8 +18,8 @@ import type { Annotation } from '../common/config';
|
|||
import type { FullProject, Metadata } from '../../types/test';
|
||||
import type * as reporterTypes from '../../types/testReporter';
|
||||
import type { ReporterV2 } from '../reporters/reporterV2';
|
||||
import { StringInternPool } from './stringInternPool';
|
||||
|
||||
export type StringIntern = (s: string) => string;
|
||||
export type JsonLocation = reporterTypes.Location;
|
||||
export type JsonError = string;
|
||||
export type JsonStackFrame = { file: string, line: number, column: number };
|
||||
|
|
@ -28,8 +28,6 @@ export type JsonStdIOType = 'stdout' | 'stderr';
|
|||
|
||||
export type JsonConfig = Pick<reporterTypes.FullConfig, 'configFile' | 'globalTimeout' | 'maxFailures' | 'metadata' | 'rootDir' | 'version' | 'workers'>;
|
||||
|
||||
export type MergeReporterConfig = Pick<reporterTypes.FullConfig, 'configFile' | 'quiet' | 'reportSlowTests' | 'rootDir' | 'reporter' >;
|
||||
|
||||
export type JsonPattern = {
|
||||
s?: string;
|
||||
r?: { source: string, flags: string };
|
||||
|
|
@ -123,27 +121,28 @@ export type JsonEvent = {
|
|||
params: any
|
||||
};
|
||||
|
||||
type TeleReporterReceiverOptions = {
|
||||
pathSeparator: string;
|
||||
mergeProjects: boolean;
|
||||
mergeTestCases: boolean;
|
||||
internString?: StringIntern;
|
||||
configOverrides?: Pick<reporterTypes.FullConfig, 'configFile' | 'quiet' | 'reportSlowTests' | 'reporter'>;
|
||||
};
|
||||
|
||||
export class TeleReporterReceiver {
|
||||
private _rootSuite: TeleSuite;
|
||||
private _pathSeparator: string;
|
||||
private _options: TeleReporterReceiverOptions;
|
||||
private _reporter: Partial<ReporterV2>;
|
||||
private _tests = new Map<string, TeleTestCase>();
|
||||
private _rootDir!: string;
|
||||
private _listOnly = false;
|
||||
private _clearPreviousResultsWhenTestBegins: boolean = false;
|
||||
private _mergeTestCases: boolean;
|
||||
private _mergeProjects: boolean;
|
||||
private _reportConfig: MergeReporterConfig | undefined;
|
||||
private _config!: reporterTypes.FullConfig;
|
||||
private _stringPool = new StringInternPool();
|
||||
|
||||
constructor(pathSeparator: string, reporter: Partial<ReporterV2>, mergeProjects: boolean, mergeTestCases: boolean, reportConfig?: MergeReporterConfig) {
|
||||
constructor(reporter: Partial<ReporterV2>, options: TeleReporterReceiverOptions) {
|
||||
this._rootSuite = new TeleSuite('', 'root');
|
||||
this._pathSeparator = pathSeparator;
|
||||
this._options = options;
|
||||
this._reporter = reporter;
|
||||
this._mergeProjects = mergeProjects;
|
||||
this._mergeTestCases = mergeTestCases;
|
||||
this._reportConfig = reportConfig;
|
||||
}
|
||||
|
||||
dispatch(mode: 'list' | 'test', message: JsonEvent): Promise<void> | void {
|
||||
|
|
@ -202,7 +201,7 @@ export class TeleReporterReceiver {
|
|||
}
|
||||
|
||||
private _onProject(project: JsonProject) {
|
||||
let projectSuite = this._mergeProjects ? this._rootSuite.suites.find(suite => suite.project()!.name === project.name) : undefined;
|
||||
let projectSuite = this._options.mergeProjects ? this._rootSuite.suites.find(suite => suite.project()!.name === project.name) : undefined;
|
||||
if (!projectSuite) {
|
||||
projectSuite = new TeleSuite(project.name, 'project');
|
||||
this._rootSuite.suites.push(projectSuite);
|
||||
|
|
@ -315,17 +314,16 @@ export class TeleReporterReceiver {
|
|||
|
||||
private _onExit(): Promise<void> | void {
|
||||
// Free up the memory from the string pool.
|
||||
this._stringPool = new StringInternPool();
|
||||
return this._reporter.onExit?.();
|
||||
}
|
||||
|
||||
private _parseConfig(config: JsonConfig): reporterTypes.FullConfig {
|
||||
const result = { ...baseFullConfig, ...config };
|
||||
if (this._reportConfig) {
|
||||
result.configFile = this._reportConfig.configFile;
|
||||
result.reportSlowTests = this._reportConfig.reportSlowTests;
|
||||
result.quiet = this._reportConfig.quiet;
|
||||
result.reporter = [...this._reportConfig.reporter];
|
||||
if (this._options.configOverrides) {
|
||||
result.configFile = this._options.configOverrides.configFile;
|
||||
result.reportSlowTests = this._options.configOverrides.reportSlowTests;
|
||||
result.quiet = this._options.configOverrides.quiet;
|
||||
result.reporter = [...this._options.configOverrides.reporter];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -375,7 +373,7 @@ export class TeleReporterReceiver {
|
|||
|
||||
private _mergeTestsInto(jsonTests: JsonTestCase[], parent: TeleSuite) {
|
||||
for (const jsonTest of jsonTests) {
|
||||
let targetTest = this._mergeTestCases ? parent.tests.find(s => s.title === jsonTest.title && s.repeatEachIndex === jsonTest.repeatEachIndex) : undefined;
|
||||
let targetTest = this._options.mergeTestCases ? parent.tests.find(s => s.title === jsonTest.title && s.repeatEachIndex === jsonTest.repeatEachIndex) : undefined;
|
||||
if (!targetTest) {
|
||||
targetTest = new TeleTestCase(jsonTest.testId, jsonTest.title, this._absoluteLocation(jsonTest.location), jsonTest.repeatEachIndex);
|
||||
targetTest.parent = parent;
|
||||
|
|
@ -410,9 +408,12 @@ export class TeleReporterReceiver {
|
|||
private _absolutePath(relativePath?: string): string | undefined {
|
||||
if (relativePath === undefined)
|
||||
return;
|
||||
return this._stringPool.internString(this._rootDir + this._pathSeparator + relativePath);
|
||||
return this._internString(this._rootDir + this._options.pathSeparator + relativePath);
|
||||
}
|
||||
|
||||
private _internString(s: string): string {
|
||||
return this._options.internString ? this._options.internString(s) : s;
|
||||
}
|
||||
}
|
||||
|
||||
export class TeleSuite {
|
||||
|
|
|
|||
|
|
@ -51,9 +51,15 @@ export async function createMergedReport(config: FullConfigInternal, dir: string
|
|||
if (shardFiles.length === 0)
|
||||
throw new Error(`No report files found in ${dir}`);
|
||||
const eventData = await mergeEvents(dir, shardFiles, stringPool, printStatus, rootDirOverride);
|
||||
// If expicit config is provided, use platform path separator, otherwise use the one from the report (if any).
|
||||
const pathSep = rootDirOverride ? path.sep : (eventData.pathSeparatorFromMetadata ?? path.sep);
|
||||
const receiver = new TeleReporterReceiver(pathSep, multiplexer, false, false, config.config);
|
||||
// If explicit config is provided, use platform path separator, otherwise use the one from the report (if any).
|
||||
const pathSeparator = rootDirOverride ? path.sep : (eventData.pathSeparatorFromMetadata ?? path.sep);
|
||||
const receiver = new TeleReporterReceiver(multiplexer, {
|
||||
pathSeparator,
|
||||
mergeProjects: false,
|
||||
mergeTestCases: false,
|
||||
internString: s => stringPool.internString(s),
|
||||
configOverrides: config.config,
|
||||
});
|
||||
printStatus(`processing test events`);
|
||||
|
||||
const dispatchEvents = async (events: JsonEvent[]) => {
|
||||
|
|
|
|||
|
|
@ -16,17 +16,17 @@
|
|||
|
||||
import path from 'path';
|
||||
import { createGuid } from 'playwright-core/lib/utils';
|
||||
import type { FullConfig, FullResult, Location, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter';
|
||||
import type { JsonAttachment, JsonConfig, JsonEvent, JsonFullResult, JsonProject, JsonStdIOType, JsonSuite, JsonTestCase, JsonTestEnd, JsonTestResultEnd, JsonTestResultStart, JsonTestStepEnd, JsonTestStepStart } from '../isomorphic/teleReceiver';
|
||||
import type * as reporterTypes from '../../types/testReporter';
|
||||
import type * as teleReceiver from '../isomorphic/teleReceiver';
|
||||
import { serializeRegexPatterns } from '../isomorphic/teleReceiver';
|
||||
import type { ReporterV2 } from './reporterV2';
|
||||
|
||||
export class TeleReporterEmitter implements ReporterV2 {
|
||||
private _messageSink: (message: JsonEvent) => void;
|
||||
private _messageSink: (message: teleReceiver.JsonEvent) => void;
|
||||
private _rootDir!: string;
|
||||
private _skipBuffers: boolean;
|
||||
|
||||
constructor(messageSink: (message: JsonEvent) => void, skipBuffers: boolean) {
|
||||
constructor(messageSink: (message: teleReceiver.JsonEvent) => void, skipBuffers: boolean) {
|
||||
this._messageSink = messageSink;
|
||||
this._skipBuffers = skipBuffers;
|
||||
}
|
||||
|
|
@ -35,19 +35,19 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
return 'v2';
|
||||
}
|
||||
|
||||
onConfigure(config: FullConfig) {
|
||||
onConfigure(config: reporterTypes.FullConfig) {
|
||||
this._rootDir = config.rootDir;
|
||||
this._messageSink({ method: 'onConfigure', params: { config: this._serializeConfig(config) } });
|
||||
}
|
||||
|
||||
onBegin(suite: Suite) {
|
||||
onBegin(suite: reporterTypes.Suite) {
|
||||
const projects = suite.suites.map(projectSuite => this._serializeProject(projectSuite));
|
||||
for (const project of projects)
|
||||
this._messageSink({ method: 'onProject', params: { project } });
|
||||
this._messageSink({ method: 'onBegin', params: undefined });
|
||||
}
|
||||
|
||||
onTestBegin(test: TestCase, result: TestResult): void {
|
||||
onTestBegin(test: reporterTypes.TestCase, result: reporterTypes.TestResult): void {
|
||||
(result as any)[idSymbol] = createGuid();
|
||||
this._messageSink({
|
||||
method: 'onTestBegin',
|
||||
|
|
@ -58,8 +58,8 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
});
|
||||
}
|
||||
|
||||
onTestEnd(test: TestCase, result: TestResult): void {
|
||||
const testEnd: JsonTestEnd = {
|
||||
onTestEnd(test: reporterTypes.TestCase, result: reporterTypes.TestResult): void {
|
||||
const testEnd: teleReceiver.JsonTestEnd = {
|
||||
testId: test.id,
|
||||
expectedStatus: test.expectedStatus,
|
||||
annotations: test.annotations,
|
||||
|
|
@ -74,7 +74,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
});
|
||||
}
|
||||
|
||||
onStepBegin(test: TestCase, result: TestResult, step: TestStep): void {
|
||||
onStepBegin(test: reporterTypes.TestCase, result: reporterTypes.TestResult, step: reporterTypes.TestStep): void {
|
||||
(step as any)[idSymbol] = createGuid();
|
||||
this._messageSink({
|
||||
method: 'onStepBegin',
|
||||
|
|
@ -86,7 +86,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
});
|
||||
}
|
||||
|
||||
onStepEnd(test: TestCase, result: TestResult, step: TestStep): void {
|
||||
onStepEnd(test: reporterTypes.TestCase, result: reporterTypes.TestResult, step: reporterTypes.TestStep): void {
|
||||
this._messageSink({
|
||||
method: 'onStepEnd',
|
||||
params: {
|
||||
|
|
@ -97,22 +97,22 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
});
|
||||
}
|
||||
|
||||
onError(error: TestError): void {
|
||||
onError(error: reporterTypes.TestError): void {
|
||||
this._messageSink({
|
||||
method: 'onError',
|
||||
params: { error }
|
||||
});
|
||||
}
|
||||
|
||||
onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult): void {
|
||||
onStdOut(chunk: string | Buffer, test?: reporterTypes.TestCase, result?: reporterTypes.TestResult): void {
|
||||
this._onStdIO('stdout', chunk, test, result);
|
||||
}
|
||||
|
||||
onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult): void {
|
||||
onStdErr(chunk: string | Buffer, test?: reporterTypes.TestCase, result?: reporterTypes.TestResult): void {
|
||||
this._onStdIO('stderr', chunk, test, result);
|
||||
}
|
||||
|
||||
private _onStdIO(type: JsonStdIOType, chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void {
|
||||
private _onStdIO(type: teleReceiver.JsonStdIOType, chunk: string | Buffer, test: void | reporterTypes.TestCase, result: void | reporterTypes.TestResult): void {
|
||||
const isBase64 = typeof chunk !== 'string';
|
||||
const data = isBase64 ? chunk.toString('base64') : chunk;
|
||||
this._messageSink({
|
||||
|
|
@ -121,8 +121,8 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
});
|
||||
}
|
||||
|
||||
async onEnd(result: FullResult) {
|
||||
const resultPayload: JsonFullResult = {
|
||||
async onEnd(result: reporterTypes.FullResult) {
|
||||
const resultPayload: teleReceiver.JsonFullResult = {
|
||||
status: result.status,
|
||||
startTime: result.startTime.getTime(),
|
||||
duration: result.duration,
|
||||
|
|
@ -142,7 +142,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
return false;
|
||||
}
|
||||
|
||||
private _serializeConfig(config: FullConfig): JsonConfig {
|
||||
private _serializeConfig(config: reporterTypes.FullConfig): teleReceiver.JsonConfig {
|
||||
return {
|
||||
configFile: this._relativePath(config.configFile),
|
||||
globalTimeout: config.globalTimeout,
|
||||
|
|
@ -154,9 +154,9 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
};
|
||||
}
|
||||
|
||||
private _serializeProject(suite: Suite): JsonProject {
|
||||
private _serializeProject(suite: reporterTypes.Suite): teleReceiver.JsonProject {
|
||||
const project = suite.project()!;
|
||||
const report: JsonProject = {
|
||||
const report: teleReceiver.JsonProject = {
|
||||
metadata: project.metadata,
|
||||
name: project.name,
|
||||
outputDir: this._relativePath(project.outputDir),
|
||||
|
|
@ -178,7 +178,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
return report;
|
||||
}
|
||||
|
||||
private _serializeSuite(suite: Suite): JsonSuite {
|
||||
private _serializeSuite(suite: reporterTypes.Suite): teleReceiver.JsonSuite {
|
||||
const result = {
|
||||
title: suite.title,
|
||||
location: this._relativeLocation(suite.location),
|
||||
|
|
@ -188,7 +188,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
return result;
|
||||
}
|
||||
|
||||
private _serializeTest(test: TestCase): JsonTestCase {
|
||||
private _serializeTest(test: reporterTypes.TestCase): teleReceiver.JsonTestCase {
|
||||
return {
|
||||
testId: test.id,
|
||||
title: test.title,
|
||||
|
|
@ -199,7 +199,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
};
|
||||
}
|
||||
|
||||
private _serializeResultStart(result: TestResult): JsonTestResultStart {
|
||||
private _serializeResultStart(result: reporterTypes.TestResult): teleReceiver.JsonTestResultStart {
|
||||
return {
|
||||
id: (result as any)[idSymbol],
|
||||
retry: result.retry,
|
||||
|
|
@ -209,7 +209,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
};
|
||||
}
|
||||
|
||||
private _serializeResultEnd(result: TestResult): JsonTestResultEnd {
|
||||
private _serializeResultEnd(result: reporterTypes.TestResult): teleReceiver.JsonTestResultEnd {
|
||||
return {
|
||||
id: (result as any)[idSymbol],
|
||||
duration: result.duration,
|
||||
|
|
@ -219,7 +219,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
};
|
||||
}
|
||||
|
||||
_serializeAttachments(attachments: TestResult['attachments']): JsonAttachment[] {
|
||||
_serializeAttachments(attachments: reporterTypes.TestResult['attachments']): teleReceiver.JsonAttachment[] {
|
||||
return attachments.map(a => {
|
||||
return {
|
||||
...a,
|
||||
|
|
@ -229,7 +229,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
});
|
||||
}
|
||||
|
||||
private _serializeStepStart(step: TestStep): JsonTestStepStart {
|
||||
private _serializeStepStart(step: reporterTypes.TestStep): teleReceiver.JsonTestStepStart {
|
||||
return {
|
||||
id: (step as any)[idSymbol],
|
||||
parentStepId: (step.parent as any)?.[idSymbol],
|
||||
|
|
@ -240,7 +240,7 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
};
|
||||
}
|
||||
|
||||
private _serializeStepEnd(step: TestStep): JsonTestStepEnd {
|
||||
private _serializeStepEnd(step: reporterTypes.TestStep): teleReceiver.JsonTestStepEnd {
|
||||
return {
|
||||
id: (step as any)[idSymbol],
|
||||
duration: step.duration,
|
||||
|
|
@ -248,9 +248,9 @@ export class TeleReporterEmitter implements ReporterV2 {
|
|||
};
|
||||
}
|
||||
|
||||
private _relativeLocation(location: Location): Location;
|
||||
private _relativeLocation(location?: Location): Location | undefined;
|
||||
private _relativeLocation(location: Location | undefined): Location | undefined {
|
||||
private _relativeLocation(location: reporterTypes.Location): reporterTypes.Location;
|
||||
private _relativeLocation(location?: reporterTypes.Location): reporterTypes.Location | undefined;
|
||||
private _relativeLocation(location: reporterTypes.Location | undefined): reporterTypes.Location | undefined {
|
||||
if (!location)
|
||||
return location;
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -640,7 +640,7 @@ const refreshRootSuite = (eraseResults: boolean): Promise<void> => {
|
|||
skipped: 0,
|
||||
};
|
||||
let config: FullConfig;
|
||||
receiver = new TeleReporterReceiver(pathSeparator, {
|
||||
receiver = new TeleReporterReceiver({
|
||||
version: () => 'v2',
|
||||
|
||||
onConfigure: (c: FullConfig) => {
|
||||
|
|
@ -649,12 +649,16 @@ const refreshRootSuite = (eraseResults: boolean): Promise<void> => {
|
|||
// run one test, we still get many tests via rootSuite.allTests().length.
|
||||
// To work around that, have a dedicated per-run receiver that will only have
|
||||
// suite for a single test run, and hence will have correct total.
|
||||
lastRunReceiver = new TeleReporterReceiver(pathSeparator, {
|
||||
lastRunReceiver = new TeleReporterReceiver({
|
||||
onBegin: (suite: Suite) => {
|
||||
lastRunTestCount = suite.allTests().length;
|
||||
lastRunReceiver = undefined;
|
||||
}
|
||||
}, true, false);
|
||||
}, {
|
||||
pathSeparator,
|
||||
mergeProjects: true,
|
||||
mergeTestCases: false
|
||||
});
|
||||
},
|
||||
|
||||
onBegin: (suite: Suite) => {
|
||||
|
|
@ -700,7 +704,11 @@ const refreshRootSuite = (eraseResults: boolean): Promise<void> => {
|
|||
onExit: () => {},
|
||||
onStepBegin: () => {},
|
||||
onStepEnd: () => {},
|
||||
}, true, true);
|
||||
}, {
|
||||
pathSeparator,
|
||||
mergeProjects: true,
|
||||
mergeTestCases: true,
|
||||
});
|
||||
receiver._setClearPreviousResultsWhenTestBegins();
|
||||
return sendMessage('list', {});
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue