Skip to content

Commit a6d1af0

Browse files
feat(rule-tester): assert suggestion messages are unique
1 parent 9f3f2ac commit a6d1af0

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

packages/rule-tester/src/RuleTester.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,23 @@ export class RuleTester extends TestFramework {
704704
const result = this.runRuleForItem(ruleName, rule, item);
705705
const messages = result.messages;
706706

707+
for (const message of messages) {
708+
if (hasOwnProperty(message, 'suggestions')) {
709+
const seenMessageIndices = new Map<string, number>();
710+
711+
for (let i = 0; i < message.suggestions.length; i += 1) {
712+
const suggestionMessage = message.suggestions[i].desc;
713+
const previous = seenMessageIndices.get(suggestionMessage);
714+
715+
assert.ok(
716+
!seenMessageIndices.has(suggestionMessage),
717+
`Suggestion message '${suggestionMessage}' reported from suggestion ${i} was previously reported by suggestion ${previous}. Suggestion messages should be unique within an error.`,
718+
);
719+
seenMessageIndices.set(suggestionMessage, i);
720+
}
721+
}
722+
}
723+
707724
if (typeof item.errors === 'number') {
708725
if (item.errors === 0) {
709726
assert.fail("Invalid cases must have 'error' value greater than 0");

packages/rule-tester/tests/eslint-base/eslint-base.test.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2226,6 +2226,39 @@ describe("RuleTester", () => {
22262226
}, /Invalid suggestion property name 'outpt'/u);
22272227
});
22282228

2229+
it("should fail if a rule produces two suggestions with the same description", () => {
2230+
assert.throws(() => {
2231+
ruleTester.run("suggestions-with-duplicate-descriptions", require("../../fixtures/testers/rule-tester/suggestions").withDuplicateDescriptions, {
2232+
valid: [],
2233+
invalid: [
2234+
{ code: "var foo = bar;", errors: 1 }
2235+
]
2236+
});
2237+
}, "Suggestion message 'Rename 'foo' to 'bar'' reported from suggestion 1 was previously reported by suggestion 0. Suggestion messages should be unique within an error.");
2238+
});
2239+
2240+
it("should fail if a rule produces two suggestions with the same messageId without data", () => {
2241+
assert.throws(() => {
2242+
ruleTester.run("suggestions-with-duplicate-messageids-no-data", require("../../fixtures/testers/rule-tester/suggestions").withDuplicateMessageIdsNoData, {
2243+
valid: [],
2244+
invalid: [
2245+
{ code: "var foo = bar;", errors: 1 }
2246+
]
2247+
});
2248+
}, "Suggestion message 'Rename identifier' reported from suggestion 1 was previously reported by suggestion 0. Suggestion messages should be unique within an error.");
2249+
});
2250+
2251+
it("should fail if a rule produces two suggestions with the same messageId with data", () => {
2252+
assert.throws(() => {
2253+
ruleTester.run("suggestions-with-duplicate-messageids-with-data", require("../../fixtures/testers/rule-tester/suggestions").withDuplicateMessageIdsWithData, {
2254+
valid: [],
2255+
invalid: [
2256+
{ code: "var foo = bar;", errors: 1 }
2257+
]
2258+
});
2259+
}, "Suggestion message 'Rename identifier 'foo' to 'bar'' reported from suggestion 1 was previously reported by suggestion 0. Suggestion messages should be unique within an error.");
2260+
});
2261+
22292262
it("should throw an error if a rule that doesn't have `meta.hasSuggestions` enabled produces suggestions", () => {
22302263
assert.throws(() => {
22312264
ruleTester.run("suggestions-missing-hasSuggestions-property", require("./fixtures/suggestions").withoutHasSuggestionsProperty, {

packages/rule-tester/tests/eslint-base/fixtures/suggestions.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,98 @@ module.exports.withMessageIds = {
6161
}
6262
};
6363

64+
module.exports.withDuplicateDescriptions = {
65+
meta: {
66+
hasSuggestions: true
67+
},
68+
create(context) {
69+
return {
70+
Identifier(node) {
71+
if (node.name === "foo") {
72+
context.report({
73+
node,
74+
message: "Avoid using identifiers name 'foo'.",
75+
suggest: [{
76+
desc: "Rename 'foo' to 'bar'",
77+
fix: fixer => fixer.replaceText(node, "bar")
78+
}, {
79+
desc: "Rename 'foo' to 'bar'",
80+
fix: fixer => fixer.replaceText(node, "baz")
81+
}]
82+
});
83+
}
84+
}
85+
};
86+
}
87+
};
88+
89+
module.exports.withDuplicateMessageIdsNoData = {
90+
meta: {
91+
messages: {
92+
avoidFoo: "Avoid using identifiers named '{{ name }}'.",
93+
renameFoo: "Rename identifier"
94+
},
95+
hasSuggestions: true
96+
},
97+
create(context) {
98+
return {
99+
Identifier(node) {
100+
if (node.name === "foo") {
101+
context.report({
102+
node,
103+
messageId: "avoidFoo",
104+
data: {
105+
name: "foo"
106+
},
107+
suggest: [{
108+
messageId: "renameFoo",
109+
fix: fixer => fixer.replaceText(node, "bar")
110+
}, {
111+
messageId: "renameFoo",
112+
fix: fixer => fixer.replaceText(node, "baz")
113+
}]
114+
});
115+
}
116+
}
117+
};
118+
}
119+
};
120+
121+
module.exports.withDuplicateMessageIdsWithData = {
122+
meta: {
123+
messages: {
124+
avoidFoo: "Avoid using identifiers named foo.",
125+
renameFoo: "Rename identifier 'foo' to '{{ newName }}'"
126+
},
127+
hasSuggestions: true
128+
},
129+
create(context) {
130+
return {
131+
Identifier(node) {
132+
if (node.name === "foo") {
133+
context.report({
134+
node,
135+
messageId: "avoidFoo",
136+
suggest: [{
137+
messageId: "renameFoo",
138+
data: {
139+
newName: "bar"
140+
},
141+
fix: fixer => fixer.replaceText(node, "bar")
142+
}, {
143+
messageId: "renameFoo",
144+
data: {
145+
newName: "bar"
146+
},
147+
fix: fixer => fixer.replaceText(node, "baz")
148+
}]
149+
});
150+
}
151+
}
152+
};
153+
}
154+
};
155+
64156
module.exports.withoutHasSuggestionsProperty = {
65157
create(context) {
66158
return {

0 commit comments

Comments
 (0)