From 8ad47b3b17126b897c7027663bd05dd4288a7ead Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Thu, 10 Oct 2024 01:45:59 +0100 Subject: [PATCH] chore: add generic overloaded toMatchObject Refs: #32986 --- packages/playwright/types/test.d.ts | 30 ++++++++++++++++++++ tests/playwright-test/types.spec.ts | 36 ++++++++++++++++++++++++ utils/generate_types/overrides-test.d.ts | 5 ++++ 3 files changed, 71 insertions(+) diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index 91fe2f2b5c..2556336b3d 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -31,6 +31,10 @@ export type ReporterDescription = Readonly< [string] | [string, any] >; +type PartialDeep = { + [P in keyof T]?: PartialDeep +} + type UseOptions = Partial & Partial; /** @@ -6423,6 +6427,32 @@ interface GenericAssertions { * @param expected Regular expression to match against. */ toMatch(expected: RegExp | string): R; + /** + * Compares contents of the value with contents of + * [`expected`](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-match-object-option-expected), + * performing "deep equality" check. Allows extra properties to be present in the value, unlike + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal), + * so you can check just a subset of object properties. + * + * When comparing arrays, the number of items must match, and each item is checked recursively. + * + * **Usage** + * + * ```js + * const value = { + * a: 1, + * b: 2, + * c: true, + * }; + * expect(value).toMatchObject({ a: 1, c: true }); + * expect(value).toMatchObject({ b: 2, c: true }); + * + * expect([{ a: 1, b: 2 }]).toMatchObject([{ a: 1 }]); + * ``` + * + * @param expected The expected object value to match against. + */ + toMatchObject>(expected: DeepPartial | Array>): R; /** * Compares contents of the value with contents of * [`expected`](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-match-object-option-expected), diff --git a/tests/playwright-test/types.spec.ts b/tests/playwright-test/types.spec.ts index c34c586f7a..83db925f1d 100644 --- a/tests/playwright-test/types.spec.ts +++ b/tests/playwright-test/types.spec.ts @@ -324,3 +324,39 @@ test('config should allow void/empty options', async ({ runTSC }) => { }); expect(result.exitCode).toBe(0); }); + +test.fixme('should check types of overloaded toMatchObject with generic parameter', async ({ runTSC }) => { + const result = await runTSC({ + 'playwright.config.ts': ` + import { defineConfig } from '@playwright/test'; + + export default defineConfig({ + }); + `, + 'a.spec.ts': ` + import { test, expect } from '@playwright/test'; + test('my test', async () => { + const value = { a: 1, b: 'foo', c: { d: 2, e: 'bar' } }; + + expect.soft(value).toMatchObject({}); + expect.soft(value).toMatchObject({ a: 1 }); + expect.soft(value).toMatchObject({ a: 1, c: { e: 'bar' } }); + expect.soft([value]).toMatchObject([{ a: 1 }]); + expect.soft([value]).toMatchObject([{ a: 1, c: { e: 'bar' } }]); + + // @ts-expect-error + expect.soft(value).toMatchObject({ a: 'a' }); + + // @ts-expect-error + expect.soft(value).toMatchObject({ c: { e: 2 } }); + + // @ts-expect-error + expect.soft([value]).toMatchObject([{ a: 'a' }]); + + // @ts-expect-error + expect.soft([value]).toMatchObject([{ c: { e: 2 } }]); + }); + ` + }); + expect(result.exitCode).toBe(0); +}); diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index be1fa7ee37..772c704494 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -30,6 +30,10 @@ export type ReporterDescription = Readonly< [string] | [string, any] >; +type DeepPartial = { + [P in keyof T]?: DeepPartial +} + type UseOptions = Partial & Partial; interface TestProject { @@ -289,6 +293,7 @@ interface GenericAssertions { toHaveLength(expected: number): R; toHaveProperty(keyPath: string | Array, value?: unknown): R; toMatch(expected: RegExp | string): R; + toMatchObject>(expected: DeepPartial | Array>): R; toMatchObject(expected: Record | Array): R; toStrictEqual(expected: unknown): R; toThrow(error?: unknown): R;