fix(client): lint:skips counts skipIf(true) and runIf(false)

skipIf and runIf were left out as run-time skips, which they are with a
real condition. With the literal true (skipIf) or false (runIf) they
switch a test off for good and gave a free way past the ratchet, while
the same file already counted Playwright's test.skip(true, 'why') for
that reason. Both now count as skips; nothing in the client uses them
today, so the counts stay as they are.
This commit is contained in:
Maurice
2026-10-08 12:58:09 +02:00
parent 1b60de27f4
commit 4062b314cf
4 changed files with 27 additions and 4 deletions
+7 -1
View File
@@ -56,7 +56,8 @@ function switchesOff(call, file) {
* skipped: it.skip / describe.skip / test.todo / test.fixme and the
* x-shorthands, each switching off a test that never runs. Playwright's
* test.skip(!seed.id, 'why') decides at run time and does not count (see
* switchesOff); neither do skipIf and runIf.
* switchesOff); neither do skipIf and runIf, unless their condition is the
* literal that always skips: skipIf(true), runIf(false).
*
* only: .only anywhere, which silently drops every other test in the file.
*
@@ -78,6 +79,11 @@ export function modifiers(source, file) {
const call = ts.isCallExpression(node.parent) && node.parent.expression === node ? node.parent : null;
// test.skip.each(table)(...) declares skipped tests without being called directly.
if (!call || switchesOff(call, file)) skipped.push(at(node));
} else if (name === 'skipIf' || name === 'runIf') {
// skipIf(true) and runIf(false) are a skip in disguise: the condition can never change.
const call = ts.isCallExpression(node.parent) && node.parent.expression === node ? node.parent : null;
const never = name === 'skipIf' ? ts.SyntaxKind.TrueKeyword : ts.SyntaxKind.FalseKeyword;
if (call?.arguments[0]?.kind === never) skipped.push(at(node));
}
} else if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && SHORTHAND.has(node.expression.text)) {
skipped.push(at(node.expression));
+3 -2
View File
@@ -8,8 +8,9 @@
* skipped blocks since April); the files that hold some are listed in
* scripts/skip-baseline.json with their count, and a file may hold no more.
* Playwright's test.fixme counts as a skip. Only a skip that decides at run
* time is left out: skipIf, runIf, and in a Playwright spec
* test.skip(condition, 'why') unless the condition is the literal true.
* time is left out: skipIf and runIf, and in a Playwright spec
* test.skip(condition, 'why'), unless the condition is a literal that always
* skips (skipIf(true), runIf(false), test.skip(true, 'why')).
* Covers the vitest tests under src/ and tests/ and the Playwright specs
* under e2e/.
*