Skip to content

Commit ca4d3b4

Browse files
fix!: stricter rule tester assertions for valid test cases (#20125)
* fix!: valid test cases must not have errors/output properties. fixes #18960 * fix: remove useless errors/output * fix: remove unused errors * fix: review suggestions * fix: review suggestions * docs: add migrating guide * chore: review suggestions Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com> --------- Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
1 parent fbae5d1 commit ca4d3b4

File tree

8 files changed

+91
-32
lines changed

8 files changed

+91
-32
lines changed

docs/src/use/migrate-to-10.0.0.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ The lists below are ordered roughly by the number of users each change is expect
3535
- [Fixer methods now require string `text` arguments](#fixer-text-must-be-string)
3636
- [New requirements for `ScopeManager` implementations](#scope-manager)
3737
- [Removal of deprecated `context` members](#rule-context)
38+
- [Prohibiting `errors` or `output` of valid RuleTester test cases](#stricter-rule-tester)
3839

3940
### Breaking changes for integration developers
4041

@@ -285,6 +286,34 @@ The removed `context` properties must be done manually as there may not be a dir
285286

286287
**Related issue(s):** [eslint/eslint#16999](https://github.com/eslint/eslint/issues/16999)
287288

289+
## <a name="stricter-rule-tester"></a> Prohibiting `errors` or `output` of valid RuleTester test cases
290+
291+
In ESLint v10.0.0, the RuleTester has become more strict about test case structure. Valid test cases (those that should not produce any linting errors) are no longer allowed to have `errors` or `output` properties.
292+
293+
​What changed:​​
294+
295+
- Previously, valid test cases could include `errors` or `output` properties, which were ignored.
296+
- Now, including these properties in valid test cases will cause the test to fail.
297+
298+
Example of invalid usage:​
299+
300+
```js
301+
// This will now throw an error in ESLint v10.0.0
302+
const validTestCases = [
303+
{
304+
code: "const foo = 'bar';",
305+
errors: 0, // ❌ Not allowed in valid test cases
306+
output: "const foo = 'bar';", // ❌ Not allowed in valid test cases
307+
},
308+
];
309+
310+
ruleTester.run("rule-id", rule, { valid: validTestCases, invalid: [] });
311+
```
312+
313+
**To address:** Remove any `errors`/`output` properties from valid test cases.
314+
315+
**Related issue(s):** [#18960](https://github.com/eslint/eslint/issues/18960)
316+
288317
## <a name="lintmessage-nodetype-removed"></a> Removal of `nodeType` property in `LintMessage` objects
289318

290319
In ESLint v10.0.0, the deprecated `nodeType` property on `LintMessage` objects has been removed. This affects consumers of the Node.js API (for example, custom formatters and editor/tool integrations) that previously relied on `message.nodeType`.

lib/rule-tester/rule-tester.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,16 @@ function assertTestCommonProperties(item) {
543543
* @throws {AssertionError} If the test case is not valid.
544544
*/
545545
function assertValidTestCase(item, seenTestCases) {
546+
// must not have properties of invalid test cases
547+
assert.ok(
548+
item.errors === void 0,
549+
"Valid test case must not have 'errors' property",
550+
);
551+
assert.ok(
552+
item.output === void 0,
553+
"Valid test case must not have 'output' property",
554+
);
555+
546556
assertTestCommonProperties(item);
547557
checkDuplicateTestCase(item, seenTestCases);
548558
}

tests/lib/rule-tester/rule-tester.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,57 @@ describe("RuleTester", () => {
731731
});
732732
});
733733

734+
describe("assert valid test cases", () => {
735+
/**
736+
* Runs valid tests
737+
* @param {Array<string|object>} valid Valid tests
738+
* @returns {void}
739+
*/
740+
function runValidTests(valid) {
741+
ruleTester.run(
742+
"no-eval",
743+
require("../../fixtures/testers/rule-tester/no-eval"),
744+
{ valid, invalid: [] },
745+
);
746+
}
747+
748+
it("Valid test case must not have 'errors' property", () => {
749+
assert.throws(() => {
750+
runValidTests([{ code: "", errors: 1 }]);
751+
}, /Valid test case must not have 'errors' property/u);
752+
753+
assert.throws(() => {
754+
runValidTests([{ code: "", errors: [{ message: "foo" }] }]);
755+
}, /Valid test case must not have 'errors' property/u);
756+
757+
assert.throws(() => {
758+
runValidTests([{ code: "", errors: 0 }]);
759+
}, /Valid test case must not have 'errors' property/u);
760+
761+
assert.throws(() => {
762+
runValidTests([{ code: "", errors: [] }]);
763+
}, /Valid test case must not have 'errors' property/u);
764+
});
765+
766+
it("Valid test case can have 'errors' property set to undefined", () => {
767+
runValidTests([{ code: "", errors: void 0 }]);
768+
});
769+
770+
it("Valid test case must not have 'output' property", () => {
771+
assert.throws(() => {
772+
runValidTests([{ code: "", output: "" }]);
773+
}, /Valid test case must not have 'output' property/u);
774+
775+
assert.throws(() => {
776+
runValidTests([{ code: "", output: null }]);
777+
}, /Valid test case must not have 'output' property/u);
778+
});
779+
780+
it("Valid test case can have 'output' property set to undefined", () => {
781+
runValidTests([{ code: "", output: void 0 }]);
782+
});
783+
});
784+
734785
it("should not throw an error when everything passes", () => {
735786
ruleTester.run(
736787
"no-eval",

tests/lib/rules/key-spacing.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,6 @@ ruleTester.run("key-spacing", rule, {
677677
},
678678
],
679679
languageOptions: { ecmaVersion: 6 },
680-
errors: [],
681680
},
682681
{
683682
code: [

tests/lib/rules/no-invalid-this.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ function extractPatterns(patterns, type) {
7777
applyCondition(thisPattern);
7878

7979
if (type === "valid") {
80-
thisPattern.errors = [];
80+
thisPattern.errors = void 0;
8181
} else {
8282
thisPattern.code += " /* should error */";
8383
}

tests/lib/rules/no-restricted-imports.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3736,11 +3736,6 @@ ruleTesterTypeScript.run("no-restricted-imports", rule, {
37363736
],
37373737
},
37383738
],
3739-
errors: [
3740-
{
3741-
messageId: "path",
3742-
},
3743-
],
37443739
},
37453740
{
37463741
code: `export { type bar, baz } from "foo";`,

tests/lib/rules/no-undef.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,14 @@ ruleTester.run("no-undef", rule, {
164164
{
165165
code: "let a; class C { static {} } a;",
166166
languageOptions: { ecmaVersion: 2022 },
167-
errors: [{ messageId: "undef", data: { name: "a" } }],
168167
},
169168
{
170169
code: "var a; class C { static {} } a;",
171170
languageOptions: { ecmaVersion: 2022 },
172-
errors: [{ messageId: "undef", data: { name: "a" } }],
173171
},
174172
{
175173
code: "a; class C { static {} } var a;",
176174
languageOptions: { ecmaVersion: 2022 },
177-
errors: [{ messageId: "undef", data: { name: "a" } }],
178175
},
179176
{
180177
code: "class C { static { C; } }",

tests/lib/rules/prefer-const.js

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -227,33 +227,11 @@ ruleTester.run("prefer-const", rule, {
227227
},
228228
{
229229
code: "class C { static { let a, b; if (foo) { ({ a, b } = foo); } } }",
230-
output: null,
231230
languageOptions: { ecmaVersion: 2022 },
232-
errors: [
233-
{
234-
messageId: "useConst",
235-
data: { name: "a" },
236-
},
237-
{
238-
messageId: "useConst",
239-
data: { name: "b" },
240-
},
241-
],
242231
},
243232
{
244233
code: "class C { static { let a, b; if (foo) ({ a, b } = foo); } }",
245-
output: null,
246234
languageOptions: { ecmaVersion: 2022 },
247-
errors: [
248-
{
249-
messageId: "useConst",
250-
data: { name: "a" },
251-
},
252-
{
253-
messageId: "useConst",
254-
data: { name: "b" },
255-
},
256-
],
257235
},
258236
{
259237
code: "class C { static { a; } } let a = 1; ",

0 commit comments

Comments
 (0)