From c7b074d39ec6f84ed4463a3a23b574bafe586828 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Mon, 18 Mar 2024 17:14:21 -0700 Subject: [PATCH] chore: prepare to reuse test server from ui mode (3) (#29989) --- .../playwright-core/src/utils/httpServer.ts | 8 ++++-- packages/playwright/src/runner/runner.ts | 2 +- .../src/runner/{uiMode.ts => testServer.ts} | 17 ++++++++----- .../playwright/src/runner/uiModeReporter.ts | 25 +++++++++++++++++++ 4 files changed, 43 insertions(+), 9 deletions(-) rename packages/playwright/src/runner/{uiMode.ts => testServer.ts} (94%) create mode 100644 packages/playwright/src/runner/uiModeReporter.ts diff --git a/packages/playwright-core/src/utils/httpServer.ts b/packages/playwright-core/src/utils/httpServer.ts index a420675096..c83c6601eb 100644 --- a/packages/playwright-core/src/utils/httpServer.ts +++ b/packages/playwright-core/src/utils/httpServer.ts @@ -86,8 +86,12 @@ export class HttpServer { transport.close = () => ws.close(); ws.on('message', async (message: string) => { const { id, method, params } = JSON.parse(message); - const result = await transport.dispatch(method, params); - ws.send(JSON.stringify({ id, result })); + try { + const result = await transport.dispatch(method, params); + ws.send(JSON.stringify({ id, result })); + } catch (e) { + ws.send(JSON.stringify({ id, error: String(e) })); + } }); ws.on('close', () => transport.onclose()); ws.on('error', () => transport.onclose()); diff --git a/packages/playwright/src/runner/runner.ts b/packages/playwright/src/runner/runner.ts index 8b25370855..4a2d329159 100644 --- a/packages/playwright/src/runner/runner.ts +++ b/packages/playwright/src/runner/runner.ts @@ -26,7 +26,7 @@ import { TestRun, createTaskRunner, createTaskRunnerForList } from './tasks'; import type { FullConfigInternal } from '../common/config'; import { colors } from 'playwright-core/lib/utilsBundle'; import { runWatchModeLoop } from './watchMode'; -import { runTestServer } from './uiMode'; +import { runTestServer } from './testServer'; import { InternalReporter } from '../reporters/internalReporter'; import { Multiplexer } from '../reporters/multiplexer'; import type { Suite } from '../common/test'; diff --git a/packages/playwright/src/runner/uiMode.ts b/packages/playwright/src/runner/testServer.ts similarity index 94% rename from packages/playwright/src/runner/uiMode.ts rename to packages/playwright/src/runner/testServer.ts index 023e2653fa..9577c52704 100644 --- a/packages/playwright/src/runner/uiMode.ts +++ b/packages/playwright/src/runner/testServer.ts @@ -21,8 +21,7 @@ import type { FullResult, Location, TestError } from '../../types/testReporter'; import { collectAffectedTestFiles, dependenciesForTestFile } from '../transform/compilationCache'; import type { FullConfigInternal } from '../common/config'; import { InternalReporter } from '../reporters/internalReporter'; -import { TeleReporterEmitter } from '../reporters/teleEmitter'; -import { createReporters } from './reporters'; +import { createReporterForTestServer, createReporters } from './reporters'; import { TestRun, createTaskRunnerForList, createTaskRunnerForWatch, createTaskRunnerForWatchSetup } from './tasks'; import { open } from 'playwright-core/lib/utilsBundle'; import ListReporter from '../reporters/list'; @@ -157,12 +156,13 @@ class TestServerDispatcher implements TestServerInterface { } async listTests(params: { reporter?: string; fileNames: string[]; }) { - this._queue = this._queue.then(() => this._innerListTests(params)); + this._queue = this._queue.then(() => this._innerListTests(params)).catch(printInternalError); await this._queue; } private async _innerListTests(params: { reporter?: string; fileNames?: string[]; }) { - const reporter = new InternalReporter(new TeleReporterEmitter(e => this._dispatchEvent('listReport', e), { omitBuffers: true })); + const wireReporter = await createReporterForTestServer(this._config, params.reporter || require.resolve('./uiModeReporter'), 'list', e => this._dispatchEvent('listReport', e)); + const reporter = new InternalReporter(wireReporter); this._config.cliArgs = params.fileNames || []; this._config.cliListOnly = true; this._config.testIdMatcher = undefined; @@ -183,7 +183,7 @@ class TestServerDispatcher implements TestServerInterface { } async runTests(params: { reporter?: string; locations?: string[] | undefined; grep?: string | undefined; testIds?: string[] | undefined; headed?: boolean | undefined; oneWorker?: boolean | undefined; trace?: 'off' | 'on' | undefined; projects?: string[] | undefined; reuseContext?: boolean | undefined; connectWsEndpoint?: string | undefined; }) { - this._queue = this._queue.then(() => this._innerRunTests(params)); + this._queue = this._queue.then(() => this._innerRunTests(params)).catch(printInternalError); await this._queue; } @@ -199,7 +199,7 @@ class TestServerDispatcher implements TestServerInterface { this._config.testIdMatcher = id => !testIdSet || testIdSet.has(id); const reporters = await createReporters(this._config, 'ui'); - reporters.push(new TeleReporterEmitter(e => this._dispatchEvent('testReport', e), { omitBuffers: true })); + reporters.push(await createReporterForTestServer(this._config, params.reporter || require.resolve('./uiModeReporter'), 'list', e => this._dispatchEvent('testReport', e))); const reporter = new InternalReporter(new Multiplexer(reporters)); const taskRunner = createTaskRunnerForWatch(this._config, reporter); const testRun = new TestRun(this._config, reporter); @@ -291,3 +291,8 @@ async function installBrowsers() { const executables = registry.defaultExecutables(); await registry.install(executables, false); } + +function printInternalError(e: Error) { + // eslint-disable-next-line no-console + console.error('Internal error:', e); +} diff --git a/packages/playwright/src/runner/uiModeReporter.ts b/packages/playwright/src/runner/uiModeReporter.ts new file mode 100644 index 0000000000..8de663149a --- /dev/null +++ b/packages/playwright/src/runner/uiModeReporter.ts @@ -0,0 +1,25 @@ +/** + * 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 { TeleReporterEmitter } from '../reporters/teleEmitter'; + +class UIModeReporter extends TeleReporterEmitter { + constructor(options: any) { + super(options._send, { omitBuffers: true }); + } +} + +export default UIModeReporter;