Compare commits

...

6 commits

Author SHA1 Message Date
Playwright Service 2ee3aaa0f5
cherry-pick(#27667): docs: make test-timeouts AAA compliant (#27676)
This PR cherry-picks the following commits:

- a005064cc8

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-10-18 08:28:43 +02:00
Playwright Service 0594783ed6
cherry-pick(#27630): fix: merge{Tests,Expects} via ESM imports (#27641)
This PR cherry-picks the following commits:

- fd2fbe9d2f

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-10-17 22:43:45 +02:00
Playwright Service a115439b47
cherry-pick(#27559): docs: Fixing a release version of a method toHaveAttribute (#27560)
This PR cherry-picks the following commits:

- 117f3f1298

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-10-12 08:54:35 +02:00
Pavel Feldman 3049d99bc8 cherry-pick(#27555): chore: composed->merge 2023-10-11 13:58:19 -07:00
Dmitry Gozman ae31f58b43
chore: mark 1.39.0 (#27550) 2023-10-11 11:20:29 -07:00
Dmitry Gozman 5313514995 cherry-pick(#27549): docs: update release notes for 1.39 2023-10-11 10:59:10 -07:00
38 changed files with 209 additions and 145 deletions

View file

@ -1152,7 +1152,7 @@ Expected attribute value.
* since: v1.18
## async method: LocatorAssertions.toHaveAttribute#2
* since: v1.40
* since: v1.39
* langs: js
Ensures the [Locator] points to an element with given attribute. The method will assert attribute
@ -1166,13 +1166,13 @@ await expect(locator).not.toHaveAttribute('open');
```
### param: LocatorAssertions.toHaveAttribute#2.name
* since: v1.40
* since: v1.39
- `name` <[string]>
Attribute name.
### option: LocatorAssertions.toHaveAttribute#2.timeout = %%-js-assertions-timeout-%%
* since: v1.40
* since: v1.39
## async method: LocatorAssertions.toHaveClass
* since: v1.20

View file

@ -6,7 +6,7 @@ toc_max_heading_level: 2
## Version 1.39
Maintenance release.
Evergreen browsers update.
### Browser Versions

View file

@ -6,7 +6,7 @@ toc_max_heading_level: 2
## Version 1.39
Maintenance release.
Evergreen browsers update.
### Browser Versions

View file

@ -8,46 +8,68 @@ import LiteYouTube from '@site/src/components/LiteYouTube';
## Version 1.39
### Extending expect with custom matchers
### Add custom matchers to your expect
You can extend Playwright assertions by providing custom matchers. These matchers will be available on the expect object.
```js title=fixtures.ts
```js title="test.spec.ts"
import { expect as baseExpect } from '@playwright/test';
export const expect = baseExpect.extend({
async toHaveAmount(locator: Locator, expected: number, options?: { timeout?: number }) {
// Note: this matcher never passes, see the documentation for a full example.
// Return a "pass" flag and a message getter.
return { pass: false, message: () => `Expected ${expected} amount` };
// ... see documentation for how to write matchers.
},
});
test('pass', async ({ page }) => {
await expect(page.getByTestId('cart')).toHaveAmount(5);
});
```
See the documentation [for a full example](./test-configuration.md#add-custom-matchers-using-expectextend).
### Merging fixtures and expect matchers
### Merge test fixtures
You can combine fixtures and custom expect matchers from multiple files or modules.
You can now merge test fixtures from multiple files or modules:
```js title="fixtures.ts"
import { composedTest, composedExpect } from '@playwright/test';
import { mergeTests } from '@playwright/test';
import { test as dbTest } from 'database-test-utils';
import { test as a11yTest } from 'a11y-test-utils';
export const test = mergeTests(dbTest, a11yTest);
```
```js title="test.spec.ts"
import { test } from './fixtures';
test('passes', async ({ database, page, a11y }) => {
// use database and a11y fixtures.
});
```
### Merge custom expect matchers
You can now merge custom expect matchers from multiple files or modules:
```js title="fixtures.ts"
import { mergeTests, mergeExpects } from '@playwright/test';
import { test as dbTest, expect as dbExpect } from 'database-test-utils';
import { test as a11yTest, expect as a11yExpect } from 'a11y-test-utils';
export const expect = composedExpect(dbExpect, a11yExpect);
export const test = composedTest(dbTest, a11yTest);
export const test = mergeTests(dbTest, a11yTest);
export const expect = mergeExpects(dbExpect, a11yExpect);
```
```js title="test.spec.ts"
import { test, expect } from './fixtures';
test('passes', async ({ database, page }) => {
test('passes', async ({ page, database }) => {
await expect(database).toHaveDatabaseUser('admin');
await expect(page).toPassA11yAudit();
});
```
### Boxed test steps
### Hide implementation details: box test steps
You can mark a [`method: Test.step`] as "boxed" so that errors inside it point to the step call site.

View file

@ -6,7 +6,7 @@ toc_max_heading_level: 2
## Version 1.39
Maintenance release.
Evergreen browsers update.
### Browser Versions

View file

@ -217,12 +217,12 @@ Do not confuse Playwright's `expect` with the [`expect` library](https://jestjs.
You can combine custom matchers from multiple files or modules.
```js title="fixtures.ts"
import { composedTest, composedExpect } from '@playwright/test';
import { mergeTests, mergeExpects } from '@playwright/test';
import { test as dbTest, expect as dbExpect } from 'database-test-utils';
import { test as a11yTest, expect as a11yExpect } from 'a11y-test-utils';
export const expect = composedExpect(dbExpect, a11yExpect);
export const test = composedTest(dbTest, a11yTest);
export const expect = mergeExpects(dbExpect, a11yExpect);
export const test = mergeTests(dbTest, a11yTest);
```
```js title="test.spec.ts"

View file

@ -9,8 +9,8 @@ Playwright Test has multiple configurable timeouts for various tasks.
|Timeout |Default |Description |
|:----------|:----------------|:--------------------------------|
|Test timeout|30000 ms|Timeout for each test, includes test, hooks and fixtures:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.6'}}>Set default</span><br/><code>{`config = { timeout: 60000 }`}</code><br/><span style={{textTransform: 'uppercase',fontSize: 'smaller', fontWeight: 'bold', opacity: '0.6'}}>Override</span><br/>`test.setTimeout(120000)` |
|Expect timeout|5000 ms|Timeout for each assertion:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.6'}}>Set default</span><br/><code>{`config = { expect: { timeout: 10000 } }`}</code><br/><span style={{textTransform: 'uppercase',fontSize: 'smaller', fontWeight: 'bold', opacity: '0.6'}}>Override</span><br/>`expect(locator).toBeVisible({ timeout: 10000 })` |
|Test timeout|30000 ms|Timeout for each test, includes test, hooks and fixtures:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.7'}}>Set default</span><br/><code>{`config = { timeout: 60000 }`}</code><br/><span style={{textTransform: 'uppercase',fontSize: 'smaller', fontWeight: 'bold', opacity: '0.7'}}>Override</span><br/>`test.setTimeout(120000)` |
|Expect timeout|5000 ms|Timeout for each assertion:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.7'}}>Set default</span><br/><code>{`config = { expect: { timeout: 10000 } }`}</code><br/><span style={{textTransform: 'uppercase',fontSize: 'smaller', fontWeight: 'bold', opacity: '0.7'}}>Override</span><br/>`expect(locator).toBeVisible({ timeout: 10000 })` |
## Test timeout
@ -144,11 +144,11 @@ If you happen to be in this section because your test are flaky, it is very like
|Timeout |Default |Description |
|:----------|:----------------|:--------------------------------|
|Action timeout| no timeout |Timeout for each action:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.6'}}>Set default</span><br/><code>{`config = { use: { actionTimeout: 10000 } }`}</code><br/><span style={{textTransform: 'uppercase',fontSize: 'smaller', fontWeight: 'bold', opacity: '0.6'}}>Override</span><br/>`locator.click({ timeout: 10000 })` |
|Navigation timeout| no timeout |Timeout for each navigation action:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.6'}}>Set default</span><br/><code>{`config = { use: { navigationTimeout: 30000 } }`}</code><br/><span style={{textTransform: 'uppercase',fontSize: 'smaller', fontWeight: 'bold', opacity: '0.6'}}>Override</span><br/>`page.goto('/', { timeout: 30000 })` |
|Global timeout|no timeout |Global timeout for the whole test run:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.6'}}>Set in config</span><br/>`config = { globalTimeout: 60*60*1000 }`<br/> |
|`beforeAll`/`afterAll` timeout|30000 ms|Timeout for the hook:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.6'}}>Set in hook</span><br/>`test.setTimeout(60000)`<br/> |
|Fixture timeout|no timeout |Timeout for an individual fixture:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.6'}}>Set in fixture</span><br/>`{ scope: 'test', timeout: 30000 }`<br/> |
|Action timeout| no timeout |Timeout for each action:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.7'}}>Set default</span><br/><code>{`config = { use: { actionTimeout: 10000 } }`}</code><br/><span style={{textTransform: 'uppercase',fontSize: 'smaller', fontWeight: 'bold', opacity: '0.7'}}>Override</span><br/>`locator.click({ timeout: 10000 })` |
|Navigation timeout| no timeout |Timeout for each navigation action:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.7'}}>Set default</span><br/><code>{`config = { use: { navigationTimeout: 30000 } }`}</code><br/><span style={{textTransform: 'uppercase',fontSize: 'smaller', fontWeight: 'bold', opacity: '0.7'}}>Override</span><br/>`page.goto('/', { timeout: 30000 })` |
|Global timeout|no timeout |Global timeout for the whole test run:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.7'}}>Set in config</span><br/>`config = { globalTimeout: 60*60*1000 }`<br/> |
|`beforeAll`/`afterAll` timeout|30000 ms|Timeout for the hook:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.7'}}>Set in hook</span><br/>`test.setTimeout(60000)`<br/> |
|Fixture timeout|no timeout |Timeout for an individual fixture:<br/><span style={{textTransform:'uppercase',fontSize:'smaller',fontWeight:'bold',opacity:'0.7'}}>Set in fixture</span><br/>`{ scope: 'test', timeout: 30000 }`<br/> |
### Set timeout for a single assertion

100
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "playwright-internal",
"version": "1.39.0-next",
"version": "1.39.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "playwright-internal",
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"workspaces": [
"packages/*"
@ -7054,10 +7054,10 @@
}
},
"packages/playwright": {
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
},
"bin": {
"playwright": "cli.js"
@ -7071,11 +7071,11 @@
},
"packages/playwright-browser-chromium": {
"name": "@playwright/browser-chromium",
"version": "1.39.0-next",
"version": "1.39.0",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
},
"engines": {
"node": ">=16"
@ -7083,11 +7083,11 @@
},
"packages/playwright-browser-firefox": {
"name": "@playwright/browser-firefox",
"version": "1.39.0-next",
"version": "1.39.0",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
},
"engines": {
"node": ">=16"
@ -7095,22 +7095,22 @@
},
"packages/playwright-browser-webkit": {
"name": "@playwright/browser-webkit",
"version": "1.39.0-next",
"version": "1.39.0",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
},
"engines": {
"node": ">=16"
}
},
"packages/playwright-chromium": {
"version": "1.39.0-next",
"version": "1.39.0",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
},
"bin": {
"playwright": "cli.js"
@ -7120,7 +7120,7 @@
}
},
"packages/playwright-core": {
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
@ -7131,11 +7131,11 @@
},
"packages/playwright-ct-core": {
"name": "@playwright/experimental-ct-core",
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.39.0-next",
"playwright-core": "1.39.0-next",
"playwright": "1.39.0",
"playwright-core": "1.39.0",
"vite": "^4.4.10"
},
"bin": {
@ -7147,10 +7147,10 @@
},
"packages/playwright-ct-react": {
"name": "@playwright/experimental-ct-react",
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-react": "^4.0.0"
},
"bin": {
@ -7179,10 +7179,10 @@
},
"packages/playwright-ct-react17": {
"name": "@playwright/experimental-ct-react17",
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-react": "^4.0.0"
},
"bin": {
@ -7211,10 +7211,10 @@
},
"packages/playwright-ct-solid": {
"name": "@playwright/experimental-ct-solid",
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"vite-plugin-solid": "^2.7.0"
},
"bin": {
@ -7229,10 +7229,10 @@
},
"packages/playwright-ct-svelte": {
"name": "@playwright/experimental-ct-svelte",
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@sveltejs/vite-plugin-svelte": "^2.1.1"
},
"bin": {
@ -7247,10 +7247,10 @@
},
"packages/playwright-ct-vue": {
"name": "@playwright/experimental-ct-vue",
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-vue": "^4.2.1"
},
"bin": {
@ -7298,10 +7298,10 @@
},
"packages/playwright-ct-vue2": {
"name": "@playwright/experimental-ct-vue2",
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-vue2": "^2.2.0"
},
"bin": {
@ -7315,11 +7315,11 @@
}
},
"packages/playwright-firefox": {
"version": "1.39.0-next",
"version": "1.39.0",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
},
"bin": {
"playwright": "cli.js"
@ -7353,10 +7353,10 @@
},
"packages/playwright-test": {
"name": "@playwright/test",
"version": "1.39.0-next",
"version": "1.39.0",
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.39.0-next"
"playwright": "1.39.0"
},
"bin": {
"playwright": "cli.js"
@ -7366,11 +7366,11 @@
}
},
"packages/playwright-webkit": {
"version": "1.39.0-next",
"version": "1.39.0",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
},
"bin": {
"playwright": "cli.js"
@ -8089,33 +8089,33 @@
"@playwright/browser-chromium": {
"version": "file:packages/playwright-browser-chromium",
"requires": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
},
"@playwright/browser-firefox": {
"version": "file:packages/playwright-browser-firefox",
"requires": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
},
"@playwright/browser-webkit": {
"version": "file:packages/playwright-browser-webkit",
"requires": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
},
"@playwright/experimental-ct-core": {
"version": "file:packages/playwright-ct-core",
"requires": {
"playwright": "1.39.0-next",
"playwright-core": "1.39.0-next",
"playwright": "1.39.0",
"playwright-core": "1.39.0",
"vite": "^4.4.10"
}
},
"@playwright/experimental-ct-react": {
"version": "file:packages/playwright-ct-react",
"requires": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-react": "^4.0.0"
},
"dependencies": {
@ -8135,7 +8135,7 @@
"@playwright/experimental-ct-react17": {
"version": "file:packages/playwright-ct-react17",
"requires": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-react": "^4.0.0"
},
"dependencies": {
@ -8155,7 +8155,7 @@
"@playwright/experimental-ct-solid": {
"version": "file:packages/playwright-ct-solid",
"requires": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"solid-js": "^1.7.0",
"vite-plugin-solid": "^2.7.0"
}
@ -8163,7 +8163,7 @@
"@playwright/experimental-ct-svelte": {
"version": "file:packages/playwright-ct-svelte",
"requires": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@sveltejs/vite-plugin-svelte": "^2.1.1",
"svelte": "^3.55.1"
}
@ -8171,7 +8171,7 @@
"@playwright/experimental-ct-vue": {
"version": "file:packages/playwright-ct-vue",
"requires": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-vue": "^4.2.1"
},
"dependencies": {
@ -8205,7 +8205,7 @@
"@playwright/experimental-ct-vue2": {
"version": "file:packages/playwright-ct-vue2",
"requires": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-vue2": "^2.2.0",
"vue": "^2.7.14"
}
@ -8213,7 +8213,7 @@
"@playwright/test": {
"version": "file:packages/playwright-test",
"requires": {
"playwright": "1.39.0-next"
"playwright": "1.39.0"
}
},
"@sindresorhus/is": {
@ -11081,13 +11081,13 @@
"version": "file:packages/playwright",
"requires": {
"fsevents": "2.3.2",
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
},
"playwright-chromium": {
"version": "file:packages/playwright-chromium",
"requires": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
},
"playwright-core": {
@ -11096,13 +11096,13 @@
"playwright-firefox": {
"version": "file:packages/playwright-firefox",
"requires": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
},
"playwright-webkit": {
"version": "file:packages/playwright-webkit",
"requires": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
},
"postcss": {

View file

@ -1,7 +1,7 @@
{
"name": "playwright-internal",
"private": true,
"version": "1.39.0-next",
"version": "1.39.0",
"description": "A high-level API to automate web browsers",
"repository": {
"type": "git",

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/browser-chromium",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "Playwright package that automatically installs Chromium",
"repository": {
"type": "git",
@ -27,6 +27,6 @@
"install": "node install.js"
},
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
}

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/browser-firefox",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "Playwright package that automatically installs Firefox",
"repository": {
"type": "git",
@ -27,6 +27,6 @@
"install": "node install.js"
},
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
}

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/browser-webkit",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "Playwright package that automatically installs WebKit",
"repository": {
"type": "git",
@ -27,6 +27,6 @@
"install": "node install.js"
},
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
}

View file

@ -1,6 +1,6 @@
{
"name": "playwright-chromium",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "A high-level API to automate Chromium",
"repository": {
"type": "git",
@ -30,6 +30,6 @@
"install": "node install.js"
},
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
}

View file

@ -1,6 +1,6 @@
{
"name": "playwright-core",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "A high-level API to automate web browsers",
"repository": {
"type": "git",

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/experimental-ct-core",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "Playwright Component Testing Helpers",
"repository": {
"type": "git",
@ -27,9 +27,9 @@
}
},
"dependencies": {
"playwright-core": "1.39.0-next",
"playwright-core": "1.39.0",
"vite": "^4.4.10",
"playwright": "1.39.0-next"
"playwright": "1.39.0"
},
"bin": {
"playwright": "cli.js"

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/experimental-ct-react",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "Playwright Component Testing for React",
"repository": {
"type": "git",
@ -29,7 +29,7 @@
}
},
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-react": "^4.0.0"
},
"bin": {

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/experimental-ct-react17",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "Playwright Component Testing for React",
"repository": {
"type": "git",
@ -29,7 +29,7 @@
}
},
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-react": "^4.0.0"
},
"bin": {

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/experimental-ct-solid",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "Playwright Component Testing for Solid",
"repository": {
"type": "git",
@ -29,7 +29,7 @@
}
},
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"vite-plugin-solid": "^2.7.0"
},
"devDependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/experimental-ct-svelte",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "Playwright Component Testing for Svelte",
"repository": {
"type": "git",
@ -29,7 +29,7 @@
}
},
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@sveltejs/vite-plugin-svelte": "^2.1.1"
},
"devDependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/experimental-ct-vue",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "Playwright Component Testing for Vue",
"repository": {
"type": "git",
@ -29,7 +29,7 @@
}
},
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-vue": "^4.2.1"
},
"bin": {

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/experimental-ct-vue2",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "Playwright Component Testing for Vue2",
"repository": {
"type": "git",
@ -29,7 +29,7 @@
}
},
"dependencies": {
"@playwright/experimental-ct-core": "1.39.0-next",
"@playwright/experimental-ct-core": "1.39.0",
"@vitejs/plugin-vue2": "^2.2.0"
},
"devDependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "playwright-firefox",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "A high-level API to automate Firefox",
"repository": {
"type": "git",
@ -30,6 +30,6 @@
"install": "node install.js"
},
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
}

View file

@ -1,6 +1,6 @@
{
"name": "@playwright/test",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "A high-level API to automate web browsers",
"repository": {
"type": "git",
@ -30,6 +30,6 @@
},
"scripts": {},
"dependencies": {
"playwright": "1.39.0-next"
"playwright": "1.39.0"
}
}

View file

@ -1,6 +1,6 @@
{
"name": "playwright-webkit",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "A high-level API to automate WebKit",
"repository": {
"type": "git",
@ -30,6 +30,6 @@
"install": "node install.js"
},
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
}
}

View file

@ -1,6 +1,6 @@
{
"name": "playwright",
"version": "1.39.0-next",
"version": "1.39.0",
"description": "A high-level API to automate web browsers",
"repository": {
"type": "git",
@ -54,7 +54,7 @@
},
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.39.0-next"
"playwright-core": "1.39.0"
},
"optionalDependencies": {
"fsevents": "2.3.2"

View file

@ -230,7 +230,7 @@ export class TestTypeImpl {
private _extend(location: Location, fixtures: Fixtures) {
if ((fixtures as any)[testTypeSymbol])
throw new Error(`test.extend() accepts fixtures object, not a test object.\nDid you mean to call composedTest()?`);
throw new Error(`test.extend() accepts fixtures object, not a test object.\nDid you mean to call mergeTests()?`);
const fixturesWithLocation: FixturesWithLocation = { fixtures, location };
return new TestTypeImpl([...this.fixtures, fixturesWithLocation]).test;
}
@ -249,12 +249,12 @@ function throwIfRunningInsideJest() {
export const rootTestType = new TestTypeImpl([]);
export function composedTest(...tests: TestType<any, any>[]) {
export function mergeTests(...tests: TestType<any, any>[]) {
let result = rootTestType;
for (const t of tests) {
const testTypeImpl = (t as any)[testTypeSymbol] as TestTypeImpl;
if (!testTypeImpl)
throw new Error(`composedTest() accepts "test" functions as parameters.\nDid you mean to call test.extend() with fixtures instead?`);
throw new Error(`mergeTests() accepts "test" functions as parameters.\nDid you mean to call test.extend() with fixtures instead?`);
// Filter out common ancestor fixtures.
const newFixtures = testTypeImpl.fixtures.filter(theirs => !result.fixtures.find(ours => ours.fixtures === theirs.fixtures));
result = new TestTypeImpl([...result.fixtures, ...newFixtures]);

View file

@ -744,7 +744,7 @@ function renderApiCall(apiName: string, params: any) {
export const test = _baseTest.extend<TestFixtures, WorkerFixtures>(playwrightFixtures);
export { defineConfig } from './common/configLoader';
export { composedTest } from './common/testType';
export { composedExpect } from './matchers/expect';
export { mergeTests } from './common/testType';
export { mergeExpects } from './matchers/expect';
export default test;

View file

@ -338,6 +338,6 @@ function computeArgsSuffix(matcherName: string, args: any[]) {
expectLibrary.extend(customMatchers);
export function composedExpect(...expects: any[]) {
export function mergeExpects(...expects: any[]) {
return expect;
}

View file

@ -28,4 +28,6 @@ export const _android = playwright._android;
export const test = playwright.test;
export const expect = playwright.expect;
export const defineConfig = playwright.defineConfig;
export const mergeTests = playwright.mergeTests;
export const mergeExpects = playwright.mergeExpects;
export default playwright.test;

View file

@ -5328,7 +5328,7 @@ type MergedTestType<List> = TestType<MergedT<List>, MergedW<List>>;
/**
* Merges fixtures
*/
export function composedTest<List extends any[]>(...tests: List): MergedTestType<List>;
export function mergeTests<List extends any[]>(...tests: List): MergedTestType<List>;
type MergedExpectMatchers<List> = List extends [Expect<infer M>, ...(infer Rest)] ? M & MergedExpectMatchers<Rest> : {};
type MergedExpect<List> = Expect<MergedExpectMatchers<List>>;
@ -5336,7 +5336,7 @@ type MergedExpect<List> = Expect<MergedExpectMatchers<List>>;
/**
* Merges expects
*/
export function composedExpect<List extends any[]>(...expects: List): MergedExpect<List>;
export function mergeExpects<List extends any[]>(...expects: List): MergedExpect<List>;
// This is required to not export everything by default. See https://github.com/Microsoft/TypeScript/issues/19545#issuecomment-340490459
export {};

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { composedTest } from '@playwright/test';
import { mergeTests } from '@playwright/test';
import { test } from '@playwright/test';
import type { CommonFixtures, CommonWorkerFixtures } from './commonFixtures';
import { commonFixtures } from './commonFixtures';
@ -26,7 +26,7 @@ import { testModeTest } from './testModeFixtures';
export const base = test;
export const baseTest = composedTest(base, coverageTest, platformTest, testModeTest)
export const baseTest = mergeTests(base, coverageTest, platformTest, testModeTest)
.extend<CommonFixtures, CommonWorkerFixtures>(commonFixtures)
.extend<ServerFixtures, ServerWorkerOptions>(serverFixtures);

View file

@ -1,9 +1,9 @@
import { test as test1, expect as expect1, composedTest, composedExpect } from '@playwright/test';
import { test as test1, expect as expect1, mergeTests, mergeExpects } from '@playwright/test';
import type { Page } from '@playwright/test';
import { test as test2, expect as expect2 } from 'playwright-test-plugin';
const test = composedTest(test1, test2);
const expect = composedExpect(expect1, expect2);
const test = mergeTests(test1, test2);
const expect = mergeExpects(expect1, expect2);
test('sample test', async ({ page, plugin }) => {
type IsPage = (typeof page) extends Page ? true : never;

View file

@ -1,8 +1,8 @@
import { test as test1, expect as expect1, composedTest, composedExpect } from '@playwright/test';
import { test as test1, expect as expect1, mergeTests, mergeExpects } from '@playwright/test';
import { test as test2, expect as expect2 } from 'playwright-test-plugin';
const test = composedTest(test1, test2);
const expect = composedExpect(expect1, expect2);
const test = mergeTests(test1, test2);
const expect = mergeExpects(expect1, expect2);
test('sample test', async ({ page, plugin }) => {
await page.setContent(`<div>hello</div><span>world</span>`);

View file

@ -632,3 +632,43 @@ test('should be able to use use execSync with a Node.js file inside a spec', asy
'fork: hello from hellofork.js',
]);
});
test('should be able to use mergeTests/mergeExpect', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.test.mjs': `
import { test as base, expect as baseExpect, mergeTests, mergeExpects } from '@playwright/test';
const test = mergeTests(
base.extend({
myFixture1: '1',
}),
base.extend({
myFixture2: '2',
}),
);
const expect = mergeExpects(
baseExpect.extend({
async toBeFoo1(page, x) {
return { pass: true, message: () => '' };
}
}),
baseExpect.extend({
async toBeFoo2(page, x) {
return { pass: true, message: () => '' };
}
}),
);
test('merged', async ({ myFixture1, myFixture2 }) => {
console.log('%%myFixture1: ' + myFixture1);
console.log('%%myFixture2: ' + myFixture2);
await expect(1).toBeFoo1();
await expect(1).toBeFoo2();
});
`,
});
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1);
expect(result.outputLines).toContain('myFixture1: 1');
expect(result.outputLines).toContain('myFixture2: 2');
});

View file

@ -879,10 +879,10 @@ test('should suppport toHaveAttribute without optional value', async ({ runTSC }
expect(result.exitCode).toBe(0);
});
test('should support composedExpect (TSC)', async ({ runTSC }) => {
test('should support mergeExpects (TSC)', async ({ runTSC }) => {
const result = await runTSC({
'a.spec.ts': `
import { test, composedExpect, expect as baseExpect } from '@playwright/test';
import { test, mergeExpects, expect as baseExpect } from '@playwright/test';
import type { Page } from '@playwright/test';
const expect1 = baseExpect.extend({
@ -897,7 +897,7 @@ test('should support composedExpect (TSC)', async ({ runTSC }) => {
}
});
const expect = composedExpect(expect1, expect2);
const expect = mergeExpects(expect1, expect2);
test('custom matchers', async ({ page }) => {
await expect(page).toBeAGoodPage(123);
@ -914,10 +914,10 @@ test('should support composedExpect (TSC)', async ({ runTSC }) => {
expect(result.exitCode).toBe(0);
});
test('should support composedExpect', async ({ runInlineTest }) => {
test('should support mergeExpects', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.spec.ts': `
import { test, composedExpect, expect as baseExpect } from '@playwright/test';
import { test, mergeExpects, expect as baseExpect } from '@playwright/test';
import type { Page } from '@playwright/test';
const expect1 = baseExpect.extend({
@ -932,7 +932,7 @@ test('should support composedExpect', async ({ runInlineTest }) => {
}
});
const expect = composedExpect(expect1, expect2);
const expect = mergeExpects(expect1, expect2);
test('custom matchers', async ({ page }) => {
await expect(page).toBeAGoodPage(123);

View file

@ -160,7 +160,7 @@ test('config should override options but not fixtures', async ({ runInlineTest }
expect(result.output).toContain('fixture-config-fixture');
});
test('composedTest should be able to merge', async ({ runInlineTest }) => {
test('mergeTests should be able to merge', async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = {
@ -168,7 +168,7 @@ test('composedTest should be able to merge', async ({ runInlineTest }) => {
};
`,
'a.test.ts': `
import { test, expect, composedTest } from '@playwright/test';
import { test, expect, mergeTests } from '@playwright/test';
const base = test.extend({
myFixture: 'abc',
});
@ -184,7 +184,7 @@ test('composedTest should be able to merge', async ({ runInlineTest }) => {
fixture2: ({}, use) => use('fixture2'),
});
const test3 = composedTest(test1, test2);
const test3 = mergeTests(test1, test2);
test3('merged', async ({ param, fixture1, myFixture, fixture2 }) => {
console.log('param-' + param);
@ -202,7 +202,7 @@ test('composedTest should be able to merge', async ({ runInlineTest }) => {
expect(result.output).toContain('fixture2-fixture2');
});
test('test.extend should print nice message when used as composedTest', async ({ runInlineTest }) => {
test('test.extend should print nice message when used as mergeTests', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.test.ts': `
import { test as base, expect } from '@playwright/test';
@ -215,14 +215,14 @@ test('test.extend should print nice message when used as composedTest', async ({
});
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(0);
expect(result.output).toContain('Did you mean to call composedTest()?');
expect(result.output).toContain('Did you mean to call mergeTests()?');
});
test('composedTest should print nice message when used as extend', async ({ runInlineTest }) => {
test('mergeTests should print nice message when used as extend', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.test.ts': `
import { test as base, expect, composedTest } from '@playwright/test';
const test3 = composedTest(base, {});
import { test as base, expect, mergeTests } from '@playwright/test';
const test3 = mergeTests(base, {});
test3('test', () => {});
`,
});

View file

@ -84,7 +84,7 @@ test('can return anything from hooks', async ({ runTSC }) => {
test('test.extend options should check types', async ({ runTSC }) => {
const result = await runTSC({
'helper.ts': `
import { test as base, expect, composedTest } from '@playwright/test';
import { test as base, expect, mergeTests } from '@playwright/test';
export type Params = { foo: string };
export const test = base;
export const test1 = test.extend<Params>({ foo: [ 'foo', { option: true } ] });
@ -100,7 +100,7 @@ test('test.extend options should check types', async ({ runTSC }) => {
// @ts-expect-error
bar: async ({ baz }, run) => { await run(42); }
});
export const test4 = composedTest(test1, testW);
export const test4 = mergeTests(test1, testW);
const test5 = test4.extend<{}, { hey: string, hey2: string }>({
// @ts-expect-error
hey: [async ({ foo }, use) => {

View file

@ -462,7 +462,7 @@ type MergedTestType<List> = TestType<MergedT<List>, MergedW<List>>;
/**
* Merges fixtures
*/
export function composedTest<List extends any[]>(...tests: List): MergedTestType<List>;
export function mergeTests<List extends any[]>(...tests: List): MergedTestType<List>;
type MergedExpectMatchers<List> = List extends [Expect<infer M>, ...(infer Rest)] ? M & MergedExpectMatchers<Rest> : {};
type MergedExpect<List> = Expect<MergedExpectMatchers<List>>;
@ -470,7 +470,7 @@ type MergedExpect<List> = Expect<MergedExpectMatchers<List>>;
/**
* Merges expects
*/
export function composedExpect<List extends any[]>(...expects: List): MergedExpect<List>;
export function mergeExpects<List extends any[]>(...expects: List): MergedExpect<List>;
// This is required to not export everything by default. See https://github.com/Microsoft/TypeScript/issues/19545#issuecomment-340490459
export {};