Skip to content

Commit 3049d99

Browse files
committed
cherry-pick(#27555): chore: composed->merge
1 parent ae31f58 commit 3049d99

File tree

13 files changed

+71
-49
lines changed

13 files changed

+71
-49
lines changed

docs/src/release-notes-js.md

+34-12
Original file line numberDiff line numberDiff line change
@@ -8,46 +8,68 @@ import LiteYouTube from '@site/src/components/LiteYouTube';
88

99
## Version 1.39
1010

11-
### Extending expect with custom matchers
11+
### Add custom matchers to your expect
1212

1313
You can extend Playwright assertions by providing custom matchers. These matchers will be available on the expect object.
1414

15-
```js title=fixtures.ts
15+
```js title="test.spec.ts"
1616
import { expect as baseExpect } from '@playwright/test';
1717
export const expect = baseExpect.extend({
1818
async toHaveAmount(locator: Locator, expected: number, options?: { timeout?: number }) {
19-
// Note: this matcher never passes, see the documentation for a full example.
20-
// Return a "pass" flag and a message getter.
21-
return { pass: false, message: () => `Expected ${expected} amount` };
19+
// ... see documentation for how to write matchers.
2220
},
2321
});
22+
23+
test('pass', async ({ page }) => {
24+
await expect(page.getByTestId('cart')).toHaveAmount(5);
25+
});
2426
```
2527

2628
See the documentation [for a full example](./test-configuration.md#add-custom-matchers-using-expectextend).
2729

28-
### Merging fixtures and expect matchers
30+
### Merge test fixtures
31+
32+
You can now merge test fixtures from multiple files or modules:
33+
34+
```js title="fixtures.ts"
35+
import { mergeTests } from '@playwright/test';
36+
import { test as dbTest } from 'database-test-utils';
37+
import { test as a11yTest } from 'a11y-test-utils';
38+
39+
export const test = mergeTests(dbTest, a11yTest);
40+
```
41+
42+
```js title="test.spec.ts"
43+
import { test } from './fixtures';
44+
45+
test('passes', async ({ database, page, a11y }) => {
46+
// use database and a11y fixtures.
47+
});
48+
```
49+
50+
### Merge custom expect matchers
2951

30-
You can combine fixtures and custom expect matchers from multiple files or modules.
52+
You can now merge custom expect matchers from multiple files or modules:
3153

3254
```js title="fixtures.ts"
33-
import { composedTest, composedExpect } from '@playwright/test';
55+
import { mergeTests, mergeExpects } from '@playwright/test';
3456
import { test as dbTest, expect as dbExpect } from 'database-test-utils';
3557
import { test as a11yTest, expect as a11yExpect } from 'a11y-test-utils';
3658

37-
export const expect = composedExpect(dbExpect, a11yExpect);
38-
export const test = composedTest(dbTest, a11yTest);
59+
export const test = mergeTests(dbTest, a11yTest);
60+
export const expect = mergeExpects(dbExpect, a11yExpect);
3961
```
4062

4163
```js title="test.spec.ts"
4264
import { test, expect } from './fixtures';
4365

44-
test('passes', async ({ database, page }) => {
66+
test('passes', async ({ page, database }) => {
4567
await expect(database).toHaveDatabaseUser('admin');
4668
await expect(page).toPassA11yAudit();
4769
});
4870
```
4971

50-
### Boxed test steps
72+
### Hide implementation details: box test steps
5173

5274
You can mark a [`method: Test.step`] as "boxed" so that errors inside it point to the step call site.
5375

docs/src/test-configuration-js.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,12 @@ Do not confuse Playwright's `expect` with the [`expect` library](https://jestjs.
217217
You can combine custom matchers from multiple files or modules.
218218
219219
```js title="fixtures.ts"
220-
import { composedTest, composedExpect } from '@playwright/test';
220+
import { mergeTests, mergeExpects } from '@playwright/test';
221221
import { test as dbTest, expect as dbExpect } from 'database-test-utils';
222222
import { test as a11yTest, expect as a11yExpect } from 'a11y-test-utils';
223223

224-
export const expect = composedExpect(dbExpect, a11yExpect);
225-
export const test = composedTest(dbTest, a11yTest);
224+
export const expect = mergeExpects(dbExpect, a11yExpect);
225+
export const test = mergeTests(dbTest, a11yTest);
226226
```
227227
228228
```js title="test.spec.ts"

packages/playwright/src/common/testType.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ export class TestTypeImpl {
230230

231231
private _extend(location: Location, fixtures: Fixtures) {
232232
if ((fixtures as any)[testTypeSymbol])
233-
throw new Error(`test.extend() accepts fixtures object, not a test object.\nDid you mean to call composedTest()?`);
233+
throw new Error(`test.extend() accepts fixtures object, not a test object.\nDid you mean to call mergeTests()?`);
234234
const fixturesWithLocation: FixturesWithLocation = { fixtures, location };
235235
return new TestTypeImpl([...this.fixtures, fixturesWithLocation]).test;
236236
}
@@ -249,12 +249,12 @@ function throwIfRunningInsideJest() {
249249

250250
export const rootTestType = new TestTypeImpl([]);
251251

252-
export function composedTest(...tests: TestType<any, any>[]) {
252+
export function mergeTests(...tests: TestType<any, any>[]) {
253253
let result = rootTestType;
254254
for (const t of tests) {
255255
const testTypeImpl = (t as any)[testTypeSymbol] as TestTypeImpl;
256256
if (!testTypeImpl)
257-
throw new Error(`composedTest() accepts "test" functions as parameters.\nDid you mean to call test.extend() with fixtures instead?`);
257+
throw new Error(`mergeTests() accepts "test" functions as parameters.\nDid you mean to call test.extend() with fixtures instead?`);
258258
// Filter out common ancestor fixtures.
259259
const newFixtures = testTypeImpl.fixtures.filter(theirs => !result.fixtures.find(ours => ours.fixtures === theirs.fixtures));
260260
result = new TestTypeImpl([...result.fixtures, ...newFixtures]);

packages/playwright/src/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ function renderApiCall(apiName: string, params: any) {
744744
export const test = _baseTest.extend<TestFixtures, WorkerFixtures>(playwrightFixtures);
745745

746746
export { defineConfig } from './common/configLoader';
747-
export { composedTest } from './common/testType';
748-
export { composedExpect } from './matchers/expect';
747+
export { mergeTests } from './common/testType';
748+
export { mergeExpects } from './matchers/expect';
749749

750750
export default test;

packages/playwright/src/matchers/expect.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,6 @@ function computeArgsSuffix(matcherName: string, args: any[]) {
338338

339339
expectLibrary.extend(customMatchers);
340340

341-
export function composedExpect(...expects: any[]) {
341+
export function mergeExpects(...expects: any[]) {
342342
return expect;
343343
}

packages/playwright/types/test.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5328,15 +5328,15 @@ type MergedTestType<List> = TestType<MergedT<List>, MergedW<List>>;
53285328
/**
53295329
* Merges fixtures
53305330
*/
5331-
export function composedTest<List extends any[]>(...tests: List): MergedTestType<List>;
5331+
export function mergeTests<List extends any[]>(...tests: List): MergedTestType<List>;
53325332

53335333
type MergedExpectMatchers<List> = List extends [Expect<infer M>, ...(infer Rest)] ? M & MergedExpectMatchers<Rest> : {};
53345334
type MergedExpect<List> = Expect<MergedExpectMatchers<List>>;
53355335

53365336
/**
53375337
* Merges expects
53385338
*/
5339-
export function composedExpect<List extends any[]>(...expects: List): MergedExpect<List>;
5339+
export function mergeExpects<List extends any[]>(...expects: List): MergedExpect<List>;
53405340

53415341
// This is required to not export everything by default. See https://github.com/Microsoft/TypeScript/issues/19545#issuecomment-340490459
53425342
export {};

tests/config/baseTest.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { composedTest } from '@playwright/test';
17+
import { mergeTests } from '@playwright/test';
1818
import { test } from '@playwright/test';
1919
import type { CommonFixtures, CommonWorkerFixtures } from './commonFixtures';
2020
import { commonFixtures } from './commonFixtures';
@@ -26,7 +26,7 @@ import { testModeTest } from './testModeFixtures';
2626

2727
export const base = test;
2828

29-
export const baseTest = composedTest(base, coverageTest, platformTest, testModeTest)
29+
export const baseTest = mergeTests(base, coverageTest, platformTest, testModeTest)
3030
.extend<CommonFixtures, CommonWorkerFixtures>(commonFixtures)
3131
.extend<ServerFixtures, ServerWorkerOptions>(serverFixtures);
3232

tests/installation/fixture-scripts/playwright-test-plugin-types.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { test as test1, expect as expect1, composedTest, composedExpect } from '@playwright/test';
1+
import { test as test1, expect as expect1, mergeTests, mergeExpects } from '@playwright/test';
22
import type { Page } from '@playwright/test';
33
import { test as test2, expect as expect2 } from 'playwright-test-plugin';
44

5-
const test = composedTest(test1, test2);
6-
const expect = composedExpect(expect1, expect2);
5+
const test = mergeTests(test1, test2);
6+
const expect = mergeExpects(expect1, expect2);
77

88
test('sample test', async ({ page, plugin }) => {
99
type IsPage = (typeof page) extends Page ? true : never;

tests/installation/fixture-scripts/plugin.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { test as test1, expect as expect1, composedTest, composedExpect } from '@playwright/test';
1+
import { test as test1, expect as expect1, mergeTests, mergeExpects } from '@playwright/test';
22
import { test as test2, expect as expect2 } from 'playwright-test-plugin';
33

4-
const test = composedTest(test1, test2);
5-
const expect = composedExpect(expect1, expect2);
4+
const test = mergeTests(test1, test2);
5+
const expect = mergeExpects(expect1, expect2);
66

77
test('sample test', async ({ page, plugin }) => {
88
await page.setContent(`<div>hello</div><span>world</span>`);

tests/playwright-test/expect.spec.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -879,10 +879,10 @@ test('should suppport toHaveAttribute without optional value', async ({ runTSC }
879879
expect(result.exitCode).toBe(0);
880880
});
881881

882-
test('should support composedExpect (TSC)', async ({ runTSC }) => {
882+
test('should support mergeExpects (TSC)', async ({ runTSC }) => {
883883
const result = await runTSC({
884884
'a.spec.ts': `
885-
import { test, composedExpect, expect as baseExpect } from '@playwright/test';
885+
import { test, mergeExpects, expect as baseExpect } from '@playwright/test';
886886
import type { Page } from '@playwright/test';
887887
888888
const expect1 = baseExpect.extend({
@@ -897,7 +897,7 @@ test('should support composedExpect (TSC)', async ({ runTSC }) => {
897897
}
898898
});
899899
900-
const expect = composedExpect(expect1, expect2);
900+
const expect = mergeExpects(expect1, expect2);
901901
902902
test('custom matchers', async ({ page }) => {
903903
await expect(page).toBeAGoodPage(123);
@@ -914,10 +914,10 @@ test('should support composedExpect (TSC)', async ({ runTSC }) => {
914914
expect(result.exitCode).toBe(0);
915915
});
916916

917-
test('should support composedExpect', async ({ runInlineTest }) => {
917+
test('should support mergeExpects', async ({ runInlineTest }) => {
918918
const result = await runInlineTest({
919919
'a.spec.ts': `
920-
import { test, composedExpect, expect as baseExpect } from '@playwright/test';
920+
import { test, mergeExpects, expect as baseExpect } from '@playwright/test';
921921
import type { Page } from '@playwright/test';
922922
923923
const expect1 = baseExpect.extend({
@@ -932,7 +932,7 @@ test('should support composedExpect', async ({ runInlineTest }) => {
932932
}
933933
});
934934
935-
const expect = composedExpect(expect1, expect2);
935+
const expect = mergeExpects(expect1, expect2);
936936
937937
test('custom matchers', async ({ page }) => {
938938
await expect(page).toBeAGoodPage(123);

tests/playwright-test/test-extend.spec.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,15 @@ test('config should override options but not fixtures', async ({ runInlineTest }
160160
expect(result.output).toContain('fixture-config-fixture');
161161
});
162162

163-
test('composedTest should be able to merge', async ({ runInlineTest }) => {
163+
test('mergeTests should be able to merge', async ({ runInlineTest }) => {
164164
const result = await runInlineTest({
165165
'playwright.config.ts': `
166166
module.exports = {
167167
use: { param: 'from-config' },
168168
};
169169
`,
170170
'a.test.ts': `
171-
import { test, expect, composedTest } from '@playwright/test';
171+
import { test, expect, mergeTests } from '@playwright/test';
172172
const base = test.extend({
173173
myFixture: 'abc',
174174
});
@@ -184,7 +184,7 @@ test('composedTest should be able to merge', async ({ runInlineTest }) => {
184184
fixture2: ({}, use) => use('fixture2'),
185185
});
186186
187-
const test3 = composedTest(test1, test2);
187+
const test3 = mergeTests(test1, test2);
188188
189189
test3('merged', async ({ param, fixture1, myFixture, fixture2 }) => {
190190
console.log('param-' + param);
@@ -202,7 +202,7 @@ test('composedTest should be able to merge', async ({ runInlineTest }) => {
202202
expect(result.output).toContain('fixture2-fixture2');
203203
});
204204

205-
test('test.extend should print nice message when used as composedTest', async ({ runInlineTest }) => {
205+
test('test.extend should print nice message when used as mergeTests', async ({ runInlineTest }) => {
206206
const result = await runInlineTest({
207207
'a.test.ts': `
208208
import { test as base, expect } from '@playwright/test';
@@ -215,14 +215,14 @@ test('test.extend should print nice message when used as composedTest', async ({
215215
});
216216
expect(result.exitCode).toBe(1);
217217
expect(result.passed).toBe(0);
218-
expect(result.output).toContain('Did you mean to call composedTest()?');
218+
expect(result.output).toContain('Did you mean to call mergeTests()?');
219219
});
220220

221-
test('composedTest should print nice message when used as extend', async ({ runInlineTest }) => {
221+
test('mergeTests should print nice message when used as extend', async ({ runInlineTest }) => {
222222
const result = await runInlineTest({
223223
'a.test.ts': `
224-
import { test as base, expect, composedTest } from '@playwright/test';
225-
const test3 = composedTest(base, {});
224+
import { test as base, expect, mergeTests } from '@playwright/test';
225+
const test3 = mergeTests(base, {});
226226
test3('test', () => {});
227227
`,
228228
});

tests/playwright-test/types-2.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ test('can return anything from hooks', async ({ runTSC }) => {
8484
test('test.extend options should check types', async ({ runTSC }) => {
8585
const result = await runTSC({
8686
'helper.ts': `
87-
import { test as base, expect, composedTest } from '@playwright/test';
87+
import { test as base, expect, mergeTests } from '@playwright/test';
8888
export type Params = { foo: string };
8989
export const test = base;
9090
export const test1 = test.extend<Params>({ foo: [ 'foo', { option: true } ] });
@@ -100,7 +100,7 @@ test('test.extend options should check types', async ({ runTSC }) => {
100100
// @ts-expect-error
101101
bar: async ({ baz }, run) => { await run(42); }
102102
});
103-
export const test4 = composedTest(test1, testW);
103+
export const test4 = mergeTests(test1, testW);
104104
const test5 = test4.extend<{}, { hey: string, hey2: string }>({
105105
// @ts-expect-error
106106
hey: [async ({ foo }, use) => {

utils/generate_types/overrides-test.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -462,15 +462,15 @@ type MergedTestType<List> = TestType<MergedT<List>, MergedW<List>>;
462462
/**
463463
* Merges fixtures
464464
*/
465-
export function composedTest<List extends any[]>(...tests: List): MergedTestType<List>;
465+
export function mergeTests<List extends any[]>(...tests: List): MergedTestType<List>;
466466

467467
type MergedExpectMatchers<List> = List extends [Expect<infer M>, ...(infer Rest)] ? M & MergedExpectMatchers<Rest> : {};
468468
type MergedExpect<List> = Expect<MergedExpectMatchers<List>>;
469469

470470
/**
471471
* Merges expects
472472
*/
473-
export function composedExpect<List extends any[]>(...expects: List): MergedExpect<List>;
473+
export function mergeExpects<List extends any[]>(...expects: List): MergedExpect<List>;
474474

475475
// This is required to not export everything by default. See https://github.com/Microsoft/TypeScript/issues/19545#issuecomment-340490459
476476
export {};

0 commit comments

Comments
 (0)