diff --git a/packages/playwright/src/program.ts b/packages/playwright/src/program.ts index 5d2322c783..d24add96d3 100644 --- a/packages/playwright/src/program.ts +++ b/packages/playwright/src/program.ts @@ -27,7 +27,7 @@ import { createMergedReport } from './reporters/merge'; import { loadConfigFromFileRestartIfNeeded, loadEmptyConfigForMergeReports } from './common/configLoader'; import type { ConfigCLIOverrides } from './common/ipc'; import type { FullResult, TestError } from '../types/testReporter'; -import type { FullConfig, TraceMode } from '../types/test'; +import type { TraceMode } from '../types/test'; import { builtInReporters, defaultReporter, defaultTimeout } from './common/config'; import { program } from 'playwright-core/lib/cli/program'; export { program } from 'playwright-core/lib/cli/program'; @@ -176,7 +176,7 @@ async function runTests(args: string[], opts: { [key: string]: any }) { gracefullyProcessExitDoNotHang(exitCode); } -export async function withRunnerAndMutedWrite(configFile: string | undefined, callback: (runner: Runner, config: FullConfig, configDir: string) => Promise) { +export async function withRunnerAndMutedWrite(configFile: string | undefined, callback: (runner: Runner) => Promise) { // Redefine process.stdout.write in case config decides to pollute stdio. const stdoutWrite = process.stdout.write.bind(process.stdout); process.stdout.write = ((a: any, b: any, c: any) => process.stderr.write(a, b, c)) as any; @@ -185,7 +185,7 @@ export async function withRunnerAndMutedWrite(configFile: string | undefined, ca if (!config) return; const runner = new Runner(config); - const result = await callback(runner, config.config, config.configDir); + const result = await callback(runner); stdoutWrite(JSON.stringify(result, undefined, 2), () => { gracefullyProcessExitDoNotHang(0); }); @@ -199,9 +199,8 @@ export async function withRunnerAndMutedWrite(configFile: string | undefined, ca } async function listTestFiles(opts: { [key: string]: any }) { - await withRunnerAndMutedWrite(opts.config, async (runner, config) => { - const frameworkPackage = (config as any)['@playwright/test']?.['packageJSON']; - return await runner.listTestFiles(frameworkPackage, opts.project); + await withRunnerAndMutedWrite(opts.config, async runner => { + return await runner.listTestFiles(); }); } diff --git a/packages/playwright/src/runner/runner.ts b/packages/playwright/src/runner/runner.ts index 51e902377a..142f0958cd 100644 --- a/packages/playwright/src/runner/runner.ts +++ b/packages/playwright/src/runner/runner.ts @@ -57,8 +57,9 @@ export class Runner { this._config = config; } - async listTestFiles(frameworkPackage: string | undefined, projectNames: string[] | undefined): Promise { - const projects = filterProjects(this._config.projects, projectNames); + async listTestFiles(): Promise { + const frameworkPackage = (this._config.config as any)['@playwright/test']?.['packageJSON']; + const projects = filterProjects(this._config.projects); const report: ConfigListFilesReport = { projects: [], cliEntryPoint: frameworkPackage ? path.join(path.dirname(frameworkPackage), 'cli.js') : undefined, diff --git a/packages/playwright/src/runner/testServer.ts b/packages/playwright/src/runner/testServer.ts index 6f03c640eb..77cfded710 100644 --- a/packages/playwright/src/runner/testServer.ts +++ b/packages/playwright/src/runner/testServer.ts @@ -29,6 +29,9 @@ import type { ConfigCLIOverrides } from '../common/ipc'; import { Runner } from './runner'; import type { FindRelatedTestFilesReport } from './runner'; import type { FullConfigInternal } from '../common/config'; +import type { TestServerInterface } from './testServerInterface'; +import { serializeError } from '../util'; +import { prepareErrorStack } from '../reporters/base'; export async function runTestServer() { if (restartWithExperimentalTsEsm(undefined, true)) @@ -60,44 +63,6 @@ export async function runTestServer() { process.stdin.on('close', () => gracefullyProcessExitDoNotHang(0)); } -export interface TestServerInterface { - list(params: { - configFile: string; - locations: string[]; - reporter: string; - env: NodeJS.ProcessEnv; - }): Promise; - - test(params: { - configFile: string; - locations: string[]; - reporter: string; - env: NodeJS.ProcessEnv; - headed?: boolean; - oneWorker?: boolean; - trace?: 'on' | 'off'; - projects?: string[]; - grep?: string; - reuseContext?: boolean; - connectWsEndpoint?: string; - }): Promise; - - findRelatedTestFiles(params: { - configFile: string; - files: string[]; - }): Promise<{ testFiles: string[]; errors?: TestError[]; }>; - - stop(params: { - configFile: string; - }): Promise; - - closeGracefully(): Promise; -} - -export interface TestServerEvents { - on(event: 'stdio', listener: (params: { type: 'stdout' | 'stderr', text?: string, buffer?: string }) => void): void; -} - class Dispatcher implements TestServerInterface { private _testRun: { run: Promise, stop: ManualPromise } | undefined; private _ws: WebSocket; @@ -123,7 +88,30 @@ class Dispatcher implements TestServerInterface { }) as any; } - async list(params: { + async listFiles(params: { + configFile: string; + }): Promise<{ + projects: { + name: string; + testDir: string; + use: { testIdAttribute?: string }; + files: string[]; + }[]; + cliEntryPoint?: string; + error?: TestError; + }> { + try { + const config = await this._loadConfig(params.configFile); + const runner = new Runner(config); + return runner.listTestFiles(); + } catch (e) { + const error: TestError = serializeError(e); + error.location = prepareErrorStack(e.stack).location; + return { projects: [], error }; + } + } + + async listTests(params: { configFile: string; locations: string[]; reporter: string; diff --git a/packages/playwright/src/runner/testServerInterface.ts b/packages/playwright/src/runner/testServerInterface.ts new file mode 100644 index 0000000000..b1e0464f71 --- /dev/null +++ b/packages/playwright/src/runner/testServerInterface.ts @@ -0,0 +1,68 @@ +/** + * 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 { TestError } from '../../types/testReporter'; + +export interface TestServerInterface { + listFiles(params: { + configFile: string; + }): Promise<{ + projects: { + name: string; + testDir: string; + use: { testIdAttribute?: string }; + files: string[]; + }[]; + cliEntryPoint?: string; + error?: TestError; + }>; + + listTests(params: { + configFile: string; + locations: string[]; + reporter: string; + env: NodeJS.ProcessEnv; + }): Promise; + + test(params: { + configFile: string; + locations: string[]; + reporter: string; + env: NodeJS.ProcessEnv; + headed?: boolean; + oneWorker?: boolean; + trace?: 'on' | 'off'; + projects?: string[]; + grep?: string; + reuseContext?: boolean; + connectWsEndpoint?: string; + }): Promise; + + findRelatedTestFiles(params: { + configFile: string; + files: string[]; + }): Promise<{ testFiles: string[]; errors?: TestError[]; }>; + + stop(params: { + configFile: string; + }): Promise; + + closeGracefully(): Promise; +} + +export interface TestServerEvents { + on(event: 'stdio', listener: (params: { type: 'stdout' | 'stderr', text?: string, buffer?: string }) => void): void; +} diff --git a/tests/playwright-test/list-files.spec.ts b/tests/playwright-test/list-files.spec.ts index 25cb3e6cee..80df3a0e5b 100644 --- a/tests/playwright-test/list-files.spec.ts +++ b/tests/playwright-test/list-files.spec.ts @@ -48,30 +48,6 @@ test('should list files', async ({ runCLICommand }) => { }); }); -test('should support wildcard list files', async ({ runCLICommand }) => { - const result = await runCLICommand({ - 'playwright.config.ts': ` - module.exports = { projects: [{ name: 'foo' }, { name: 'bar' }] }; - `, - 'a.test.js': `` - }, 'list-files', ['--project', 'f*o']); - expect(result.exitCode).toBe(0); - - const data = JSON.parse(result.stdout); - expect(data).toEqual({ - projects: [ - { - name: 'foo', - testDir: expect.stringContaining('list-files-should-support-wildcard-list-files-playwright-test'), - use: {}, - files: [ - expect.stringContaining('a.test.js') - ] - } - ] - }); -}); - test('should include testIdAttribute', async ({ runCLICommand }) => { const result = await runCLICommand({ 'playwright.config.ts': `