From 0ab4a345d0302647ece2f5409fdd7b7a50ee306c Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Fri, 24 Sep 2021 12:51:40 -0700 Subject: [PATCH] feat(test runner): improve fixture typings for function fixtures 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 234eb9b23b764..91329580c4e65 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 8375c4f8e3077..708087b0d48a8 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 0dc3004bd10d0..48f9c0074c2d7 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' }]; } & {