chore: split InternalReporter and Multiplexer (#22671)

The multiplexer will be reused in the blob report merger.
This commit is contained in:
Yury Semikhatsky 2023-04-26 17:55:58 -07:00 committed by GitHub
parent e809ecdc5d
commit 51aca72c35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 180 additions and 112 deletions

View File

@ -15,11 +15,11 @@
*/
import type { FullConfig, Suite } from '../../types/testReporter';
import type { Multiplexer } from '../reporters/multiplexer';
import type { InternalReporter } from '../reporters/internalReporter';
export interface TestRunnerPlugin {
name: string;
setup?(config: FullConfig, configDir: string, reporter: Multiplexer): Promise<void>;
setup?(config: FullConfig, configDir: string, reporter: InternalReporter): Promise<void>;
babelPlugins?(): Promise<[string, any?][]>;
begin?(suite: Suite): Promise<void>;
end?(): Promise<void>;

View File

@ -23,7 +23,7 @@ import type { FullConfig } from '../../types/testReporter';
import type { TestRunnerPlugin } from '.';
import type { FullConfigInternal } from '../common/config';
import { envWithoutExperimentalLoaderOptions } from '../util';
import type { Multiplexer } from '../reporters/multiplexer';
import type { InternalReporter } from '../reporters/internalReporter';
export type WebServerPluginOptions = {
@ -49,7 +49,7 @@ export class WebServerPlugin implements TestRunnerPlugin {
private _processExitedPromise!: Promise<any>;
private _options: WebServerPluginOptions;
private _checkPortOnly: boolean;
private _reporter?: Multiplexer;
private _reporter?: InternalReporter;
name = 'playwright:webserver';
constructor(options: WebServerPluginOptions, checkPortOnly: boolean) {
@ -57,7 +57,7 @@ export class WebServerPlugin implements TestRunnerPlugin {
this._checkPortOnly = checkPortOnly;
}
public async setup(config: FullConfig, configDir: string, reporter: Multiplexer) {
public async setup(config: FullConfig, configDir: string, reporter: InternalReporter) {
this._reporter = reporter;
this._isAvailable = getIsAvailableFunction(this._options.url, this._checkPortOnly, !!this._options.ignoreHTTPSErrors, this._reporter.onStdErr?.bind(this._reporter));
this._options.cwd = this._options.cwd ? path.resolve(configDir, this._options.cwd) : configDir;
@ -148,7 +148,7 @@ async function isPortUsed(port: number): Promise<boolean> {
return await innerIsPortUsed('127.0.0.1') || await innerIsPortUsed('::1');
}
async function isURLAvailable(url: URL, ignoreHTTPSErrors: boolean, onStdErr: Multiplexer['onStdErr']) {
async function isURLAvailable(url: URL, ignoreHTTPSErrors: boolean, onStdErr: InternalReporter['onStdErr']) {
let statusCode = await httpStatusCode(url, ignoreHTTPSErrors, onStdErr);
if (statusCode === 404 && url.pathname === '/') {
const indexUrl = new URL(url);
@ -158,7 +158,7 @@ async function isURLAvailable(url: URL, ignoreHTTPSErrors: boolean, onStdErr: Mu
return statusCode >= 200 && statusCode < 404;
}
async function httpStatusCode(url: URL, ignoreHTTPSErrors: boolean, onStdErr: Multiplexer['onStdErr']): Promise<number> {
async function httpStatusCode(url: URL, ignoreHTTPSErrors: boolean, onStdErr: InternalReporter['onStdErr']): Promise<number> {
return new Promise(resolve => {
debugWebServer(`HTTP GET: ${url}`);
httpRequest({
@ -191,7 +191,7 @@ async function waitFor(waitFn: () => Promise<boolean>, cancellationToken: { canc
}
}
function getIsAvailableFunction(url: string, checkPortOnly: boolean, ignoreHTTPSErrors: boolean, onStdErr: Multiplexer['onStdErr']) {
function getIsAvailableFunction(url: string, checkPortOnly: boolean, ignoreHTTPSErrors: boolean, onStdErr: InternalReporter['onStdErr']) {
const urlObject = new URL(url);
if (!checkPortOnly)
return () => isURLAvailable(urlObject, ignoreHTTPSErrors, onStdErr);

View File

@ -0,0 +1,121 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { FullConfig, TestCase, TestError, TestResult, FullResult, TestStep, Reporter } from '../../types/testReporter';
import { Suite } from '../common/test';
import type { FullConfigInternal } from '../common/config';
import { addSnippetToError } from './base';
import { Multiplexer } from './multiplexer';
type StdIOChunk = {
chunk: string | Buffer;
test?: TestCase;
result?: TestResult;
};
export class InternalReporter {
private _multiplexer: Multiplexer;
private _deferred: { error?: TestError, stdout?: StdIOChunk, stderr?: StdIOChunk }[] | null = [];
private _config!: FullConfigInternal;
constructor(reporters: Reporter[]) {
this._multiplexer = new Multiplexer(reporters);
}
onConfigure(config: FullConfigInternal) {
this._config = config;
}
onBegin(config: FullConfig, suite: Suite) {
this._multiplexer.onBegin(config, suite);
const deferred = this._deferred!;
this._deferred = null;
for (const item of deferred) {
if (item.error)
this.onError(item.error);
if (item.stdout)
this.onStdOut(item.stdout.chunk, item.stdout.test, item.stdout.result);
if (item.stderr)
this.onStdErr(item.stderr.chunk, item.stderr.test, item.stderr.result);
}
}
onTestBegin(test: TestCase, result: TestResult) {
this._multiplexer.onTestBegin(test, result);
}
onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult) {
if (this._deferred) {
this._deferred.push({ stdout: { chunk, test, result } });
return;
}
this._multiplexer.onStdOut(chunk, test, result);
}
onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult) {
if (this._deferred) {
this._deferred.push({ stderr: { chunk, test, result } });
return;
}
this._multiplexer.onStdErr(chunk, test, result);
}
onTestEnd(test: TestCase, result: TestResult) {
this._addSnippetToTestErrors(test, result);
this._multiplexer.onTestEnd(test, result);
}
async onEnd() { }
async onExit(result: FullResult) {
if (this._deferred) {
// onBegin was not reported, emit it.
this.onBegin(this._config.config, new Suite('', 'root'));
}
await this._multiplexer.onEnd(result);
await this._multiplexer.onExit();
}
onError(error: TestError) {
if (this._deferred) {
this._deferred.push({ error });
return;
}
addSnippetToError(this._config.config, error);
this._multiplexer.onError(error);
}
onStepBegin(test: TestCase, result: TestResult, step: TestStep) {
this._multiplexer.onStepBegin(test, result, step);
}
onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
this._addSnippetToStepError(test, step);
this._multiplexer.onStepEnd(test, result, step);
}
private _addSnippetToTestErrors(test: TestCase, result: TestResult) {
for (const error of result.errors)
addSnippetToError(this._config.config, error, test.location.file);
}
private _addSnippetToStepError(test: TestCase, step: TestStep) {
if (step.error)
addSnippetToError(this._config.config, step.error, test.location.file);
}
}

View File

@ -15,47 +15,18 @@
*/
import type { FullConfig, TestCase, TestError, TestResult, FullResult, TestStep, Reporter } from '../../types/testReporter';
import { Suite } from '../common/test';
import type { FullConfigInternal } from '../common/config';
import { addSnippetToError } from './base';
import type { Suite } from '../common/test';
type StdIOChunk = {
chunk: string | Buffer;
test?: TestCase;
result?: TestResult;
};
export class Multiplexer {
export class Multiplexer implements Reporter {
private _reporters: Reporter[];
private _deferred: { error?: TestError, stdout?: StdIOChunk, stderr?: StdIOChunk }[] | null = [];
private _config!: FullConfigInternal;
constructor(reporters: Reporter[]) {
this._reporters = reporters;
}
printsToStdio() {
return this._reporters.some(r => r.printsToStdio ? r.printsToStdio() : true);
}
onConfigure(config: FullConfigInternal) {
this._config = config;
}
onBegin(config: FullConfig, suite: Suite) {
for (const reporter of this._reporters)
wrap(() => reporter.onBegin?.(config, suite));
const deferred = this._deferred!;
this._deferred = null;
for (const item of deferred) {
if (item.error)
this.onError(item.error);
if (item.stdout)
this.onStdOut(item.stdout.chunk, item.stdout.test, item.stdout.result);
if (item.stderr)
this.onStdErr(item.stderr.chunk, item.stderr.test, item.stderr.result);
}
}
onTestBegin(test: TestCase, result: TestResult) {
@ -64,76 +35,52 @@ export class Multiplexer {
}
onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult) {
if (this._deferred) {
this._deferred.push({ stdout: { chunk, test, result } });
return;
}
for (const reporter of this._reporters)
wrap(() => reporter.onStdOut?.(chunk, test, result));
}
onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult) {
if (this._deferred) {
this._deferred.push({ stderr: { chunk, test, result } });
return;
}
for (const reporter of this._reporters)
wrap(() => reporter.onStdErr?.(chunk, test, result));
}
onTestEnd(test: TestCase, result: TestResult) {
this._addSnippetToTestErrors(test, result);
for (const reporter of this._reporters)
wrap(() => reporter.onTestEnd?.(test, result));
}
async onEnd() { }
async onExit(result: FullResult) {
if (this._deferred) {
// onBegin was not reported, emit it.
this.onBegin(this._config.config, new Suite('', 'root'));
}
async onEnd(result: FullResult) {
for (const reporter of this._reporters)
await Promise.resolve().then(() => reporter.onEnd?.(result)).catch(e => console.error('Error in reporter', e));
await wrapAsync(() => reporter.onEnd?.(result));
}
async onExit() {
for (const reporter of this._reporters)
await Promise.resolve().then(() => reporter.onExit?.()).catch(e => console.error('Error in reporter', e));
await wrapAsync(() => reporter.onExit?.());
}
onError(error: TestError) {
if (this._deferred) {
this._deferred.push({ error });
return;
}
addSnippetToError(this._config.config, error);
for (const reporter of this._reporters)
wrap(() => reporter.onError?.(error));
}
onStepBegin(test: TestCase, result: TestResult, step: TestStep) {
for (const reporter of this._reporters)
wrap(() => (reporter as any).onStepBegin?.(test, result, step));
wrap(() => reporter.onStepBegin?.(test, result, step));
}
onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
this._addSnippetToStepError(test, step);
for (const reporter of this._reporters)
wrap(() => (reporter as any).onStepEnd?.(test, result, step));
wrap(() => reporter.onStepEnd?.(test, result, step));
}
}
private _addSnippetToTestErrors(test: TestCase, result: TestResult) {
for (const error of result.errors)
addSnippetToError(this._config.config, error, test.location.file);
async function wrapAsync(callback: () => void | Promise<void>) {
try {
await callback();
} catch (e) {
console.error('Error in reporter', e);
}
private _addSnippetToStepError(test: TestCase, step: TestStep) {
if (step.error)
addSnippetToError(this._config.config, step.error, test.location.file);
}
}
function wrap(callback: () => void) {

View File

@ -24,7 +24,7 @@ import { ManualPromise } from 'playwright-core/lib/utils';
import { WorkerHost } from './workerHost';
import type { TestGroup } from './testGroups';
import type { FullConfigInternal } from '../common/config';
import type { Multiplexer } from '../reporters/multiplexer';
import type { InternalReporter } from '../reporters/internalReporter';
type TestResultData = {
result: TestResult;
@ -46,14 +46,14 @@ export class Dispatcher {
private _testById = new Map<string, TestData>();
private _config: FullConfigInternal;
private _reporter: Multiplexer;
private _reporter: InternalReporter;
private _hasWorkerErrors = false;
private _failureCount = 0;
private _extraEnvByProjectId: EnvByProjectId = new Map();
private _producedEnvByProjectId: EnvByProjectId = new Map();
constructor(config: FullConfigInternal, reporter: Multiplexer) {
constructor(config: FullConfigInternal, reporter: InternalReporter) {
this._config = config;
this._reporter = reporter;
}
@ -75,7 +75,7 @@ export class Dispatcher {
for (const test of group.tests) {
const result = test._appendTestResult();
result.status = 'skipped';
this._reporter.onTestBegin?.(test, result);
this._reporter.onTestBegin(test, result);
test.annotations = [...test._staticAnnotations];
this._reportTestEnd(test, result);
}
@ -222,7 +222,7 @@ export class Dispatcher {
result.parallelIndex = worker.parallelIndex;
result.workerIndex = worker.workerIndex;
result.startTime = new Date(params.startWallTime);
this._reporter.onTestBegin?.(data.test, result);
this._reporter.onTestBegin(data.test, result);
worker.currentTestId = params.testId;
};
worker.addListener('testBegin', onTestBegin);
@ -284,7 +284,7 @@ export class Dispatcher {
};
steps.set(params.stepId, step);
(parentStep || result).steps.push(step);
this._reporter.onStepBegin?.(data.test, result, step);
this._reporter.onStepBegin(data.test, result, step);
};
worker.on('stepBegin', onStepBegin);
@ -298,14 +298,14 @@ export class Dispatcher {
const { result, steps } = runData;
const step = steps.get(params.stepId);
if (!step) {
this._reporter.onStdErr?.('Internal error: step end without step begin: ' + params.stepId, data.test, result);
this._reporter.onStdErr('Internal error: step end without step begin: ' + params.stepId, data.test, result);
return;
}
step.duration = params.wallTime - step.startTime.getTime();
if (params.error)
step.error = params.error;
steps.delete(params.stepId);
this._reporter.onStepEnd?.(data.test, result, step);
this._reporter.onStepEnd(data.test, result, step);
};
worker.on('stepEnd', onStepEnd);
@ -342,7 +342,7 @@ export class Dispatcher {
if (onlyStartedTests)
return true;
result = data.test._appendTestResult();
this._reporter.onTestBegin?.(test, result);
this._reporter.onTestBegin(test, result);
}
result.errors = [...errors];
result.error = result.errors[0];
@ -358,7 +358,7 @@ export class Dispatcher {
// Let's just fail the test run.
this._hasWorkerErrors = true;
for (const error of params.fatalErrors)
this._reporter.onError?.(error);
this._reporter.onError(error);
}
};
@ -410,7 +410,7 @@ export class Dispatcher {
// Emulate a "skipped" run, and drop this test from remaining.
const result = test._appendTestResult();
this._reporter.onTestBegin?.(test, result);
this._reporter.onTestBegin(test, result);
result.status = 'skipped';
this._reportTestEnd(test, result);
return false;
@ -470,17 +470,17 @@ export class Dispatcher {
worker.on('stdOut', (params: TestOutputPayload) => {
const { chunk, test, result } = handleOutput(params);
result?.stdout.push(chunk);
this._reporter.onStdOut?.(chunk, test, result);
this._reporter.onStdOut(chunk, test, result);
});
worker.on('stdErr', (params: TestOutputPayload) => {
const { chunk, test, result } = handleOutput(params);
result?.stderr.push(chunk);
this._reporter.onStdErr?.(chunk, test, result);
this._reporter.onStdErr(chunk, test, result);
});
worker.on('teardownErrors', (params: TeardownErrorsPayload) => {
this._hasWorkerErrors = true;
for (const error of params.fatalErrors)
this._reporter.onError?.(error);
this._reporter.onError(error);
});
worker.on('exit', () => {
const producedEnv = this._producedEnvByProjectId.get(testGroup.projectId) || {};
@ -509,7 +509,7 @@ export class Dispatcher {
private _reportTestEnd(test: TestCase, result: TestResult) {
if (result.status !== 'skipped' && result.status !== test.expectedStatus)
++this._failureCount;
this._reporter.onTestEnd?.(test, result);
this._reporter.onTestEnd(test, result);
const maxFailures = this._config.config.maxFailures;
if (maxFailures && this._failureCount === maxFailures)
this.stop().catch(e => {});

View File

@ -25,7 +25,7 @@ import type { FullConfigInternal } from '../common/config';
import { colors } from 'playwright-core/lib/utilsBundle';
import { runWatchModeLoop } from './watchMode';
import { runUIMode } from './uiMode';
import { Multiplexer } from '../reporters/multiplexer';
import { InternalReporter } from '../reporters/internalReporter';
export class Runner {
private _config: FullConfigInternal;
@ -69,7 +69,7 @@ export class Runner {
// Legacy webServer support.
webServerPluginsForConfig(config).forEach(p => config.plugins.push({ factory: p }));
const reporter = new Multiplexer(await createReporters(config, listOnly ? 'list' : 'run'));
const reporter = new InternalReporter(await createReporters(config, listOnly ? 'list' : 'run'));
const taskRunner = listOnly ? createTaskRunnerForList(config, reporter, 'in-process')
: createTaskRunner(config, reporter);

View File

@ -19,20 +19,20 @@ import { ManualPromise, monotonicTime } from 'playwright-core/lib/utils';
import type { FullResult, TestError } from '../../reporter';
import { SigIntWatcher } from './sigIntWatcher';
import { serializeError } from '../util';
import type { Multiplexer } from '../reporters/multiplexer';
import type { InternalReporter } from '../reporters/internalReporter';
type TaskTeardown = () => Promise<any> | undefined;
export type Task<Context> = (context: Context, errors: TestError[]) => Promise<TaskTeardown | void> | undefined;
export class TaskRunner<Context> {
private _tasks: { name: string, task: Task<Context> }[] = [];
private _reporter: Multiplexer;
private _reporter: InternalReporter;
private _hasErrors = false;
private _interrupted = false;
private _isTearDown = false;
private _globalTimeoutForError: number;
constructor(reporter: Multiplexer, globalTimeoutForError: number) {
constructor(reporter: InternalReporter, globalTimeoutForError: number) {
this._reporter = reporter;
this._globalTimeoutForError = globalTimeoutForError;
}

View File

@ -20,7 +20,7 @@ import { promisify } from 'util';
import { debug, rimraf } from 'playwright-core/lib/utilsBundle';
import { Dispatcher, type EnvByProjectId } from './dispatcher';
import type { TestRunnerPluginRegistration } from '../plugins';
import type { Multiplexer } from '../reporters/multiplexer';
import type { InternalReporter } from '../reporters/internalReporter';
import { createTestGroups, type TestGroup } from '../runner/testGroups';
import type { Task } from './taskRunner';
import { TaskRunner } from './taskRunner';
@ -44,7 +44,7 @@ export type Phase = {
};
export class TestRun {
readonly reporter: Multiplexer;
readonly reporter: InternalReporter;
readonly config: FullConfigInternal;
rootSuite: Suite | undefined = undefined;
readonly phases: Phase[] = [];
@ -53,13 +53,13 @@ export class TestRun {
projectType: Map<FullProjectInternal, 'top-level' | 'dependency'> = new Map();
projectSuites: Map<FullProjectInternal, Suite[]> = new Map();
constructor(config: FullConfigInternal, reporter: Multiplexer) {
constructor(config: FullConfigInternal, reporter: InternalReporter) {
this.config = config;
this.reporter = reporter;
}
}
export function createTaskRunner(config: FullConfigInternal, reporter: Multiplexer): TaskRunner<TestRun> {
export function createTaskRunner(config: FullConfigInternal, reporter: InternalReporter): TaskRunner<TestRun> {
const taskRunner = new TaskRunner<TestRun>(reporter, config.config.globalTimeout);
addGlobalSetupTasks(taskRunner, config);
taskRunner.addTask('load tests', createLoadTask('in-process', true));
@ -67,13 +67,13 @@ export function createTaskRunner(config: FullConfigInternal, reporter: Multiplex
return taskRunner;
}
export function createTaskRunnerForWatchSetup(config: FullConfigInternal, reporter: Multiplexer): TaskRunner<TestRun> {
export function createTaskRunnerForWatchSetup(config: FullConfigInternal, reporter: InternalReporter): TaskRunner<TestRun> {
const taskRunner = new TaskRunner<TestRun>(reporter, 0);
addGlobalSetupTasks(taskRunner, config);
return taskRunner;
}
export function createTaskRunnerForWatch(config: FullConfigInternal, reporter: Multiplexer, additionalFileMatcher?: Matcher): TaskRunner<TestRun> {
export function createTaskRunnerForWatch(config: FullConfigInternal, reporter: InternalReporter, additionalFileMatcher?: Matcher): TaskRunner<TestRun> {
const taskRunner = new TaskRunner<TestRun>(reporter, 0);
taskRunner.addTask('load tests', createLoadTask('out-of-process', true, additionalFileMatcher));
addRunTasks(taskRunner, config);
@ -91,7 +91,7 @@ function addGlobalSetupTasks(taskRunner: TaskRunner<TestRun>, config: FullConfig
function addRunTasks(taskRunner: TaskRunner<TestRun>, config: FullConfigInternal) {
taskRunner.addTask('create phases', createPhasesTask());
taskRunner.addTask('report begin', async ({ reporter, rootSuite }) => {
reporter.onBegin?.(config.config, rootSuite!);
reporter.onBegin(config.config, rootSuite!);
return () => reporter.onEnd();
});
for (const plugin of config.plugins)
@ -101,11 +101,11 @@ function addRunTasks(taskRunner: TaskRunner<TestRun>, config: FullConfigInternal
return taskRunner;
}
export function createTaskRunnerForList(config: FullConfigInternal, reporter: Multiplexer, mode: 'in-process' | 'out-of-process'): TaskRunner<TestRun> {
export function createTaskRunnerForList(config: FullConfigInternal, reporter: InternalReporter, mode: 'in-process' | 'out-of-process'): TaskRunner<TestRun> {
const taskRunner = new TaskRunner<TestRun>(reporter, config.config.globalTimeout);
taskRunner.addTask('load tests', createLoadTask(mode, false));
taskRunner.addTask('report begin', async ({ reporter, rootSuite }) => {
reporter.onBegin?.(config.config, rootSuite!);
reporter.onBegin(config.config, rootSuite!);
return () => reporter.onEnd();
});
return taskRunner;

View File

@ -20,7 +20,7 @@ import { isUnderTest, ManualPromise } from 'playwright-core/lib/utils';
import type { FullResult } from '../../reporter';
import { clearCompilationCache, collectAffectedTestFiles, dependenciesForTestFile } from '../common/compilationCache';
import type { FullConfigInternal } from '../common/config';
import { Multiplexer } from '../reporters/multiplexer';
import { InternalReporter } from '../reporters/internalReporter';
import { TeleReporterEmitter } from '../reporters/teleEmitter';
import { createReporters } from './reporters';
import { TestRun, createTaskRunnerForList, createTaskRunnerForWatch, createTaskRunnerForWatchSetup } from './tasks';
@ -65,7 +65,7 @@ class UIMode {
}
async runGlobalSetup(): Promise<FullResult['status']> {
const reporter = new Multiplexer([new ListReporter()]);
const reporter = new InternalReporter([new ListReporter()]);
const taskRunner = createTaskRunnerForWatchSetup(this._config, reporter);
reporter.onConfigure(this._config);
const testRun = new TestRun(this._config, reporter);
@ -144,7 +144,7 @@ class UIMode {
private async _listTests() {
const listReporter = new TeleReporterEmitter(e => this._dispatchEvent(e));
const reporter = new Multiplexer([listReporter]);
const reporter = new InternalReporter([listReporter]);
this._config.cliListOnly = true;
this._config.testIdMatcher = undefined;
const taskRunner = createTaskRunnerForList(this._config, reporter, 'out-of-process');
@ -169,7 +169,7 @@ class UIMode {
const reporters = await createReporters(this._config, 'ui');
reporters.push(new TeleReporterEmitter(e => this._dispatchEvent(e)));
const reporter = new Multiplexer(reporters);
const reporter = new InternalReporter(reporters);
const taskRunner = createTaskRunnerForWatch(this._config, reporter);
const testRun = new TestRun(this._config, reporter);
clearCompilationCache();

View File

@ -17,7 +17,7 @@
import readline from 'readline';
import { createGuid, ManualPromise } from 'playwright-core/lib/utils';
import type { FullConfigInternal, FullProjectInternal } from '../common/config';
import { Multiplexer } from '../reporters/multiplexer';
import { InternalReporter } from '../reporters/internalReporter';
import { createFileMatcher, createFileMatcherFromArguments } from '../util';
import type { Matcher } from '../util';
import { TestRun, createTaskRunnerForWatch, createTaskRunnerForWatchSetup } from './tasks';
@ -112,7 +112,7 @@ export async function runWatchModeLoop(config: FullConfigInternal): Promise<Full
p.project.retries = 0;
// Perform global setup.
const reporter = new Multiplexer([new ListReporter()]);
const reporter = new InternalReporter([new ListReporter()]);
const testRun = new TestRun(config, reporter);
const taskRunner = createTaskRunnerForWatchSetup(config, reporter);
reporter.onConfigure(config);
@ -275,7 +275,7 @@ async function runTests(config: FullConfigInternal, failedTestIdCollector: Set<s
title?: string,
}) {
printConfiguration(config, options?.title);
const reporter = new Multiplexer([new ListReporter()]);
const reporter = new InternalReporter([new ListReporter()]);
const taskRunner = createTaskRunnerForWatch(config, reporter, options?.additionalFileMatcher);
const testRun = new TestRun(config, reporter);
clearCompilationCache();