]>
Commit | Line | Data |
---|---|---|
eb39fafa DC |
1 | /** |
2 | * @fileoverview Tests for ESLint Tester | |
3 | * @author Nicholas C. Zakas | |
4 | */ | |
5 | "use strict"; | |
6 | ||
7 | //------------------------------------------------------------------------------ | |
8 | // Requirements | |
9 | //------------------------------------------------------------------------------ | |
10 | const sinon = require("sinon"), | |
11 | EventEmitter = require("events"), | |
12 | { RuleTester } = require("../../../lib/rule-tester"), | |
13 | assert = require("chai").assert, | |
5422a9cc | 14 | nodeAssert = require("assert"); |
eb39fafa DC |
15 | |
16 | const NODE_ASSERT_STRICT_EQUAL_OPERATOR = (() => { | |
17 | try { | |
18 | nodeAssert.strictEqual(1, 2); | |
19 | } catch (err) { | |
20 | return err.operator; | |
21 | } | |
22 | throw new Error("unexpected successful assertion"); | |
23 | })(); | |
24 | ||
5422a9cc TL |
25 | /** |
26 | * Do nothing. | |
27 | * @returns {void} | |
28 | */ | |
29 | function noop() { | |
30 | ||
31 | // do nothing. | |
32 | } | |
33 | ||
eb39fafa DC |
34 | //------------------------------------------------------------------------------ |
35 | // Rewire Things | |
36 | //------------------------------------------------------------------------------ | |
37 | ||
38 | /* | |
39 | * So here's the situation. Because RuleTester uses it() and describe() from | |
40 | * Mocha, any failures would show up in the output of this test file. That means | |
41 | * when we tested that a failure is thrown, that would also count as a failure | |
42 | * in the testing for RuleTester. In order to remove those results from the | |
43 | * results of this file, we need to overwrite it() and describe() just in | |
44 | * RuleTester to do nothing but run code. Effectively, it() and describe() | |
45 | * just become regular functions inside of index.js, not at all related to Mocha. | |
46 | * That allows the results of this file to be untainted and therefore accurate. | |
47 | * | |
48 | * To assert that the right arguments are passed to RuleTester.describe/it, an | |
49 | * event emitter is used which emits the arguments. | |
50 | */ | |
51 | ||
52 | const ruleTesterTestEmitter = new EventEmitter(); | |
53 | ||
54 | //------------------------------------------------------------------------------ | |
55 | // Tests | |
56 | //------------------------------------------------------------------------------ | |
57 | ||
58 | describe("RuleTester", () => { | |
59 | ||
60 | // Stub `describe()` and `it()` while this test suite. | |
61 | before(() => { | |
62 | RuleTester.describe = function(text, method) { | |
63 | ruleTesterTestEmitter.emit("describe", text, method); | |
64 | return method.call(this); | |
65 | }; | |
66 | RuleTester.it = function(text, method) { | |
67 | ruleTesterTestEmitter.emit("it", text, method); | |
68 | return method.call(this); | |
69 | }; | |
70 | }); | |
71 | after(() => { | |
72 | RuleTester.describe = null; | |
73 | RuleTester.it = null; | |
74 | }); | |
75 | ||
76 | let ruleTester; | |
77 | ||
78 | /** | |
79 | * A helper function to verify Node.js core error messages. | |
80 | * @param {string} actual The actual input | |
81 | * @param {string} expected The expected input | |
82 | * @returns {Function} Error callback to verify that the message is correct | |
83 | * for the actual and expected input. | |
84 | */ | |
85 | function assertErrorMatches(actual, expected) { | |
86 | const err = new nodeAssert.AssertionError({ | |
87 | actual, | |
88 | expected, | |
89 | operator: NODE_ASSERT_STRICT_EQUAL_OPERATOR | |
90 | }); | |
91 | ||
92 | return err.message; | |
93 | } | |
94 | ||
95 | beforeEach(() => { | |
96 | RuleTester.resetDefaultConfig(); | |
97 | ruleTester = new RuleTester(); | |
98 | }); | |
99 | ||
100 | it("should not throw an error when everything passes", () => { | |
101 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
102 | valid: [ | |
103 | "Eval(foo)" | |
104 | ], | |
105 | invalid: [ | |
106 | { code: "eval(foo)", errors: [{ message: "eval sucks.", type: "CallExpression" }] } | |
107 | ] | |
108 | }); | |
109 | }); | |
110 | ||
111 | it("should throw an error when valid code is invalid", () => { | |
112 | ||
113 | assert.throws(() => { | |
114 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
115 | valid: [ | |
116 | "eval(foo)" | |
117 | ], | |
118 | invalid: [ | |
119 | { code: "eval(foo)", errors: [{ message: "eval sucks.", type: "CallExpression" }] } | |
120 | ] | |
121 | }); | |
122 | }, /Should have no errors but had 1/u); | |
123 | }); | |
124 | ||
125 | it("should throw an error when valid code is invalid", () => { | |
126 | ||
127 | assert.throws(() => { | |
128 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
129 | valid: [ | |
130 | { code: "eval(foo)" } | |
131 | ], | |
132 | invalid: [ | |
133 | { code: "eval(foo)", errors: [{ message: "eval sucks.", type: "CallExpression" }] } | |
134 | ] | |
135 | }); | |
136 | }, /Should have no errors but had 1/u); | |
137 | }); | |
138 | ||
139 | it("should throw an error if invalid code is valid", () => { | |
140 | ||
141 | assert.throws(() => { | |
142 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
143 | valid: [ | |
144 | "Eval(foo)" | |
145 | ], | |
146 | invalid: [ | |
147 | { code: "Eval(foo)", errors: [{ message: "eval sucks.", type: "CallExpression" }] } | |
148 | ] | |
149 | }); | |
150 | }, /Should have 1 error but had 0/u); | |
151 | }); | |
152 | ||
153 | it("should throw an error when the error message is wrong", () => { | |
154 | assert.throws(() => { | |
155 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
156 | ||
157 | // Only the invalid test matters here | |
158 | valid: [ | |
159 | "bar = baz;" | |
160 | ], | |
161 | invalid: [ | |
162 | { code: "var foo = bar;", errors: [{ message: "Bad error message." }] } | |
163 | ] | |
164 | }); | |
165 | }, assertErrorMatches("Bad var.", "Bad error message.")); | |
166 | }); | |
167 | ||
168 | it("should throw an error when the error message regex does not match", () => { | |
169 | assert.throws(() => { | |
170 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
171 | valid: [], | |
172 | invalid: [ | |
173 | { code: "var foo = bar;", errors: [{ message: /Bad error message/u }] } | |
174 | ] | |
175 | }); | |
176 | }, /Expected 'Bad var.' to match \/Bad error message\//u); | |
177 | }); | |
178 | ||
179 | it("should throw an error when the error is not a supported type", () => { | |
180 | assert.throws(() => { | |
181 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
182 | ||
183 | // Only the invalid test matters here | |
184 | valid: [ | |
185 | "bar = baz;" | |
186 | ], | |
187 | invalid: [ | |
188 | { code: "var foo = bar;", errors: [42] } | |
189 | ] | |
190 | }); | |
191 | }, /Error should be a string, object, or RegExp/u); | |
192 | }); | |
193 | ||
194 | it("should throw an error when any of the errors is not a supported type", () => { | |
195 | assert.throws(() => { | |
196 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
197 | ||
198 | // Only the invalid test matters here | |
199 | valid: [ | |
200 | "bar = baz;" | |
201 | ], | |
202 | invalid: [ | |
203 | { code: "var foo = bar; var baz = quux", errors: [{ type: "VariableDeclaration" }, null] } | |
204 | ] | |
205 | }); | |
206 | }, /Error should be a string, object, or RegExp/u); | |
207 | }); | |
208 | ||
209 | it("should throw an error when the error is a string and it does not match error message", () => { | |
210 | assert.throws(() => { | |
211 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
212 | ||
213 | // Only the invalid test matters here | |
214 | valid: [ | |
215 | "bar = baz;" | |
216 | ], | |
217 | invalid: [ | |
218 | { code: "var foo = bar;", errors: ["Bad error message."] } | |
219 | ] | |
220 | }); | |
221 | }, assertErrorMatches("Bad var.", "Bad error message.")); | |
222 | }); | |
223 | ||
224 | it("should throw an error when the error is a string and it does not match error message", () => { | |
225 | assert.throws(() => { | |
226 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
227 | ||
228 | valid: [ | |
229 | ], | |
230 | invalid: [ | |
231 | { code: "var foo = bar;", errors: [/Bad error message/u] } | |
232 | ] | |
233 | }); | |
234 | }, /Expected 'Bad var.' to match \/Bad error message\//u); | |
235 | }); | |
236 | ||
237 | it("should not throw an error when the error is a string and it matches error message", () => { | |
238 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
239 | ||
240 | // Only the invalid test matters here | |
241 | valid: [ | |
242 | "bar = baz;" | |
243 | ], | |
244 | invalid: [ | |
245 | { code: "var foo = bar;", output: " foo = bar;", errors: ["Bad var."] } | |
246 | ] | |
247 | }); | |
248 | }); | |
249 | ||
250 | it("should not throw an error when the error is a regex and it matches error message", () => { | |
251 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
252 | valid: [], | |
253 | invalid: [ | |
254 | { code: "var foo = bar;", output: " foo = bar;", errors: [/^Bad var/u] } | |
255 | ] | |
256 | }); | |
257 | }); | |
258 | ||
259 | it("should throw an error when the error is an object with an unknown property name", () => { | |
260 | assert.throws(() => { | |
261 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
262 | valid: [ | |
263 | "bar = baz;" | |
264 | ], | |
265 | invalid: [ | |
266 | { code: "var foo = bar;", errors: [{ Message: "Bad var." }] } | |
267 | ] | |
268 | }); | |
269 | }, /Invalid error property name 'Message'/u); | |
270 | }); | |
271 | ||
272 | it("should throw an error when any of the errors is an object with an unknown property name", () => { | |
273 | assert.throws(() => { | |
274 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
275 | valid: [ | |
276 | "bar = baz;" | |
277 | ], | |
278 | invalid: [ | |
279 | { | |
280 | code: "var foo = bar; var baz = quux", | |
281 | errors: [ | |
282 | { message: "Bad var.", type: "VariableDeclaration" }, | |
283 | { message: "Bad var.", typo: "VariableDeclaration" } | |
284 | ] | |
285 | } | |
286 | ] | |
287 | }); | |
288 | }, /Invalid error property name 'typo'/u); | |
289 | }); | |
290 | ||
291 | it("should not throw an error when the error is a regex in an object and it matches error message", () => { | |
292 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
293 | valid: [], | |
294 | invalid: [ | |
295 | { code: "var foo = bar;", output: " foo = bar;", errors: [{ message: /^Bad var/u }] } | |
296 | ] | |
297 | }); | |
298 | }); | |
299 | ||
300 | it("should throw an error when the expected output doesn't match", () => { | |
301 | assert.throws(() => { | |
302 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
303 | valid: [ | |
304 | "bar = baz;" | |
305 | ], | |
306 | invalid: [ | |
307 | { code: "var foo = bar;", output: "foo = bar", errors: [{ message: "Bad var.", type: "VariableDeclaration" }] } | |
308 | ] | |
309 | }); | |
310 | }, /Output is incorrect/u); | |
311 | }); | |
312 | ||
313 | it("should use strict equality to compare output", () => { | |
314 | const replaceProgramWith5Rule = { | |
6f036462 TL |
315 | meta: { |
316 | fixable: "code" | |
317 | }, | |
318 | ||
eb39fafa DC |
319 | create: context => ({ |
320 | Program(node) { | |
321 | context.report({ node, message: "bad", fix: fixer => fixer.replaceText(node, "5") }); | |
322 | } | |
323 | }) | |
324 | }; | |
325 | ||
326 | // Should not throw. | |
327 | ruleTester.run("foo", replaceProgramWith5Rule, { | |
328 | valid: [], | |
329 | invalid: [ | |
330 | { code: "var foo = bar;", output: "5", errors: 1 } | |
331 | ] | |
332 | }); | |
333 | ||
334 | assert.throws(() => { | |
335 | ruleTester.run("foo", replaceProgramWith5Rule, { | |
336 | valid: [], | |
337 | invalid: [ | |
338 | { code: "var foo = bar;", output: 5, errors: 1 } | |
339 | ] | |
340 | }); | |
341 | }, /Output is incorrect/u); | |
342 | }); | |
343 | ||
344 | it("should throw an error when the expected output doesn't match and errors is just a number", () => { | |
345 | assert.throws(() => { | |
346 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
347 | valid: [ | |
348 | "bar = baz;" | |
349 | ], | |
350 | invalid: [ | |
351 | { code: "var foo = bar;", output: "foo = bar", errors: 1 } | |
352 | ] | |
353 | }); | |
354 | }, /Output is incorrect/u); | |
355 | }); | |
356 | ||
357 | it("should not throw an error when the expected output is null and no errors produce output", () => { | |
358 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
359 | valid: [ | |
360 | "bar = baz;" | |
361 | ], | |
362 | invalid: [ | |
363 | { code: "eval(x)", errors: 1, output: null }, | |
364 | { code: "eval(x); eval(y);", errors: 2, output: null } | |
365 | ] | |
366 | }); | |
367 | }); | |
368 | ||
369 | it("should throw an error when the expected output is null and problems produce output", () => { | |
370 | assert.throws(() => { | |
371 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
372 | valid: [ | |
373 | "bar = baz;" | |
374 | ], | |
375 | invalid: [ | |
376 | { code: "var foo = bar;", output: null, errors: 1 } | |
377 | ] | |
378 | }); | |
379 | }, /Expected no autofixes to be suggested/u); | |
380 | ||
381 | assert.throws(() => { | |
382 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
383 | valid: [ | |
384 | "bar = baz;" | |
385 | ], | |
386 | invalid: [ | |
387 | { | |
388 | code: "var foo = bar; var qux = boop;", | |
389 | output: null, | |
390 | errors: 2 | |
391 | } | |
392 | ] | |
393 | }); | |
394 | }, /Expected no autofixes to be suggested/u); | |
395 | }); | |
396 | ||
397 | it("should throw an error when the expected output is null and only some problems produce output", () => { | |
398 | assert.throws(() => { | |
399 | ruleTester.run("fixes-one-problem", require("../../fixtures/testers/rule-tester/fixes-one-problem"), { | |
400 | valid: [], | |
401 | invalid: [ | |
402 | { code: "foo", output: null, errors: 2 } | |
403 | ] | |
404 | }); | |
405 | }, /Expected no autofixes to be suggested/u); | |
406 | }); | |
407 | ||
408 | it("should throw an error when the expected output isn't specified and problems produce output", () => { | |
409 | assert.throws(() => { | |
410 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
411 | valid: [ | |
412 | "bar = baz;" | |
413 | ], | |
414 | invalid: [ | |
415 | { code: "var foo = bar;", errors: 1 } | |
416 | ] | |
417 | }); | |
418 | }, "The rule fixed the code. Please add 'output' property."); | |
419 | }); | |
420 | ||
421 | it("should throw an error if invalid code specifies wrong type", () => { | |
422 | assert.throws(() => { | |
423 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
424 | valid: [ | |
425 | "Eval(foo)" | |
426 | ], | |
427 | invalid: [ | |
428 | { code: "eval(foo)", errors: [{ message: "eval sucks.", type: "CallExpression2" }] } | |
429 | ] | |
430 | }); | |
431 | }, /Error type should be CallExpression2, found CallExpression/u); | |
432 | }); | |
433 | ||
434 | it("should throw an error if invalid code specifies wrong line", () => { | |
435 | assert.throws(() => { | |
436 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
437 | valid: [ | |
438 | "Eval(foo)" | |
439 | ], | |
440 | invalid: [ | |
441 | { code: "eval(foo)", errors: [{ message: "eval sucks.", type: "CallExpression", line: 5 }] } | |
442 | ] | |
443 | }); | |
444 | }, /Error line should be 5/u); | |
445 | }); | |
446 | ||
447 | it("should not skip line assertion if line is a falsy value", () => { | |
448 | assert.throws(() => { | |
449 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
450 | valid: [ | |
451 | "Eval(foo)" | |
452 | ], | |
453 | invalid: [ | |
454 | { code: "\neval(foo)", errors: [{ message: "eval sucks.", type: "CallExpression", line: 0 }] } | |
455 | ] | |
456 | }); | |
457 | }, /Error line should be 0/u); | |
458 | }); | |
459 | ||
460 | it("should throw an error if invalid code specifies wrong column", () => { | |
461 | const wrongColumn = 10, | |
462 | expectedErrorMessage = "Error column should be 1"; | |
463 | ||
464 | assert.throws(() => { | |
465 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
466 | valid: ["Eval(foo)"], | |
467 | invalid: [{ | |
468 | code: "eval(foo)", | |
469 | errors: [{ | |
470 | message: "eval sucks.", | |
471 | column: wrongColumn | |
472 | }] | |
473 | }] | |
474 | }); | |
475 | }, expectedErrorMessage); | |
476 | }); | |
477 | ||
6f036462 TL |
478 | it("should throw error for empty error array", () => { |
479 | assert.throws(() => { | |
480 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
481 | valid: [], | |
482 | invalid: [{ | |
483 | code: "var foo;", | |
484 | errors: [] | |
485 | }] | |
486 | }); | |
487 | }, /Invalid cases must have at least one error/u); | |
488 | }); | |
489 | ||
490 | it("should throw error for errors : 0", () => { | |
491 | assert.throws(() => { | |
492 | ruleTester.run( | |
493 | "suggestions-messageIds", | |
494 | require("../../fixtures/testers/rule-tester/suggestions") | |
495 | .withMessageIds, | |
496 | { | |
497 | valid: [], | |
498 | invalid: [ | |
499 | { | |
500 | code: "var foo;", | |
501 | errors: 0 | |
502 | } | |
503 | ] | |
504 | } | |
505 | ); | |
506 | }, /Invalid cases must have 'error' value greater than 0/u); | |
507 | }); | |
508 | ||
eb39fafa DC |
509 | it("should not skip column assertion if column is a falsy value", () => { |
510 | assert.throws(() => { | |
511 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
512 | valid: ["Eval(foo)"], | |
513 | invalid: [{ | |
514 | code: "var foo; eval(foo)", | |
515 | errors: [{ message: "eval sucks.", column: 0 }] | |
516 | }] | |
517 | }); | |
518 | }, /Error column should be 0/u); | |
519 | }); | |
520 | ||
521 | it("should throw an error if invalid code specifies wrong endLine", () => { | |
522 | assert.throws(() => { | |
523 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
524 | valid: [ | |
525 | "bar = baz;" | |
526 | ], | |
527 | invalid: [ | |
528 | { code: "var foo = bar;", output: "foo = bar", errors: [{ message: "Bad var.", type: "VariableDeclaration", endLine: 10 }] } | |
529 | ] | |
530 | }); | |
531 | }, "Error endLine should be 10"); | |
532 | }); | |
533 | ||
534 | it("should throw an error if invalid code specifies wrong endColumn", () => { | |
535 | assert.throws(() => { | |
536 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
537 | valid: [ | |
538 | "bar = baz;" | |
539 | ], | |
540 | invalid: [ | |
541 | { code: "var foo = bar;", output: "foo = bar", errors: [{ message: "Bad var.", type: "VariableDeclaration", endColumn: 10 }] } | |
542 | ] | |
543 | }); | |
544 | }, "Error endColumn should be 10"); | |
545 | }); | |
546 | ||
547 | it("should throw an error if invalid code has the wrong number of errors", () => { | |
548 | assert.throws(() => { | |
549 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
550 | valid: [ | |
551 | "Eval(foo)" | |
552 | ], | |
553 | invalid: [ | |
554 | { | |
555 | code: "eval(foo)", | |
556 | errors: [ | |
557 | { message: "eval sucks.", type: "CallExpression" }, | |
558 | { message: "eval sucks.", type: "CallExpression" } | |
559 | ] | |
560 | } | |
561 | ] | |
562 | }); | |
563 | }, /Should have 2 errors but had 1/u); | |
564 | }); | |
565 | ||
566 | it("should throw an error if invalid code does not have errors", () => { | |
567 | assert.throws(() => { | |
568 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
569 | valid: [ | |
570 | "Eval(foo)" | |
571 | ], | |
572 | invalid: [ | |
573 | { code: "eval(foo)" } | |
574 | ] | |
575 | }); | |
576 | }, /Did not specify errors for an invalid test of no-eval/u); | |
577 | }); | |
578 | ||
579 | it("should throw an error if invalid code has the wrong explicit number of errors", () => { | |
580 | assert.throws(() => { | |
581 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
582 | valid: [ | |
583 | "Eval(foo)" | |
584 | ], | |
585 | invalid: [ | |
586 | { code: "eval(foo)", errors: 2 } | |
587 | ] | |
588 | }); | |
589 | }, /Should have 2 errors but had 1/u); | |
590 | }); | |
591 | ||
592 | it("should throw an error if there's a parsing error in a valid test", () => { | |
593 | assert.throws(() => { | |
594 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
595 | valid: [ | |
596 | "1eval('foo')" | |
597 | ], | |
598 | invalid: [ | |
599 | { code: "eval('foo')", errors: [{}] } | |
600 | ] | |
601 | }); | |
602 | }, /fatal parsing error/iu); | |
603 | }); | |
604 | ||
605 | it("should throw an error if there's a parsing error in an invalid test", () => { | |
606 | assert.throws(() => { | |
607 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
608 | valid: [ | |
609 | "noeval('foo')" | |
610 | ], | |
611 | invalid: [ | |
612 | { code: "1eval('foo')", errors: [{}] } | |
613 | ] | |
614 | }); | |
615 | }, /fatal parsing error/iu); | |
616 | }); | |
617 | ||
618 | it("should throw an error if there's a parsing error in an invalid test and errors is just a number", () => { | |
619 | assert.throws(() => { | |
620 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
621 | valid: [ | |
622 | "noeval('foo')" | |
623 | ], | |
624 | invalid: [ | |
625 | { code: "1eval('foo')", errors: 1 } | |
626 | ] | |
627 | }); | |
628 | }, /fatal parsing error/iu); | |
629 | }); | |
630 | ||
631 | // https://github.com/eslint/eslint/issues/4779 | |
632 | it("should throw an error if there's a parsing error and output doesn't match", () => { | |
633 | assert.throws(() => { | |
634 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
635 | valid: [], | |
636 | invalid: [ | |
637 | { code: "eval(`foo`)", output: "eval(`foo`);", errors: [{}] } | |
638 | ] | |
639 | }); | |
640 | }, /fatal parsing error/iu); | |
641 | }); | |
642 | ||
643 | it("should not throw an error if invalid code has at least an expected empty error object", () => { | |
644 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
645 | valid: ["Eval(foo)"], | |
646 | invalid: [{ | |
647 | code: "eval(foo)", | |
648 | errors: [{}] | |
649 | }] | |
650 | }); | |
651 | }); | |
652 | ||
653 | it("should pass-through the globals config of valid tests to the to rule", () => { | |
654 | ruleTester.run("no-test-global", require("../../fixtures/testers/rule-tester/no-test-global"), { | |
655 | valid: [ | |
656 | "var test = 'foo'", | |
657 | { | |
658 | code: "var test2 = 'bar'", | |
659 | globals: { test: true } | |
660 | } | |
661 | ], | |
662 | invalid: [{ code: "bar", errors: 1 }] | |
663 | }); | |
664 | }); | |
665 | ||
666 | it("should pass-through the globals config of invalid tests to the to rule", () => { | |
667 | ruleTester.run("no-test-global", require("../../fixtures/testers/rule-tester/no-test-global"), { | |
668 | valid: ["var test = 'foo'"], | |
669 | invalid: [ | |
670 | { | |
671 | code: "var test = 'foo'; var foo = 'bar'", | |
672 | errors: 1 | |
673 | }, | |
674 | { | |
675 | code: "var test = 'foo'", | |
676 | globals: { foo: true }, | |
677 | errors: [{ message: "Global variable foo should not be used." }] | |
678 | } | |
679 | ] | |
680 | }); | |
681 | }); | |
682 | ||
683 | it("should pass-through the settings config to rules", () => { | |
684 | ruleTester.run("no-test-settings", require("../../fixtures/testers/rule-tester/no-test-settings"), { | |
685 | valid: [ | |
686 | { | |
687 | code: "var test = 'bar'", settings: { test: 1 } | |
688 | } | |
689 | ], | |
690 | invalid: [ | |
691 | { | |
692 | code: "var test = 'bar'", settings: { "no-test": 22 }, errors: 1 | |
693 | } | |
694 | ] | |
695 | }); | |
696 | }); | |
697 | ||
698 | it("should pass-through the filename to the rule", () => { | |
699 | (function() { | |
700 | ruleTester.run("", require("../../fixtures/testers/rule-tester/no-test-filename"), { | |
701 | valid: [ | |
702 | { | |
703 | code: "var foo = 'bar'", | |
704 | filename: "somefile.js" | |
705 | } | |
706 | ], | |
707 | invalid: [ | |
708 | { | |
709 | code: "var foo = 'bar'", | |
710 | errors: [ | |
711 | { message: "Filename test was not defined." } | |
712 | ] | |
713 | } | |
714 | ] | |
715 | }); | |
716 | }()); | |
717 | }); | |
718 | ||
719 | it("should pass-through the options to the rule", () => { | |
720 | ruleTester.run("no-invalid-args", require("../../fixtures/testers/rule-tester/no-invalid-args"), { | |
721 | valid: [ | |
722 | { | |
723 | code: "var foo = 'bar'", | |
724 | options: [false] | |
725 | } | |
726 | ], | |
727 | invalid: [ | |
728 | { | |
729 | code: "var foo = 'bar'", | |
730 | options: [true], | |
731 | errors: [{ message: "Invalid args" }] | |
732 | } | |
733 | ] | |
734 | }); | |
735 | }); | |
736 | ||
737 | it("should throw an error if the options are an object", () => { | |
738 | assert.throws(() => { | |
739 | ruleTester.run("no-invalid-args", require("../../fixtures/testers/rule-tester/no-invalid-args"), { | |
740 | valid: [ | |
741 | { | |
742 | code: "foo", | |
743 | options: { ok: true } | |
744 | } | |
745 | ], | |
746 | invalid: [] | |
747 | }); | |
748 | }, /options must be an array/u); | |
749 | }); | |
750 | ||
751 | it("should throw an error if the options are a number", () => { | |
752 | assert.throws(() => { | |
753 | ruleTester.run("no-invalid-args", require("../../fixtures/testers/rule-tester/no-invalid-args"), { | |
754 | valid: [ | |
755 | { | |
756 | code: "foo", | |
757 | options: 0 | |
758 | } | |
759 | ], | |
760 | invalid: [] | |
761 | }); | |
762 | }, /options must be an array/u); | |
763 | }); | |
764 | ||
765 | it("should pass-through the parser to the rule", () => { | |
766 | const spy = sinon.spy(ruleTester.linter, "verify"); | |
767 | ||
768 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
769 | valid: [ | |
770 | { | |
771 | code: "Eval(foo)" | |
772 | } | |
773 | ], | |
774 | invalid: [ | |
775 | { | |
776 | code: "eval(foo)", | |
777 | parser: require.resolve("esprima"), | |
6f036462 | 778 | errors: [{ line: 1 }] |
eb39fafa DC |
779 | } |
780 | ] | |
781 | }); | |
782 | assert.strictEqual(spy.args[1][1].parser, require.resolve("esprima")); | |
783 | }); | |
784 | ||
785 | it("should pass-through services from parseForESLint to the rule", () => { | |
786 | const enhancedParserPath = require.resolve("../../fixtures/parsers/enhanced-parser"); | |
787 | const disallowHiRule = { | |
788 | create: context => ({ | |
789 | Literal(node) { | |
790 | const disallowed = context.parserServices.test.getMessage(); // returns "Hi!" | |
791 | ||
792 | if (node.value === disallowed) { | |
793 | context.report({ node, message: `Don't use '${disallowed}'` }); | |
794 | } | |
795 | } | |
796 | }) | |
797 | }; | |
798 | ||
799 | ruleTester.run("no-hi", disallowHiRule, { | |
800 | valid: [ | |
801 | { | |
802 | code: "'Hello!'", | |
803 | parser: enhancedParserPath | |
804 | } | |
805 | ], | |
806 | invalid: [ | |
807 | { | |
808 | code: "'Hi!'", | |
809 | parser: enhancedParserPath, | |
810 | errors: [{ message: "Don't use 'Hi!'" }] | |
811 | } | |
812 | ] | |
813 | }); | |
814 | }); | |
815 | ||
816 | it("should prevent invalid options schemas", () => { | |
817 | assert.throws(() => { | |
818 | ruleTester.run("no-invalid-schema", require("../../fixtures/testers/rule-tester/no-invalid-schema"), { | |
819 | valid: [ | |
820 | "var answer = 6 * 7;", | |
821 | { code: "var answer = 6 * 7;", options: [] } | |
822 | ], | |
823 | invalid: [ | |
824 | { code: "var answer = 6 * 7;", options: ["bar"], errors: [{ message: "Expected nothing." }] } | |
825 | ] | |
826 | }); | |
827 | }, "Schema for rule no-invalid-schema is invalid:,\titems: should be object\n\titems[0].enum: should NOT have fewer than 1 items\n\titems: should match some schema in anyOf"); | |
828 | ||
829 | }); | |
830 | ||
831 | it("should prevent schema violations in options", () => { | |
832 | assert.throws(() => { | |
833 | ruleTester.run("no-schema-violation", require("../../fixtures/testers/rule-tester/no-schema-violation"), { | |
834 | valid: [ | |
835 | "var answer = 6 * 7;", | |
836 | { code: "var answer = 6 * 7;", options: ["foo"] } | |
837 | ], | |
838 | invalid: [ | |
839 | { code: "var answer = 6 * 7;", options: ["bar"], errors: [{ message: "Expected foo." }] } | |
840 | ] | |
841 | }); | |
842 | }, /Value "bar" should be equal to one of the allowed values./u); | |
843 | ||
844 | }); | |
845 | ||
846 | it("should disallow invalid defaults in rules", () => { | |
847 | const ruleWithInvalidDefaults = { | |
848 | meta: { | |
849 | schema: [ | |
850 | { | |
851 | oneOf: [ | |
852 | { enum: ["foo"] }, | |
853 | { | |
854 | type: "object", | |
855 | properties: { | |
856 | foo: { | |
857 | enum: ["foo", "bar"], | |
858 | default: "foo" | |
859 | } | |
860 | }, | |
861 | additionalProperties: false | |
862 | } | |
863 | ] | |
864 | } | |
865 | ] | |
866 | }, | |
867 | create: () => ({}) | |
868 | }; | |
869 | ||
870 | assert.throws(() => { | |
871 | ruleTester.run("invalid-defaults", ruleWithInvalidDefaults, { | |
872 | valid: [ | |
873 | { | |
874 | code: "foo", | |
875 | options: [{}] | |
876 | } | |
877 | ], | |
878 | invalid: [] | |
879 | }); | |
880 | }, /Schema for rule invalid-defaults is invalid: default is ignored for: data1\.foo/u); | |
881 | }); | |
882 | ||
883 | it("throw an error when an unknown config option is included", () => { | |
884 | assert.throws(() => { | |
885 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
886 | valid: [ | |
887 | { code: "Eval(foo)", foo: "bar" } | |
888 | ], | |
889 | invalid: [] | |
890 | }); | |
891 | }, /ESLint configuration in rule-tester is invalid./u); | |
892 | }); | |
893 | ||
894 | it("throw an error when an invalid config value is included", () => { | |
895 | assert.throws(() => { | |
896 | ruleTester.run("no-eval", require("../../fixtures/testers/rule-tester/no-eval"), { | |
897 | valid: [ | |
898 | { code: "Eval(foo)", env: ["es6"] } | |
899 | ], | |
900 | invalid: [] | |
901 | }); | |
902 | }, /Property "env" is the wrong type./u); | |
903 | }); | |
904 | ||
905 | it("should pass-through the tester config to the rule", () => { | |
906 | ruleTester = new RuleTester({ | |
907 | globals: { test: true } | |
908 | }); | |
909 | ||
910 | ruleTester.run("no-test-global", require("../../fixtures/testers/rule-tester/no-test-global"), { | |
911 | valid: [ | |
912 | "var test = 'foo'", | |
913 | "var test2 = test" | |
914 | ], | |
915 | invalid: [{ code: "bar", errors: 1, globals: { foo: true } }] | |
916 | }); | |
917 | }); | |
918 | ||
919 | it("should correctly set the globals configuration", () => { | |
920 | const config = { globals: { test: true } }; | |
921 | ||
922 | RuleTester.setDefaultConfig(config); | |
923 | assert( | |
924 | RuleTester.getDefaultConfig().globals.test, | |
925 | "The default config object is incorrect" | |
926 | ); | |
927 | }); | |
928 | ||
929 | it("should correctly reset the global configuration", () => { | |
930 | const config = { globals: { test: true } }; | |
931 | ||
932 | RuleTester.setDefaultConfig(config); | |
933 | RuleTester.resetDefaultConfig(); | |
934 | assert.deepStrictEqual( | |
935 | RuleTester.getDefaultConfig(), | |
936 | { rules: {} }, | |
937 | "The default configuration has not reset correctly" | |
938 | ); | |
939 | }); | |
940 | ||
941 | it("should enforce the global configuration to be an object", () => { | |
942 | ||
943 | /** | |
944 | * Set the default config for the rules tester | |
945 | * @param {Object} config configuration object | |
946 | * @returns {Function} Function to be executed | |
947 | * @private | |
948 | */ | |
949 | function setConfig(config) { | |
950 | return function() { | |
951 | RuleTester.setDefaultConfig(config); | |
952 | }; | |
953 | } | |
954 | assert.throw(setConfig()); | |
955 | assert.throw(setConfig(1)); | |
956 | assert.throw(setConfig(3.14)); | |
957 | assert.throw(setConfig("foo")); | |
958 | assert.throw(setConfig(null)); | |
959 | assert.throw(setConfig(true)); | |
960 | }); | |
961 | ||
962 | it("should pass-through the globals config to the tester then to the to rule", () => { | |
963 | const config = { globals: { test: true } }; | |
964 | ||
965 | RuleTester.setDefaultConfig(config); | |
966 | ruleTester = new RuleTester(); | |
967 | ||
968 | ruleTester.run("no-test-global", require("../../fixtures/testers/rule-tester/no-test-global"), { | |
969 | valid: [ | |
970 | "var test = 'foo'", | |
971 | "var test2 = test" | |
972 | ], | |
973 | invalid: [{ code: "bar", errors: 1, globals: { foo: true } }] | |
974 | }); | |
975 | }); | |
976 | ||
977 | it("should throw an error if AST was modified", () => { | |
978 | assert.throws(() => { | |
979 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast"), { | |
980 | valid: [ | |
981 | "var foo = 0;" | |
982 | ], | |
983 | invalid: [] | |
984 | }); | |
985 | }, "Rule should not modify AST."); | |
986 | assert.throws(() => { | |
987 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast"), { | |
988 | valid: [], | |
989 | invalid: [ | |
990 | { code: "var bar = 0;", errors: ["error"] } | |
991 | ] | |
992 | }); | |
993 | }, "Rule should not modify AST."); | |
994 | }); | |
995 | ||
996 | it("should throw an error if AST was modified (at Program)", () => { | |
997 | assert.throws(() => { | |
998 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-first"), { | |
999 | valid: [ | |
1000 | "var foo = 0;" | |
1001 | ], | |
1002 | invalid: [] | |
1003 | }); | |
1004 | }, "Rule should not modify AST."); | |
1005 | assert.throws(() => { | |
1006 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-first"), { | |
1007 | valid: [], | |
1008 | invalid: [ | |
1009 | { code: "var bar = 0;", errors: ["error"] } | |
1010 | ] | |
1011 | }); | |
1012 | }, "Rule should not modify AST."); | |
1013 | }); | |
1014 | ||
1015 | it("should throw an error if AST was modified (at Program:exit)", () => { | |
1016 | assert.throws(() => { | |
1017 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-last"), { | |
1018 | valid: [ | |
1019 | "var foo = 0;" | |
1020 | ], | |
1021 | invalid: [] | |
1022 | }); | |
1023 | }, "Rule should not modify AST."); | |
1024 | assert.throws(() => { | |
1025 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-last"), { | |
1026 | valid: [], | |
1027 | invalid: [ | |
1028 | { code: "var bar = 0;", errors: ["error"] } | |
1029 | ] | |
1030 | }); | |
1031 | }, "Rule should not modify AST."); | |
1032 | }); | |
1033 | ||
1034 | it("should throw an error if rule uses start and end properties on nodes, tokens or comments", () => { | |
1035 | const usesStartEndRule = { | |
1036 | create(context) { | |
1037 | ||
1038 | const sourceCode = context.getSourceCode(); | |
1039 | ||
1040 | return { | |
1041 | CallExpression(node) { | |
1042 | noop(node.arguments[1].start); | |
1043 | }, | |
1044 | "BinaryExpression[operator='+']"(node) { | |
1045 | noop(node.end); | |
1046 | }, | |
1047 | "UnaryExpression[operator='-']"(node) { | |
1048 | noop(sourceCode.getFirstToken(node).start); | |
1049 | }, | |
1050 | ConditionalExpression(node) { | |
1051 | noop(sourceCode.getFirstToken(node).end); | |
1052 | }, | |
1053 | BlockStatement(node) { | |
1054 | noop(sourceCode.getCommentsInside(node)[0].start); | |
1055 | }, | |
1056 | ObjectExpression(node) { | |
1057 | noop(sourceCode.getCommentsInside(node)[0].end); | |
1058 | }, | |
1059 | Decorator(node) { | |
1060 | noop(node.start); | |
1061 | } | |
1062 | }; | |
1063 | } | |
1064 | }; | |
1065 | ||
1066 | assert.throws(() => { | |
1067 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1068 | valid: ["foo(a, b)"], | |
1069 | invalid: [] | |
1070 | }); | |
1071 | }, "Use node.range[0] instead of node.start"); | |
1072 | assert.throws(() => { | |
1073 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1074 | valid: [], | |
1075 | invalid: [{ code: "var a = b * (c + d) / e;", errors: 1 }] | |
1076 | }); | |
1077 | }, "Use node.range[1] instead of node.end"); | |
1078 | assert.throws(() => { | |
1079 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1080 | valid: [], | |
1081 | invalid: [{ code: "var a = -b * c;", errors: 1 }] | |
1082 | }); | |
1083 | }, "Use token.range[0] instead of token.start"); | |
1084 | assert.throws(() => { | |
1085 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1086 | valid: ["var a = b ? c : d;"], | |
1087 | invalid: [] | |
1088 | }); | |
1089 | }, "Use token.range[1] instead of token.end"); | |
1090 | assert.throws(() => { | |
1091 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1092 | valid: ["function f() { /* comment */ }"], | |
1093 | invalid: [] | |
1094 | }); | |
1095 | }, "Use token.range[0] instead of token.start"); | |
1096 | assert.throws(() => { | |
1097 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1098 | valid: [], | |
1099 | invalid: [{ code: "var x = //\n {\n //comment\n //\n}", errors: 1 }] | |
1100 | }); | |
1101 | }, "Use token.range[1] instead of token.end"); | |
1102 | ||
1103 | const enhancedParserPath = require.resolve("../../fixtures/parsers/enhanced-parser"); | |
1104 | ||
1105 | assert.throws(() => { | |
1106 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1107 | valid: [{ code: "foo(a, b)", parser: enhancedParserPath }], | |
1108 | invalid: [] | |
1109 | }); | |
1110 | }, "Use node.range[0] instead of node.start"); | |
1111 | assert.throws(() => { | |
1112 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1113 | valid: [], | |
1114 | invalid: [{ code: "var a = b * (c + d) / e;", parser: enhancedParserPath, errors: 1 }] | |
1115 | }); | |
1116 | }, "Use node.range[1] instead of node.end"); | |
1117 | assert.throws(() => { | |
1118 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1119 | valid: [], | |
1120 | invalid: [{ code: "var a = -b * c;", parser: enhancedParserPath, errors: 1 }] | |
1121 | }); | |
1122 | }, "Use token.range[0] instead of token.start"); | |
1123 | assert.throws(() => { | |
1124 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1125 | valid: [{ code: "var a = b ? c : d;", parser: enhancedParserPath }], | |
1126 | invalid: [] | |
1127 | }); | |
1128 | }, "Use token.range[1] instead of token.end"); | |
1129 | assert.throws(() => { | |
1130 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1131 | valid: [{ code: "function f() { /* comment */ }", parser: enhancedParserPath }], | |
1132 | invalid: [] | |
1133 | }); | |
1134 | }, "Use token.range[0] instead of token.start"); | |
1135 | assert.throws(() => { | |
1136 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1137 | valid: [], | |
1138 | invalid: [{ code: "var x = //\n {\n //comment\n //\n}", parser: enhancedParserPath, errors: 1 }] | |
1139 | }); | |
1140 | }, "Use token.range[1] instead of token.end"); | |
1141 | ||
1142 | assert.throws(() => { | |
1143 | ruleTester.run("uses-start-end", usesStartEndRule, { | |
1144 | valid: [{ code: "@foo class A {}", parser: require.resolve("../../fixtures/parsers/enhanced-parser2") }], | |
1145 | invalid: [] | |
1146 | }); | |
1147 | }, "Use node.range[0] instead of node.start"); | |
1148 | }); | |
1149 | ||
1150 | it("should throw an error if no test scenarios given", () => { | |
1151 | assert.throws(() => { | |
1152 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-last")); | |
1153 | }, "Test Scenarios for rule foo : Could not find test scenario object"); | |
1154 | }); | |
1155 | ||
1156 | it("should throw an error if no acceptable test scenario object is given", () => { | |
1157 | assert.throws(() => { | |
1158 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-last"), []); | |
1159 | }, "Test Scenarios for rule foo is invalid:\nCould not find any valid test scenarios\nCould not find any invalid test scenarios"); | |
1160 | assert.throws(() => { | |
1161 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-last"), ""); | |
1162 | }, "Test Scenarios for rule foo : Could not find test scenario object"); | |
1163 | assert.throws(() => { | |
1164 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-last"), 2); | |
1165 | }, "Test Scenarios for rule foo : Could not find test scenario object"); | |
1166 | assert.throws(() => { | |
1167 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-last"), {}); | |
1168 | }, "Test Scenarios for rule foo is invalid:\nCould not find any valid test scenarios\nCould not find any invalid test scenarios"); | |
1169 | assert.throws(() => { | |
1170 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-last"), { | |
1171 | valid: [] | |
1172 | }); | |
1173 | }, "Test Scenarios for rule foo is invalid:\nCould not find any invalid test scenarios"); | |
1174 | assert.throws(() => { | |
1175 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/modify-ast-at-last"), { | |
1176 | invalid: [] | |
1177 | }); | |
1178 | }, "Test Scenarios for rule foo is invalid:\nCould not find any valid test scenarios"); | |
1179 | }); | |
1180 | ||
1181 | // Nominal message/messageId use cases | |
1182 | it("should assert match if message provided in both test and result.", () => { | |
1183 | assert.throws(() => { | |
1184 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/messageId").withMessageOnly, { | |
1185 | valid: [], | |
1186 | invalid: [{ code: "foo", errors: [{ message: "something" }] }] | |
1187 | }); | |
1188 | }, /Avoid using variables named/u); | |
1189 | ||
1190 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/messageId").withMessageOnly, { | |
1191 | valid: [], | |
1192 | invalid: [{ code: "foo", errors: [{ message: "Avoid using variables named 'foo'." }] }] | |
1193 | }); | |
1194 | }); | |
1195 | ||
1196 | it("should assert match between messageId if provided in both test and result.", () => { | |
1197 | assert.throws(() => { | |
1198 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/messageId").withMetaWithData, { | |
1199 | valid: [], | |
1200 | invalid: [{ code: "foo", errors: [{ messageId: "unused" }] }] | |
1201 | }); | |
1202 | }, "messageId 'avoidFoo' does not match expected messageId 'unused'."); | |
1203 | ||
1204 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/messageId").withMetaWithData, { | |
1205 | valid: [], | |
1206 | invalid: [{ code: "foo", errors: [{ messageId: "avoidFoo" }] }] | |
1207 | }); | |
1208 | }); | |
1209 | it("should assert match between resulting message output if messageId and data provided in both test and result", () => { | |
1210 | assert.throws(() => { | |
1211 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/messageId").withMetaWithData, { | |
1212 | valid: [], | |
1213 | invalid: [{ code: "foo", errors: [{ messageId: "avoidFoo", data: { name: "notFoo" } }] }] | |
1214 | }); | |
1215 | }, "Hydrated message \"Avoid using variables named 'notFoo'.\" does not match \"Avoid using variables named 'foo'.\""); | |
1216 | }); | |
1217 | ||
1218 | // messageId/message misconfiguration cases | |
1219 | it("should throw if user tests for both message and messageId", () => { | |
1220 | assert.throws(() => { | |
1221 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/messageId").withMetaWithData, { | |
1222 | valid: [], | |
1223 | invalid: [{ code: "foo", errors: [{ message: "something", messageId: "avoidFoo" }] }] | |
1224 | }); | |
1225 | }, "Error should not specify both 'message' and a 'messageId'."); | |
1226 | }); | |
1227 | it("should throw if user tests for messageId but the rule doesn't use the messageId meta syntax.", () => { | |
1228 | assert.throws(() => { | |
1229 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/messageId").withMessageOnly, { | |
1230 | valid: [], | |
1231 | invalid: [{ code: "foo", errors: [{ messageId: "avoidFoo" }] }] | |
1232 | }); | |
1233 | }, "Error can not use 'messageId' if rule under test doesn't define 'meta.messages'"); | |
1234 | }); | |
1235 | it("should throw if user tests for messageId not listed in the rule's meta syntax.", () => { | |
1236 | assert.throws(() => { | |
1237 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/messageId").withMetaWithData, { | |
1238 | valid: [], | |
1239 | invalid: [{ code: "foo", errors: [{ messageId: "useFoo" }] }] | |
1240 | }); | |
1241 | }, /Invalid messageId 'useFoo'/u); | |
1242 | }); | |
1243 | it("should throw if data provided without messageId.", () => { | |
1244 | assert.throws(() => { | |
1245 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/messageId").withMetaWithData, { | |
1246 | valid: [], | |
1247 | invalid: [{ code: "foo", errors: [{ data: "something" }] }] | |
1248 | }); | |
1249 | }, "Error must specify 'messageId' if 'data' is used."); | |
1250 | }); | |
1251 | ||
6f036462 TL |
1252 | // fixable rules with or without `meta` property |
1253 | it("should not throw an error if a rule that has `meta.fixable` produces fixes", () => { | |
1254 | const replaceProgramWith5Rule = { | |
1255 | meta: { | |
1256 | fixable: "code" | |
1257 | }, | |
1258 | create(context) { | |
1259 | return { | |
1260 | Program(node) { | |
1261 | context.report({ node, message: "bad", fix: fixer => fixer.replaceText(node, "5") }); | |
1262 | } | |
1263 | }; | |
1264 | } | |
1265 | }; | |
1266 | ||
1267 | ruleTester.run("replaceProgramWith5", replaceProgramWith5Rule, { | |
1268 | valid: [], | |
1269 | invalid: [ | |
1270 | { code: "var foo = bar;", output: "5", errors: 1 } | |
1271 | ] | |
1272 | }); | |
1273 | }); | |
1274 | it("should throw an error if a new-format rule that doesn't have `meta` produces fixes", () => { | |
1275 | const replaceProgramWith5Rule = { | |
1276 | create(context) { | |
1277 | return { | |
1278 | Program(node) { | |
1279 | context.report({ node, message: "bad", fix: fixer => fixer.replaceText(node, "5") }); | |
1280 | } | |
1281 | }; | |
1282 | } | |
1283 | }; | |
1284 | ||
1285 | assert.throws(() => { | |
1286 | ruleTester.run("replaceProgramWith5", replaceProgramWith5Rule, { | |
1287 | valid: [], | |
1288 | invalid: [ | |
1289 | { code: "var foo = bar;", output: "5", errors: 1 } | |
1290 | ] | |
1291 | }); | |
1292 | }, "Fixable rules should export a `meta.fixable` property."); | |
1293 | }); | |
1294 | it("should throw an error if a legacy-format rule produces fixes", () => { | |
1295 | ||
1296 | /** | |
1297 | * Legacy-format rule (a function instead of an object with `create` method). | |
1298 | * @param {RuleContext} context The ESLint rule context object. | |
1299 | * @returns {Object} Listeners. | |
1300 | */ | |
1301 | function replaceProgramWith5Rule(context) { | |
1302 | return { | |
1303 | Program(node) { | |
1304 | context.report({ node, message: "bad", fix: fixer => fixer.replaceText(node, "5") }); | |
1305 | } | |
1306 | }; | |
1307 | } | |
1308 | ||
1309 | assert.throws(() => { | |
1310 | ruleTester.run("replaceProgramWith5", replaceProgramWith5Rule, { | |
1311 | valid: [], | |
1312 | invalid: [ | |
1313 | { code: "var foo = bar;", output: "5", errors: 1 } | |
1314 | ] | |
1315 | }); | |
1316 | }, "Fixable rules should export a `meta.fixable` property."); | |
1317 | }); | |
1318 | ||
eb39fafa DC |
1319 | describe("suggestions", () => { |
1320 | it("should pass with valid suggestions (tested using desc)", () => { | |
1321 | ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/suggestions").basic, { | |
1322 | valid: [ | |
1323 | "var boo;" | |
1324 | ], | |
1325 | invalid: [{ | |
1326 | code: "var foo;", | |
1327 | errors: [{ | |
1328 | suggestions: [{ | |
1329 | desc: "Rename identifier 'foo' to 'bar'", | |
1330 | output: "var bar;" | |
1331 | }] | |
1332 | }] | |
1333 | }] | |
1334 | }); | |
1335 | }); | |
1336 | ||
1337 | it("should pass with suggestions on multiple lines", () => { | |
1338 | ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/suggestions").basic, { | |
1339 | valid: [], | |
1340 | invalid: [ | |
1341 | { | |
1342 | code: "function foo() {\n var foo = 1;\n}", | |
1343 | errors: [{ | |
1344 | suggestions: [{ | |
1345 | desc: "Rename identifier 'foo' to 'bar'", | |
1346 | output: "function bar() {\n var foo = 1;\n}" | |
1347 | }] | |
1348 | }, { | |
1349 | suggestions: [{ | |
1350 | desc: "Rename identifier 'foo' to 'bar'", | |
1351 | output: "function foo() {\n var bar = 1;\n}" | |
1352 | }] | |
1353 | }] | |
1354 | } | |
1355 | ] | |
1356 | }); | |
1357 | }); | |
1358 | ||
1359 | it("should pass with valid suggestions (tested using messageIds)", () => { | |
1360 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1361 | valid: [], | |
1362 | invalid: [{ | |
1363 | code: "var foo;", | |
1364 | errors: [{ | |
1365 | suggestions: [{ | |
1366 | messageId: "renameFoo", | |
1367 | output: "var bar;" | |
1368 | }, { | |
1369 | messageId: "renameFoo", | |
1370 | output: "var baz;" | |
1371 | }] | |
1372 | }] | |
1373 | }] | |
1374 | }); | |
1375 | }); | |
1376 | ||
1377 | it("should pass with valid suggestions (one tested using messageIds, the other using desc)", () => { | |
1378 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1379 | valid: [], | |
1380 | invalid: [{ | |
1381 | code: "var foo;", | |
1382 | errors: [{ | |
1383 | suggestions: [{ | |
1384 | messageId: "renameFoo", | |
1385 | output: "var bar;" | |
1386 | }, { | |
1387 | desc: "Rename identifier 'foo' to 'baz'", | |
1388 | output: "var baz;" | |
1389 | }] | |
1390 | }] | |
1391 | }] | |
1392 | }); | |
1393 | }); | |
1394 | ||
1395 | it("should pass with valid suggestions (tested using both desc and messageIds for the same suggestion)", () => { | |
1396 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1397 | valid: [], | |
1398 | invalid: [{ | |
1399 | code: "var foo;", | |
1400 | errors: [{ | |
1401 | suggestions: [{ | |
1402 | desc: "Rename identifier 'foo' to 'bar'", | |
1403 | messageId: "renameFoo", | |
1404 | output: "var bar;" | |
1405 | }, { | |
1406 | desc: "Rename identifier 'foo' to 'baz'", | |
1407 | messageId: "renameFoo", | |
1408 | output: "var baz;" | |
1409 | }] | |
1410 | }] | |
1411 | }] | |
1412 | }); | |
1413 | }); | |
1414 | ||
1415 | it("should pass with valid suggestions (tested using only desc on a rule that utilizes meta.messages)", () => { | |
1416 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1417 | valid: [], | |
1418 | invalid: [{ | |
1419 | code: "var foo;", | |
1420 | errors: [{ | |
1421 | suggestions: [{ | |
1422 | desc: "Rename identifier 'foo' to 'bar'", | |
1423 | output: "var bar;" | |
1424 | }, { | |
1425 | desc: "Rename identifier 'foo' to 'baz'", | |
1426 | output: "var baz;" | |
1427 | }] | |
1428 | }] | |
1429 | }] | |
1430 | }); | |
1431 | }); | |
1432 | ||
1433 | it("should pass with valid suggestions (tested using messageIds and data)", () => { | |
1434 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1435 | valid: [], | |
1436 | invalid: [{ | |
1437 | code: "var foo;", | |
1438 | errors: [{ | |
1439 | suggestions: [{ | |
1440 | messageId: "renameFoo", | |
1441 | data: { newName: "bar" }, | |
1442 | output: "var bar;" | |
1443 | }, { | |
1444 | messageId: "renameFoo", | |
1445 | data: { newName: "baz" }, | |
1446 | output: "var baz;" | |
1447 | }] | |
1448 | }] | |
1449 | }] | |
1450 | }); | |
1451 | }); | |
1452 | ||
1453 | ||
1454 | it("should pass when tested using empty suggestion test objects if the array length is correct", () => { | |
1455 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1456 | valid: [], | |
1457 | invalid: [{ | |
1458 | code: "var foo;", | |
1459 | errors: [{ | |
1460 | suggestions: [{}, {}] | |
1461 | }] | |
1462 | }] | |
1463 | }); | |
1464 | }); | |
1465 | ||
1466 | it("should support explicitly expecting no suggestions", () => { | |
1467 | [void 0, null, false, []].forEach(suggestions => { | |
1468 | ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/no-eval"), { | |
1469 | valid: [], | |
1470 | invalid: [{ | |
1471 | code: "eval('var foo');", | |
1472 | errors: [{ | |
1473 | suggestions | |
1474 | }] | |
1475 | }] | |
1476 | }); | |
1477 | }); | |
1478 | }); | |
1479 | ||
1480 | it("should fail when expecting no suggestions and there are suggestions", () => { | |
1481 | [void 0, null, false, []].forEach(suggestions => { | |
1482 | assert.throws(() => { | |
1483 | ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/suggestions").basic, { | |
1484 | valid: [], | |
1485 | invalid: [{ | |
1486 | code: "var foo;", | |
1487 | errors: [{ | |
1488 | suggestions | |
1489 | }] | |
1490 | }] | |
1491 | }); | |
1492 | }, "Error should have no suggestions on error with message: \"Avoid using identifiers named 'foo'.\""); | |
1493 | }); | |
1494 | }); | |
1495 | ||
1496 | it("should fail when testing for suggestions that don't exist", () => { | |
1497 | assert.throws(() => { | |
1498 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
1499 | valid: [], | |
1500 | invalid: [{ | |
1501 | code: "var foo;", | |
1502 | errors: [{ | |
1503 | suggestions: [{ | |
1504 | messageId: "this-does-not-exist" | |
1505 | }] | |
1506 | }] | |
1507 | }] | |
1508 | }); | |
1509 | }, "Error should have an array of suggestions. Instead received \"undefined\" on error with message: \"Bad var.\""); | |
1510 | }); | |
1511 | ||
1512 | it("should fail when there are a different number of suggestions", () => { | |
1513 | assert.throws(() => { | |
1514 | ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/suggestions").basic, { | |
1515 | valid: [], | |
1516 | invalid: [{ | |
1517 | code: "var foo;", | |
1518 | errors: [{ | |
1519 | suggestions: [{ | |
1520 | desc: "Rename identifier 'foo' to 'bar'", | |
1521 | output: "var bar;" | |
1522 | }, { | |
1523 | desc: "Rename identifier 'foo' to 'baz'", | |
1524 | output: "var baz;" | |
1525 | }] | |
1526 | }] | |
1527 | }] | |
1528 | }); | |
1529 | }, "Error should have 2 suggestions. Instead found 1 suggestions"); | |
1530 | }); | |
1531 | ||
1532 | it("should throw if the suggestion description doesn't match", () => { | |
1533 | assert.throws(() => { | |
1534 | ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/suggestions").basic, { | |
1535 | valid: [], | |
1536 | invalid: [{ | |
1537 | code: "var foo;", | |
1538 | errors: [{ | |
1539 | suggestions: [{ | |
1540 | desc: "not right", | |
1541 | output: "var baz;" | |
1542 | }] | |
1543 | }] | |
1544 | }] | |
1545 | }); | |
1546 | }, "Error Suggestion at index 0 : desc should be \"not right\" but got \"Rename identifier 'foo' to 'bar'\" instead."); | |
1547 | }); | |
1548 | ||
1549 | it("should throw if the suggestion description doesn't match (although messageIds match)", () => { | |
1550 | assert.throws(() => { | |
1551 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1552 | valid: [], | |
1553 | invalid: [{ | |
1554 | code: "var foo;", | |
1555 | errors: [{ | |
1556 | suggestions: [{ | |
1557 | desc: "Rename identifier 'foo' to 'bar'", | |
1558 | messageId: "renameFoo", | |
1559 | output: "var bar;" | |
1560 | }, { | |
1561 | desc: "Rename id 'foo' to 'baz'", | |
1562 | messageId: "renameFoo", | |
1563 | output: "var baz;" | |
1564 | }] | |
1565 | }] | |
1566 | }] | |
1567 | }); | |
1568 | }, "Error Suggestion at index 1 : desc should be \"Rename id 'foo' to 'baz'\" but got \"Rename identifier 'foo' to 'baz'\" instead."); | |
1569 | }); | |
1570 | ||
1571 | it("should throw if the suggestion messageId doesn't match", () => { | |
1572 | assert.throws(() => { | |
1573 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1574 | valid: [], | |
1575 | invalid: [{ | |
1576 | code: "var foo;", | |
1577 | errors: [{ | |
1578 | suggestions: [{ | |
1579 | messageId: "unused", | |
1580 | output: "var bar;" | |
1581 | }, { | |
1582 | messageId: "renameFoo", | |
1583 | output: "var baz;" | |
1584 | }] | |
1585 | }] | |
1586 | }] | |
1587 | }); | |
1588 | }, "Error Suggestion at index 0 : messageId should be 'unused' but got 'renameFoo' instead."); | |
1589 | }); | |
1590 | ||
1591 | it("should throw if the suggestion messageId doesn't match (although descriptions match)", () => { | |
1592 | assert.throws(() => { | |
1593 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1594 | valid: [], | |
1595 | invalid: [{ | |
1596 | code: "var foo;", | |
1597 | errors: [{ | |
1598 | suggestions: [{ | |
1599 | desc: "Rename identifier 'foo' to 'bar'", | |
1600 | messageId: "renameFoo", | |
1601 | output: "var bar;" | |
1602 | }, { | |
1603 | desc: "Rename identifier 'foo' to 'baz'", | |
1604 | messageId: "avoidFoo", | |
1605 | output: "var baz;" | |
1606 | }] | |
1607 | }] | |
1608 | }] | |
1609 | }); | |
1610 | }, "Error Suggestion at index 1 : messageId should be 'avoidFoo' but got 'renameFoo' instead."); | |
1611 | }); | |
1612 | ||
1613 | it("should throw if test specifies messageId for a rule that doesn't have meta.messages", () => { | |
1614 | assert.throws(() => { | |
1615 | ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/suggestions").basic, { | |
1616 | valid: [], | |
1617 | invalid: [{ | |
1618 | code: "var foo;", | |
1619 | errors: [{ | |
1620 | suggestions: [{ | |
1621 | messageId: "renameFoo", | |
1622 | output: "var bar;" | |
1623 | }] | |
1624 | }] | |
1625 | }] | |
1626 | }); | |
1627 | }, "Error Suggestion at index 0 : Test can not use 'messageId' if rule under test doesn't define 'meta.messages'."); | |
1628 | }); | |
1629 | ||
1630 | it("should throw if test specifies messageId that doesn't exist in the rule's meta.messages", () => { | |
1631 | assert.throws(() => { | |
1632 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1633 | valid: [], | |
1634 | invalid: [{ | |
1635 | code: "var foo;", | |
1636 | errors: [{ | |
1637 | suggestions: [{ | |
1638 | messageId: "renameFoo", | |
1639 | output: "var bar;" | |
1640 | }, { | |
1641 | messageId: "removeFoo", | |
1642 | output: "var baz;" | |
1643 | }] | |
1644 | }] | |
1645 | }] | |
1646 | }); | |
1647 | }, "Error Suggestion at index 1 : Test has invalid messageId 'removeFoo', the rule under test allows only one of ['avoidFoo', 'unused', 'renameFoo']."); | |
1648 | }); | |
1649 | ||
1650 | it("should throw if hydrated desc doesn't match (wrong data value)", () => { | |
1651 | assert.throws(() => { | |
1652 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1653 | valid: [], | |
1654 | invalid: [{ | |
1655 | code: "var foo;", | |
1656 | errors: [{ | |
1657 | suggestions: [{ | |
1658 | messageId: "renameFoo", | |
1659 | data: { newName: "car" }, | |
1660 | output: "var bar;" | |
1661 | }, { | |
1662 | messageId: "renameFoo", | |
1663 | data: { newName: "baz" }, | |
1664 | output: "var baz;" | |
1665 | }] | |
1666 | }] | |
1667 | }] | |
1668 | }); | |
1669 | }, "Error Suggestion at index 0 : Hydrated test desc \"Rename identifier 'foo' to 'car'\" does not match received desc \"Rename identifier 'foo' to 'bar'\"."); | |
1670 | }); | |
1671 | ||
1672 | it("should throw if hydrated desc doesn't match (wrong data key)", () => { | |
1673 | assert.throws(() => { | |
1674 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1675 | valid: [], | |
1676 | invalid: [{ | |
1677 | code: "var foo;", | |
1678 | errors: [{ | |
1679 | suggestions: [{ | |
1680 | messageId: "renameFoo", | |
1681 | data: { newName: "bar" }, | |
1682 | output: "var bar;" | |
1683 | }, { | |
1684 | messageId: "renameFoo", | |
1685 | data: { name: "baz" }, | |
1686 | output: "var baz;" | |
1687 | }] | |
1688 | }] | |
1689 | }] | |
1690 | }); | |
1691 | }, "Error Suggestion at index 1 : Hydrated test desc \"Rename identifier 'foo' to '{{ newName }}'\" does not match received desc \"Rename identifier 'foo' to 'baz'\"."); | |
1692 | }); | |
1693 | ||
1694 | it("should throw if test specifies both desc and data", () => { | |
1695 | assert.throws(() => { | |
1696 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1697 | valid: [], | |
1698 | invalid: [{ | |
1699 | code: "var foo;", | |
1700 | errors: [{ | |
1701 | suggestions: [{ | |
1702 | desc: "Rename identifier 'foo' to 'bar'", | |
1703 | messageId: "renameFoo", | |
1704 | data: { newName: "bar" }, | |
1705 | output: "var bar;" | |
1706 | }, { | |
1707 | messageId: "renameFoo", | |
1708 | data: { newName: "baz" }, | |
1709 | output: "var baz;" | |
1710 | }] | |
1711 | }] | |
1712 | }] | |
1713 | }); | |
1714 | }, "Error Suggestion at index 0 : Test should not specify both 'desc' and 'data'."); | |
1715 | }); | |
1716 | ||
1717 | it("should throw if test uses data but doesn't specify messageId", () => { | |
1718 | assert.throws(() => { | |
1719 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1720 | valid: [], | |
1721 | invalid: [{ | |
1722 | code: "var foo;", | |
1723 | errors: [{ | |
1724 | suggestions: [{ | |
1725 | messageId: "renameFoo", | |
1726 | data: { newName: "bar" }, | |
1727 | output: "var bar;" | |
1728 | }, { | |
1729 | data: { newName: "baz" }, | |
1730 | output: "var baz;" | |
1731 | }] | |
1732 | }] | |
1733 | }] | |
1734 | }); | |
1735 | }, "Error Suggestion at index 1 : Test must specify 'messageId' if 'data' is used."); | |
1736 | }); | |
1737 | ||
1738 | it("should throw if the resulting suggestion output doesn't match", () => { | |
1739 | assert.throws(() => { | |
1740 | ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/suggestions").basic, { | |
1741 | valid: [], | |
1742 | invalid: [{ | |
1743 | code: "var foo;", | |
1744 | errors: [{ | |
1745 | suggestions: [{ | |
1746 | desc: "Rename identifier 'foo' to 'bar'", | |
1747 | output: "var baz;" | |
1748 | }] | |
1749 | }] | |
1750 | }] | |
1751 | }); | |
1752 | }, "Expected the applied suggestion fix to match the test suggestion output"); | |
1753 | }); | |
1754 | ||
1755 | it("should fail when specified suggestion isn't an object", () => { | |
1756 | assert.throws(() => { | |
1757 | ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/suggestions").basic, { | |
1758 | valid: [], | |
1759 | invalid: [{ | |
1760 | code: "var foo;", | |
1761 | errors: [{ | |
1762 | suggestions: [null] | |
1763 | }] | |
1764 | }] | |
1765 | }); | |
1766 | }, "Test suggestion in 'suggestions' array must be an object."); | |
1767 | ||
1768 | assert.throws(() => { | |
1769 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1770 | valid: [], | |
1771 | invalid: [{ | |
1772 | code: "var foo;", | |
1773 | errors: [{ | |
1774 | suggestions: [ | |
1775 | { | |
1776 | messageId: "renameFoo", | |
1777 | output: "var bar;" | |
1778 | }, | |
1779 | "Rename identifier 'foo' to 'baz'" | |
1780 | ] | |
1781 | }] | |
1782 | }] | |
1783 | }); | |
1784 | }, "Test suggestion in 'suggestions' array must be an object."); | |
1785 | }); | |
1786 | ||
1787 | it("should fail when the suggestion is an object with an unknown property name", () => { | |
1788 | assert.throws(() => { | |
1789 | ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/suggestions").basic, { | |
1790 | valid: [ | |
1791 | "var boo;" | |
1792 | ], | |
1793 | invalid: [{ | |
1794 | code: "var foo;", | |
1795 | errors: [{ | |
1796 | suggestions: [{ | |
1797 | message: "Rename identifier 'foo' to 'bar'" | |
1798 | }] | |
1799 | }] | |
1800 | }] | |
1801 | }); | |
1802 | }, /Invalid suggestion property name 'message'/u); | |
1803 | }); | |
1804 | ||
1805 | it("should fail when any of the suggestions is an object with an unknown property name", () => { | |
1806 | assert.throws(() => { | |
1807 | ruleTester.run("suggestions-messageIds", require("../../fixtures/testers/rule-tester/suggestions").withMessageIds, { | |
1808 | valid: [], | |
1809 | invalid: [{ | |
1810 | code: "var foo;", | |
1811 | errors: [{ | |
1812 | suggestions: [{ | |
1813 | messageId: "renameFoo", | |
1814 | output: "var bar;" | |
1815 | }, { | |
1816 | messageId: "renameFoo", | |
1817 | outpt: "var baz;" | |
1818 | }] | |
1819 | }] | |
1820 | }] | |
1821 | }); | |
1822 | }, /Invalid suggestion property name 'outpt'/u); | |
1823 | }); | |
1824 | }); | |
1825 | ||
1826 | describe("naming test cases", () => { | |
1827 | ||
1828 | /** | |
1829 | * Asserts that a particular value will be emitted from an EventEmitter. | |
1830 | * @param {EventEmitter} emitter The emitter that should emit a value | |
1831 | * @param {string} emitType The type of emission to listen for | |
1832 | * @param {*} expectedValue The value that should be emitted | |
1833 | * @returns {Promise} A Promise that fulfills if the value is emitted, and rejects if something else is emitted. | |
1834 | * The Promise will be indefinitely pending if no value is emitted. | |
1835 | */ | |
1836 | function assertEmitted(emitter, emitType, expectedValue) { | |
1837 | return new Promise((resolve, reject) => { | |
1838 | emitter.once(emitType, emittedValue => { | |
1839 | if (emittedValue === expectedValue) { | |
1840 | resolve(); | |
1841 | } else { | |
1842 | reject(new Error(`Expected ${expectedValue} to be emitted but ${emittedValue} was emitted instead.`)); | |
1843 | } | |
1844 | }); | |
1845 | }); | |
1846 | } | |
1847 | ||
1848 | it("should use the first argument as the name of the test suite", () => { | |
1849 | const assertion = assertEmitted(ruleTesterTestEmitter, "describe", "this-is-a-rule-name"); | |
1850 | ||
1851 | ruleTester.run("this-is-a-rule-name", require("../../fixtures/testers/rule-tester/no-var"), { | |
1852 | valid: [], | |
1853 | invalid: [] | |
1854 | }); | |
1855 | ||
1856 | return assertion; | |
1857 | }); | |
1858 | ||
1859 | it("should use the test code as the name of the tests for valid code (string form)", () => { | |
1860 | const assertion = assertEmitted(ruleTesterTestEmitter, "it", "valid(code);"); | |
1861 | ||
1862 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/no-var"), { | |
1863 | valid: [ | |
1864 | "valid(code);" | |
1865 | ], | |
1866 | invalid: [] | |
1867 | }); | |
1868 | ||
1869 | return assertion; | |
1870 | }); | |
1871 | ||
1872 | it("should use the test code as the name of the tests for valid code (object form)", () => { | |
1873 | const assertion = assertEmitted(ruleTesterTestEmitter, "it", "valid(code);"); | |
1874 | ||
1875 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/no-var"), { | |
1876 | valid: [ | |
1877 | { | |
1878 | code: "valid(code);" | |
1879 | } | |
1880 | ], | |
1881 | invalid: [] | |
1882 | }); | |
1883 | ||
1884 | return assertion; | |
1885 | }); | |
1886 | ||
1887 | it("should use the test code as the name of the tests for invalid code", () => { | |
1888 | const assertion = assertEmitted(ruleTesterTestEmitter, "it", "var x = invalid(code);"); | |
1889 | ||
1890 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/no-var"), { | |
1891 | valid: [], | |
1892 | invalid: [ | |
1893 | { | |
1894 | code: "var x = invalid(code);", | |
1895 | output: " x = invalid(code);", | |
1896 | errors: 1 | |
1897 | } | |
1898 | ] | |
1899 | }); | |
1900 | ||
1901 | return assertion; | |
1902 | }); | |
1903 | ||
1904 | // https://github.com/eslint/eslint/issues/8142 | |
1905 | it("should use the empty string as the name of the test if the test case is an empty string", () => { | |
1906 | const assertion = assertEmitted(ruleTesterTestEmitter, "it", ""); | |
1907 | ||
1908 | ruleTester.run("foo", require("../../fixtures/testers/rule-tester/no-var"), { | |
1909 | valid: [ | |
1910 | { | |
1911 | code: "" | |
1912 | } | |
1913 | ], | |
1914 | invalid: [] | |
1915 | }); | |
1916 | ||
1917 | return assertion; | |
1918 | }); | |
1919 | }); | |
1920 | ||
1921 | // https://github.com/eslint/eslint/issues/11615 | |
1922 | it("should fail the case if autofix made a syntax error.", () => { | |
1923 | assert.throw(() => { | |
1924 | ruleTester.run( | |
1925 | "foo", | |
1926 | context => ({ | |
1927 | Identifier(node) { | |
1928 | context.report({ | |
1929 | node, | |
1930 | message: "make a syntax error", | |
1931 | fix(fixer) { | |
1932 | return fixer.replaceText(node, "one two"); | |
1933 | } | |
1934 | }); | |
1935 | } | |
1936 | }), | |
1937 | { | |
1938 | valid: ["one()"], | |
1939 | invalid: [] | |
1940 | } | |
1941 | ); | |
56c4a2cb | 1942 | }, /A fatal parsing error occurred in autofix.\nError: .+\nAutofix output:\n.+/u); |
eb39fafa DC |
1943 | }); |
1944 | ||
1945 | describe("sanitize test cases", () => { | |
1946 | let originalRuleTesterIt; | |
1947 | let spyRuleTesterIt; | |
1948 | ||
1949 | before(() => { | |
1950 | originalRuleTesterIt = RuleTester.it; | |
1951 | spyRuleTesterIt = sinon.spy(); | |
1952 | RuleTester.it = spyRuleTesterIt; | |
1953 | }); | |
1954 | after(() => { | |
1955 | RuleTester.it = originalRuleTesterIt; | |
1956 | }); | |
1957 | beforeEach(() => { | |
1958 | spyRuleTesterIt.resetHistory(); | |
1959 | ruleTester = new RuleTester(); | |
1960 | }); | |
1961 | it("should present newline when using back-tick as new line", () => { | |
1962 | const code = ` | |
1963 | var foo = bar;`; | |
1964 | ||
1965 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
1966 | valid: [], | |
1967 | invalid: [ | |
1968 | { | |
1969 | code, | |
1970 | errors: [/^Bad var/u] | |
1971 | } | |
1972 | ] | |
1973 | }); | |
1974 | sinon.assert.calledWith(spyRuleTesterIt, code); | |
1975 | }); | |
1976 | it("should present \\u0000 as a string", () => { | |
1977 | const code = "\u0000"; | |
1978 | ||
1979 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
1980 | valid: [], | |
1981 | invalid: [ | |
1982 | { | |
1983 | code, | |
1984 | errors: [/^Bad var/u] | |
1985 | } | |
1986 | ] | |
1987 | }); | |
1988 | sinon.assert.calledWith(spyRuleTesterIt, "\\u0000"); | |
1989 | }); | |
1990 | it("should present the pipe character correctly", () => { | |
1991 | const code = "var foo = bar || baz;"; | |
1992 | ||
1993 | ruleTester.run("no-var", require("../../fixtures/testers/rule-tester/no-var"), { | |
1994 | valid: [], | |
1995 | invalid: [ | |
1996 | { | |
1997 | code, | |
1998 | errors: [/^Bad var/u] | |
1999 | } | |
2000 | ] | |
2001 | }); | |
2002 | sinon.assert.calledWith(spyRuleTesterIt, code); | |
2003 | }); | |
2004 | ||
2005 | }); | |
6f036462 | 2006 | |
eb39fafa | 2007 | }); |