diff --git a/packages/runner/src/utils/collect.ts b/packages/runner/src/utils/collect.ts index d9f595c0e4b8..f492cc5c789b 100644 --- a/packages/runner/src/utils/collect.ts +++ b/packages/runner/src/utils/collect.ts @@ -15,7 +15,7 @@ export function interpretTaskModes( ): void { const matchedLocations: number[] = [] - const traverseSuite = (suite: Suite, parentIsOnly?: boolean) => { + const traverseSuite = (suite: Suite, parentIsOnly?: boolean, parentMatchedWithLocation?: boolean) => { const suiteIsOnly = parentIsOnly || suite.mode === 'only' suite.tasks.forEach((t) => { @@ -37,22 +37,28 @@ export function interpretTaskModes( t.mode = 'run' } } - if (t.type === 'test') { - if (namePattern && !getTaskFullName(t).match(namePattern)) { + + let hasLocationMatch = parentMatchedWithLocation + // Match test location against provided locations, only run if present + // in `testLocations`. Note: if `includeTaskLocations` is not enabled, + // all test will be skipped. + if (testLocations !== undefined && testLocations.length !== 0) { + if (t.location && testLocations?.includes(t.location.line)) { + t.mode = 'run' + matchedLocations.push(t.location.line) + hasLocationMatch = true + } + else if (parentMatchedWithLocation) { + t.mode = 'run' + } + else if (t.type === 'test') { t.mode = 'skip' } + } - // Match test location against provided locations, only run if present - // in `testLocations`. Note: if `includeTaskLocations` is not enabled, - // all test will be skipped. - if (testLocations !== undefined && testLocations.length !== 0) { - if (t.location && testLocations?.includes(t.location.line)) { - t.mode = 'run' - matchedLocations.push(t.location.line) - } - else { - t.mode = 'skip' - } + if (t.type === 'test') { + if (namePattern && !getTaskFullName(t).match(namePattern)) { + t.mode = 'skip' } } else if (t.type === 'suite') { @@ -60,7 +66,7 @@ export function interpretTaskModes( skipAllTasks(t) } else { - traverseSuite(t, includeTask) + traverseSuite(t, includeTask, hasLocationMatch) } } }) @@ -73,7 +79,7 @@ export function interpretTaskModes( } } - traverseSuite(file, parentIsOnly) + traverseSuite(file, parentIsOnly, false) const nonMatching = testLocations?.filter(loc => !matchedLocations.includes(loc)) if (nonMatching && nonMatching.length !== 0) { diff --git a/test/cli/test/location-filters.test.ts b/test/cli/test/location-filters.test.ts index 0873b3963cac..6bbc0fa177a4 100644 --- a/test/cli/test/location-filters.test.ts +++ b/test/cli/test/location-filters.test.ts @@ -18,6 +18,54 @@ describe('location filter with list command', () => { expect(stderr).toEqual('') }) + test('finds "basic suite" at correct line number', async () => { + const { stdout, stderr } = await runVitestCli( + 'list', + `-r=${fixturePath}`, + `${fixturePath}/basic.test.ts:3`, + ) + + expect(stdout).toMatchInlineSnapshot(` + "basic.test.ts > basic suite > inner suite > some test + basic.test.ts > basic suite > inner suite > another test + basic.test.ts > basic suite > basic test + " + `) + expect(stderr).toEqual('') + }) + + test('finds "inner suite" at correct line number', async () => { + const { stdout, stderr } = await runVitestCli( + 'list', + `-r=${fixturePath}`, + `${fixturePath}/basic.test.ts:4`, + ) + + expect(stdout).toMatchInlineSnapshot(` + "basic.test.ts > basic suite > inner suite > some test + basic.test.ts > basic suite > inner suite > another test + " + `) + expect(stderr).toEqual('') + }) + + test('handles matching test inside a suite', async () => { + const { stdout, stderr } = await runVitestCli( + 'list', + `-r=${fixturePath}`, + `${fixturePath}/basic.test.ts:3`, + `${fixturePath}/basic.test.ts:9`, + ) + + expect(stdout).toMatchInlineSnapshot(` + "basic.test.ts > basic suite > inner suite > some test + basic.test.ts > basic suite > inner suite > another test + basic.test.ts > basic suite > basic test + " + `) + expect(stderr).toEqual('') + }) + test('handles file with a dash in the name', async () => { const { stdout, stderr } = await runVitestCli( 'list', @@ -120,13 +168,48 @@ describe('location filter with run command', () => { `${fixturePath}/math.test.ts:3`, ) - // expect(`${stdout}\n--------------------\n${stderr}`).toEqual('') - expect(stdout).contain('1 passed') expect(stdout).contain('1 skipped') expect(stderr).toEqual('') }) + test('finds "basic suite" at correct line number', async () => { + const { stdout, stderr } = await runVitestCli( + 'run', + `-r=${fixturePath}`, + `${fixturePath}/basic.test.ts:3`, + ) + + expect(stdout).contain('3 passed') + expect(stdout).contain('1 skipped') + expect(stderr).toEqual('') + }) + + test('finds "inner suite" at correct line number', async () => { + const { stdout, stderr } = await runVitestCli( + 'run', + `-r=${fixturePath}`, + `${fixturePath}/basic.test.ts:4`, + ) + + expect(stdout).contain('2 passed') + expect(stdout).contain('2 skipped') + expect(stderr).toEqual('') + }) + + test('handles matching test inside a suite', async () => { + const { stdout, stderr } = await runVitestCli( + 'run', + `-r=${fixturePath}`, + `${fixturePath}/basic.test.ts:3`, + `${fixturePath}/basic.test.ts:9`, + ) + + expect(stdout).contain('3 passed') + expect(stdout).contain('1 skipped') + expect(stderr).toEqual('') + }) + test('handles file with a dash in the name', async () => { const { stdout, stderr } = await runVitestCli( 'run',