Merge branch 'main' into aria-snapshots
4
.github/workflows/tests_bidi.yml
vendored
|
|
@ -7,7 +7,8 @@ on:
|
|||
- main
|
||||
paths:
|
||||
- .github/workflows/tests_bidi.yml
|
||||
- packages/playwright-core/src/server/bidi/*
|
||||
- packages/playwright-core/src/server/bidi/**
|
||||
- tests/bidi/**
|
||||
schedule:
|
||||
# Run every day at midnight
|
||||
- cron: '0 0 * * *'
|
||||
|
|
@ -18,7 +19,6 @@ env:
|
|||
jobs:
|
||||
test_bidi:
|
||||
name: BiDi
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
|
|
|
|||
1
.github/workflows/tests_components.yml
vendored
|
|
@ -20,7 +20,6 @@ env:
|
|||
jobs:
|
||||
test_components:
|
||||
name: ${{ matrix.os }} - Node.js ${{ matrix.node-version }}
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
|
|||
5
.github/workflows/tests_others.yml
vendored
|
|
@ -21,7 +21,6 @@ env:
|
|||
jobs:
|
||||
test_stress:
|
||||
name: Stress - ${{ matrix.os }}
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -58,7 +57,6 @@ jobs:
|
|||
|
||||
test_webview2:
|
||||
name: WebView2
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
runs-on: windows-2022
|
||||
permissions:
|
||||
|
|
@ -89,7 +87,6 @@ jobs:
|
|||
|
||||
test_clock_frozen_time_linux:
|
||||
name: time library - ${{ matrix.clock }}
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
permissions:
|
||||
id-token: write # This is required for OIDC login (azure/login) to succeed
|
||||
|
|
@ -115,7 +112,6 @@ jobs:
|
|||
|
||||
test_clock_frozen_time_test_runner:
|
||||
name: time test runner - ${{ matrix.clock }}
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
|
|
@ -140,7 +136,6 @@ jobs:
|
|||
|
||||
test_electron:
|
||||
name: Electron - ${{ matrix.os }}
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
|
|||
6
.github/workflows/tests_primary.yml
vendored
|
|
@ -27,7 +27,6 @@ env:
|
|||
jobs:
|
||||
test_linux:
|
||||
name: ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }})
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -60,7 +59,6 @@ jobs:
|
|||
|
||||
test_linux_chromium_tot:
|
||||
name: ${{ matrix.os }} (chromium tip-of-tree)
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -85,7 +83,6 @@ jobs:
|
|||
|
||||
test_test_runner:
|
||||
name: Test Runner
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -130,7 +127,6 @@ jobs:
|
|||
|
||||
test_web_components:
|
||||
name: Web Components
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -166,7 +162,6 @@ jobs:
|
|||
|
||||
test_vscode_extension:
|
||||
name: VSCode Extension
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PWTEST_BOT_NAME: "vscode-extension"
|
||||
|
|
@ -203,7 +198,6 @@ jobs:
|
|||
|
||||
test_package_installations:
|
||||
name: "Installation Test ${{ matrix.os }}"
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
|
|||
13
.github/workflows/tests_secondary.yml
vendored
|
|
@ -26,7 +26,6 @@ permissions:
|
|||
jobs:
|
||||
test_linux:
|
||||
name: ${{ matrix.os }} (${{ matrix.browser }})
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -47,7 +46,6 @@ jobs:
|
|||
|
||||
test_mac:
|
||||
name: ${{ matrix.os }} (${{ matrix.browser }})
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -75,7 +73,6 @@ jobs:
|
|||
|
||||
test_win:
|
||||
name: "Windows"
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -95,7 +92,6 @@ jobs:
|
|||
|
||||
test-package-installations-other-node-versions:
|
||||
name: "Installation Test ${{ matrix.os }} (${{ matrix.node_version }})"
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
|
|
@ -129,7 +125,6 @@ jobs:
|
|||
|
||||
headed_tests:
|
||||
name: "headed ${{ matrix.browser }} (${{ matrix.os }})"
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -156,7 +151,6 @@ jobs:
|
|||
|
||||
transport_linux:
|
||||
name: "Transport"
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -178,7 +172,6 @@ jobs:
|
|||
|
||||
tracing_linux:
|
||||
name: Tracing ${{ matrix.browser }} ${{ matrix.channel }}
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -206,7 +199,6 @@ jobs:
|
|||
|
||||
test_chromium_channels:
|
||||
name: Test ${{ matrix.channel }} on ${{ matrix.runs-on }}
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
strategy:
|
||||
|
|
@ -229,7 +221,6 @@ jobs:
|
|||
|
||||
chromium_tot:
|
||||
name: Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }}
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
|
|
@ -252,7 +243,6 @@ jobs:
|
|||
|
||||
chromium_tot_headless_shell:
|
||||
name: Chromium tip-of-tree headless-shell-${{ matrix.os }}
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
|
|
@ -274,7 +264,6 @@ jobs:
|
|||
|
||||
firefox_beta:
|
||||
name: Firefox Beta ${{ matrix.os }}
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
|
|
@ -296,7 +285,6 @@ jobs:
|
|||
|
||||
build-playwright-driver:
|
||||
name: "build-playwright-driver"
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -310,7 +298,6 @@ jobs:
|
|||
|
||||
test_channel_chromium:
|
||||
name: Test channel=chromium
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
|
|||
1
.github/workflows/tests_service.yml
vendored
|
|
@ -10,7 +10,6 @@ env:
|
|||
jobs:
|
||||
test:
|
||||
name: "Service"
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
|
|||
1
.github/workflows/tests_video.yml
vendored
|
|
@ -14,7 +14,6 @@ env:
|
|||
jobs:
|
||||
video_linux:
|
||||
name: "Video Linux"
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
environment: allow-uploading-flakiness-results
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
|
|||
1
.github/workflows/trigger_tests.yml
vendored
|
|
@ -9,7 +9,6 @@ on:
|
|||
jobs:
|
||||
trigger:
|
||||
name: "trigger"
|
||||
if: github.repository == 'microsoft/playwright'
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- run: |
|
||||
|
|
|
|||
|
|
@ -2250,7 +2250,6 @@ Asserts that the target element matches the given [accessibility snapshot](../ar
|
|||
```js
|
||||
await expect(page.locator('body')).toMatchAriaSnapshot();
|
||||
await expect(page.locator('body')).toMatchAriaSnapshot({ name: 'snapshot' });
|
||||
await expect(page.locator('body')).toMatchAriaSnapshot({ path: '/path/to/snapshot.yml' });
|
||||
```
|
||||
|
||||
```python async
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@
|
|||
},
|
||||
{
|
||||
"name": "firefox",
|
||||
"revision": "1471",
|
||||
"revision": "1472",
|
||||
"installByDefault": true,
|
||||
"browserVersion": "134.0"
|
||||
},
|
||||
{
|
||||
"name": "firefox-beta",
|
||||
"revision": "1467",
|
||||
"revision": "1468",
|
||||
"installByDefault": false,
|
||||
"browserVersion": "133.0b9"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -139,6 +139,9 @@ function defaultProfilePreferences(
|
|||
'dom.min_background_timeout_value_without_budget_throttling': 0,
|
||||
'dom.timeout.enable_budget_timer_throttling': false,
|
||||
|
||||
// Disable HTTPS-First upgrades
|
||||
'dom.security.https_first': false,
|
||||
|
||||
// Only load extensions from the application and user profile
|
||||
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
|
||||
'extensions.autoDisableScopes': 0,
|
||||
|
|
|
|||
|
|
@ -301,6 +301,11 @@ export module Protocol {
|
|||
forcedColors: ("active"|"none")|null;
|
||||
};
|
||||
export type setForcedColorsReturnValue = void;
|
||||
export type setContrastParameters = {
|
||||
browserContextId?: string;
|
||||
contrast: ("less"|"more"|"custom"|"no-preference")|null;
|
||||
};
|
||||
export type setContrastReturnValue = void;
|
||||
export type setVideoRecordingOptionsParameters = {
|
||||
browserContextId?: string;
|
||||
options?: {
|
||||
|
|
@ -530,6 +535,7 @@ export module Protocol {
|
|||
colorScheme?: ("dark"|"light"|"no-preference");
|
||||
reducedMotion?: ("reduce"|"no-preference");
|
||||
forcedColors?: ("active"|"none");
|
||||
contrast?: ("less"|"more"|"custom"|"no-preference");
|
||||
};
|
||||
export type setEmulatedMediaReturnValue = void;
|
||||
export type setCacheDisabledParameters = {
|
||||
|
|
@ -1131,6 +1137,7 @@ export module Protocol {
|
|||
"Browser.setColorScheme": Browser.setColorSchemeParameters;
|
||||
"Browser.setReducedMotion": Browser.setReducedMotionParameters;
|
||||
"Browser.setForcedColors": Browser.setForcedColorsParameters;
|
||||
"Browser.setContrast": Browser.setContrastParameters;
|
||||
"Browser.setVideoRecordingOptions": Browser.setVideoRecordingOptionsParameters;
|
||||
"Browser.cancelDownload": Browser.cancelDownloadParameters;
|
||||
"Heap.collectGarbage": Heap.collectGarbageParameters;
|
||||
|
|
@ -1213,6 +1220,7 @@ export module Protocol {
|
|||
"Browser.setColorScheme": Browser.setColorSchemeReturnValue;
|
||||
"Browser.setReducedMotion": Browser.setReducedMotionReturnValue;
|
||||
"Browser.setForcedColors": Browser.setForcedColorsReturnValue;
|
||||
"Browser.setContrast": Browser.setContrastReturnValue;
|
||||
"Browser.setVideoRecordingOptions": Browser.setVideoRecordingOptionsReturnValue;
|
||||
"Browser.cancelDownload": Browser.cancelDownloadReturnValue;
|
||||
"Heap.collectGarbage": Heap.collectGarbageReturnValue;
|
||||
|
|
|
|||
|
|
@ -214,12 +214,6 @@ export class HttpServer {
|
|||
}
|
||||
|
||||
private _onRequest(request: http.IncomingMessage, response: http.ServerResponse) {
|
||||
response.setHeader('Access-Control-Allow-Origin', '*');
|
||||
response.setHeader('Access-Control-Request-Method', '*');
|
||||
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
|
||||
if (request.headers.origin)
|
||||
response.setHeader('Access-Control-Allow-Headers', request.headers.origin);
|
||||
|
||||
if (request.method === 'OPTIONS') {
|
||||
response.writeHead(200);
|
||||
response.end();
|
||||
|
|
|
|||
|
|
@ -240,8 +240,8 @@ function validateConfig(file: string, config: Config) {
|
|||
}
|
||||
|
||||
if ('updateSnapshots' in config && config.updateSnapshots !== undefined) {
|
||||
if (typeof config.updateSnapshots !== 'string' || !['all', 'none', 'missing'].includes(config.updateSnapshots))
|
||||
throw errorWithFile(file, `config.updateSnapshots must be one of "all", "none" or "missing"`);
|
||||
if (typeof config.updateSnapshots !== 'string' || !['all', 'changed', 'missing', 'none'].includes(config.updateSnapshots))
|
||||
throw errorWithFile(file, `config.updateSnapshots must be one of "all", "changed", "missing" or "none"`);
|
||||
}
|
||||
|
||||
if ('workers' in config && config.workers !== undefined) {
|
||||
|
|
|
|||
|
|
@ -30,12 +30,13 @@ import path from 'path';
|
|||
type ToMatchAriaSnapshotExpected = {
|
||||
name?: string;
|
||||
path?: string;
|
||||
timeout?: number;
|
||||
} | string;
|
||||
|
||||
export async function toMatchAriaSnapshot(
|
||||
this: ExpectMatcherState,
|
||||
receiver: LocatorEx,
|
||||
expectedParam: ToMatchAriaSnapshotExpected,
|
||||
expectedParam?: ToMatchAriaSnapshotExpected,
|
||||
options: { timeout?: number } = {},
|
||||
): Promise<MatcherResult<string | RegExp, string>> {
|
||||
const matcherName = 'toMatchAriaSnapshot';
|
||||
|
|
@ -55,9 +56,11 @@ export async function toMatchAriaSnapshot(
|
|||
};
|
||||
|
||||
let expected: string;
|
||||
let timeout: number;
|
||||
let expectedPath: string | undefined;
|
||||
if (isString(expectedParam)) {
|
||||
expected = expectedParam;
|
||||
timeout = options.timeout ?? this.timeout;
|
||||
} else {
|
||||
if (expectedParam?.name) {
|
||||
expectedPath = testInfo.snapshotPath(sanitizeFilePathBeforeExtension(expectedParam.name));
|
||||
|
|
@ -71,6 +74,7 @@ export async function toMatchAriaSnapshot(
|
|||
expectedPath = testInfo.snapshotPath(sanitizeForFilePath(trimLongString(fullTitleWithoutSpec)) + '.yml');
|
||||
}
|
||||
expected = await fs.promises.readFile(expectedPath, 'utf8').catch(() => '');
|
||||
timeout = expectedParam?.timeout ?? this.timeout;
|
||||
}
|
||||
|
||||
const generateMissingBaseline = updateSnapshots === 'missing' && !expected;
|
||||
|
|
@ -84,7 +88,6 @@ export async function toMatchAriaSnapshot(
|
|||
}
|
||||
}
|
||||
|
||||
const timeout = options.timeout ?? this.timeout;
|
||||
expected = unshift(expected);
|
||||
const { matches: pass, received, log, timedOut } = await receiver._expect('to.match.aria', { expectedValue: expected, isNot: this.isNot, timeout });
|
||||
const typedReceived = received as MatcherReceived | typeof kNoElementsFoundError;
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ function overridesFromOptions(options: { [key: string]: any }): ConfigCLIOverrid
|
|||
if (['all', 'changed', 'missing', 'none'].includes(options.updateSnapshots))
|
||||
updateSnapshots = options.updateSnapshots;
|
||||
else
|
||||
updateSnapshots = 'updateSnapshots' in options ? 'changed' : 'missing';
|
||||
updateSnapshots = 'updateSnapshots' in options ? 'changed' : undefined;
|
||||
|
||||
const overrides: ConfigCLIOverrides = {
|
||||
forbidOnly: options.forbidOnly ? true : undefined,
|
||||
|
|
|
|||
1
packages/playwright/types/test.d.ts
vendored
|
|
@ -8690,7 +8690,6 @@ interface LocatorAssertions {
|
|||
* ```js
|
||||
* await expect(page.locator('body')).toMatchAriaSnapshot();
|
||||
* await expect(page.locator('body')).toMatchAriaSnapshot({ name: 'snapshot' });
|
||||
* await expect(page.locator('body')).toMatchAriaSnapshot({ path: '/path/to/snapshot.yml' });
|
||||
* ```
|
||||
*
|
||||
* @param options
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@
|
|||
let textarea = document.querySelector('textarea');
|
||||
textarea.focus();
|
||||
textarea.addEventListener('keydown', event => {
|
||||
log('Keydown:', event.key, event.code, event.which, modifiers(event));
|
||||
log('Keydown:', event.key, event.code, getLocation(event), modifiers(event));
|
||||
});
|
||||
textarea.addEventListener('keypress', event => {
|
||||
log('Keypress:', event.key, event.code, event.which, event.charCode, modifiers(event));
|
||||
log('Keypress:', event.key, event.code, getLocation(event), event.charCode, modifiers(event));
|
||||
});
|
||||
textarea.addEventListener('keyup', event => {
|
||||
log('Keyup:', event.key, event.code, event.which, modifiers(event));
|
||||
log('Keyup:', event.key, event.code, getLocation(event), modifiers(event));
|
||||
});
|
||||
function modifiers(event) {
|
||||
let m = [];
|
||||
|
|
@ -28,6 +28,15 @@
|
|||
m.push('Shift')
|
||||
return '[' + m.join(' ') + ']';
|
||||
}
|
||||
function getLocation(event) {
|
||||
switch (event.location) {
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_STANDARD: return 'STANDARD';
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_LEFT: return 'LEFT';
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_RIGHT: return 'RIGHT';
|
||||
case KeyboardEvent.DOM_KEY_LOCATION_NUMPAD: return 'NUMPAD';
|
||||
default: return 'Unknown: ' + event.location;
|
||||
};
|
||||
}
|
||||
function log(...args) {
|
||||
console.log.apply(console, args);
|
||||
result += args.join(' ') + '\n';
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ class CsvReporter implements Reporter {
|
|||
if (test.ok() && !fixme)
|
||||
continue;
|
||||
const row = [];
|
||||
row.push(csvEscape(`${file.title} :: ${test.title}`));
|
||||
const [, , , ...titles] = test.titlePath();
|
||||
row.push(csvEscape(`${file.title} :: ${titles.join(' › ')}`));
|
||||
row.push(test.expectedStatus);
|
||||
row.push(test.outcome());
|
||||
if (fixme) {
|
||||
|
|
@ -67,7 +68,7 @@ class CsvReporter implements Reporter {
|
|||
const csv = rows.map(r => r.join(',')).join('\n');
|
||||
const reportFile = path.resolve(this._options.configDir, this._options.outputFile || 'test-results.csv');
|
||||
this._pendingWrite = (async () => {
|
||||
await fs.mkdirSync(path.dirname(reportFile), { recursive: true });
|
||||
await fs.promises.mkdir(path.dirname(reportFile), { recursive: true });
|
||||
await fs.promises.writeFile(reportFile, csv);
|
||||
})();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -459,8 +459,13 @@ await page1.GotoAsync("about:blank?foo");`);
|
|||
const cli = runCLI([`--save-storage=${storageFileName}`, `--save-har=${harFileName}`]);
|
||||
await cli.waitFor(`import { test, expect } from '@playwright/test'`);
|
||||
await cli.process.kill('SIGINT');
|
||||
const { exitCode } = await cli.process.exited;
|
||||
expect(exitCode).toBe(130);
|
||||
const { exitCode, signal } = await cli.process.exited;
|
||||
if (exitCode !== null) {
|
||||
expect(exitCode).toBe(130);
|
||||
} else {
|
||||
// If the runner is slow enough, the process will be forcibly terminated by the signal
|
||||
expect(signal).toBe('SIGINT');
|
||||
}
|
||||
expect(fs.existsSync(storageFileName)).toBeTruthy();
|
||||
expect(fs.existsSync(harFileName)).toBeTruthy();
|
||||
});
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 474 B |
|
After Width: | Height: | Size: 138 B |
|
After Width: | Height: | Size: 113 B |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 181 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 181 B |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 311 B |
|
After Width: | Height: | Size: 26 KiB |
|
|
@ -41,6 +41,20 @@ it('should fire for fetches', async ({ page, server }) => {
|
|||
expect(requests.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should fire for fetches with keepalive: true', {
|
||||
annotation: {
|
||||
type: 'issue',
|
||||
description: 'https://github.com/microsoft/playwright/issues/34497'
|
||||
}
|
||||
}, async ({ page, server, browserName }) => {
|
||||
it.fixme(browserName === 'firefox');
|
||||
const requests = [];
|
||||
page.on('request', request => requests.push(request));
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.evaluate(() => fetch('/empty.html', { keepalive: true }));
|
||||
expect(requests.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should report requests and responses handled by service worker', async ({ page, server, isAndroid, isElectron }) => {
|
||||
it.fixme(isAndroid);
|
||||
it.fixme(isElectron);
|
||||
|
|
|
|||
|
|
@ -93,18 +93,18 @@ it('should report shiftKey', async ({ page, server, browserName, platform }) =>
|
|||
const codeForKey = { 'Shift': 16, 'Alt': 18, 'Control': 17 };
|
||||
for (const modifierKey in codeForKey) {
|
||||
await keyboard.down(modifierKey);
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: ' + modifierKey + ' ' + modifierKey + 'Left ' + codeForKey[modifierKey] + ' [' + modifierKey + ']');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: ' + modifierKey + ' ' + modifierKey + 'Left LEFT [' + modifierKey + ']');
|
||||
await keyboard.down('!');
|
||||
// Shift+! will generate a keypress
|
||||
if (modifierKey === 'Shift')
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: ! Digit1 49 [' + modifierKey + ']\nKeypress: ! Digit1 33 33 [' + modifierKey + ']');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: ! Digit1 STANDARD [' + modifierKey + ']\nKeypress: ! Digit1 STANDARD 33 [' + modifierKey + ']');
|
||||
else
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: ! Digit1 49 [' + modifierKey + ']');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: ! Digit1 STANDARD [' + modifierKey + ']');
|
||||
|
||||
await keyboard.up('!');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keyup: ! Digit1 49 [' + modifierKey + ']');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keyup: ! Digit1 STANDARD [' + modifierKey + ']');
|
||||
await keyboard.up(modifierKey);
|
||||
expect(await page.evaluate('getResult()')).toBe('Keyup: ' + modifierKey + ' ' + modifierKey + 'Left ' + codeForKey[modifierKey] + ' []');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keyup: ' + modifierKey + ' ' + modifierKey + 'Left LEFT []');
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -112,31 +112,31 @@ it('should report multiple modifiers', async ({ page, server }) => {
|
|||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
const keyboard = page.keyboard;
|
||||
await keyboard.down('Control');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: Control ControlLeft 17 [Control]');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: Control ControlLeft LEFT [Control]');
|
||||
await keyboard.down('Alt');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: Alt AltLeft 18 [Alt Control]');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: Alt AltLeft LEFT [Alt Control]');
|
||||
await keyboard.down(';');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: ; Semicolon 186 [Alt Control]');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keydown: ; Semicolon STANDARD [Alt Control]');
|
||||
await keyboard.up(';');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keyup: ; Semicolon 186 [Alt Control]');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keyup: ; Semicolon STANDARD [Alt Control]');
|
||||
await keyboard.up('Control');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keyup: Control ControlLeft 17 [Alt]');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keyup: Control ControlLeft LEFT [Alt]');
|
||||
await keyboard.up('Alt');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keyup: Alt AltLeft 18 []');
|
||||
expect(await page.evaluate('getResult()')).toBe('Keyup: Alt AltLeft LEFT []');
|
||||
});
|
||||
|
||||
it('should send proper codes while typing', async ({ page, server }) => {
|
||||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
await page.keyboard.type('!');
|
||||
expect(await page.evaluate('getResult()')).toBe(
|
||||
['Keydown: ! Digit1 49 []',
|
||||
'Keypress: ! Digit1 33 33 []',
|
||||
'Keyup: ! Digit1 49 []'].join('\n'));
|
||||
['Keydown: ! Digit1 STANDARD []',
|
||||
'Keypress: ! Digit1 STANDARD 33 []',
|
||||
'Keyup: ! Digit1 STANDARD []'].join('\n'));
|
||||
await page.keyboard.type('^');
|
||||
expect(await page.evaluate('getResult()')).toBe(
|
||||
['Keydown: ^ Digit6 54 []',
|
||||
'Keypress: ^ Digit6 94 94 []',
|
||||
'Keyup: ^ Digit6 54 []'].join('\n'));
|
||||
['Keydown: ^ Digit6 STANDARD []',
|
||||
'Keypress: ^ Digit6 STANDARD 94 []',
|
||||
'Keyup: ^ Digit6 STANDARD []'].join('\n'));
|
||||
});
|
||||
|
||||
it('should send proper codes while typing with shift', async ({ page, server }) => {
|
||||
|
|
@ -145,10 +145,10 @@ it('should send proper codes while typing with shift', async ({ page, server })
|
|||
await keyboard.down('Shift');
|
||||
await page.keyboard.type('~');
|
||||
expect(await page.evaluate('getResult()')).toBe(
|
||||
['Keydown: Shift ShiftLeft 16 [Shift]',
|
||||
'Keydown: ~ Backquote 192 [Shift]', // 192 is ` keyCode
|
||||
'Keypress: ~ Backquote 126 126 [Shift]', // 126 is ~ charCode
|
||||
'Keyup: ~ Backquote 192 [Shift]'].join('\n'));
|
||||
['Keydown: Shift ShiftLeft LEFT [Shift]',
|
||||
'Keydown: ~ Backquote STANDARD [Shift]',
|
||||
'Keypress: ~ Backquote STANDARD 126 [Shift]',
|
||||
'Keyup: ~ Backquote STANDARD [Shift]'].join('\n'));
|
||||
await keyboard.up('Shift');
|
||||
});
|
||||
|
||||
|
|
@ -173,54 +173,54 @@ it('should press plus', async ({ page, server }) => {
|
|||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
await page.keyboard.press('+');
|
||||
expect(await page.evaluate('getResult()')).toBe(
|
||||
['Keydown: + Equal 187 []', // 192 is ` keyCode
|
||||
'Keypress: + Equal 43 43 []', // 126 is ~ charCode
|
||||
'Keyup: + Equal 187 []'].join('\n'));
|
||||
['Keydown: + Equal STANDARD []',
|
||||
'Keypress: + Equal STANDARD 43 []',
|
||||
'Keyup: + Equal STANDARD []'].join('\n'));
|
||||
});
|
||||
|
||||
it('should press shift plus', async ({ page, server }) => {
|
||||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
await page.keyboard.press('Shift++');
|
||||
expect(await page.evaluate('getResult()')).toBe(
|
||||
['Keydown: Shift ShiftLeft 16 [Shift]',
|
||||
'Keydown: + Equal 187 [Shift]', // 192 is ` keyCode
|
||||
'Keypress: + Equal 43 43 [Shift]', // 126 is ~ charCode
|
||||
'Keyup: + Equal 187 [Shift]',
|
||||
'Keyup: Shift ShiftLeft 16 []'].join('\n'));
|
||||
['Keydown: Shift ShiftLeft LEFT [Shift]',
|
||||
'Keydown: + Equal STANDARD [Shift]',
|
||||
'Keypress: + Equal STANDARD 43 [Shift]',
|
||||
'Keyup: + Equal STANDARD [Shift]',
|
||||
'Keyup: Shift ShiftLeft LEFT []'].join('\n'));
|
||||
});
|
||||
|
||||
it('should support plus-separated modifiers', async ({ page, server }) => {
|
||||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
await page.keyboard.press('Shift+~');
|
||||
expect(await page.evaluate('getResult()')).toBe(
|
||||
['Keydown: Shift ShiftLeft 16 [Shift]',
|
||||
'Keydown: ~ Backquote 192 [Shift]', // 192 is ` keyCode
|
||||
'Keypress: ~ Backquote 126 126 [Shift]', // 126 is ~ charCode
|
||||
'Keyup: ~ Backquote 192 [Shift]',
|
||||
'Keyup: Shift ShiftLeft 16 []'].join('\n'));
|
||||
['Keydown: Shift ShiftLeft LEFT [Shift]',
|
||||
'Keydown: ~ Backquote STANDARD [Shift]',
|
||||
'Keypress: ~ Backquote STANDARD 126 [Shift]',
|
||||
'Keyup: ~ Backquote STANDARD [Shift]',
|
||||
'Keyup: Shift ShiftLeft LEFT []'].join('\n'));
|
||||
});
|
||||
|
||||
it('should support multiple plus-separated modifiers', async ({ page, server }) => {
|
||||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
await page.keyboard.press('Control+Shift+~');
|
||||
expect(await page.evaluate('getResult()')).toBe(
|
||||
['Keydown: Control ControlLeft 17 [Control]',
|
||||
'Keydown: Shift ShiftLeft 16 [Control Shift]',
|
||||
'Keydown: ~ Backquote 192 [Control Shift]', // 192 is ` keyCode
|
||||
'Keyup: ~ Backquote 192 [Control Shift]',
|
||||
'Keyup: Shift ShiftLeft 16 [Control]',
|
||||
'Keyup: Control ControlLeft 17 []'].join('\n'));
|
||||
['Keydown: Control ControlLeft LEFT [Control]',
|
||||
'Keydown: Shift ShiftLeft LEFT [Control Shift]',
|
||||
'Keydown: ~ Backquote STANDARD [Control Shift]',
|
||||
'Keyup: ~ Backquote STANDARD [Control Shift]',
|
||||
'Keyup: Shift ShiftLeft LEFT [Control]',
|
||||
'Keyup: Control ControlLeft LEFT []'].join('\n'));
|
||||
});
|
||||
|
||||
it('should shift raw codes', async ({ page, server }) => {
|
||||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
await page.keyboard.press('Shift+Digit3');
|
||||
expect(await page.evaluate('getResult()')).toBe(
|
||||
['Keydown: Shift ShiftLeft 16 [Shift]',
|
||||
'Keydown: # Digit3 51 [Shift]', // 51 is # keyCode
|
||||
'Keypress: # Digit3 35 35 [Shift]', // 35 is # charCode
|
||||
'Keyup: # Digit3 51 [Shift]',
|
||||
'Keyup: Shift ShiftLeft 16 []'].join('\n'));
|
||||
['Keydown: Shift ShiftLeft LEFT [Shift]',
|
||||
'Keydown: # Digit3 STANDARD [Shift]',
|
||||
'Keypress: # Digit3 STANDARD 35 [Shift]',
|
||||
'Keyup: # Digit3 STANDARD [Shift]',
|
||||
'Keyup: Shift ShiftLeft LEFT []'].join('\n'));
|
||||
});
|
||||
|
||||
it('should specify repeat property', async ({ page, server }) => {
|
||||
|
|
@ -710,7 +710,7 @@ it('should have correct Keydown/Keyup order when pressing Escape key', async ({
|
|||
await page.goto(server.PREFIX + '/input/keyboard.html');
|
||||
await page.keyboard.press('Escape');
|
||||
expect(await page.evaluate('getResult()')).toBe(`
|
||||
Keydown: Escape Escape 27 []
|
||||
Keyup: Escape Escape 27 []
|
||||
Keydown: Escape Escape STANDARD []
|
||||
Keyup: Escape Escape STANDARD []
|
||||
`.trim());
|
||||
});
|
||||
|
|
|
|||
|
|
@ -152,3 +152,60 @@ test('should generate snapshot name', async ({ runInlineTest }, testInfo) => {
|
|||
const snapshot2 = await fs.promises.readFile(testInfo.outputPath('__snapshots__/a.spec.ts/test-name-2.yml'), 'utf8');
|
||||
expect(snapshot2).toBe('- heading "hello world 2" [level=1]');
|
||||
});
|
||||
|
||||
for (const updateSnapshots of ['all', 'changed', 'missing', 'none']) {
|
||||
test(`should update snapshot with the update-snapshots=${updateSnapshots} (config)`, async ({ runInlineTest }, testInfo) => {
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.ts': `
|
||||
export default {
|
||||
snapshotPathTemplate: '__snapshots__/{testFilePath}/{arg}{ext}',
|
||||
updateSnapshots: '${updateSnapshots}',
|
||||
};
|
||||
`,
|
||||
'a.spec.ts': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('test', async ({ page }) => {
|
||||
await page.setContent(\`<h1>New content</h1>\`);
|
||||
await expect(page.locator('body')).toMatchAriaSnapshot({ timeout: 1 });
|
||||
});
|
||||
`,
|
||||
'__snapshots__/a.spec.ts/test-1.yml': '- heading "Old content" [level=1]',
|
||||
});
|
||||
|
||||
const rebase = updateSnapshots === 'all' || updateSnapshots === 'changed';
|
||||
expect(result.exitCode).toBe(rebase ? 0 : 1);
|
||||
if (rebase) {
|
||||
const snapshotOutputPath = testInfo.outputPath('__snapshots__/a.spec.ts/test-1.yml');
|
||||
expect(result.output).toContain(`A snapshot is generated at`);
|
||||
const data = fs.readFileSync(snapshotOutputPath);
|
||||
expect(data.toString()).toBe('- heading "New content" [level=1]');
|
||||
} else {
|
||||
expect(result.output).toContain(`expect.toMatchAriaSnapshot`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
test('should respect timeout', async ({ runInlineTest }, testInfo) => {
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.ts': `
|
||||
export default {
|
||||
snapshotPathTemplate: '__snapshots__/{testFilePath}/{arg}{ext}',
|
||||
};
|
||||
`,
|
||||
'test.yml': `
|
||||
- heading "hello world"
|
||||
`,
|
||||
'a.spec.ts': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
import path from 'path';
|
||||
test('test', async ({ page }) => {
|
||||
await page.setContent(\`<h1>hello world</h1>\`);
|
||||
await expect(page.locator('body')).toMatchAriaSnapshot({ timeout: 1 });
|
||||
});
|
||||
`,
|
||||
'__snapshots__/a.spec.ts/test-1.yml': '- heading "new world" [level=1]',
|
||||
});
|
||||
|
||||
expect(result.exitCode).toBe(1);
|
||||
expect(result.output).toContain(`Timed out 1ms waiting for`);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -341,6 +341,36 @@ test('should update snapshot with the update-snapshots flag', async ({ runInline
|
|||
expect(data.toString()).toBe(ACTUAL_SNAPSHOT);
|
||||
});
|
||||
|
||||
for (const updateSnapshots of ['all', 'changed', 'missing', 'none']) {
|
||||
test(`should update snapshot with the update-snapshots=${updateSnapshots} (config)`, async ({ runInlineTest }, testInfo) => {
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.ts': `export default { updateSnapshots: '${updateSnapshots}' };`,
|
||||
...files,
|
||||
'a.spec.js-snapshots/snapshot.txt': 'Hello world',
|
||||
'a.spec.js': `
|
||||
const { test, expect } = require('./helper');
|
||||
test('is a test', ({}) => {
|
||||
expect('Hello world updated').toMatchSnapshot('snapshot.txt');
|
||||
});
|
||||
`
|
||||
});
|
||||
|
||||
const rebase = updateSnapshots === 'all' || updateSnapshots === 'changed';
|
||||
expect(result.exitCode).toBe(rebase ? 0 : 1);
|
||||
if (rebase) {
|
||||
const snapshotOutputPath = testInfo.outputPath('a.spec.js-snapshots/snapshot.txt');
|
||||
if (updateSnapshots === 'all')
|
||||
expect(result.output).toContain(`${snapshotOutputPath} is not the same, writing actual.`);
|
||||
if (updateSnapshots === 'changed')
|
||||
expect(result.output).toContain(`${snapshotOutputPath} does not match, writing actual.`);
|
||||
const data = fs.readFileSync(snapshotOutputPath);
|
||||
expect(data.toString()).toBe('Hello world updated');
|
||||
} else {
|
||||
expect(result.output).toContain(`toMatchSnapshot`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
test('should ignore text snapshot with the ignore-snapshots flag', async ({ runInlineTest }, testInfo) => {
|
||||
const EXPECTED_SNAPSHOT = 'Hello world';
|
||||
const ACTUAL_SNAPSHOT = 'Hello world updated';
|
||||
|
|
@ -1140,3 +1170,25 @@ test('should throw if a Promise was passed to toMatchSnapshot', async ({ runInli
|
|||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(1);
|
||||
});
|
||||
|
||||
|
||||
test('should respect update snapshot option from config', async ({ runInlineTest }, testInfo) => {
|
||||
const EXPECTED_SNAPSHOT = 'Hello world';
|
||||
const ACTUAL_SNAPSHOT = 'Hello world updated';
|
||||
const result = await runInlineTest({
|
||||
...files,
|
||||
'a.spec.js-snapshots/snapshot.txt': EXPECTED_SNAPSHOT,
|
||||
'a.spec.js': `
|
||||
const { test, expect } = require('./helper');
|
||||
test('is a test', ({}) => {
|
||||
expect('${ACTUAL_SNAPSHOT}').toMatchSnapshot('snapshot.txt');
|
||||
});
|
||||
`
|
||||
}, { 'update-snapshots': true });
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
const snapshotOutputPath = testInfo.outputPath('a.spec.js-snapshots/snapshot.txt');
|
||||
expect(result.output).toContain(`${snapshotOutputPath} does not match, writing actual.`);
|
||||
const data = fs.readFileSync(snapshotOutputPath);
|
||||
expect(data.toString()).toBe(ACTUAL_SNAPSHOT);
|
||||
});
|
||||
|
|
|
|||