feat(test runner): test.reset() to reset options to default/config value (#18561)
This commit is contained in:
		
							parent
							
								
									7a9f1b5ee4
								
							
						
					
					
						commit
						6fef227f43
					
				|  | @ -1077,6 +1077,51 @@ Test function that takes one or two arguments: an object with fixtures and optio | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | ## method: Test.reset | ||||||
|  | * since: v1.28 | ||||||
|  | 
 | ||||||
|  | Resets options that were set up in the configuration file or with [`method: Test.use`] to their default or config-specified value. | ||||||
|  | 
 | ||||||
|  | ```js tab=js-js | ||||||
|  | const { test, expect } = require('@playwright/test'); | ||||||
|  | 
 | ||||||
|  | test.reset({ | ||||||
|  |   // Reset storage state to the default empty value. | ||||||
|  |   storageStage: 'default', | ||||||
|  | 
 | ||||||
|  |   // Reset locale to the value specified in the config file. | ||||||
|  |   locale: 'config', | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | test('example', async ({ page }) => { | ||||||
|  |   // ... | ||||||
|  | }); | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```js tab=js-ts | ||||||
|  | import { test, expect } from '@playwright/test'; | ||||||
|  | 
 | ||||||
|  | test.reset({ | ||||||
|  |   // Reset storage state to the default empty value. | ||||||
|  |   storageStage: 'default', | ||||||
|  | 
 | ||||||
|  |   // Reset locale to the value specified in the config file. | ||||||
|  |   locale: 'config', | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | test('example', async ({ page }) => { | ||||||
|  |   // ... | ||||||
|  | }); | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### param: Test.reset.fixtures | ||||||
|  | * since: v1.28 | ||||||
|  | - `options` <[Object]> | ||||||
|  | 
 | ||||||
|  | An object with options set to either `'config'` or `'default'`. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| ## method: Test.setTimeout | ## method: Test.setTimeout | ||||||
| * since: v1.10 | * since: v1.10 | ||||||
|  |  | ||||||
|  | @ -48,8 +48,13 @@ type FixtureRegistration = { | ||||||
|   id: string; |   id: string; | ||||||
|   // A fixture override can use the previous version of the fixture.
 |   // A fixture override can use the previous version of the fixture.
 | ||||||
|   super?: FixtureRegistration; |   super?: FixtureRegistration; | ||||||
|  |   // Whether this fixture is an option value set from the config.
 | ||||||
|  |   fromConfig?: boolean; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | export const kResetToConfig = Symbol('reset-to-config'); | ||||||
|  | export const kResetToDefault = Symbol('reset-to-default'); | ||||||
|  | 
 | ||||||
| class Fixture { | class Fixture { | ||||||
|   runner: FixtureRunner; |   runner: FixtureRunner; | ||||||
|   registration: FixtureRegistration; |   registration: FixtureRegistration; | ||||||
|  | @ -188,7 +193,7 @@ export class FixturePool { | ||||||
|   constructor(fixturesList: FixturesWithLocation[], parentPool?: FixturePool, disallowWorkerFixtures?: boolean) { |   constructor(fixturesList: FixturesWithLocation[], parentPool?: FixturePool, disallowWorkerFixtures?: boolean) { | ||||||
|     this.registrations = new Map(parentPool ? parentPool.registrations : []); |     this.registrations = new Map(parentPool ? parentPool.registrations : []); | ||||||
| 
 | 
 | ||||||
|     for (const { fixtures, location } of fixturesList) { |     for (const { fixtures, location, fromConfig } of fixturesList) { | ||||||
|       for (const entry of Object.entries(fixtures)) { |       for (const entry of Object.entries(fixtures)) { | ||||||
|         const name = entry[0]; |         const name = entry[0]; | ||||||
|         let value = entry[1]; |         let value = entry[1]; | ||||||
|  | @ -222,17 +227,30 @@ export class FixturePool { | ||||||
|         if (options.scope === 'worker' && disallowWorkerFixtures) |         if (options.scope === 'worker' && disallowWorkerFixtures) | ||||||
|           throw errorWithLocations(`Cannot use({ ${name} }) in a describe group, because it forces a new worker.\nMake it top-level in the test file or put in the configuration file.`, { location, name }); |           throw errorWithLocations(`Cannot use({ ${name} }) in a describe group, because it forces a new worker.\nMake it top-level in the test file or put in the configuration file.`, { location, name }); | ||||||
| 
 | 
 | ||||||
|         // Overriding option with "undefined" value means setting it to the default value
 |         if (fn === undefined && options.option) { | ||||||
|         // from the original declaration of the option.
 |           // Overriding option with "undefined" value means setting it to the config value.
 | ||||||
|         if (fn === undefined && options.option && previous) { |           fn = kResetToConfig; | ||||||
|           let original = previous; |         } | ||||||
|           while (original.super) |         if (fn === kResetToConfig || fn === kResetToDefault) { | ||||||
|             original = original.super; |           // Find the target fixture to copy the reset value from.
 | ||||||
|           fn = original.fn; |           // It is either the original definition, or "fromConfig" one.
 | ||||||
|  |           //
 | ||||||
|  |           // Note that "reset to config" behaves like "reset to default"
 | ||||||
|  |           // if no value is set in the config.
 | ||||||
|  |           let targetFixture = previous; | ||||||
|  |           while (targetFixture && targetFixture.super) { | ||||||
|  |             if (fn === kResetToConfig && targetFixture.fromConfig) | ||||||
|  |               break; | ||||||
|  |             targetFixture = targetFixture.super; | ||||||
|  |           } | ||||||
|  |           if (targetFixture) | ||||||
|  |             fn = targetFixture.fn; | ||||||
|  |           else | ||||||
|  |             fn = undefined; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const deps = fixtureParameterNames(fn, location); |         const deps = fixtureParameterNames(fn, location); | ||||||
|         const registration: FixtureRegistration = { id: '', name, location, scope: options.scope, fn, auto: options.auto, option: options.option, timeout: options.timeout, customTitle: options.customTitle, deps, super: previous }; |         const registration: FixtureRegistration = { id: '', name, location, scope: options.scope, fn, auto: options.auto, option: options.option, timeout: options.timeout, customTitle: options.customTitle, deps, super: previous, fromConfig }; | ||||||
|         registrationId(registration); |         registrationId(registration); | ||||||
|         this.registrations.set(name, registration); |         this.registrations.set(name, registration); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  | @ -440,18 +440,17 @@ class ProjectSuiteBuilder { | ||||||
|       return testType.fixtures; |       return testType.fixtures; | ||||||
|     const result: FixturesWithLocation[] = []; |     const result: FixturesWithLocation[] = []; | ||||||
|     for (const f of testType.fixtures) { |     for (const f of testType.fixtures) { | ||||||
|  |       result.push(f); | ||||||
|       const optionsFromConfig: Fixtures = {}; |       const optionsFromConfig: Fixtures = {}; | ||||||
|       const originalFixtures: Fixtures = {}; |  | ||||||
|       for (const [key, value] of Object.entries(f.fixtures)) { |       for (const [key, value] of Object.entries(f.fixtures)) { | ||||||
|         if (isFixtureOption(value) && configKeys.has(key)) |         if (isFixtureOption(value) && configKeys.has(key)) | ||||||
|           (optionsFromConfig as any)[key] = [(configUse as any)[key], value[1]]; |           (optionsFromConfig as any)[key] = [(configUse as any)[key], value[1]]; | ||||||
|         else |  | ||||||
|           (originalFixtures as any)[key] = value; |  | ||||||
|       } |       } | ||||||
|       if (Object.entries(optionsFromConfig).length) |       if (Object.entries(optionsFromConfig).length) { | ||||||
|         result.push({ fixtures: optionsFromConfig, location: { file: `project#${this._project._id}`, line: 1, column: 1 } }); |         // Add config options immediately after original option definition,
 | ||||||
|       if (Object.entries(originalFixtures).length) |         // so that any test.use() override it.
 | ||||||
|         result.push({ fixtures: originalFixtures, location: f.location }); |         result.push({ fixtures: optionsFromConfig, location: { file: `project#${this._project._id}`, line: 1, column: 1 }, fromConfig: true }); | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|     return result; |     return result; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| import { expect } from './expect'; | import { expect } from './expect'; | ||||||
|  | import { kResetToConfig, kResetToDefault } from './fixtures'; | ||||||
| import { currentlyLoadingFileSuite, currentTestInfo, setCurrentlyLoadingFileSuite } from './globals'; | import { currentlyLoadingFileSuite, currentTestInfo, setCurrentlyLoadingFileSuite } from './globals'; | ||||||
| import { TestCase, Suite } from './test'; | import { TestCase, Suite } from './test'; | ||||||
| import { wrapFunctionWithLocation } from './transform'; | import { wrapFunctionWithLocation } from './transform'; | ||||||
|  | @ -54,6 +55,7 @@ export class TestTypeImpl { | ||||||
|     test.setTimeout = wrapFunctionWithLocation(this._setTimeout.bind(this)); |     test.setTimeout = wrapFunctionWithLocation(this._setTimeout.bind(this)); | ||||||
|     test.step = wrapFunctionWithLocation(this._step.bind(this)); |     test.step = wrapFunctionWithLocation(this._step.bind(this)); | ||||||
|     test.use = wrapFunctionWithLocation(this._use.bind(this)); |     test.use = wrapFunctionWithLocation(this._use.bind(this)); | ||||||
|  |     test.reset = wrapFunctionWithLocation(this._reset.bind(this)); | ||||||
|     test.extend = wrapFunctionWithLocation(this._extend.bind(this)); |     test.extend = wrapFunctionWithLocation(this._extend.bind(this)); | ||||||
|     test._extendTest = wrapFunctionWithLocation(this._extendTest.bind(this)); |     test._extendTest = wrapFunctionWithLocation(this._extendTest.bind(this)); | ||||||
|     test.info = () => { |     test.info = () => { | ||||||
|  | @ -206,6 +208,20 @@ export class TestTypeImpl { | ||||||
|     suite._use.push({ fixtures, location }); |     suite._use.push({ fixtures, location }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   private _reset(location: Location, resets: Fixtures) { | ||||||
|  |     const suite = this._ensureCurrentSuite(location, `test.reset()`); | ||||||
|  |     const fixtures: any = {}; | ||||||
|  |     for (const [key, value] of Object.entries(resets)) { | ||||||
|  |       if (value === 'config') | ||||||
|  |         fixtures[key] = kResetToConfig; | ||||||
|  |       else if (value === 'default') | ||||||
|  |         fixtures[key] = kResetToDefault; | ||||||
|  |       else | ||||||
|  |         throw errorWithLocation(location, `test.reset() supports "config" or "default", got unexpected value "${value}"`); | ||||||
|  |     } | ||||||
|  |     suite._use.push({ fixtures, location }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   private async _step<T>(location: Location, title: string, body: () => Promise<T>): Promise<T> { |   private async _step<T>(location: Location, title: string, body: () => Promise<T>): Promise<T> { | ||||||
|     const testInfo = currentTestInfo(); |     const testInfo = currentTestInfo(); | ||||||
|     if (!testInfo) |     if (!testInfo) | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ export type { Location } from '../types/testReporter'; | ||||||
| export type FixturesWithLocation = { | export type FixturesWithLocation = { | ||||||
|   fixtures: Fixtures; |   fixtures: Fixtures; | ||||||
|   location: Location; |   location: Location; | ||||||
|  |   fromConfig?: boolean; | ||||||
| }; | }; | ||||||
| export type Annotation = { type: string, description?: string }; | export type Annotation = { type: string, description?: string }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2519,6 +2519,29 @@ export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue | ||||||
|    * @param options An object with local options. |    * @param options An object with local options. | ||||||
|    */ |    */ | ||||||
|   use(fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs>): void; |   use(fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs>): void; | ||||||
|  |   /** | ||||||
|  |    * Resets options that were set up in the configuration file or with | ||||||
|  |    * [test.use(options)](https://playwright.dev/docs/api/class-test#test-use) to their default or config-specified value.
 | ||||||
|  |    * | ||||||
|  |    * ```js
 | ||||||
|  |    * import { test, expect } from '@playwright/test'; | ||||||
|  |    * | ||||||
|  |    * test.reset({ | ||||||
|  |    *   // Reset storage state to the default empty value.
 | ||||||
|  |    *   storageStage: 'default', | ||||||
|  |    * | ||||||
|  |    *   // Reset locale to the value specified in the config file.
 | ||||||
|  |    *   locale: 'config', | ||||||
|  |    * }); | ||||||
|  |    * | ||||||
|  |    * test('example', async ({ page }) => { | ||||||
|  |    *   // ...
 | ||||||
|  |    * }); | ||||||
|  |    * ``` | ||||||
|  |    * | ||||||
|  |    * @param options An object with options set to either `'config'` or `'default'`. | ||||||
|  |    */ | ||||||
|  |   reset(options: ResetOptions<TestArgs & WorkerArgs>): void; | ||||||
|   /** |   /** | ||||||
|    * Declares a test step. |    * Declares a test step. | ||||||
|    * |    * | ||||||
|  | @ -2643,6 +2666,7 @@ export type Fixtures<T extends KeyValue = {}, W extends KeyValue = {}, PT extend | ||||||
| } & { | } & { | ||||||
|   [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 }]; |   [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 }]; | ||||||
| }; | }; | ||||||
|  | type ResetOptions<T extends KeyValue> = { [K in keyof T]?: 'config' | 'default' }; | ||||||
| 
 | 
 | ||||||
| type BrowserName = 'chromium' | 'firefox' | 'webkit'; | type BrowserName = 'chromium' | 'firefox' | 'webkit'; | ||||||
| type BrowserChannel = Exclude<LaunchOptions['channel'], undefined>; | type BrowserChannel = Exclude<LaunchOptions['channel'], undefined>; | ||||||
|  |  | ||||||
|  | @ -225,54 +225,3 @@ test('test._extendTest should print nice message when used as extend', async ({ | ||||||
|   expect(result.passed).toBe(0); |   expect(result.passed).toBe(0); | ||||||
|   expect(result.output).toContain('Did you mean to call test.extend() with fixtures instead?'); |   expect(result.output).toContain('Did you mean to call test.extend() with fixtures instead?'); | ||||||
| }); | }); | ||||||
| 
 |  | ||||||
| test('test.use() with undefined should not be ignored', async ({ runInlineTest }) => { |  | ||||||
|   const result = await runInlineTest({ |  | ||||||
|     'playwright.config.ts': ` |  | ||||||
|       module.exports = { |  | ||||||
|         use: { option1: 'config' }, |  | ||||||
|       }; |  | ||||||
|     `,
 |  | ||||||
|     'a.test.js': ` |  | ||||||
|       const test = pwt.test.extend({ |  | ||||||
|         option1: [ 'default', { option: true } ], |  | ||||||
|         option2: [ 'default', { option: true } ], |  | ||||||
|       }); |  | ||||||
|       test('test1', async ({ option1, option2 }) => { |  | ||||||
|         console.log('test1: option1=' + option1); |  | ||||||
|         console.log('test1: option2=' + option2); |  | ||||||
|       }); |  | ||||||
| 
 |  | ||||||
|       test.describe('', () => { |  | ||||||
|         test.use({ option1: 'foo', option2: 'foo' }); |  | ||||||
|         test('test2', async ({ option1, option2 }) => { |  | ||||||
|           console.log('test2: option1=' + option1); |  | ||||||
|           console.log('test2: option2=' + option2); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         test.describe('', () => { |  | ||||||
|           test.use({ option1: undefined, option2: undefined }); |  | ||||||
|           test('test3', async ({ option1, option2 }) => { |  | ||||||
|             console.log('test3: option1=' + option1); |  | ||||||
|             console.log('test3: option2=' + option2); |  | ||||||
|           }); |  | ||||||
|         }); |  | ||||||
|       }); |  | ||||||
| 
 |  | ||||||
|       test.extend({ option1: undefined, option2: undefined })('test4', async ({ option1, option2 }) => { |  | ||||||
|         console.log('test4: option1=' + option1); |  | ||||||
|         console.log('test4: option2=' + option2); |  | ||||||
|       }); |  | ||||||
|     `,
 |  | ||||||
|   }); |  | ||||||
|   expect(result.exitCode).toBe(0); |  | ||||||
|   expect(result.passed).toBe(4); |  | ||||||
|   expect(result.output).toContain('test1: option1=config'); |  | ||||||
|   expect(result.output).toContain('test1: option2=default'); |  | ||||||
|   expect(result.output).toContain('test2: option1=foo'); |  | ||||||
|   expect(result.output).toContain('test2: option2=foo'); |  | ||||||
|   expect(result.output).toContain('test3: option1=config'); |  | ||||||
|   expect(result.output).toContain('test3: option2=default'); |  | ||||||
|   expect(result.output).toContain('test4: option1=config'); |  | ||||||
|   expect(result.output).toContain('test4: option2=default'); |  | ||||||
| }); |  | ||||||
|  |  | ||||||
|  | @ -179,3 +179,109 @@ test('test.use() should throw if called from beforeAll ', async ({ runInlineTest | ||||||
|   expect(result.output).toContain('Playwright Test did not expect test.use() to be called here'); |   expect(result.output).toContain('Playwright Test did not expect test.use() to be called here'); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | test('test.use() with undefined should not be ignored', async ({ runInlineTest }) => { | ||||||
|  |   const result = await runInlineTest({ | ||||||
|  |     'playwright.config.ts': ` | ||||||
|  |       module.exports = { | ||||||
|  |         use: { option1: 'config' }, | ||||||
|  |       }; | ||||||
|  |     `,
 | ||||||
|  |     'a.test.js': ` | ||||||
|  |       const test = pwt.test.extend({ | ||||||
|  |         option1: [ 'default', { option: true } ], | ||||||
|  |         option2: [ 'default', { option: true } ], | ||||||
|  |       }); | ||||||
|  |       test('test1', async ({ option1, option2 }) => { | ||||||
|  |         console.log('test1: option1=' + option1); | ||||||
|  |         console.log('test1: option2=' + option2); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       test.describe('', () => { | ||||||
|  |         test.use({ option1: 'foo', option2: 'foo' }); | ||||||
|  |         test('test2', async ({ option1, option2 }) => { | ||||||
|  |           console.log('test2: option1=' + option1); | ||||||
|  |           console.log('test2: option2=' + option2); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         test.describe('', () => { | ||||||
|  |           test.use({ option1: undefined, option2: undefined }); | ||||||
|  |           test('test3', async ({ option1, option2 }) => { | ||||||
|  |             console.log('test3: option1=' + option1); | ||||||
|  |             console.log('test3: option2=' + option2); | ||||||
|  |           }); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       test.extend({ option1: undefined, option2: undefined })('test4', async ({ option1, option2 }) => { | ||||||
|  |         console.log('test4: option1=' + option1); | ||||||
|  |         console.log('test4: option2=' + option2); | ||||||
|  |       }); | ||||||
|  |     `,
 | ||||||
|  |   }); | ||||||
|  |   expect(result.exitCode).toBe(0); | ||||||
|  |   expect(result.passed).toBe(4); | ||||||
|  |   expect(result.output).toContain('test1: option1=config'); | ||||||
|  |   expect(result.output).toContain('test1: option2=default'); | ||||||
|  |   expect(result.output).toContain('test2: option1=foo'); | ||||||
|  |   expect(result.output).toContain('test2: option2=foo'); | ||||||
|  |   expect(result.output).toContain('test3: option1=config'); | ||||||
|  |   expect(result.output).toContain('test3: option2=default'); | ||||||
|  |   expect(result.output).toContain('test4: option1=config'); | ||||||
|  |   expect(result.output).toContain('test4: option2=default'); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | test('test.reset() should reset to default or config', async ({ runInlineTest }) => { | ||||||
|  |   const result = await runInlineTest({ | ||||||
|  |     'playwright.config.ts': ` | ||||||
|  |       module.exports = { | ||||||
|  |         use: { option1: 'config-value' }, | ||||||
|  |       }; | ||||||
|  |     `,
 | ||||||
|  |     'a.test.js': ` | ||||||
|  |       const test = pwt.test.extend({ | ||||||
|  |         option1: [ 'default-value', { option: true } ], | ||||||
|  |         option2: [ 'default-value', { option: true } ], | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       test.use({ option1: 'use-value', option2: 'use-value' }); | ||||||
|  |       test('test1', async ({ option1, option2 }) => { | ||||||
|  |         console.log('test1: option1=' + option1); | ||||||
|  |         console.log('test1: option2=' + option2); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       test.describe(() => { | ||||||
|  |         test.reset({ option1: 'default', option2: 'default' }); | ||||||
|  |         test('test2', async ({ option1, option2 }) => { | ||||||
|  |           console.log('test2: option1=' + option1); | ||||||
|  |           console.log('test2: option2=' + option2); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       test.describe(() => { | ||||||
|  |         test.reset({ option1: 'config', option2: 'config' }); | ||||||
|  |         test('test3', async ({ option1, option2 }) => { | ||||||
|  |           console.log('test3: option1=' + option1); | ||||||
|  |           console.log('test3: option2=' + option2); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  |     `,
 | ||||||
|  |   }); | ||||||
|  |   expect(result.exitCode).toBe(0); | ||||||
|  |   expect(result.passed).toBe(3); | ||||||
|  |   expect(result.output).toContain('test1: option1=use-value'); | ||||||
|  |   expect(result.output).toContain('test1: option2=use-value'); | ||||||
|  |   expect(result.output).toContain('test2: option1=default-value'); | ||||||
|  |   expect(result.output).toContain('test2: option2=default-value'); | ||||||
|  |   expect(result.output).toContain('test3: option1=config-value'); | ||||||
|  |   expect(result.output).toContain('test3: option2=default-value'); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | test('test.reset() throws for unsupported value', async ({ runInlineTest }) => { | ||||||
|  |   const result = await runInlineTest({ | ||||||
|  |     'a.test.js': ` | ||||||
|  |       pwt.test.reset({ option: 'foo' }); | ||||||
|  |     `,
 | ||||||
|  |   }); | ||||||
|  |   expect(result.exitCode).toBe(1); | ||||||
|  |   expect(result.output).toContain('test.reset() supports "config" or "default", got unexpected value "foo"'); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | @ -136,6 +136,13 @@ test('should check types of fixtures', async ({ runTSC }) => { | ||||||
|       // @ts-expect-error
 |       // @ts-expect-error
 | ||||||
|       test.use({ baz: 'baz' }); |       test.use({ baz: 'baz' }); | ||||||
| 
 | 
 | ||||||
|  |       test.reset({ foo: 'default' }); | ||||||
|  |       test.reset({ foo: 'config' }); | ||||||
|  |       // @ts-expect-error
 | ||||||
|  |       test.reset({ unknown: 'config' }); | ||||||
|  |       // @ts-expect-error
 | ||||||
|  |       test.reset({ foo: 'unknown' }); | ||||||
|  | 
 | ||||||
|       test('my test', async ({ foo, bar }) => { |       test('my test', async ({ foo, bar }) => { | ||||||
|         bar += parseInt(foo); |         bar += parseInt(foo); | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|  | @ -151,6 +151,7 @@ export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue | ||||||
|   beforeAll(inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise<any> | any): void; |   beforeAll(inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise<any> | any): void; | ||||||
|   afterAll(inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise<any> | any): void; |   afterAll(inner: (args: TestArgs & WorkerArgs, testInfo: TestInfo) => Promise<any> | any): void; | ||||||
|   use(fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs>): void; |   use(fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs>): void; | ||||||
|  |   reset(options: ResetOptions<TestArgs & WorkerArgs>): void; | ||||||
|   step<T>(title: string, body: () => Promise<T>): Promise<T>; |   step<T>(title: string, body: () => Promise<T>): 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 KeyValue, W extends KeyValue = {}>(fixtures: Fixtures<T, W, TestArgs, WorkerArgs>): TestType<TestArgs & T, WorkerArgs & W>; | ||||||
|  | @ -171,6 +172,7 @@ export type Fixtures<T extends KeyValue = {}, W extends KeyValue = {}, PT extend | ||||||
| } & { | } & { | ||||||
|   [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 }]; |   [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 }]; | ||||||
| }; | }; | ||||||
|  | type ResetOptions<T extends KeyValue> = { [K in keyof T]?: 'config' | 'default' }; | ||||||
| 
 | 
 | ||||||
| type BrowserName = 'chromium' | 'firefox' | 'webkit'; | type BrowserName = 'chromium' | 'firefox' | 'webkit'; | ||||||
| type BrowserChannel = Exclude<LaunchOptions['channel'], undefined>; | type BrowserChannel = Exclude<LaunchOptions['channel'], undefined>; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue