Merge branch 'microsoft:main' into main

This commit is contained in:
ryanrosello-og 2024-07-02 18:41:06 +08:00 committed by GitHub
commit 2f91918256
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 91 additions and 18 deletions

View file

@ -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

View file

@ -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.

View file

@ -27,7 +27,7 @@
},
{
"name": "webkit",
"revision": "2039",
"revision": "2041",
"installByDefault": true,
"revisionOverrides": {
"mac10.14": "1446",

View file

@ -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<channels.ElectronLaunchOptions, 'env'|'extraHTTPHeaders'|'recordHar'|'colorScheme'|'acceptDownloads'> & {
env?: Env,
@ -116,7 +116,13 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
}
async close() {
await this._context.close().catch(() => {});
try {
await this._context.close();
} catch (e) {
if (isTargetClosedError(e))
return;
throw e;
}
}
async waitForEvent(event: string, optionsOrPredicate: WaitForEventOptions = {}): Promise<any> {

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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() });
}
}

View file

@ -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,<title>Playwright</title><h1>Playwright</h1>');
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)));
});

View file

@ -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',
]));