diff --git a/docs/src/ci.md b/docs/src/ci.md index 2556cbf241..69a59a70dc 100644 --- a/docs/src/ci.md +++ b/docs/src/ci.md @@ -601,6 +601,23 @@ steps: - 'CI=true' ``` +### Drone +* langs: js + +To run Playwright tests on Drone, use our public Docker image ([see Dockerfile](./docker.md)). + +```yml +kind: pipeline +name: default +type: docker + +steps: + - name: test + image: mcr.microsoft.com/playwright:v%%VERSION%%-jammy + commands: + - npx playwright test +``` + ## Caching browsers Caching browser binaries is not recommended, since the amount of time it takes to restore the cache is comparable to the time it takes to download the binaries. Especially under Linux, [operating system dependencies](./browsers.md#install-system-dependencies) need to be installed, which are not cacheable. @@ -633,7 +650,7 @@ By default, Playwright launches browsers in headless mode. See in our [Running t On Linux agents, headed execution requires [Xvfb](https://en.wikipedia.org/wiki/Xvfb) to be installed. Our [Docker image](./docker.md) and GitHub Action have Xvfb pre-installed. To run browsers in headed mode with Xvfb, add `xvfb-run` before the actual command. ```bash js -xvfb-run npx playwrght test +xvfb-run npx playwright test ``` ```bash python xvfb-run pytest diff --git a/docs/src/release-notes-csharp.md b/docs/src/release-notes-csharp.md index 97b0c9cd50..9172478402 100644 --- a/docs/src/release-notes-csharp.md +++ b/docs/src/release-notes-csharp.md @@ -17,9 +17,9 @@ Utilizing the new [Clock] API allows to manipulate and control time within tests ```csharp // Initialize clock with some time before the test time and let the page load naturally. // `Date.now` will progress as the timers fire. -await Page.Clock.InstallAsync(new +await Page.Clock.InstallAsync(new() { - Time = new DateTime(2024, 2, 2, 8, 0, 0) + TimeDate = new DateTime(2024, 2, 2, 8, 0, 0) }); await Page.GotoAsync("http://localhost:3333"); @@ -28,11 +28,11 @@ await Page.GotoAsync("http://localhost:3333"); await Page.Clock.PauseAtAsync(new DateTime(2024, 2, 2, 10, 0, 0)); // Assert the page state. -await Expect(Page.GetByTestId("current-time")).ToHaveText("2/2/2024, 10:00:00 AM"); +await Expect(Page.GetByTestId("current-time")).ToHaveTextAsync("2/2/2024, 10:00:00 AM"); // Close the laptop lid again and open it at 10:30am. await Page.Clock.FastForwardAsync("30:00"); -await Expect(Page.GetByTestId("current-time")).ToHaveText("2/2/2024, 10:30:00 AM"); +await Expect(Page.GetByTestId("current-time")).ToHaveTextAsync("2/2/2024, 10:30:00 AM"); ``` See [the clock guide](./clock.md) for more details. diff --git a/packages/playwright-core/browsers.json b/packages/playwright-core/browsers.json index 761a95ce6b..8dff6bf676 100644 --- a/packages/playwright-core/browsers.json +++ b/packages/playwright-core/browsers.json @@ -27,7 +27,7 @@ }, { "name": "webkit", - "revision": "2039", + "revision": "2041", "installByDefault": true, "revisionOverrides": { "mac10.14": "1446", diff --git a/packages/playwright-core/src/client/electron.ts b/packages/playwright-core/src/client/electron.ts index a9e90b77f2..fcabfa494f 100644 --- a/packages/playwright-core/src/client/electron.ts +++ b/packages/playwright-core/src/client/electron.ts @@ -29,7 +29,7 @@ import type { Page } from './page'; import { ConsoleMessage } from './consoleMessage'; import type { Env, WaitForEventOptions, Headers, BrowserContextOptions } from './types'; import { Waiter } from './waiter'; -import { TargetClosedError } from './errors'; +import { TargetClosedError, isTargetClosedError } from './errors'; type ElectronOptions = Omit & { env?: Env, @@ -116,7 +116,13 @@ export class ElectronApplication extends ChannelOwner {}); + try { + await this._context.close(); + } catch (e) { + if (isTargetClosedError(e)) + return; + throw e; + } } async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise { diff --git a/packages/playwright-ct-react/package.json b/packages/playwright-ct-react/package.json index 01426b8b15..295af3f34a 100644 --- a/packages/playwright-ct-react/package.json +++ b/packages/playwright-ct-react/package.json @@ -26,7 +26,8 @@ "./hooks": { "types": "./hooks.d.ts", "default": "./hooks.mjs" - } + }, + "./package.json": "./package.json" }, "dependencies": { "@playwright/experimental-ct-core": "1.46.0-next", diff --git a/packages/playwright-ct-react17/package.json b/packages/playwright-ct-react17/package.json index ca94174e73..8d0fee1168 100644 --- a/packages/playwright-ct-react17/package.json +++ b/packages/playwright-ct-react17/package.json @@ -26,7 +26,8 @@ "./hooks": { "types": "./hooks.d.ts", "default": "./hooks.mjs" - } + }, + "./package.json": "./package.json" }, "dependencies": { "@playwright/experimental-ct-core": "1.46.0-next", diff --git a/packages/playwright-ct-solid/package.json b/packages/playwright-ct-solid/package.json index 07b34f44a4..ed46930149 100644 --- a/packages/playwright-ct-solid/package.json +++ b/packages/playwright-ct-solid/package.json @@ -26,7 +26,8 @@ "./hooks": { "types": "./hooks.d.ts", "default": "./hooks.mjs" - } + }, + "./package.json": "./package.json" }, "dependencies": { "@playwright/experimental-ct-core": "1.46.0-next", diff --git a/packages/playwright-ct-svelte/package.json b/packages/playwright-ct-svelte/package.json index 3a52fc70a5..2b35018c03 100644 --- a/packages/playwright-ct-svelte/package.json +++ b/packages/playwright-ct-svelte/package.json @@ -26,7 +26,8 @@ "./hooks": { "types": "./hooks.d.ts", "default": "./hooks.mjs" - } + }, + "./package.json": "./package.json" }, "dependencies": { "@playwright/experimental-ct-core": "1.46.0-next", diff --git a/packages/playwright-ct-vue/package.json b/packages/playwright-ct-vue/package.json index 66be15de8e..fdda54207a 100644 --- a/packages/playwright-ct-vue/package.json +++ b/packages/playwright-ct-vue/package.json @@ -26,7 +26,8 @@ "./hooks": { "types": "./hooks.d.ts", "default": "./hooks.mjs" - } + }, + "./package.json": "./package.json" }, "dependencies": { "@playwright/experimental-ct-core": "1.46.0-next", diff --git a/packages/playwright-ct-vue2/package.json b/packages/playwright-ct-vue2/package.json index 74d48c8b41..70981c4f9b 100644 --- a/packages/playwright-ct-vue2/package.json +++ b/packages/playwright-ct-vue2/package.json @@ -26,7 +26,8 @@ "./hooks": { "types": "./hooks.d.ts", "default": "./hooks.mjs" - } + }, + "./package.json": "./package.json" }, "dependencies": { "@playwright/experimental-ct-core": "1.46.0-next", diff --git a/packages/playwright/src/index.ts b/packages/playwright/src/index.ts index a258cbcad5..79184cc135 100644 --- a/packages/playwright/src/index.ts +++ b/packages/playwright/src/index.ts @@ -609,7 +609,7 @@ class ArtifactsRecorder { if ((tracing as any)[this._startedCollectingArtifacts]) return; (tracing as any)[this._startedCollectingArtifacts] = true; - if (this._testInfo._tracing.traceOptions()) + if (this._testInfo._tracing.traceOptions() && (tracing as any)[kTracingStarted]) await tracing.stopChunk({ path: this._testInfo._tracing.generateNextTraceRecordingPath() }); } } diff --git a/tests/installation/playwright-electron-should-work.spec.ts b/tests/installation/playwright-electron-should-work.spec.ts index 4de28e8b54..5c6ced0948 100755 --- a/tests/installation/playwright-electron-should-work.spec.ts +++ b/tests/installation/playwright-electron-should-work.spec.ts @@ -15,6 +15,7 @@ */ import { test } from './npmTest'; import fs from 'fs'; +import { expect } from 'packages/playwright-test'; import path from 'path'; test('electron should work', async ({ exec, tsc, writeFiles }) => { @@ -39,3 +40,46 @@ test('electron should work with special characters in path', async ({ exec, tmpW cwd: path.join(folderName) }); }); + +test('should work when wrapped inside @playwright/test and trace is enabled', async ({ exec, tmpWorkspace, writeFiles }) => { + await exec('npm i -D @playwright/test electron@31'); + await writeFiles({ + 'electron-with-tracing.spec.ts': ` + import { test, expect, _electron } from '@playwright/test'; + + test('should work', async ({ trace }) => { + const electronApp = await _electron.launch({ args: [${JSON.stringify(path.join(__dirname, '../electron/electron-window-app.js'))}] }); + + const window = await electronApp.firstWindow(); + if (trace) + await window.context().tracing.start({ screenshots: true, snapshots: true }); + + await window.goto('data:text/html,Playwright

Playwright

'); + await expect(window).toHaveTitle(/Playwright/); + await expect(window.getByRole('heading')).toHaveText('Playwright'); + + const path = test.info().outputPath('electron-trace.zip'); + if (trace) { + await window.context().tracing.stop({ path }); + test.info().attachments.push({ name: 'trace', path, contentType: 'application/zip' }); + } + await electronApp.close(); + }); + `, + }); + const jsonOutputName = test.info().outputPath('report.json'); + await exec('npx playwright test --trace=on --reporter=json electron-with-tracing.spec.ts', { + env: { PLAYWRIGHT_JSON_OUTPUT_NAME: jsonOutputName } + }); + const traces = [ + // our actual trace. + path.join(tmpWorkspace, 'test-results', 'electron-with-tracing-should-work', 'electron-trace.zip'), + // contains the expect() calls + path.join(tmpWorkspace, 'test-results', 'electron-with-tracing-should-work', 'trace.zip'), + ]; + for (const trace of traces) + expect(fs.existsSync(trace)).toBe(true); + const report = JSON.parse(fs.readFileSync(jsonOutputName, 'utf-8')); + expect(new Set(['trace'])).toEqual(new Set(report.suites[0].specs[0].tests[0].results[0].attachments.map(a => a.name))); + expect(new Set(traces.map(p => fs.realpathSync(p)))).toEqual(new Set(report.suites[0].specs[0].tests[0].results[0].attachments.map(a => a.path))); +}); diff --git a/tests/page/page-set-input-files.spec.ts b/tests/page/page-set-input-files.spec.ts index 22ce7151cd..76a53fa571 100644 --- a/tests/page/page-set-input-files.spec.ts +++ b/tests/page/page-set-input-files.spec.ts @@ -16,7 +16,7 @@ */ import { test as it, expect } from './pageTest'; -import { attachFrame, chromiumVersionLessThan } from '../config/utils'; +import { attachFrame } from '../config/utils'; import path from 'path'; import fs from 'fs'; @@ -37,7 +37,7 @@ it('should upload the file', async ({ page, server, asset }) => { }, input)).toBe('contents of the file'); }); -it('should upload a folder', async ({ page, server, browserName, headless, browserVersion, isAndroid }) => { +it('should upload a folder', async ({ page, server, browserName, headless, browserMajorVersion, isAndroid }) => { it.skip(isAndroid); it.skip(os.platform() === 'darwin' && parseInt(os.release().split('.')[0], 10) <= 21, 'WebKit on macOS-12 is frozen'); @@ -54,7 +54,7 @@ it('should upload a folder', async ({ page, server, browserName, headless, brows await input.setInputFiles(dir); expect(new Set(await page.evaluate(e => [...e.files].map(f => f.webkitRelativePath), input))).toEqual(new Set([ // https://issues.chromium.org/issues/345393164 - ...((browserName === 'chromium' && headless && !process.env.PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW && chromiumVersionLessThan(browserVersion, '127.0.6533.0')) ? [] : ['file-upload-test/sub-dir/really.txt']), + ...((browserName === 'chromium' && headless && !process.env.PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW && browserMajorVersion < 127) ? [] : ['file-upload-test/sub-dir/really.txt']), 'file-upload-test/file1.txt', 'file-upload-test/file2', ]));