diff --git a/packages/runner/src/suite.ts b/packages/runner/src/suite.ts index 52ef60388..ded1f6a60 100644 --- a/packages/runner/src/suite.ts +++ b/packages/runner/src/suite.ts @@ -340,7 +340,9 @@ function createSuiteCollector( }, {} as TestOptions) const testOwnMeta = options.meta + const parentOptions = collectorContext.currentSuite?.options options = { + ...parentOptions, ...tagsOptions, ...options, } @@ -440,12 +442,7 @@ function createSuiteCollector( optionsOrFn?: TestOptions | TestFunction, timeoutOrTest?: number | TestFunction, ) { - let { options, handler } = parseArguments(optionsOrFn, timeoutOrTest) - - // inherit repeats, retry, timeout from suite - if (typeof suiteOptions === 'object') { - options = Object.assign({}, suiteOptions, options) - } + const { options, handler } = parseArguments(optionsOrFn, timeoutOrTest) const concurrent = this.concurrent ?? options?.concurrent if (concurrent != null) { diff --git a/test/e2e/test/test-tags.test.ts b/test/e2e/test/test-tags.test.ts index 9567cb36d..be488295c 100644 --- a/test/e2e/test/test-tags.test.ts +++ b/test/e2e/test/test-tags.test.ts @@ -654,7 +654,6 @@ test('concurrent false tag option opts out of sequence.concurrent', async () => { "basic.test.js": { "test 1": { - "concurrent": true, "mode": "run", "tags": [ "non-concurrent-tag", @@ -662,7 +661,6 @@ test('concurrent false tag option opts out of sequence.concurrent', async () => "timeout": 5000, }, "test 2": { - "concurrent": true, "mode": "run", "tags": [ "non-concurrent-tag", @@ -1757,6 +1755,61 @@ test('multiple tags with meta are merged with priority order', async () => { `) }) +test('tag options override inherited suite options', async () => { + const { stderr, buildTree } = await runInlineTests({ + 'basic.test.js': ` + describe('with suite options', { timeout: 1000, repeats: 1, concurrent: true }, () => { + test('tag wins', { tags: ['my-tag'] }, () => {}) + test('explicit test wins', { tags: ['my-tag'], timeout: 9999 }, () => {}) + }) + describe('without suite options', () => { + test('tag applies', { tags: ['my-tag'] }, () => {}) + }) + `, + 'vitest.config.js': { + test: { + globals: true, + tags: [{ name: 'my-tag', timeout: 5000, repeats: 2, concurrent: false }], + }, + }, + }) + expect(stderr).toBe('') + expect(buildOptionsTree(buildTree)).toMatchInlineSnapshot(` + { + "basic.test.js": { + "with suite options": { + "explicit test wins": { + "mode": "run", + "repeats": 2, + "tags": [ + "my-tag", + ], + "timeout": 9999, + }, + "tag wins": { + "mode": "run", + "repeats": 2, + "tags": [ + "my-tag", + ], + "timeout": 5000, + }, + }, + "without suite options": { + "tag applies": { + "mode": "run", + "repeats": 2, + "tags": [ + "my-tag", + ], + "timeout": 5000, + }, + }, + }, + } + `) +}) + function getTestTree(builder: (fn: (test: TestCase) => any) => any) { return builder(test => test.options.tags) } diff --git a/test/unit/test/task-collector.test.ts b/test/unit/test/task-collector.test.ts index c44698ef4..1feddd2c2 100644 --- a/test/unit/test/task-collector.test.ts +++ b/test/unit/test/task-collector.test.ts @@ -50,6 +50,36 @@ describe('collector.extend should preserve handler wrapping', () => { }) }) +describe('suite.task inherits suite options', { meta: { yay: true } as any, concurrent: true, repeats: 1, retry: 2, timeout: 1234 }, () => { + const customTest = TestRunner.createTaskCollector(function ( + this: object, + name: string, + fn: () => void, + ) { + TestRunner.getCurrentSuite().task(name, { ...this, handler: fn }) + }) + + customTest('inherits options from current suite', ({ task }) => { + expect({ + concurrent: task.concurrent, + meta: task.meta, + repeats: task.repeats, + retry: task.retry, + timeout: task.timeout, + }).toMatchInlineSnapshot(` + { + "concurrent": true, + "meta": { + "yay": true, + }, + "repeats": 1, + "retry": 2, + "timeout": 1234, + } + `) + }) +}) + describe('empty tests and suites are todos', () => { describe('suite should be todo') test('test should be todo')