From d22dd4a4e7a5baeaf6be28a78a5f164d6f44dce5 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Fri, 24 Sep 2021 19:59:30 -0700 Subject: [PATCH] feat(test runner): improve fixture typings for function fixtures (#9138) When fixture value `R` is a function, TypeScript sometimes confuses function `R` and function `async ({}, use) => {}`. This leads to `any` types in the latter because it could be either of the functions as TS thinks. The solution is to only accept the second syntax, assuming that noone passes fixture value that is a function as is: ```js // This will stop working. test.extend<{ foo: (x: number) => number }>({ foo: x => 2 * x, }); // This will get inferred types and autocomplete. test.extend<{ foo: (x: number) => number }>({ foo: async ({}, use) => { await use(x => 2 * x); }, }); ``` --- tests/playwright-test/types.spec.ts | 12 ++++++++++++ types/test.d.ts | 4 ++-- utils/generate_types/overrides-test.d.ts | 4 ++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/playwright-test/types.spec.ts b/tests/playwright-test/types.spec.ts index 234eb9b23b..91329580c4 100644 --- a/tests/playwright-test/types.spec.ts +++ b/tests/playwright-test/types.spec.ts @@ -82,6 +82,18 @@ test('should check types of fixtures', async ({runTSC}) => { // @ts-expect-error }, { scope: 'test' } ], }); + + type AssertNotAny = {notRealProperty: number} extends S ? false : true; + type AssertType = S extends T ? AssertNotAny : false; + const funcTest = pwt.test.extend<{ foo: (x: number, y: string) => Promise }>({ + foo: async ({}, use) => { + await use(async (x, y) => { + const assertionX: AssertType = true; + const assertionY: AssertType = true; + return y; + }); + }, + }) `, 'playwright.config.ts': ` import { MyOptions } from './helper'; diff --git a/types/test.d.ts b/types/test.d.ts index 8375c4f8e3..708087b0d4 100644 --- a/types/test.d.ts +++ b/types/test.d.ts @@ -2282,8 +2282,8 @@ export interface TestType = (args: Args, use: (r: R) => Promise, testInfo: TestInfo) => any; export type WorkerFixture = (args: Args, use: (r: R) => Promise, workerInfo: WorkerInfo) => any; -type TestFixtureValue = R | TestFixture; -type WorkerFixtureValue = R | WorkerFixture; +type TestFixtureValue = Exclude | TestFixture; +type WorkerFixtureValue = Exclude | WorkerFixture; export type Fixtures = { [K in keyof PW]?: WorkerFixtureValue | [WorkerFixtureValue, { scope: 'worker' }]; } & { diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index 0dc3004bd1..48f9c0074c 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -265,8 +265,8 @@ export interface TestType = (args: Args, use: (r: R) => Promise, testInfo: TestInfo) => any; export type WorkerFixture = (args: Args, use: (r: R) => Promise, workerInfo: WorkerInfo) => any; -type TestFixtureValue = R | TestFixture; -type WorkerFixtureValue = R | WorkerFixture; +type TestFixtureValue = Exclude | TestFixture; +type WorkerFixtureValue = Exclude | WorkerFixture; export type Fixtures = { [K in keyof PW]?: WorkerFixtureValue | [WorkerFixtureValue, { scope: 'worker' }]; } & {