chore: download and launch chromium-headless-shell for headless chromium (#33454)

This commit is contained in:
Dmitry Gozman 2024-11-13 10:52:28 +00:00 коммит произвёл GitHub
Родитель d685763c49
Коммит f54d3f44c2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
25 изменённых файлов: 217 добавлений и 122 удалений

23
.github/workflows/tests_secondary.yml поставляемый
Просмотреть файл

@ -274,7 +274,7 @@ jobs:
strategy:
fail-fast: false
matrix:
runs-on: [ubuntu-latest, macos-latest, windows-latest]
runs-on: [ubuntu-latest]
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v4
@ -288,3 +288,24 @@ jobs:
flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }}
env:
PWTEST_CHANNEL: chromium-headless-shell
test_chromium_next:
name: Test chromium-next channel
environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }}
strategy:
fail-fast: false
matrix:
runs-on: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/run-test
with:
browsers-to-install: chromium
command: npm run ctest
bot-name: "chromium-next-${{ matrix.runs-on }}"
flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }}
flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }}
flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }}
env:
PWTEST_CHANNEL: chromium-next

Просмотреть файл

@ -338,6 +338,32 @@ dotnet test --settings:webkit.runsettings
For Google Chrome, Microsoft Edge and other Chromium-based browsers, by default, Playwright uses open source Chromium builds. Since the Chromium project is ahead of the branded browsers, when the world is on Google Chrome N, Playwright already supports Chromium N+1 that will be released in Google Chrome and Microsoft Edge a few weeks later.
Playwright ships a regular Chromium build for headed operations and a separate [Chromium headless shell](https://developer.chrome.com/blog/chrome-headless-shell) for headless mode. These two behave differently in some edge cases, but the majority of testing scenarios are not affected. Note this behavior has changed in Playwright version 1.49, see [issue #33566](https://github.com/microsoft/playwright/issues/33566) for details.
#### Save on download size
If you are only running tests in headless, for example on CI, you can avoid downloading a headed version of Chromium by specifying `chromium-headless-shell` during installation.
```bash js
# When only running tests headlessly
npx playwright install chromium-headless-shell firefox webkit
```
```bash java
# When only running tests headlessly
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install chromium-headless-shell firefox webkit"
```
```bash python
# When only running tests headlessly
playwright install chromium-headless-shell firefox webkit
```
```bash csharp
# When only running tests headlessly
pwsh bin/Debug/netX/playwright.ps1 install chromium-headless-shell firefox webkit
```
### Google Chrome & Microsoft Edge
While Playwright can download and use the recent Chromium build, it can operate against the branded Google Chrome and Microsoft Edge browsers available on the machine (note that Playwright doesn't install them by default). In particular, the current Playwright version will support Stable and Beta channels of these browsers.
@ -348,6 +374,10 @@ Available channels are `chrome`, `msedge`, `chrome-beta`, `msedge-beta` or `msed
Certain Enterprise Browser Policies may impact Playwright's ability to launch and control Google Chrome and Microsoft Edge. Running in an environment with browser policies is outside of the Playwright project's scope.
:::
:::warning
Google Chrome and Microsoft Edge have switched to a [new headless mode](https://developer.chrome.com/docs/chromium/headless) implementation that is closer to a regular headed mode. This differs from [chromium headless shell](https://developer.chrome.com/blog/chrome-headless-shell) that is used in Playwright by default when running headless, so expect different behavior in some cases. See [issue #33566](https://github.com/microsoft/playwright/issues/33566) fore details.
:::
```js
import { defineConfig, devices } from '@playwright/test';
@ -472,12 +502,6 @@ rarely the case), you will also want to use the official channel.
Google Chrome and Microsoft Edge respect enterprise policies, which include limitations to the capabilities, network proxy, mandatory extensions that stand in the way of testing. So if you are part of the organization that uses such policies, it is easiest to use bundled Chromium for your local testing, you can still opt into stable channels on the bots that are typically free of such restrictions.
### Chromium Headless Shell
Playwright runs a regular Chromium build in headed and headless modes. Note that headless mode has changed in Playwright version 1.49 when Chromium entirely switched to the [new headless implementation](https://developer.chrome.com/docs/chromium/headless).
Playwright also provides [`'chromium-headless-shell'` channel](https://developer.chrome.com/blog/chrome-headless-shell) that differs from the regular Chromium browser in features, performance and behavior. If you would like to optimize your CI performance and can tolerate different behavior in some cases, install and use this channel similarly to [Google Chrome & Microsoft Edge](#google-chrome--microsoft-edge).
### Firefox
Playwright's Firefox version matches the recent [Firefox Stable](https://www.mozilla.org/en-US/firefox/new/) build. Playwright doesn't work with the branded version of Firefox since it relies on patches.

Просмотреть файл

@ -214,10 +214,6 @@ def test_popup_page(page: Page, extension_id: str) -> None:
## Headless mode
:::danger
`headless=new` mode is not officially supported by Playwright and might result in unexpected behavior.
:::
By default, Chrome's headless mode in Playwright does not support Chrome extensions. To overcome this limitation, you can run Chrome's persistent context with a new headless mode by using the following code:
```js title="fixtures.ts"

Просмотреть файл

@ -8,57 +8,57 @@ import LiteYouTube from '@site/src/components/LiteYouTube';
## Version 1.49
### New Chromium Headless
### Breaking: channels `chrome`, `msedge` and similar switch to new headless
Prior to this release, Playwright was running the old established implementation of Chromium headless. However, Chromium had entirely switched to the [new headless mode](https://developer.chrome.com/docs/chromium/headless) implementation, so Playwright had to switch as well.
Prior to this release, Playwright was running the old established implementation of [Chromium headless mode](https://developer.chrome.com/docs/chromium/headless). However, Chromium had entirely **switched to the new headless mode**, and **removed the old one**.
Most likely, this change should go unnoticed for you. However, the new headless implementation differs in a number of ways, for example when handling pdf documents, so please file an issue if you encounter a problem.
![Chromium Headless](https://github.com/user-attachments/assets/2829e86a-dfe2-4743-a6d4-2aa65beea890)
### Chromium Headless Shell
If you are using a browser channel, for example `'chrome'` or `'msedge'`, the headless mode switch **will affect you**. Most likely, you will have to update some of your tests and all of your screenshot expectations. See [issue #33566](https://github.com/microsoft/playwright/issues/33566) for more details.
Playwright now also ships `chromium-headless-shell` channel that is a separate build that closely follows the old headless implementation. If you would like to keep the old behavior before you are ready to switch to the new headless, please fallback to this channel:
#### Chromium headless shell
1. First, install this channel prior to running tests. Make sure to list all browsers that you use.
Starting with this release, Playwright downloads and runs two different browser builds - one is a regular headed chromium and the other is a chromium headless shell. This should be transparent to you, **no action is needed**. You can learn more in [issue #33566](https://github.com/microsoft/playwright/issues/33566).
```bash
# running tests in all three browsers, headless and headed
npx playwright install chromium chromium-headless-shell firefox webkit
If you are only running tests in headless, for example on CI, you can avoid downloading a headed version of Chromium by specifying `chromium-headless-shell` during installation.
# running tests in all three browsers on CI, headless only
npx playwright install chromium-headless-shell firefox webkit
```
```bash
# only running tests headlessly
npx playwright install chromium-headless-shell firefox webkit
```
1. Update your config file to specify `'chromium-headless-shell'` channel.
Playwright will skip downloading headed chromium build, and will use `chromium-headless-shell` when running headless.
```js
import { defineConfig, devices } from '@playwright/test';
#### Opt-in to new headless
export default defineConfig({
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
channel: 'chromium-headless-shell',
},
We encourage everyone to try and switch to the new headless by using the `chromium-next` channel.
First, install this channel prior to running tests. Make sure to list all the browsers that you use.
```bash
npx playwright install chromium-next firefox webkit
```
Then update your config file to specify `'chromium-next'` channel.
```js
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
channel: 'chromium-next',
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});
```
1. Note that `chromium-headless-shell` channel only supports headless operations. If you try to run tests in headed mode, it will automatically fallback to regular `chromium`.
},
],
});
```
### Browser Versions
- Chromium 131.0.6778.24
- Chromium 131.0.6778.33
- Mozilla Firefox 132.0
- WebKit 18.0

Просмотреть файл

@ -10,7 +10,7 @@
{
"name": "chromium-headless-shell",
"revision": "1148",
"installByDefault": false,
"installByDefault": true,
"browserVersion": "131.0.6778.33"
},
{

Просмотреть файл

@ -300,7 +300,7 @@ export class Chromium extends BrowserType {
// See https://github.com/microsoft/playwright/issues/7362
chromeArguments.push('--enable-use-zoom-for-dsf=false');
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1407025.
if (options.headless)
if (options.headless && (!options.channel || options.channel === 'chromium-headless-shell'))
chromeArguments.push('--use-angle');
}
@ -349,9 +349,9 @@ export class Chromium extends BrowserType {
}
override getExecutableName(options: types.LaunchOptions): string {
if (options.channel === 'chromium-headless-shell' && !options.headless)
return 'chromium';
return options.channel || 'chromium';
if (options.channel)
return options.channel;
return options.headless ? 'chromium-headless-shell' : 'chromium';
}
}

Просмотреть файл

@ -79,7 +79,7 @@ const EXECUTABLE_PATHS = {
};
type DownloadPaths = Record<HostPlatform, string | undefined>;
const DOWNLOAD_PATHS: Record<BrowserName | InternalTool, DownloadPaths> = {
const DOWNLOAD_PATHS: Record<BrowserName | InternalTool | 'chromium-headless-shell', DownloadPaths> = {
'chromium': {
'<unknown>': undefined,
'ubuntu18.04-x64': undefined,
@ -403,9 +403,9 @@ function readDescriptors(browsersJSON: BrowsersJSON): BrowsersJSONDescriptor[] {
}
export type BrowserName = 'chromium' | 'firefox' | 'webkit' | 'bidi';
type InternalTool = 'ffmpeg' | 'firefox-beta' | 'chromium-tip-of-tree' | 'chromium-headless-shell' |'android';
type InternalTool = 'ffmpeg' | 'firefox-beta' | 'chromium-tip-of-tree' | 'android';
type BidiChannel = 'bidi-firefox-stable' | 'bidi-firefox-beta' | 'bidi-firefox-nightly' | 'bidi-chrome-canary' | 'bidi-chrome-stable' | 'bidi-chromium';
type ChromiumChannel = 'chrome' | 'chrome-beta' | 'chrome-dev' | 'chrome-canary' | 'msedge' | 'msedge-beta' | 'msedge-dev' | 'msedge-canary';
type ChromiumChannel = 'chrome' | 'chrome-beta' | 'chrome-dev' | 'chrome-canary' | 'chromium-headless-shell' | 'chromium-next' | 'msedge' | 'msedge-beta' | 'msedge-dev' | 'msedge-canary';
const allDownloadable = ['android', 'chromium', 'firefox', 'webkit', 'ffmpeg', 'firefox-beta', 'chromium-tip-of-tree', 'chromium-headless-shell'];
export interface Executable {
@ -488,11 +488,26 @@ export class Registry {
_dependencyGroup: 'chromium',
_isHermeticInstallation: true,
});
this._executables.push({
type: 'channel',
name: 'chromium-next',
browserName: 'chromium',
directory: chromium.dir,
executablePath: () => chromiumExecutable,
executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium-next', chromiumExecutable, chromium.installByDefault, sdkLanguage),
installType: 'download-on-demand',
_validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, chromium.dir, ['chrome-linux'], [], ['chrome-win']),
downloadURLs: this._downloadURLs(chromium),
browserVersion: chromium.browserVersion,
_install: () => this._downloadExecutable(chromium, chromiumExecutable),
_dependencyGroup: 'chromium',
_isHermeticInstallation: true,
});
const chromiumHeadlessShell = descriptors.find(d => d.name === 'chromium-headless-shell')!;
const chromiumHeadlessShellExecutable = findExecutablePath(chromiumHeadlessShell.dir, 'chromium-headless-shell');
this._executables.push({
type: 'tool',
type: 'channel',
name: 'chromium-headless-shell',
browserName: 'chromium',
directory: chromiumHeadlessShell.dir,
@ -885,6 +900,8 @@ export class Registry {
set.add(executable);
if (executable.browserName === 'chromium')
set.add(this.findExecutable('ffmpeg')!);
if (executable.name === 'chromium')
set.add(this.findExecutable('chromium-headless-shell')!);
}
return Array.from(set);
}

Просмотреть файл

@ -31,13 +31,19 @@ export const TMP_WORKSPACES = path.join(os.platform() === 'darwin' ? '/tmp' : os
const debug = debugLogger('itest');
const expect = _expect.extend({
toHaveLoggedSoftwareDownload(received: any, browsers: ('chromium' | 'firefox' | 'webkit' | 'ffmpeg')[]) {
toHaveLoggedSoftwareDownload(received: any, browsers: ('chromium' | 'chromium-headless-shell' | 'firefox' | 'webkit' | 'ffmpeg')[]) {
if (typeof received !== 'string')
throw new Error(`Expected argument to be a string.`);
const downloaded = new Set();
for (const [, browser] of received.matchAll(/^.*(chromium|firefox|webkit|ffmpeg).*playwright build v\d+\)? downloaded.*$/img))
downloaded.add(browser.toLowerCase());
let index = 0;
while (true) {
const match = received.substring(index).match(/(chromium|chromium headless shell|firefox|webkit|ffmpeg)[\s\d\.]+\(?playwright build v\d+\)? downloaded/im);
if (!match)
break;
downloaded.add(match[1].replace(/\s/g, '-').toLowerCase());
index += match.index + 1;
}
const expected = browsers;
if (expected.length === downloaded.size && expected.every(browser => downloaded.has(browser))) {
@ -143,7 +149,7 @@ export const test = _test
installedSoftwareOnDisk: async ({ isolateBrowsers, _browsersPath }, use) => {
if (!isolateBrowsers)
throw new Error(`Test that checks browser installation must set "isolateBrowsers" to true`);
await use(async () => fs.promises.readdir(_browsersPath).catch(() => []).then(files => files.map(f => f.split('-')[0]).filter(f => !f.startsWith('.'))));
await use(async () => fs.promises.readdir(_browsersPath).catch(() => []).then(files => files.map(f => f.split('-')[0].replace(/_/g, '-')).filter(f => !f.startsWith('.'))));
},
exec: async ({ tmpWorkspace, _browsersPath, isolateBrowsers }, use, testInfo) => {
await use(async (cmd: string, ...argsAndOrOptions: [] | [...string[]] | [...string[], ExecOptions] | [ExecOptions]) => {

Просмотреть файл

@ -35,8 +35,8 @@ test('npx playwright install global', async ({ exec, installedSoftwareOnDisk })
test.skip(process.platform === 'win32', 'isLikelyNpxGlobal() does not work in this setup on our bots');
const result = await exec('npx playwright install');
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'chromium-headless-shell', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'chromium-headless-shell', 'ffmpeg', 'firefox', 'webkit']);
expect(result).not.toContain(`Please run the following command to download new browsers`);
expect(result).toContain(`To avoid unexpected behavior, please install your dependencies first`);
});

Просмотреть файл

@ -41,8 +41,8 @@ for (const cdn of CDNS) {
test(`playwright cdn failover should work (${cdn})`, async ({ exec, installedSoftwareOnDisk }) => {
await exec('npm i playwright');
const result = await exec('npx playwright install', { env: { PW_TEST_CDN_THAT_SHOULD_WORK: cdn, DEBUG: 'pw:install' } });
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'chromium-headless-shell', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'chromium-headless-shell', 'ffmpeg', 'firefox', 'webkit']);
const dls = parsedDownloads(result);
for (const software of ['chromium', 'ffmpeg', 'firefox', 'webkit'])
expect(dls).toContainEqual({ status: 200, name: software, url: expect.stringContaining(cdn) });

Просмотреть файл

@ -23,14 +23,14 @@ test('install command should work', async ({ exec, installedSoftwareOnDisk }) =>
await test.step('playwright install chromium', async () => {
const result = await exec('npx playwright install chromium');
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg']);
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'chromium-headless-shell', 'ffmpeg']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'chromium-headless-shell', 'ffmpeg']);
});
await test.step('playwright install', async () => {
const result = await exec('npx playwright install');
expect(result).toHaveLoggedSoftwareDownload(['firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'chromium-headless-shell', 'ffmpeg', 'firefox', 'webkit']);
});
await exec('node sanity.js playwright', { env: { PLAYWRIGHT_BROWSERS_PATH: '0' } });
@ -50,7 +50,7 @@ test('install command should work', async ({ exec, installedSoftwareOnDisk }) =>
test('should be able to remove browsers', async ({ exec, installedSoftwareOnDisk }) => {
await exec('npm i playwright');
await exec('npx playwright install chromium');
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'chromium-headless-shell', 'ffmpeg']);
await exec('npx playwright uninstall');
expect(await installedSoftwareOnDisk()).toEqual([]);
});

Просмотреть файл

@ -25,7 +25,7 @@ for (const browser of ['chromium', 'firefox', 'webkit']) {
const browserName = pkg.split('-')[1];
const expectedSoftware = [browserName];
if (browserName === 'chromium')
expectedSoftware.push('ffmpeg');
expectedSoftware.push('chromium-headless-shell', 'ffmpeg');
expect(result).toHaveLoggedSoftwareDownload(expectedSoftware as any);
expect(await installedSoftwareOnDisk()).toEqual(expectedSoftware);
expect(result).not.toContain(`To avoid unexpected behavior, please install your dependencies first`);
@ -39,7 +39,7 @@ for (const browser of ['chromium', 'firefox', 'webkit']) {
const pkg = `@playwright/browser-${browser}`;
const expectedSoftware = [browser];
if (browser === 'chromium')
expectedSoftware.push('ffmpeg');
expectedSoftware.push('chromium-headless-shell', 'ffmpeg');
const result1 = await exec('npm i --foreground-scripts', pkg);
expect(result1).toHaveLoggedSoftwareDownload(expectedSoftware as any);
@ -69,13 +69,22 @@ test(`playwright should work`, async ({ exec, installedSoftwareOnDisk }) => {
expect(await installedSoftwareOnDisk()).toEqual([]);
const result2 = await exec('npx playwright install');
expect(result2).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(result2).toHaveLoggedSoftwareDownload(['chromium', 'chromium-headless-shell', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'chromium-headless-shell', 'ffmpeg', 'firefox', 'webkit']);
await exec('node sanity.js playwright chromium firefox webkit');
await exec('node esm-playwright.mjs');
});
test(`playwright should work with chromium-next`, async ({ exec, installedSoftwareOnDisk }) => {
const result1 = await exec('npm i --foreground-scripts playwright');
expect(result1).toHaveLoggedSoftwareDownload([]);
expect(await installedSoftwareOnDisk()).toEqual([]);
const result2 = await exec('npx playwright install chromium-next');
expect(result2).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg']);
});
test('@playwright/test should work', async ({ exec, installedSoftwareOnDisk }) => {
const result1 = await exec('npm i --foreground-scripts @playwright/test');
expect(result1).toHaveLoggedSoftwareDownload([]);
@ -84,8 +93,8 @@ test('@playwright/test should work', async ({ exec, installedSoftwareOnDisk }) =
await exec('npx playwright test -c . sample.spec.js', { expectToExitWithError: true, message: 'should not be able to run tests without installing browsers' });
const result2 = await exec('npx playwright install');
expect(result2).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(result2).toHaveLoggedSoftwareDownload(['chromium', 'chromium-headless-shell', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'chromium-headless-shell', 'ffmpeg', 'firefox', 'webkit']);
await exec('node sanity.js @playwright/test chromium firefox webkit');
await exec('node', 'esm-playwright-test.mjs');

Просмотреть файл

@ -58,7 +58,7 @@ test('should validate dependencies correctly if skipped during install', async (
DEBUG: 'pw:install',
},
});
expect(result).toContain(`validating host requirements for "chromium"`);
expect(result).toContain(`validating host requirements for "chromium-headless-shell"`);
expect(result).not.toContain(`validating host requirements for "firefox"`);
expect(result).not.toContain(`validating host requirements for "webkit"`);
});

Просмотреть файл

@ -15,26 +15,33 @@
* limitations under the License.
*/
import { browserTest as it, expect } from '../config/browserTest';
import { browserTest as base, expect } from '../config/browserTest';
it('should fail without credentials', async ({ browser, server, browserName, channel }) => {
const it = base.extend<{ failsOn401: boolean }>({
failsOn401: async ({ browserName, headless, channel }, use) => {
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
await use(browserName === 'chromium' && !isHeadlessShell);
},
});
it('should fail without credentials', async ({ browser, server, failsOn401 }) => {
server.setAuth('/empty.html', 'user', 'pass');
const context = await browser.newContext();
const page = await context.newPage();
const responseOrError = await page.goto(server.EMPTY_PAGE).catch(e => e);
if (browserName === 'chromium' && channel !== 'chromium-headless-shell')
if (failsOn401)
expect(responseOrError.message).toContain('net::ERR_INVALID_AUTH_CREDENTIALS');
else
expect(responseOrError.status()).toBe(401);
});
it('should work with setHTTPCredentials', async ({ browser, server, browserName, channel }) => {
it('should work with setHTTPCredentials', async ({ browser, server, failsOn401 }) => {
server.setAuth('/empty.html', 'user', 'pass');
const context = await browser.newContext();
const page = await context.newPage();
let responseOrError = await page.goto(server.EMPTY_PAGE).catch(e => e);
if (browserName === 'chromium' && channel !== 'chromium-headless-shell')
if (failsOn401)
expect(responseOrError.message).toContain('net::ERR_INVALID_AUTH_CREDENTIALS');
else
expect(responseOrError.status()).toBe(401);
@ -102,21 +109,21 @@ it('should work with correct credentials and matching origin case insensitive',
await context.close();
});
it('should fail with correct credentials and mismatching scheme', async ({ browser, server, browserName, channel }) => {
it('should fail with correct credentials and mismatching scheme', async ({ browser, server, failsOn401 }) => {
server.setAuth('/empty.html', 'user', 'pass');
const context = await browser.newContext({
httpCredentials: { username: 'user', password: 'pass', origin: server.PREFIX.replace('http://', 'https://') }
});
const page = await context.newPage();
const responseOrError = await page.goto(server.EMPTY_PAGE).catch(e => e);
if (browserName === 'chromium' && channel !== 'chromium-headless-shell')
if (failsOn401)
expect(responseOrError.message).toContain('net::ERR_INVALID_AUTH_CREDENTIALS');
else
expect(responseOrError.status()).toBe(401);
await context.close();
});
it('should fail with correct credentials and mismatching hostname', async ({ browser, server, browserName, channel }) => {
it('should fail with correct credentials and mismatching hostname', async ({ browser, server, failsOn401 }) => {
server.setAuth('/empty.html', 'user', 'pass');
const hostname = new URL(server.PREFIX).hostname;
const origin = server.PREFIX.replace(hostname, 'mismatching-hostname');
@ -125,14 +132,14 @@ it('should fail with correct credentials and mismatching hostname', async ({ bro
});
const page = await context.newPage();
const responseOrError = await page.goto(server.EMPTY_PAGE).catch(e => e);
if (browserName === 'chromium' && channel !== 'chromium-headless-shell')
if (failsOn401)
expect(responseOrError.message).toContain('net::ERR_INVALID_AUTH_CREDENTIALS');
else
expect(responseOrError.status()).toBe(401);
await context.close();
});
it('should fail with correct credentials and mismatching port', async ({ browser, server, browserName, channel }) => {
it('should fail with correct credentials and mismatching port', async ({ browser, server, failsOn401 }) => {
server.setAuth('/empty.html', 'user', 'pass');
const origin = server.PREFIX.replace(server.PORT.toString(), (server.PORT + 1).toString());
const context = await browser.newContext({
@ -140,7 +147,7 @@ it('should fail with correct credentials and mismatching port', async ({ browser
});
const page = await context.newPage();
const responseOrError = await page.goto(server.EMPTY_PAGE).catch(e => e);
if (browserName === 'chromium' && channel !== 'chromium-headless-shell')
if (failsOn401)
expect(responseOrError.message).toContain('net::ERR_INVALID_AUTH_CREDENTIALS');
else
expect(responseOrError.status()).toBe(401);

Просмотреть файл

@ -170,6 +170,8 @@ for (const kind of ['launchServer', 'run-server'] as const) {
});
test('should ignore page.pause when headed', async ({ connect, startRemoteServer, browserType, channel }) => {
test.skip(channel === 'chromium-headless-shell', 'shell is never headed');
const headless = (browserType as any)._defaultLaunchOptions.headless;
(browserType as any)._defaultLaunchOptions.headless = false;
const remoteServer = await startRemoteServer(kind);

Просмотреть файл

@ -52,8 +52,10 @@ it('should open devtools when "devtools: true" option is given', async ({ browse
await browser.close();
});
it('should return background pages', async ({ browserType, createUserDataDir, asset, channel }) => {
it.skip(channel === 'chromium-headless-shell', 'Headless Shell has no support for extensions');
it('should return background pages', async ({ browserType, createUserDataDir, asset, headless, channel }) => {
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.skip(isHeadlessShell, 'Headless Shell has no support for extensions');
const userDataDir = await createUserDataDir();
const extensionPath = asset('simple-extension');
const extensionOptions = {
@ -76,8 +78,10 @@ it('should return background pages', async ({ browserType, createUserDataDir, as
expect(context.backgroundPages().length).toBe(0);
});
it('should return background pages when recording video', async ({ browserType, createUserDataDir, asset, channel }, testInfo) => {
it.skip(channel === 'chromium-headless-shell', 'Headless Shell has no support for extensions');
it('should return background pages when recording video', async ({ browserType, createUserDataDir, asset, headless, channel }, testInfo) => {
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.skip(isHeadlessShell, 'Headless Shell has no support for extensions');
const userDataDir = await createUserDataDir();
const extensionPath = asset('simple-extension');
const extensionOptions = {
@ -101,8 +105,10 @@ it('should return background pages when recording video', async ({ browserType,
await context.close();
});
it('should support request/response events when using backgroundPage()', async ({ browserType, createUserDataDir, asset, server, channel }) => {
it.skip(channel === 'chromium-headless-shell', 'Headless Shell has no support for extensions');
it('should support request/response events when using backgroundPage()', async ({ browserType, createUserDataDir, asset, server, headless, channel }) => {
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.skip(isHeadlessShell, 'Headless Shell has no support for extensions');
server.setRoute('/empty.html', (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html', 'x-response-foobar': 'BarFoo' });
res.end(`<span>hello world!</span>`);
@ -151,8 +157,10 @@ it('should support request/response events when using backgroundPage()', async (
it('should report console messages from content script', {
annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/32762' }
}, async ({ browserType, createUserDataDir, asset, server, channel }) => {
it.skip(channel === 'chromium-headless-shell', 'Headless Shell has no support for extensions');
}, async ({ browserType, createUserDataDir, asset, server, headless, channel }) => {
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.skip(isHeadlessShell, 'Headless Shell has no support for extensions');
const userDataDir = await createUserDataDir();
const extensionPath = asset('extension-with-logging');
const extensionOptions = {
@ -184,13 +192,3 @@ it('should not create pages automatically', async ({ browserType }) => {
await browser.close();
expect(targets.length).toBe(0);
});
it('should fallback to regular chromium when running chromium-headless-shell channel as headed', async ({ browserType, channel }) => {
it.skip(channel !== 'chromium-headless-shell');
const browser = await browserType.launch({ channel: 'chromium-headless-shell', headless: false });
const page = await browser.newPage();
const ua = await page.evaluate(() => navigator.userAgent);
await browser.close();
expect(ua).not.toContain('Headless');
});

Просмотреть файл

@ -636,8 +636,10 @@ it('should be able to download a inline PDF file via response interception', asy
await page.close();
});
it('should be able to download a inline PDF file via navigation', async ({ browser, server, asset, browserName, channel }) => {
it.skip(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'We expect PDF Viewer to open up in Chromium');
it('should be able to download a inline PDF file via navigation', async ({ browser, server, asset, browserName, channel, headless }) => {
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.skip(browserName === 'chromium' && !isHeadlessShell, 'We expect PDF Viewer to open up in headed Chromium');
const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE);
await page.setContent(`

