Skip to content

Commit

Permalink
fix(types): update types for test.extend (#33784)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgozman authored Dec 9, 2024
1 parent dfa2446 commit 0937d2f
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 20 deletions.
19 changes: 9 additions & 10 deletions packages/playwright/types/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1891,7 +1891,7 @@ type ConditionBody<TestArgs> = (args: TestArgs) => boolean;
* ```
*
*/
export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue> {
export interface TestType<TestArgs extends {}, WorkerArgs extends {}> {
/**
* Declares a test.
* - `test(title, body)`
Expand Down Expand Up @@ -5632,7 +5632,7 @@ export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue
* Learn more about [fixtures](https://playwright.dev/docs/test-fixtures) and [parametrizing tests](https://playwright.dev/docs/test-parameterize).
* @param fixtures An object containing fixtures and/or options. Learn more about [fixtures format](https://playwright.dev/docs/test-fixtures).
*/
extend<T extends KeyValue, W extends KeyValue = {}>(fixtures: Fixtures<T, W, TestArgs, WorkerArgs>): TestType<TestArgs & T, WorkerArgs & W>;
extend<T extends {}, W extends {} = {}>(fixtures: Fixtures<T, W, TestArgs, WorkerArgs>): TestType<TestArgs & T, WorkerArgs & W>;
/**
* Returns information about the currently running test. This method can only be called during the test execution,
* otherwise it throws.
Expand All @@ -5653,19 +5653,18 @@ export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue
info(): TestInfo;
}

type KeyValue = { [key: string]: any };
export type TestFixture<R, Args extends KeyValue> = (args: Args, use: (r: R) => Promise<void>, testInfo: TestInfo) => any;
export type WorkerFixture<R, Args extends KeyValue> = (args: Args, use: (r: R) => Promise<void>, workerInfo: WorkerInfo) => any;
type TestFixtureValue<R, Args extends KeyValue> = Exclude<R, Function> | TestFixture<R, Args>;
type WorkerFixtureValue<R, Args extends KeyValue> = Exclude<R, Function> | WorkerFixture<R, Args>;
export type Fixtures<T extends KeyValue = {}, W extends KeyValue = {}, PT extends KeyValue = {}, PW extends KeyValue = {}> = {
export type TestFixture<R, Args extends {}> = (args: Args, use: (r: R) => Promise<void>, testInfo: TestInfo) => any;
export type WorkerFixture<R, Args extends {}> = (args: Args, use: (r: R) => Promise<void>, workerInfo: WorkerInfo) => any;
type TestFixtureValue<R, Args extends {}> = Exclude<R, Function> | TestFixture<R, Args>;
type WorkerFixtureValue<R, Args extends {}> = Exclude<R, Function> | WorkerFixture<R, Args>;
export type Fixtures<T extends {} = {}, W extends {} = {}, PT extends {} = {}, PW extends {} = {}> = {
[K in keyof PW]?: WorkerFixtureValue<PW[K], W & PW> | [WorkerFixtureValue<PW[K], W & PW>, { scope: 'worker', timeout?: number | undefined, title?: string, box?: boolean }];
} & {
[K in keyof PT]?: TestFixtureValue<PT[K], T & W & PT & PW> | [TestFixtureValue<PT[K], T & W & PT & PW>, { scope: 'test', timeout?: number | undefined, title?: string, box?: boolean }];
} & {
[K in keyof W]?: [WorkerFixtureValue<W[K], W & PW>, { scope: 'worker', auto?: boolean, option?: boolean, timeout?: number | undefined, title?: string, box?: boolean }];
[K in Exclude<keyof W, keyof PW | keyof PT>]?: [WorkerFixtureValue<W[K], W & PW>, { scope: 'worker', auto?: boolean, option?: boolean, timeout?: number | undefined, title?: string, box?: boolean }];
} & {
[K in keyof T]?: TestFixtureValue<T[K], T & W & PT & PW> | [TestFixtureValue<T[K], T & W & PT & PW>, { scope?: 'test', auto?: boolean, option?: boolean, timeout?: number | undefined, title?: string, box?: boolean }];
[K in Exclude<keyof T, keyof PW | keyof PT>]?: TestFixtureValue<T[K], T & W & PT & PW> | [TestFixtureValue<T[K], T & W & PT & PW>, { scope?: 'test', auto?: boolean, option?: boolean, timeout?: number | undefined, title?: string, box?: boolean }];
};

type BrowserName = 'chromium' | 'firefox' | 'webkit';
Expand Down
1 change: 1 addition & 0 deletions tests/components/ct-react17/tests/render.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ test('render an empty component', async ({ mount, page }) => {
const testWithServer = test.extend(serverFixtures);
testWithServer(
'components routing should go through context',
// @ts-ignore "serverFixtures" are imported from the impl without any types
async ({ mount, context, server }) => {
server.setRoute('/hello', (req: any, res: any) => {
res.write('served via server');
Expand Down
65 changes: 65 additions & 0 deletions tests/playwright-test/types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,71 @@ test('should check types of fixtures', async ({ runTSC }) => {
await use(x);
},
});
base.extend({
page: async ({ page }) => {
type IsPage = (typeof page) extends Page ? true : never;
const isPage: IsPage = true;
},
});
base.extend<{ myFixture: (arg: number) => void }>({
page: async ({ page }) => {
type IsPage = (typeof page) extends Page ? true : never;
const isPage: IsPage = true;
},
});
base.extend({
// @ts-expect-error
myFixture: async ({ page }) => {
type IsPage = (typeof page) extends Page ? true : never;
const isPage: IsPage = true;
}
});
base.extend<{ myFixture: (arg: number) => void }>({
myFixture: async ({ page }) => {
type IsPage = (typeof page) extends Page ? true : never;
const isPage: IsPage = true;
}
});
base.extend({
page: async ({ page }) => {
type IsPage = (typeof page) extends Page ? true : never;
const isPage: IsPage = true;
},
// @ts-expect-error
myFixture: async ({ page }) => {
type IsPage = (typeof page) extends Page ? true : never;
const isPage: IsPage = true;
}
});
base.extend<{ myFixture: (arg: number) => void }>({
page: async ({ page }) => {
type IsPage = (typeof page) extends Page ? true : never;
const isPage: IsPage = true;
},
myFixture: async ({ page }) => {
type IsPage = (typeof page) extends Page ? true : never;
const isPage: IsPage = true;
}
});
base.extend<{ myFixture: (arg: number) => void }>({
// @ts-expect-error
myFixture: (arg: number) => {},
});
base.extend<{ myFixture: (arg: number) => void }>({
myFixture: async (_, use) => {
use((arg: number) => {});
// @ts-expect-error
use((arg: string) => {});
}
});
`,
'playwright.config.ts': `
import { MyOptions } from './helper';
Expand Down
19 changes: 9 additions & 10 deletions utils/generate_types/overrides-test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export type TestDetails = {
type TestBody<TestArgs> = (args: TestArgs, testInfo: TestInfo) => Promise<void> | void;
type ConditionBody<TestArgs> = (args: TestArgs) => boolean;

export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue> {
export interface TestType<TestArgs extends {}, WorkerArgs extends {}> {
(title: string, body: TestBody<TestArgs & WorkerArgs>): void;
(title: string, details: TestDetails, body: TestBody<TestArgs & WorkerArgs>): void;

Expand Down Expand Up @@ -164,23 +164,22 @@ export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue
use(fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs>): void;
step<T>(title: string, body: () => T | Promise<T>, options?: { box?: boolean, location?: Location, timeout?: number }): Promise<T>;
expect: Expect<{}>;
extend<T extends KeyValue, W extends KeyValue = {}>(fixtures: Fixtures<T, W, TestArgs, WorkerArgs>): TestType<TestArgs & T, WorkerArgs & W>;
extend<T extends {}, W extends {} = {}>(fixtures: Fixtures<T, W, TestArgs, WorkerArgs>): TestType<TestArgs & T, WorkerArgs & W>;
info(): TestInfo;
}

type KeyValue = { [key: string]: any };
export type TestFixture<R, Args extends KeyValue> = (args: Args, use: (r: R) => Promise<void>, testInfo: TestInfo) => any;
export type WorkerFixture<R, Args extends KeyValue> = (args: Args, use: (r: R) => Promise<void>, workerInfo: WorkerInfo) => any;
type TestFixtureValue<R, Args extends KeyValue> = Exclude<R, Function> | TestFixture<R, Args>;
type WorkerFixtureValue<R, Args extends KeyValue> = Exclude<R, Function> | WorkerFixture<R, Args>;
export type Fixtures<T extends KeyValue = {}, W extends KeyValue = {}, PT extends KeyValue = {}, PW extends KeyValue = {}> = {
export type TestFixture<R, Args extends {}> = (args: Args, use: (r: R) => Promise<void>, testInfo: TestInfo) => any;
export type WorkerFixture<R, Args extends {}> = (args: Args, use: (r: R) => Promise<void>, workerInfo: WorkerInfo) => any;
type TestFixtureValue<R, Args extends {}> = Exclude<R, Function> | TestFixture<R, Args>;
type WorkerFixtureValue<R, Args extends {}> = Exclude<R, Function> | WorkerFixture<R, Args>;
export type Fixtures<T extends {} = {}, W extends {} = {}, PT extends {} = {}, PW extends {} = {}> = {
[K in keyof PW]?: WorkerFixtureValue<PW[K], W & PW> | [WorkerFixtureValue<PW[K], W & PW>, { scope: 'worker', timeout?: number | undefined, title?: string, box?: boolean }];
} & {
[K in keyof PT]?: TestFixtureValue<PT[K], T & W & PT & PW> | [TestFixtureValue<PT[K], T & W & PT & PW>, { scope: 'test', timeout?: number | undefined, title?: string, box?: boolean }];
} & {
[K in keyof W]?: [WorkerFixtureValue<W[K], W & PW>, { scope: 'worker', auto?: boolean, option?: boolean, timeout?: number | undefined, title?: string, box?: boolean }];
[K in Exclude<keyof W, keyof PW | keyof PT>]?: [WorkerFixtureValue<W[K], W & PW>, { scope: 'worker', auto?: boolean, option?: boolean, timeout?: number | undefined, title?: string, box?: boolean }];
} & {
[K in keyof T]?: TestFixtureValue<T[K], T & W & PT & PW> | [TestFixtureValue<T[K], T & W & PT & PW>, { scope?: 'test', auto?: boolean, option?: boolean, timeout?: number | undefined, title?: string, box?: boolean }];
[K in Exclude<keyof T, keyof PW | keyof PT>]?: TestFixtureValue<T[K], T & W & PT & PW> | [TestFixtureValue<T[K], T & W & PT & PW>, { scope?: 'test', auto?: boolean, option?: boolean, timeout?: number | undefined, title?: string, box?: boolean }];
};

type BrowserName = 'chromium' | 'firefox' | 'webkit';
Expand Down

0 comments on commit 0937d2f

Please sign in to comment.