Skip to content

Commit 141e72a

Browse files
authored
fix(collect): don't treat extra props on test return as tests (#9871)
1 parent b78f538 commit 141e72a

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

packages/vitest/src/node/ast-collect.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ function astParseFile(filepath: string, code: string) {
157157
if (property && ['each', 'for', 'skipIf', 'runIf', 'extend', 'scoped', 'override'].includes(property)) {
158158
return
159159
}
160+
// skip properties on return values of calls - e.g., test('name', fn).skip()
161+
if (callee.type === 'MemberExpression' && callee.object?.type === 'CallExpression') {
162+
return
163+
}
160164
// derive mode from the full chain (handles any order like .skip.concurrent or .concurrent.skip)
161165
let mode: 'run' | 'skip' | 'only' | 'todo' = 'run'
162166
for (const prop of properties) {

test/cli/test/static-collect.test.ts

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,159 @@ test('invalid @module-tag throws and error', async () => {
14071407
`)
14081408
})
14091409

1410+
test('collects tests with runIf modifier', async () => {
1411+
const testModule = await collectTests(`
1412+
import { test } from 'vitest'
1413+
1414+
describe('runIf tests', () => {
1415+
test.runIf(true)('runs conditionally', () => {})
1416+
test.runIf(false)('also conditional', () => {})
1417+
})
1418+
`)
1419+
expect(testModule).toMatchInlineSnapshot(`
1420+
{
1421+
"runIf tests": {
1422+
"also conditional": {
1423+
"errors": [],
1424+
"fullName": "runIf tests > also conditional",
1425+
"id": "-1732721377_0_1",
1426+
"location": "6:22",
1427+
"mode": "skip",
1428+
"state": "skipped",
1429+
},
1430+
"runs conditionally": {
1431+
"errors": [],
1432+
"fullName": "runIf tests > runs conditionally",
1433+
"id": "-1732721377_0_0",
1434+
"location": "5:21",
1435+
"mode": "skip",
1436+
"state": "skipped",
1437+
},
1438+
},
1439+
}
1440+
`)
1441+
})
1442+
1443+
test('collects tests with skipIf modifier', async () => {
1444+
const testModule = await collectTests(`
1445+
import { test } from 'vitest'
1446+
1447+
describe('skipIf tests', () => {
1448+
test.skipIf(true)('skips conditionally', () => {})
1449+
test.skipIf(false)('also conditional skip', () => {})
1450+
})
1451+
`)
1452+
expect(testModule).toMatchInlineSnapshot(`
1453+
{
1454+
"skipIf tests": {
1455+
"also conditional skip": {
1456+
"errors": [],
1457+
"fullName": "skipIf tests > also conditional skip",
1458+
"id": "-1732721377_0_1",
1459+
"location": "6:23",
1460+
"mode": "skip",
1461+
"state": "skipped",
1462+
},
1463+
"skips conditionally": {
1464+
"errors": [],
1465+
"fullName": "skipIf tests > skips conditionally",
1466+
"id": "-1732721377_0_0",
1467+
"location": "5:22",
1468+
"mode": "skip",
1469+
"state": "skipped",
1470+
},
1471+
},
1472+
}
1473+
`)
1474+
})
1475+
1476+
test('collects tests with for modifier', async () => {
1477+
const testModule = await collectTests(`
1478+
import { test } from 'vitest'
1479+
1480+
describe('for tests', () => {
1481+
test.for([1, 2, 3])('test with for %i', (num) => {})
1482+
test.skip.for([1, 2])('skipped for %i', (num) => {})
1483+
})
1484+
`)
1485+
expect(testModule).toMatchInlineSnapshot(`
1486+
{
1487+
"for tests": {
1488+
"skipped for %i": {
1489+
"dynamic": true,
1490+
"each": true,
1491+
"errors": [],
1492+
"fullName": "for tests > skipped for %i",
1493+
"id": "-1732721377_0_1-dynamic",
1494+
"location": "6:26",
1495+
"mode": "skip",
1496+
"state": "skipped",
1497+
},
1498+
"test with for %i": {
1499+
"dynamic": true,
1500+
"each": true,
1501+
"errors": [],
1502+
"fullName": "for tests > test with for %i",
1503+
"id": "-1732721377_0_0-dynamic",
1504+
"location": "5:24",
1505+
"mode": "run",
1506+
"state": "pending",
1507+
},
1508+
},
1509+
}
1510+
`)
1511+
})
1512+
1513+
test('properties on test don\'t generate tests', async () => {
1514+
const testModule = await collectTests(`
1515+
import { test, describe } from 'vitest'
1516+
1517+
test('actual test', () => {}).withProp(true).withProp(false)
1518+
test.for([])('actual 2 test', () => {}).withProp('a2').withProp('a3')
1519+
testContext('actual 3 test', () => {}).withProp('q4').withProp('q5')
1520+
test('actual 4 test', () => {}).skip('hello world')
1521+
testContext().withProp('q6').withProp('q7')
1522+
`)
1523+
expect(testModule).toMatchInlineSnapshot(`
1524+
{
1525+
"actual 2 test": {
1526+
"dynamic": true,
1527+
"each": true,
1528+
"errors": [],
1529+
"fullName": "actual 2 test",
1530+
"id": "-1732721377_1-dynamic",
1531+
"location": "5:15",
1532+
"mode": "run",
1533+
"state": "pending",
1534+
},
1535+
"actual 3 test": {
1536+
"errors": [],
1537+
"fullName": "actual 3 test",
1538+
"id": "-1732721377_2",
1539+
"location": "6:4",
1540+
"mode": "run",
1541+
"state": "pending",
1542+
},
1543+
"actual 4 test": {
1544+
"errors": [],
1545+
"fullName": "actual 4 test",
1546+
"id": "-1732721377_3",
1547+
"location": "7:4",
1548+
"mode": "run",
1549+
"state": "pending",
1550+
},
1551+
"actual test": {
1552+
"errors": [],
1553+
"fullName": "actual test",
1554+
"id": "-1732721377_0",
1555+
"location": "4:4",
1556+
"mode": "run",
1557+
"state": "pending",
1558+
},
1559+
}
1560+
`)
1561+
})
1562+
14101563
async function collectTestModule(code: string, options?: CliOptions) {
14111564
const vitest = await createVitest(
14121565
'test',

0 commit comments

Comments
 (0)