Просмотреть файл

@ -104,7 +104,8 @@ it('should change document.activeElement', async ({ page, server }) => {
it('should not affect screenshots', async ({ page, server, browserName, headless, isWindows, channel }) => {
it.skip(browserName === 'webkit' && isWindows && !headless, 'WebKit/Windows/headed has a larger minimal viewport. See https://github.com/microsoft/playwright/issues/22616');
it.skip(browserName === 'firefox' && !headless, 'Firefox headed produces a different image');
it.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'https://github.com/microsoft/playwright/issues/33330');
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.fixme(browserName === 'chromium' && !isHeadlessShell, 'https://github.com/microsoft/playwright/issues/33330');
const page2 = await page.context().newPage();
await Promise.all([

Просмотреть файл

@ -19,6 +19,7 @@ import { PNG } from 'playwright-core/lib/utilsBundle';
import { expect, playwrightTest as it } from '../config/browserTest';
it.use({ headless: false });
it.skip(({ channel }) => channel === 'chromium-headless-shell', 'shell is never headed');
it('should have default url when launching browser @smoke', async ({ launchPersistent }) => {
const { context } = await launchPersistent();

Просмотреть файл

@ -44,6 +44,7 @@ it('should kill browser process on timeout after close', async ({ browserType, m
it('should throw a friendly error if its headed and there is no xserver on linux running', async ({ mode, browserType, platform, channel }) => {
it.skip(platform !== 'linux');
it.skip(mode.startsWith('service'));
it.skip(channel === 'chromium-headless-shell', 'shell is never headed');
const error: Error = await browserType.launch({
headless: false,

Просмотреть файл

@ -156,8 +156,9 @@ it('should support clipboard read', async ({ page, context, server, browserName,
if (browserName !== 'webkit')
expect(await getPermission(page, 'clipboard-read')).toBe('prompt');
if (browserName === 'chromium' && channel === 'chromium-headless-shell') {
// Chromium shows a dialog and does not resolve the promise.
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
if (browserName === 'chromium' && isHeadlessShell) {
// Chromium (but not headless-shell) shows a dialog and does not resolve the promise.
const error = await page.evaluate(() => navigator.clipboard.readText()).catch(e => e);
expect(error.toString()).toContain('denied');
}

Просмотреть файл

@ -22,8 +22,10 @@ import { verifyViewport } from '../config/utils';
browserTest.describe('page screenshot', () => {
browserTest.skip(({ browserName, headless }) => browserName === 'firefox' && !headless, 'Firefox headed produces a different image.');
browserTest('should run in parallel in multiple pages', async ({ server, contextFactory, browserName, channel }) => {
browserTest.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'https://github.com/microsoft/playwright/issues/33330');
browserTest('should run in parallel in multiple pages', async ({ server, contextFactory, browserName, headless, channel }) => {
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
browserTest.fixme(browserName === 'chromium' && !isHeadlessShell, 'https://github.com/microsoft/playwright/issues/33330');
const context = await contextFactory();
const N = 5;
const pages = await Promise.all(Array(N).fill(0).map(async () => {

Просмотреть файл

@ -430,8 +430,9 @@ for (const params of [
}
]) {
browserTest(`should produce screencast frames ${params.id}`, async ({ video, contextFactory, browserName, platform, headless, channel }, testInfo) => {
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
browserTest.skip(browserName === 'chromium' && video === 'on', 'Same screencast resolution conflicts');
browserTest.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'Chromium screencast has a min width issue');
browserTest.fixme(browserName === 'chromium' && !isHeadlessShell, 'Chromium (but not headless-shell) screencast has a min width issue');
browserTest.fixme(params.id === 'fit' && browserName === 'chromium' && platform === 'darwin', 'High DPI maxes image at 600x600');
browserTest.fixme(params.id === 'fit' && browserName === 'webkit' && platform === 'linux', 'Image size is flaky');
browserTest.fixme(browserName === 'firefox' && !headless, 'Image size is different');

Просмотреть файл

@ -475,7 +475,8 @@ it.describe('screencast', () => {
it('should scale frames down to the requested size ', async ({ browser, browserName, server, headless, channel }, testInfo) => {
it.fixme(!headless, 'Fails on headed');
it.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'Fails on Chromiums');
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.fixme(browserName === 'chromium' && !isHeadlessShell, 'Chromium (but not headless shell) has a min width issue');
const context = await browser.newContext({
recordVideo: {
@ -722,9 +723,10 @@ it.describe('screencast', () => {
expect(files.length).toBe(1);
});
it('should capture full viewport', async ({ browserType, browserName, isWindows, channel }, testInfo) => {
it('should capture full viewport', async ({ browserType, browserName, isWindows, headless, channel }, testInfo) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/22411' });
it.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'The square is not on the video');
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.fixme(browserName === 'chromium' && !isHeadlessShell, 'The square is not on the video');
it.fixme(browserName === 'firefox' && isWindows, 'https://github.com/microsoft/playwright/issues/14405');
const size = { width: 600, height: 400 };
const browser = await browserType.launch();
@ -759,7 +761,8 @@ it.describe('screencast', () => {
it('should capture full viewport on hidpi', async ({ browserType, browserName, headless, isWindows, isLinux, channel }, testInfo) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/22411' });
it.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'The square is not on the video');
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.fixme(browserName === 'chromium' && !isHeadlessShell, 'The square is not on the video');
it.fixme(browserName === 'firefox' && isWindows, 'https://github.com/microsoft/playwright/issues/14405');
it.fixme(browserName === 'webkit' && isLinux && !headless, 'https://github.com/microsoft/playwright/issues/22617');
const size = { width: 600, height: 400 };
@ -797,7 +800,8 @@ it.describe('screencast', () => {
it('should work with video+trace', async ({ browser, trace, headless, browserName, channel }, testInfo) => {
it.skip(trace === 'on');
it.fixme(!headless, 'different trace screencast image size on all browsers');
it.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'different trace screencast image size on Chromium');
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.fixme(browserName === 'chromium' && !isHeadlessShell, 'different trace screencast image size');
const size = { width: 500, height: 400 };
const traceFile = testInfo.outputPath('trace.zip');

Просмотреть файл

@ -119,8 +119,9 @@ it('clicking checkbox should activate it', async ({ page, browserName, headless,
it('tab should cycle between single input and browser', {
annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/32339' }
}, async ({ page, browserName, channel }) => {
it.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'Chromium keeps input focused.');
}, async ({ page, browserName, headless, channel }) => {
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.fixme(browserName === 'chromium' && !isHeadlessShell, 'Chromium keeps input focused.');
it.fixme(browserName !== 'chromium');
await page.setContent(`<label for="input1">input1</label>
<input id="input1">
@ -146,8 +147,9 @@ it('tab should cycle between single input and browser', {
it('tab should cycle between document elements and browser', {
annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/32339' }
}, async ({ page, browserName, channel }) => {
it.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'Chromium keeps last input focused.');
}, async ({ page, browserName, headless, channel }) => {
const isHeadlessShell = channel === 'chromium-headless-shell' || (!channel && headless);
it.fixme(browserName === 'chromium' && !isHeadlessShell, 'Chromium keeps last input focused.');
it.fixme(browserName !== 'chromium');
await page.setContent(`
<input id="input1">