fix(fixtures): make undefined option mean "default value" (#16026)

In the following example, `locale` inside the `describe`
would be reverted to the default value:

```js
test.use({ locale: 'en-GB' });

test.decsribe(() => {
  test.use({ locale: undefined });
});
```
This commit is contained in:
Dmitry Gozman 2022-07-28 12:57:05 -07:00 committed by GitHub
parent 792aa6a080
commit 3d89506704
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 17 deletions

View file

@ -203,7 +203,7 @@ export class FixturePool {
};
value = value[0];
}
const fn = value as (Function | any);
let fn = value as (Function | any);
const previous = this.registrations.get(name);
if (previous && options) {
@ -222,6 +222,15 @@ export class FixturePool {
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 });
// Overriding option with "undefined" value means setting it to the default value
// from the original declaration of the option.
if (fn === undefined && options.option && previous) {
let original = previous;
while (original.super)
original = original.super;
fn = original.fn;
}
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 };
registrationId(registration);

View file

@ -230,35 +230,49 @@ test('test.use() with undefined should not be ignored', async ({ runInlineTest }
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = {
use: { option: 'config' },
use: { option1: 'config' },
};
`,
'a.test.js': `
const test = pwt.test.extend({ option: [ 'default', { option: true } ] });
test('test1', async ({ option }) => {
console.log('test1-' + option);
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({ option: 'foo' });
test('test2', async ({ option }) => {
console.log('test2-' + option);
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({ option: undefined });
test('test3', async ({ option }) => {
console.log('test3-' + option);
test.use({ option1: undefined, option2: undefined });
test('test3', async ({ option1, option2 }) => {
console.log('test3: option1=' + option1);
console.log('test3: option2=' + option2);
});
});
});
test.extend({ option: undefined })('test4', async ({ option }) => {
console.log('test4-' + option);
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-config');
expect(result.output).toContain('test2-foo');
expect(result.output).toContain('test3-undefined');
expect(result.output).toContain('test4-undefined');
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');
});