diff --git a/playwright.config.ts b/playwright.config.ts index 0a5703889..e8cd3fd46 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -18,6 +18,7 @@ import { WorkerOptions } from './tests/utils'; const config: PlaywrightTestConfig = { testDir: './tests', + outputDir: './test-results/inner', fullyParallel: true, forbidOnly: !!process.env.CI, workers: process.env.CI ? 1 : undefined, diff --git a/src/backend.ts b/src/backend.ts index a3528b76b..804a46884 100644 --- a/src/backend.ts +++ b/src/backend.ts @@ -20,41 +20,47 @@ import * as vscodeTypes from './vscodeTypes'; import EventEmitter from 'events'; import { WebSocketTransport } from './transport'; +export type BackendServerOptions = { + args: string[], + cwd: string, + envProvider: () => NodeJS.ProcessEnv, + clientFactory: () => T, + dumpIO?: boolean, +}; + export class BackendServer { private _vscode: vscodeTypes.VSCode; - private _args: string[]; - private _cwd: string; - private _envProvider: () => NodeJS.ProcessEnv; - private _clientFactory: () => T; + private _options: BackendServerOptions; - constructor(vscode: vscodeTypes.VSCode, args: string[], cwd: string, envProvider: () => NodeJS.ProcessEnv, clientFactory: () => T) { + constructor(vscode: vscodeTypes.VSCode, options: BackendServerOptions) { this._vscode = vscode; - this._args = args; - this._cwd = cwd; - this._envProvider = envProvider; - this._clientFactory = clientFactory; + this._options = options; } async start(): Promise { - const node = await findNode(this._vscode, this._cwd); - const serverProcess = spawn(node, this._args, { - cwd: this._cwd, + const node = await findNode(this._vscode, this._options.cwd); + const serverProcess = spawn(node, this._options.args, { + cwd: this._options.cwd, stdio: 'pipe', env: { ...process.env, - ...this._envProvider(), + ...this._options.envProvider(), }, }); - const client = this._clientFactory(); + const client = this._options.clientFactory(); - serverProcess.stderr?.on('data', () => {}); + serverProcess.stderr?.on('data', data => { + if (this._options.dumpIO) + console.log('[server err]', data.toString()); + }); serverProcess.on('error', error => { client._onErrorEvent.fire(error); }); - return new Promise(fulfill => { serverProcess.stdout?.on('data', async data => { + if (this._options.dumpIO) + console.log('[server out]', data.toString()); const match = data.toString().match(/Listening on (.*)/); if (!match) return; diff --git a/src/extension.ts b/src/extension.ts index ce72d0161..30f2c0140 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -30,6 +30,7 @@ import { NodeJSNotFoundError, ansiToHtml } from './utils'; import * as vscodeTypes from './vscodeTypes'; import { WorkspaceChange, WorkspaceObserver } from './workspaceObserver'; import { TraceViewer } from './traceViewer'; +import { TestServerController } from './testServerController'; const stackUtils = new StackUtils({ cwd: '/ensure_absolute_paths' @@ -87,6 +88,7 @@ export class Extension implements RunHooks { } | undefined; private _diagnostics: Record<'configErrors' | 'testErrors', vscodeTypes.DiagnosticCollection>; private _treeItemObserver: TreeItemObserver; + private _testServerController: TestServerController; constructor(vscode: vscodeTypes.VSCode) { this._vscode = vscode; @@ -111,7 +113,8 @@ export class Extension implements RunHooks { this._settingsModel = new SettingsModel(vscode); this._reusedBrowser = new ReusedBrowser(this._vscode, this._settingsModel, this._envProvider.bind(this)); this._traceViewer = new TraceViewer(this._vscode, this._settingsModel, this._envProvider.bind(this)); - this._playwrightTest = new PlaywrightTest(this._vscode, this._settingsModel, this, this._isUnderTest, this._envProvider.bind(this)); + this._testServerController = new TestServerController(this._vscode, this._envProvider.bind(this)); + this._playwrightTest = new PlaywrightTest(this._vscode, this._settingsModel, this, this._isUnderTest, this._testServerController, this._envProvider.bind(this)); this._testController = vscode.tests.createTestController('pw.extension.testController', 'Playwright'); this._testController.resolveHandler = item => this._resolveChildren(item); this._testController.refreshHandler = () => this._rebuildModel(true).then(() => {}); @@ -214,6 +217,7 @@ export class Extension implements RunHooks { this._reusedBrowser, ...Object.values(this._diagnostics), this._treeItemObserver, + this._testServerController, ]; await this._rebuildModel(false); diff --git a/src/oopReporter.ts b/src/oopReporter.ts index d4ee5485d..a19bc5d05 100644 --- a/src/oopReporter.ts +++ b/src/oopReporter.ts @@ -66,13 +66,15 @@ class OopReporter implements Reporter { constructor() { this._transport = WebSocketTransport.connect(process.env.PW_TEST_REPORTER_WS_ENDPOINT!); - this._transport.then(t => { - t.onmessage = message => { - if (message.method === 'stop') - process.emit('SIGINT' as any); - }; - t.onclose = () => process.exit(0); - }); + if (process.env.PW_TEST_REPORTER_SELF_DESTRUCT) { + this._transport.then(t => { + t.onmessage = message => { + if (message.method === 'stop') + process.emit('SIGINT' as any); + }; + t.onclose = () => process.exit(0); + }); + } } printsToStdio() { @@ -177,7 +179,8 @@ class OopReporter implements Reporter { async onEnd(result: FullResult) { this._emit('onEnd', {}); // Embedder is responsible for terminating the connection. - await new Promise(() => {}); + if (process.env.PW_TEST_REPORTER_SELF_DESTRUCT) + await new Promise(() => {}); } private _emit(method: string, params: Object) { diff --git a/src/playwrightTest.ts b/src/playwrightTest.ts index 6e97a80fd..c8c2b142a 100644 --- a/src/playwrightTest.ts +++ b/src/playwrightTest.ts @@ -23,6 +23,7 @@ import { ReporterServer } from './reporterServer'; import { findNode, spawnAsync } from './utils'; import * as vscodeTypes from './vscodeTypes'; import { SettingsModel } from './settingsModel'; +import { TestServerController } from './testServerController'; export type TestConfig = { workspaceFolder: string; @@ -47,8 +48,12 @@ export interface TestListener { const pathSeparator = process.platform === 'win32' ? ';' : ':'; export type PlaywrightTestOptions = { + headed?: boolean, + oneWorker?: boolean, + trace?: 'on' | 'off', projects?: string[]; grep?: string; + reuseContext?: boolean, connectWsEndpoint?: string; }; @@ -64,12 +69,14 @@ export class PlaywrightTest { private _envProvider: () => NodeJS.ProcessEnv; private _vscode: vscodeTypes.VSCode; private _settingsModel: SettingsModel; + private _testServerController: TestServerController; - constructor(vscode: vscodeTypes.VSCode, settingsModel: SettingsModel, runHooks: RunHooks, isUnderTest: boolean, envProvider: () => NodeJS.ProcessEnv) { + constructor(vscode: vscodeTypes.VSCode, settingsModel: SettingsModel, runHooks: RunHooks, isUnderTest: boolean, testServerController: TestServerController, envProvider: () => NodeJS.ProcessEnv) { this._vscode = vscode; this._settingsModel = settingsModel; this._runHooks = runHooks; this._isUnderTest = isUnderTest; + this._testServerController = testServerController; this._envProvider = envProvider; } @@ -117,15 +124,33 @@ export class PlaywrightTest { const locationArg = locations ? locations : []; if (token?.isCancellationRequested) return; - const testOptions = await this._runHooks.onWillRunTests(config, false); + const externalOptions = await this._runHooks.onWillRunTests(config, false); + const showBrowser = this._settingsModel.showBrowser.get() && !!externalOptions.connectWsEndpoint; + + let trace: 'on' | 'off' | undefined; + if (this._settingsModel.showTrace.get()) + trace = 'on'; + // "Show browser" mode forces context reuse that survives over multiple test runs. + // Playwright Test sets up `tracesDir` inside the `test-results` folder, so it will be removed between runs. + // When context is reused, its ongoing tracing will fail with ENOENT because trace files + // were suddenly removed. So we disable tracing in this case. + if (this._settingsModel.showBrowser.get()) + trace = 'off'; + + const options: PlaywrightTestOptions = { + grep: parametrizedTestTitle, + projects: projectNames.length ? projectNames.filter(Boolean) : undefined, + headed: showBrowser && !this._isUnderTest, + oneWorker: showBrowser, + trace, + reuseContext: showBrowser, + connectWsEndpoint: showBrowser ? externalOptions.connectWsEndpoint : undefined, + }; + try { if (token?.isCancellationRequested) return; - await this._test(config, locationArg, 'run', { - grep: parametrizedTestTitle, - projects: projectNames.filter(Boolean), - ...testOptions - }, listener, token); + await this._test(config, locationArg, 'run', options, listener, token); } finally { await this._runHooks.onDidRunTests(false); } @@ -146,6 +171,13 @@ export class PlaywrightTest { } private async _test(config: TestConfig, locations: string[], mode: 'list' | 'run', options: PlaywrightTestOptions, listener: TestListener, token: vscodeTypes.CancellationToken): Promise { + if (process.env.PWTEST_VSCODE_SERVER) + await this._testWithServer(config, locations, mode, options, listener, token); + else + await this._testWithCLI(config, locations, mode, options, listener, token); + } + + private async _testWithCLI(config: TestConfig, locations: string[], mode: 'list' | 'run', options: PlaywrightTestOptions, listener: TestListener, token: vscodeTypes.CancellationToken): Promise { // Playwright will restart itself as child process in the ESM mode and won't inherit the 3/4 pipes. // Always use ws transport to mitigate it. const reporterServer = new ReporterServer(this._vscode); @@ -176,21 +208,13 @@ export class PlaywrightTest { '--repeat-each', '1', '--retries', '0', ]; - const showBrowser = this._settingsModel.showBrowser.get() && !!options.connectWsEndpoint; - if (mode === 'run') { - if (showBrowser && !this._isUnderTest) - allArgs.push('--headed'); - if (showBrowser) - allArgs.push('--workers', '1'); - if (this._settingsModel.showTrace.get()) - allArgs.push('--trace', 'on'); - // "Show browser" mode forces context reuse that survives over multiple test runs. - // Playwright Test sets up `tracesDir` inside the `test-results` folder, so it will be removed between runs. - // When context is reused, its ongoing tracing will fail with ENOENT because trace files - // were suddenly removed. So we disable tracing in this case. - if (this._settingsModel.showBrowser.get()) - allArgs.push('--trace', 'off'); - } + + if (options.headed) + allArgs.push('--headed'); + if (options.oneWorker) + allArgs.push('--workers', '1'); + if (options.trace) + allArgs.push('--trace', options.trace); const childProcess = spawn(node, allArgs, { cwd: configFolder, @@ -201,9 +225,9 @@ export class PlaywrightTest { // Don't debug tests when running them. NODE_OPTIONS: undefined, ...this._envProvider(), - PW_TEST_REUSE_CONTEXT: showBrowser ? '1' : undefined, - PW_TEST_CONNECT_WS_ENDPOINT: showBrowser ? options.connectWsEndpoint : undefined, - ...(await reporterServer.env()), + PW_TEST_REUSE_CONTEXT: options.reuseContext ? '1' : undefined, + PW_TEST_CONNECT_WS_ENDPOINT: options.connectWsEndpoint, + ...(await reporterServer.env({ selfDestruct: true })), // Reset VSCode's options that affect nested Electron. ELECTRON_RUN_AS_NODE: undefined, FORCE_COLOR: '1', @@ -218,6 +242,33 @@ export class PlaywrightTest { await reporterServer.wireTestListener(listener, token); } + private async _testWithServer(config: TestConfig, locations: string[], mode: 'list' | 'run', options: PlaywrightTestOptions, listener: TestListener, token: vscodeTypes.CancellationToken): Promise { + const reporterServer = new ReporterServer(this._vscode); + const testServer = await this._testServerController.testServerFor(config); + if (!testServer) + return; + if (token?.isCancellationRequested) + return; + const env = await reporterServer.env({ selfDestruct: false }); + const reporter = reporterServer.reporterFile(); + if (mode === 'list') + testServer.list({ locations, reporter, env }); + if (mode === 'run') { + testServer.test({ locations, reporter, env, options }); + token.onCancellationRequested(() => { + testServer.stop(); + }); + testServer.on('stdio', params => { + if (params.type === 'stdout') + listener.onStdOut?.(unwrapString(params)); + if (params.type === 'stderr') + listener.onStdErr?.(unwrapString(params)); + }); + } + + await reporterServer.wireTestListener(listener, token); + } + async debugTests(vscode: vscodeTypes.VSCode, config: TestConfig, projectNames: string[], testDirs: string[], settingsEnv: NodeJS.ProcessEnv, locations: string[] | null, listener: TestListener, parametrizedTestTitle: string | undefined, token: vscodeTypes.CancellationToken) { const configFolder = path.dirname(config.configFile); const configFile = path.basename(config.configFile); @@ -255,7 +306,7 @@ export class PlaywrightTest { CI: this._isUnderTest ? undefined : process.env.CI, ...settingsEnv, PW_TEST_CONNECT_WS_ENDPOINT: testOptions.connectWsEndpoint, - ...(await reporterServer.env()), + ...(await reporterServer.env({ selfDestruct: true })), // Reset VSCode's options that affect nested Electron. ELECTRON_RUN_AS_NODE: undefined, FORCE_COLOR: '1', @@ -289,3 +340,7 @@ export class PlaywrightTest { function escapeRegex(text: string) { return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } + +function unwrapString(params: { text?: string, buffer?: string }): string | Buffer { + return params.buffer ? Buffer.from(params.buffer, 'base64') : params.text || ''; +} diff --git a/src/reporterServer.ts b/src/reporterServer.ts index 5e046677f..9c3d86cc0 100644 --- a/src/reporterServer.ts +++ b/src/reporterServer.ts @@ -33,11 +33,16 @@ export class ReporterServer { this._clientSocketPromise = new Promise(f => this._clientSocketCallback = f); } - async env() { + reporterFile() { + return require.resolve('./oopReporter'); + } + + async env(options: { selfDestruct: boolean }) { const wsEndpoint = await this._listen(); return { - PW_TEST_REPORTER: require.resolve('./oopReporter'), + PW_TEST_REPORTER: this.reporterFile(), PW_TEST_REPORTER_WS_ENDPOINT: wsEndpoint, + PW_TEST_REPORTER_SELF_DESTRUCT: options.selfDestruct ? '1' : '', }; } diff --git a/src/reusedBrowser.ts b/src/reusedBrowser.ts index d4cfeeff3..59f373234 100644 --- a/src/reusedBrowser.ts +++ b/src/reusedBrowser.ts @@ -88,7 +88,12 @@ export class ReusedBrowser implements vscodeTypes.Disposable { PW_EXTENSION_MODE: '1', }); - const backendServer = new BackendServer(this._vscode, args, cwd, envProvider, () => new Backend(this._vscode)); + const backendServer = new BackendServer(this._vscode, { + args, + cwd, + envProvider, + clientFactory: () => new Backend(this._vscode) + }); const backend = await backendServer.start(); if (!backend) return; diff --git a/src/testServerController.ts b/src/testServerController.ts new file mode 100644 index 000000000..01e30a49d --- /dev/null +++ b/src/testServerController.ts @@ -0,0 +1,72 @@ +/** + * 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 { BackendClient, BackendServer } from './backend'; +import { TestConfig } from './playwrightTest'; +import * as vscodeTypes from './vscodeTypes'; + +export class TestServerController implements vscodeTypes.Disposable { + private _vscode: vscodeTypes.VSCode; + private _testServers = new Map(); + private _envProvider: () => NodeJS.ProcessEnv; + + constructor(vscode: vscodeTypes.VSCode, envProvider: () => NodeJS.ProcessEnv) { + this._vscode = vscode; + this._envProvider = envProvider; + } + + async testServerFor(config: TestConfig): Promise { + const existing = this._testServers.get(config); + if (existing) + return existing; + const args = [config.cli, 'test-server']; + const testServerBackend = new BackendServer(this._vscode, { + args, + cwd: config.workspaceFolder, + envProvider: this._envProvider, + clientFactory: () => new TestServer(this._vscode), + dumpIO: false, + }); + const testServer = await testServerBackend.start(); + if (!testServer) + return null; + this._testServers.set(config, testServer); + return testServer; + } + + dispose() { + for (const backend of this._testServers.values()) + backend.close(); + this._testServers.clear(); + } +} + +class TestServer extends BackendClient { + override async initialize(): Promise { + } + + async list(params: any) { + await this.send('list', params); + } + + async test(params: any) { + await this.send('test', params); + } + + async stop() { + await this.send('stop', {}); + } +} diff --git a/tests/debug-tests.spec.ts b/tests/debug-tests.spec.ts index 5406d9a46..971818c25 100644 --- a/tests/debug-tests.spec.ts +++ b/tests/debug-tests.spec.ts @@ -42,7 +42,7 @@ test('should debug all tests', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > debug -c playwright.config.js `); @@ -69,7 +69,7 @@ test('should debug one test', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > debug -c playwright.config.js tests/test.spec.ts:3 diff --git a/tests/decorations.spec.ts b/tests/decorations.spec.ts index 6fe08c574..115de1742 100644 --- a/tests/decorations.spec.ts +++ b/tests/decorations.spec.ts @@ -63,7 +63,7 @@ test('should highlight steps while running', async ({ activate }) => { [5:18 - 5:18]: decorator #2 {"after":{"contentText":" — Xms"}} `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js diff --git a/tests/global-errors.spec.ts b/tests/global-errors.spec.ts index bf6868405..5d8e95fc4 100644 --- a/tests/global-errors.spec.ts +++ b/tests/global-errors.spec.ts @@ -28,7 +28,7 @@ test('should report duplicate test title', async ({ activate }) => { }); await testController.expandTestItems(/test.spec.ts/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts `); @@ -69,7 +69,7 @@ test('should report error in global setup', async ({ activate }) => { globalSetup.ts:[3:21 - 3:21] Error: expect(`); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js `); diff --git a/tests/list-files.spec.ts b/tests/list-files.spec.ts index 36177ae28..c14021ca9 100644 --- a/tests/list-files.spec.ts +++ b/tests/list-files.spec.ts @@ -26,11 +26,11 @@ test('should list files', async ({ activate }) => { `, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); @@ -44,10 +44,10 @@ test('should list files top level if no testDir', async ({ activate }, testInfo) `, }, { rootDir: testInfo.outputPath('myWorkspace') }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - test.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); @@ -64,7 +64,7 @@ test('should list only test files', async ({ activate }) => { `, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts `); @@ -79,7 +79,7 @@ test('should list folders', async ({ activate }) => { 'tests/a/b/c/d/test-c.spec.ts': ``, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - a - b @@ -92,7 +92,7 @@ test('should list folders', async ({ activate }) => { - test-a.spec.ts - test-b.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); @@ -103,12 +103,12 @@ test('should pick new files', async ({ activate }) => { 'tests/test-1.spec.ts': `` }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); @@ -117,13 +117,13 @@ test('should pick new files', async ({ activate }) => { workspaceFolder.addFile('tests/test-2.spec.ts', '') ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts - test-2.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright list-files -c playwright.config.js `); @@ -135,7 +135,7 @@ test('should not pick non-test files', async ({ activate }) => { 'tests/test-1.spec.ts': `` }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts `); @@ -146,7 +146,7 @@ test('should not pick non-test files', async ({ activate }) => { workspaceFolder.addFile('tests/test-2.spec.ts', ''), ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts - test-2.spec.ts @@ -158,7 +158,7 @@ test('should tolerate missing testDir', async ({ activate }) => { 'playwright.config.js': `module.exports = { testDir: 'tests' }`, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` `); await Promise.all([ @@ -166,7 +166,7 @@ test('should tolerate missing testDir', async ({ activate }) => { workspaceFolder.addFile('tests/test.spec.ts', '') ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts `); @@ -180,14 +180,14 @@ test('should remove deleted files', async ({ activate }) => { 'tests/test-3.spec.ts': ``, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts - test-2.spec.ts - test-3.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); @@ -196,13 +196,13 @@ test('should remove deleted files', async ({ activate }) => { workspaceFolder.removeFile('tests/test-2.spec.ts') ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts - test-3.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); @@ -215,7 +215,7 @@ test('should do nothing for not loaded changed file', async ({ activate }) => { 'tests/test-3.spec.ts': ``, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts - test-2.spec.ts @@ -242,14 +242,14 @@ test('should support multiple configs', async ({ activate }) => { test(two', async () => {}); `, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests1 - test.spec.ts - tests2 - test.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` tests1> playwright list-files -c playwright.config.js tests2> playwright list-files -c playwright.config.js `); @@ -273,13 +273,13 @@ test('should support multiple projects', async ({ activate }) => { test(two', async () => {}); `, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test1.spec.ts - test2.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); @@ -306,13 +306,13 @@ test('should support multiple projects with filter', async ({ activate }) => { test(three', async () => {}); `, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test1.spec.ts - test2.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); @@ -325,11 +325,11 @@ test('should list files in relative folder', async ({ activate }) => { test('one', async () => {}); `, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` foo/bar> playwright list-files -c playwright.config.js `); }); @@ -358,7 +358,7 @@ test('should list files in multi-folder workspace', async ({ activate }, testInf const context = { subscriptions: [] }; await extension.activate(context); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - folder1 - test.spec.ts - folder2 @@ -376,11 +376,11 @@ test('should ignore errors when listing files', async ({ activate }) => { `, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright list-files -c playwright.config.ts `); diff --git a/tests/list-tests.spec.ts b/tests/list-tests.spec.ts index 0f10b36cc..0530c4601 100644 --- a/tests/list-tests.spec.ts +++ b/tests/list-tests.spec.ts @@ -27,13 +27,13 @@ test('should list tests on expand', async ({ activate }) => { }); await testController.expandTestItems(/test.spec.ts/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts `); @@ -55,7 +55,7 @@ test('should list tests for visible editors', async ({ activate }) => { await vscode.openEditors('**/test*.spec.ts'); await new Promise(f => testController.onDidChangeTestItem(f)); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test1.spec.ts - one [2:0] @@ -63,7 +63,7 @@ test('should list tests for visible editors', async ({ activate }) => { - two [2:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test1.spec.ts tests/test2.spec.ts `); @@ -92,7 +92,7 @@ test('should list suits', async ({ activate }) => { }); await testController.expandTestItems(/test.spec.ts/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] @@ -120,7 +120,7 @@ test('should discover new tests', async ({ activate }) => { await testController.expandTestItems(/test.spec.ts/); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts `); @@ -134,14 +134,14 @@ test('should discover new tests', async ({ activate }) => { `) ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] - two [3:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts @@ -157,7 +157,7 @@ test('should discover new tests with active editor', async ({ activate }) => { `, }); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); @@ -176,14 +176,14 @@ test('should discover new tests with active editor', async ({ activate }) => { vscode.openEditors('**/test2.spec.ts'), ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test1.spec.ts - test2.spec.ts - two [2:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test2.spec.ts @@ -200,7 +200,7 @@ test('should discover tests on add + change', async ({ activate }) => { workspaceFolder.addFile('test.spec.ts', ``) ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - test.spec.ts `); @@ -214,12 +214,12 @@ test('should discover tests on add + change', async ({ activate }) => { `) ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - test.spec.ts - one [2:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null test.spec.ts @@ -238,7 +238,7 @@ test('should discover new test at existing location', async ({ activate }) => { await testController.expandTestItems(/test.spec.ts/); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts `); @@ -251,13 +251,13 @@ test('should discover new test at existing location', async ({ activate }) => { `) ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - two [2:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts @@ -276,12 +276,12 @@ test('should remove deleted tests', async ({ activate }) => { await testController.expandTestItems(/test.spec.ts/); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts `); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] @@ -296,13 +296,13 @@ test('should remove deleted tests', async ({ activate }) => { `) ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts @@ -321,7 +321,7 @@ test('should forget tests after error before first test', async ({ activate }) = await testController.expandTestItems(/test.spec.ts/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] @@ -338,7 +338,7 @@ test('should forget tests after error before first test', async ({ activate }) = `) ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts `); @@ -357,12 +357,12 @@ test('should regain tests after error is fixed', async ({ activate }) => { await testController.expandTestItems(/test.spec.ts/); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts `); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts `); @@ -376,14 +376,14 @@ test('should regain tests after error is fixed', async ({ activate }) => { `) ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] - two [3:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts @@ -406,7 +406,7 @@ test('should support multiple configs', async ({ activate }) => { await testController.expandTestItems(/test.spec/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests1 - test.spec.ts - one [2:0] @@ -415,7 +415,7 @@ test('should support multiple configs', async ({ activate }) => { - two [2:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` tests1> playwright list-files -c playwright.config.js tests2> playwright list-files -c playwright.config.js tests1> playwright test -c playwright.config.js --list --reporter=null test.spec.ts @@ -444,14 +444,14 @@ test('should support multiple projects', async ({ activate }) => { await testController.expandTestItems(/test1.spec/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test1.spec.ts - one [2:0] - test2.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test1.spec.ts `); @@ -468,7 +468,7 @@ test('should list parametrized tests', async ({ activate }) => { }); await testController.expandTestItems(/test.spec.ts/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [3:0] @@ -491,7 +491,7 @@ test('should list tests in parametrized groups', async ({ activate }) => { }); await testController.expandTestItems(/test.spec.ts/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - level 1 [3:0] @@ -514,7 +514,7 @@ test('should not run config reporters', async ({ activate }, testInfo) => { }); await testController.expandTestItems(/test.spec.ts/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] @@ -544,7 +544,7 @@ test('should list tests in multi-folder workspace', async ({ activate }, testInf }); await testController.expandTestItems(/test.spec.ts/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - folder1 - test.spec.ts - one [2:0] diff --git a/tests/mock/vscode.ts b/tests/mock/vscode.ts index 27a9c0228..2e7a51fb7 100644 --- a/tests/mock/vscode.ts +++ b/tests/mock/vscode.ts @@ -297,6 +297,7 @@ export class TestMessage { result.push(`${indent}${path.basename(this.location.uri.fsPath)}:${this.location.range.toString()}`); const message = this.message.render(); for (let line of message.split('\n')) { + line = line.replace(/at .*\/test-results.*[/\\]tests(.*)\)/, 'at tests$1'); if (this.location && line.includes(' at')) line = line.replace(/\\/g, '/'); if (this.location && line.includes('    at')) diff --git a/tests/profile-discovery.spec.ts b/tests/profile-discovery.spec.ts index cedcc7d34..18b54d0ad 100644 --- a/tests/profile-discovery.spec.ts +++ b/tests/profile-discovery.spec.ts @@ -39,7 +39,7 @@ test('should create run & debug profiles', async ({ activate }, testInfo) => { expect(runProfiles[1].kind).toBe(vscode.TestRunProfileKind.Debug); expect(runProfiles[1].isDefault).toBeFalsy(); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); @@ -71,7 +71,7 @@ test('should create run & debug profile per project', async ({ activate }, testI expect(runProfiles[3].kind).toBe(vscode.TestRunProfileKind.Debug); expect(runProfiles[1].isDefault).toBeFalsy(); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); diff --git a/tests/run-annotations.spec.ts b/tests/run-annotations.spec.ts index 2fd57b10b..c67c66b72 100644 --- a/tests/run-annotations.spec.ts +++ b/tests/run-annotations.spec.ts @@ -55,7 +55,7 @@ test('should mark test as skipped', async ({ activate }) => { skipped `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js `); diff --git a/tests/run-tests.spec.ts b/tests/run-tests.spec.ts index 5ce472bdb..8a33f0ddc 100644 --- a/tests/run-tests.spec.ts +++ b/tests/run-tests.spec.ts @@ -43,7 +43,7 @@ test('should run all tests', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js `); @@ -70,7 +70,7 @@ test('should run one test', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js tests/test.spec.ts:3 @@ -133,7 +133,7 @@ test('should run file', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js tests/test.spec.ts `); @@ -167,7 +167,7 @@ test('should run folder', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js tests/folder `); @@ -298,7 +298,7 @@ test('should only create test run if file belongs to context', async ({ activate expect(testRuns).toHaveLength(1); } - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` tests1> playwright list-files -c playwright.config.js tests2> playwright list-files -c playwright.config.js tests1> playwright test -c playwright.config.js test1.spec.ts @@ -311,7 +311,7 @@ test('should only create test run if file belongs to context', async ({ activate expect(testRuns).toHaveLength(1); } - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` tests1> playwright list-files -c playwright.config.js tests2> playwright list-files -c playwright.config.js tests1> playwright test -c playwright.config.js test1.spec.ts @@ -340,7 +340,7 @@ test('should only create test run if folder belongs to context', async ({ activa await Promise.all(profiles.map(p => p.run(items))); expect(testRuns).toHaveLength(1); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` tests1> playwright list-files -c playwright.config.js tests2> playwright list-files -c playwright.config.js tests1> playwright test -c playwright.config.js foo1 @@ -369,7 +369,7 @@ test('should only create test run if test belongs to context', async ({ activate await Promise.all(profiles.map(p => p.run(items))); expect(testRuns).toHaveLength(1); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` tests1> playwright list-files -c playwright.config.js tests2> playwright list-files -c playwright.config.js tests2> playwright test -c playwright.config.js --list --reporter=null foo2/bar2/test2.spec.ts @@ -395,7 +395,7 @@ test('should run all projects at once', async ({ activate }) => { const profiles = testController.runProfiles.filter(p => p.kind === vscode.TestRunProfileKind.Run); await Promise.all(profiles.map(p => p.run())); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --project=projectOne --project=projectTwo `); @@ -428,7 +428,7 @@ test('should group projects by config', async ({ activate }) => { const profiles = testController.runProfiles.filter(p => p.kind === vscode.TestRunProfileKind.Run); await Promise.all(profiles.map(p => p.run())); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` tests1> playwright list-files -c playwright.config.js tests2> playwright list-files -c playwright.config.js tests1> playwright test -c playwright.config.js --project=projectOne --project=projectTwo @@ -516,7 +516,7 @@ test('should not remove other tests when running focused test', async ({ activat const testItems = testController.findTestItems(/two/); await testController.run(testItems); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] @@ -558,7 +558,7 @@ test('should run all parametrized tests', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js tests/test.spec.ts:4 @@ -588,7 +588,7 @@ test('should run one parametrized test', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js --grep=test two tests/test.spec.ts:4 @@ -626,7 +626,7 @@ test('should run one parametrized groups', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js --grep=group three tests/test.spec.ts:4 @@ -660,7 +660,7 @@ test('should run tests in parametrized groups', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js --grep=level 1 tests/test.spec.ts:4 @@ -677,7 +677,7 @@ test('should run tests in parametrized groups', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js --grep=level 1 tests/test.spec.ts:4 @@ -696,12 +696,12 @@ test('should list tests in relative folder', async ({ activate }) => { await testController.expandTestItems(/test.spec/); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` foo/bar> playwright list-files -c playwright.config.js foo/bar> playwright test -c playwright.config.js --list --reporter=null ../../tests/test.spec.ts `); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] @@ -736,7 +736,7 @@ test('should specify project', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --project=project 1 tests1/test.spec.ts `); @@ -757,7 +757,7 @@ test('should run tests concurrently', async ({ activate }) => { await Promise.all([profile.run(), profile.run(), profile.run()]); expect(runs).toHaveLength(1); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js `); @@ -788,7 +788,7 @@ test('should report project-specific failures', async ({ activate }) => { ...profile.map(p => p.run()), ]); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --project=projectA --project=projectB --project=projectC `); @@ -846,7 +846,7 @@ test('should discover tests after running one test', async ({ activate }) => { await testController.expandTestItems(/test2.spec.ts/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test1.spec.ts - one [2:0] @@ -941,7 +941,7 @@ test('should show warning when tests do not belong to projects', async ({ activa await profile.run(items); } - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` tests1> playwright list-files -c playwright.config.js tests2> playwright list-files -c playwright.config.js `); diff --git a/tests/source-map.spec.ts b/tests/source-map.spec.ts index afda7ae7e..5db7ac7ad 100644 --- a/tests/source-map.spec.ts +++ b/tests/source-map.spec.ts @@ -23,11 +23,11 @@ test('should list files', async ({ activate }) => { 'build/test.spec.js': testSpecJs('test.spec'), 'build/test.spec.js.map': testSpecJsMap('test.spec'), }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); @@ -41,14 +41,14 @@ test('should list tests on expand', async ({ activate }) => { }); await testController.expandTestItems(/test.spec.ts/); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] - two [3:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts `); @@ -65,14 +65,14 @@ test('should list tests for visible editors', async ({ activate }) => { await vscode.openEditors('**/test.spec.ts'); await new Promise(f => testController.onDidChangeTestItem(f)); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - one [2:0] - two [3:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts `); @@ -86,12 +86,12 @@ test('should pick new files', async ({ activate }) => { 'build/test-1.spec.js.map': testSpecJsMap('test-1.spec'), }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); @@ -102,13 +102,13 @@ test('should pick new files', async ({ activate }) => { workspaceFolder.addFile('build/test-2.spec.js.map', testSpecJsMap('test-2.spec')), ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts - test-2.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright list-files -c playwright.config.js `); @@ -128,14 +128,14 @@ test('should remove deleted files', async ({ activate }) => { 'build/test-3.spec.js.map': testSpecJsMap('test-3.spec'), }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts - test-2.spec.ts - test-3.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); @@ -146,13 +146,13 @@ test('should remove deleted files', async ({ activate }) => { workspaceFolder.removeFile('build/test-2.spec.js.map'), ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test-1.spec.ts - test-3.spec.ts `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); @@ -167,7 +167,7 @@ test('should discover new tests', async ({ activate }) => { await testController.expandTestItems(/test.spec.ts/); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts `); @@ -179,7 +179,7 @@ test('should discover new tests', async ({ activate }) => { workspaceFolder.changeFile('build/test.spec.js.map', testSpecJsMapAfter), ]); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests - test.spec.ts - new [2:0] @@ -187,7 +187,7 @@ test('should discover new tests', async ({ activate }) => { - two [4:0] `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts @@ -214,7 +214,7 @@ test('should run all tests', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js `); @@ -240,7 +240,7 @@ test('should run one test', async ({ activate }) => { passed `); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js > playwright test -c playwright.config.js --list --reporter=null tests/test.spec.ts > playwright test -c playwright.config.js tests/test.spec.ts:3 diff --git a/tests/track-configs.spec.ts b/tests/track-configs.spec.ts index 8cc6101f1..8d2c2f58f 100644 --- a/tests/track-configs.spec.ts +++ b/tests/track-configs.spec.ts @@ -18,7 +18,7 @@ import { expect, test } from './utils'; test('should load first config', async ({ activate }) => { const { vscode, testController, workspaceFolder } = await activate({}); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` `); workspaceFolder.addFile('playwright.config.js', `module.exports = { testDir: 'tests' }`); @@ -33,7 +33,7 @@ test('should load first config', async ({ activate }) => { `; while (testController.renderTestTree() !== golden) await new Promise(f => setTimeout(f, 200)); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright.config.js `); }); @@ -46,7 +46,7 @@ test('should load second config', async ({ activate }) => { test('one', async () => {}); `, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests1 - test.spec.ts `); @@ -65,7 +65,7 @@ test('should load second config', async ({ activate }) => { `; while (testController.renderTestTree() !== golden) await new Promise(f => setTimeout(f, 200)); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright1.config.js > playwright list-files -c playwright1.config.js > playwright list-files -c playwright2.config.js @@ -85,7 +85,7 @@ test('should remove model for config', async ({ activate }) => { test('one', async () => {}); `, }); - expect(testController.renderTestTree()).toBe(` + expect(testController).toHaveTestTree(` - tests1 - test.spec.ts - tests2 @@ -100,7 +100,7 @@ test('should remove model for config', async ({ activate }) => { `; while (testController.renderTestTree() !== golden) await new Promise(f => setTimeout(f, 200)); - expect(vscode.renderExecLog(' ')).toBe(` + expect(vscode).toHaveExecLog(` > playwright list-files -c playwright1.config.js > playwright list-files -c playwright2.config.js > playwright list-files -c playwright2.config.js diff --git a/tests/utils.ts b/tests/utils.ts index c8aee89fc..079da1e1d 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { expect, test as baseTest, Browser, chromium, Page } from '@playwright/test'; +import { expect as baseExpect, test as baseTest, Browser, chromium, Page } from '@playwright/test'; import { Extension } from '../out/extension'; import { TestController, VSCode, WorkspaceFolder } from './mock/vscode'; import path from 'path'; @@ -33,7 +33,37 @@ export type WorkerOptions = { mode: 'default' | 'reuse'; }; -export { expect } from '@playwright/test'; +// Make sure connect tests work with the locally-rolled version. +process.env.PW_VERSION_OVERRIDE = require('@playwright/test/package.json').version; + +export const expect = baseExpect.extend({ + toHaveTestTree(testController: TestController, expectedTree: string) { + try { + expect(testController.renderTestTree()).toBe(expectedTree); + return { pass: true, message: () => '' }; + } catch (e) { + return { + pass: false, + message: () => e.toString() + }; + } + }, + + toHaveExecLog(vscode: VSCode, expectedLog: string) { + if (process.env.PWTEST_VSCODE_SERVER) + return { pass: true, message: () => '' }; + try { + expect(vscode.renderExecLog(' ')).toBe(expectedLog); + return { pass: true, message: () => '' }; + } catch (e) { + return { + pass: false, + message: () => e.toString() + }; + } + } +}); + export const test = baseTest.extend({ mode: ['default', { option: true, scope: 'worker' }], diff --git a/utils/roll-locally.js b/utils/roll-locally.js new file mode 100644 index 000000000..746d891ba --- /dev/null +++ b/utils/roll-locally.js @@ -0,0 +1,38 @@ +/** + * 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. + */ + +const { execSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +const packageNames = ['playwright-core', 'playwright', 'playwright-test']; + +(async () => { + const playwrightWorkspace = path.resolve(__dirname, '../../playwright'); + for (const packageName of packageNames) { + console.log('Packaging ' + packageName); + console.log(execSync(`node ./utils/pack_package ${packageName} ` + path.join(__dirname, `../out/${packageName}.tgz`), { cwd: playwrightWorkspace }).toString()); + } + const nodeModules = path.join(__dirname, '../test-results', 'node_modules'); + await fs.promises.mkdir(nodeModules, { recursive: true }); + for (const packageName of packageNames) { + const packagePath = path.join(__dirname, '../out', packageName + '.tgz'); + if (fs.existsSync(packagePath)) { + console.log('Extracting ' + packageName); + console.log(execSync(`npm install ${packagePath}`, { cwd: nodeModules }).toString()); + } + } +})();