fix(types): update types for test.extend
- Replace `KeyValue` with `{}` to avoid inferring `KeyValue` when not intended
and turning all properties into `any`.
- Employ `as Exclude<K, keyof PW | keyof PT>` technique to make sure
overridden fixtures inherit from the base test type, and are not looked up
in the extended fixtures list where they are not present.
This should fix errors with TypeScript 5.8.
This commit is contained in:
parent
84df6e3297
commit
c1447eb8c1
19
packages/playwright/types/test.d.ts
vendored
19
packages/playwright/types/test.d.ts
vendored
|
|
@ -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.
|
* Declares a test.
|
||||||
* - `test(title, body)`
|
* - `test(title, body)`
|
||||||
|
|
@ -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).
|
* 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).
|
* @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,
|
* Returns information about the currently running test. This method can only be called during the test execution,
|
||||||
* otherwise it throws.
|
* otherwise it throws.
|
||||||
|
|
@ -5653,19 +5653,18 @@ export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue
|
||||||
info(): TestInfo;
|
info(): TestInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyValue = { [key: string]: any };
|
export type TestFixture<R, Args extends {}> = (args: Args, use: (r: R) => Promise<void>, testInfo: TestInfo) => any;
|
||||||
export type TestFixture<R, Args extends KeyValue> = (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;
|
||||||
export type WorkerFixture<R, Args extends KeyValue> = (args: Args, use: (r: R) => Promise<void>, workerInfo: WorkerInfo) => any;
|
type TestFixtureValue<R, Args extends {}> = Exclude<R, Function> | TestFixture<R, Args>;
|
||||||
type TestFixtureValue<R, Args extends KeyValue> = Exclude<R, Function> | TestFixture<R, Args>;
|
type WorkerFixtureValue<R, Args extends {}> = Exclude<R, Function> | WorkerFixture<R, Args>;
|
||||||
type WorkerFixtureValue<R, Args extends KeyValue> = Exclude<R, Function> | WorkerFixture<R, Args>;
|
export type Fixtures<T extends {} = {}, W extends {} = {}, PT extends {} = {}, PW extends {} = {}> = {
|
||||||
export type Fixtures<T extends KeyValue = {}, W extends KeyValue = {}, PT extends KeyValue = {}, PW extends KeyValue = {}> = {
|
|
||||||
[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 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 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';
|
type BrowserName = 'chromium' | 'firefox' | 'webkit';
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ test('render an empty component', async ({ mount, page }) => {
|
||||||
const testWithServer = test.extend(serverFixtures);
|
const testWithServer = test.extend(serverFixtures);
|
||||||
testWithServer(
|
testWithServer(
|
||||||
'components routing should go through context',
|
'components routing should go through context',
|
||||||
|
// @ts-ignore "serverFixtures" are imported from the impl without any types
|
||||||
async ({ mount, context, server }) => {
|
async ({ mount, context, server }) => {
|
||||||
server.setRoute('/hello', (req: any, res: any) => {
|
server.setRoute('/hello', (req: any, res: any) => {
|
||||||
res.write('served via server');
|
res.write('served via server');
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,71 @@ test('should check types of fixtures', async ({ runTSC }) => {
|
||||||
await use(x);
|
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': `
|
'playwright.config.ts': `
|
||||||
import { MyOptions } from './helper';
|
import { MyOptions } from './helper';
|
||||||
|
|
|
||||||
19
utils/generate_types/overrides-test.d.ts
vendored
19
utils/generate_types/overrides-test.d.ts
vendored
|
|
@ -78,7 +78,7 @@ export type TestDetails = {
|
||||||
type TestBody<TestArgs> = (args: TestArgs, testInfo: TestInfo) => Promise<void> | void;
|
type TestBody<TestArgs> = (args: TestArgs, testInfo: TestInfo) => Promise<void> | void;
|
||||||
type ConditionBody<TestArgs> = (args: TestArgs) => boolean;
|
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, body: TestBody<TestArgs & WorkerArgs>): void;
|
||||||
(title: string, details: TestDetails, body: TestBody<TestArgs & WorkerArgs>): void;
|
(title: string, details: TestDetails, body: TestBody<TestArgs & WorkerArgs>): void;
|
||||||
|
|
||||||
|
|
@ -164,23 +164,22 @@ export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue
|
||||||
use(fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs>): void;
|
use(fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs>): void;
|
||||||
step<T>(title: string, body: () => T | Promise<T>, options?: { box?: boolean, location?: Location, timeout?: number }): Promise<T>;
|
step<T>(title: string, body: () => T | Promise<T>, options?: { box?: boolean, location?: Location, timeout?: number }): Promise<T>;
|
||||||
expect: Expect<{}>;
|
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;
|
info(): TestInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyValue = { [key: string]: any };
|
export type TestFixture<R, Args extends {}> = (args: Args, use: (r: R) => Promise<void>, testInfo: TestInfo) => any;
|
||||||
export type TestFixture<R, Args extends KeyValue> = (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;
|
||||||
export type WorkerFixture<R, Args extends KeyValue> = (args: Args, use: (r: R) => Promise<void>, workerInfo: WorkerInfo) => any;
|
type TestFixtureValue<R, Args extends {}> = Exclude<R, Function> | TestFixture<R, Args>;
|
||||||
type TestFixtureValue<R, Args extends KeyValue> = Exclude<R, Function> | TestFixture<R, Args>;
|
type WorkerFixtureValue<R, Args extends {}> = Exclude<R, Function> | WorkerFixture<R, Args>;
|
||||||
type WorkerFixtureValue<R, Args extends KeyValue> = Exclude<R, Function> | WorkerFixture<R, Args>;
|
export type Fixtures<T extends {} = {}, W extends {} = {}, PT extends {} = {}, PW extends {} = {}> = {
|
||||||
export type Fixtures<T extends KeyValue = {}, W extends KeyValue = {}, PT extends KeyValue = {}, PW extends KeyValue = {}> = {
|
|
||||||
[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 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 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';
|
type BrowserName = 'chromium' | 'firefox' | 'webkit';
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue