]> git.proxmox.com Git - pve-eslint.git/blob - eslint/tests/lib/cli-engine/formatters/codeframe.js
first commit
[pve-eslint.git] / eslint / tests / lib / cli-engine / formatters / codeframe.js
1 /**
2 * @fileoverview Tests for codeframe reporter.
3 * @author Vitor Balocco
4 */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const assert = require("chai").assert;
13 const sinon = require("sinon");
14 const proxyquire = require("proxyquire");
15 const chalk = require("chalk");
16 const path = require("path");
17 const stripAnsi = require("strip-ansi");
18
19 // Chalk protects its methods so we need to inherit from it for Sinon to work.
20 const chalkStub = Object.create(chalk, {
21 yellow: {
22 value(str) {
23 return chalk.yellow(str);
24 },
25 writable: true
26 },
27 red: {
28 value(str) {
29 return chalk.red(str);
30 },
31 writable: true
32 }
33 });
34
35 chalkStub.yellow.bold = chalk.yellow.bold;
36 chalkStub.red.bold = chalk.red.bold;
37
38 const formatter = proxyquire("../../../../lib/cli-engine/formatters/codeframe", { chalk: chalkStub });
39
40 //------------------------------------------------------------------------------
41 // Tests
42 //------------------------------------------------------------------------------
43
44 describe("formatter:codeframe", () => {
45 afterEach(() => {
46 sinon.verifyAndRestore();
47 });
48
49 describe("when passed no messages", () => {
50 const code = [{
51 filePath: "foo.js",
52 messages: [],
53 errorCount: 0,
54 warningCount: 0
55 }];
56
57 it("should return nothing", () => {
58 const result = formatter(code);
59
60 assert.strictEqual(result, "");
61 });
62 });
63
64 describe("when passed a single warning message", () => {
65 const code = [{
66 filePath: path.join(process.cwd(), "lib", "foo.js"),
67 source: "var foo = 1;\n var bar = 2;\n",
68 messages: [{
69 message: "Unexpected foo.",
70 severity: 1,
71 line: 1,
72 column: 5,
73 ruleId: "foo"
74 }],
75 errorCount: 0,
76 warningCount: 1,
77 fixableErrorCount: 0,
78 fixableWarningCount: 0
79 }];
80
81 it("should return a string in the correct format for warnings", () => {
82 const result = formatter(code);
83
84 assert.strictEqual(stripAnsi(result), [
85 `warning: Unexpected foo (foo) at ${path.join("lib", "foo.js")}:1:5:`,
86 "> 1 | var foo = 1;",
87 " | ^",
88 " 2 | var bar = 2;",
89 " 3 | ",
90 "\n",
91 "1 warning found."
92 ].join("\n"));
93 });
94
95 it("should return bold yellow summary when there are only warnings", () => {
96 sinon.spy(chalkStub.yellow, "bold");
97 sinon.spy(chalkStub.red, "bold");
98
99 formatter(code);
100
101 assert.strictEqual(chalkStub.yellow.bold.callCount, 1);
102 assert.strictEqual(chalkStub.red.bold.callCount, 0);
103 });
104
105 describe("when the warning is fixable", () => {
106 beforeEach(() => {
107 code[0].fixableWarningCount = 1;
108 });
109
110 it("should return a string in the correct format", () => {
111 const result = formatter(code);
112
113 assert.strictEqual(stripAnsi(result), [
114 `warning: Unexpected foo (foo) at ${path.join("lib", "foo.js")}:1:5:`,
115 "> 1 | var foo = 1;",
116 " | ^",
117 " 2 | var bar = 2;",
118 " 3 | ",
119 "\n",
120 "1 warning found.",
121 "1 warning potentially fixable with the `--fix` option."
122 ].join("\n"));
123 });
124 });
125 });
126
127 describe("when passed a single error message", () => {
128 const code = [{
129 filePath: path.join(process.cwd(), "lib", "foo.js"),
130 source: "var foo = 1;\n var bar = 2;\n",
131 messages: [{
132 message: "Unexpected foo.",
133 severity: 2,
134 line: 1,
135 column: 5,
136 ruleId: "foo"
137 }],
138 errorCount: 1,
139 warningCount: 0
140 }];
141
142 it("should return a string in the correct format for errors", () => {
143 const result = formatter(code);
144
145 assert.strictEqual(stripAnsi(result), [
146 `error: Unexpected foo (foo) at ${path.join("lib", "foo.js")}:1:5:`,
147 "> 1 | var foo = 1;",
148 " | ^",
149 " 2 | var bar = 2;",
150 " 3 | ",
151 "\n",
152 "1 error found."
153 ].join("\n"));
154 });
155
156 it("should return bold red summary when there are errors", () => {
157 sinon.spy(chalkStub.yellow, "bold");
158 sinon.spy(chalkStub.red, "bold");
159
160 formatter(code);
161
162 assert.strictEqual(chalkStub.yellow.bold.callCount, 0);
163 assert.strictEqual(chalkStub.red.bold.callCount, 1);
164 });
165 });
166
167 describe("when passed a message that ends with ' .'", () => {
168 const code = [{
169 filePath: "foo.js",
170 messages: [{
171 ruleId: "foo",
172 message: "Unexpected .",
173 severity: 2,
174 source: "foo"
175 }],
176 errorCount: 1,
177 warningCount: 0
178 }];
179
180 it("should return a string in the correct format (retaining the ' .')", () => {
181 const result = formatter(code);
182
183 assert.strictEqual(stripAnsi(result), "error: Unexpected . (foo) at foo.js\n\n\n1 error found.");
184 });
185 });
186
187 describe("when passed multiple messages", () => {
188 const code = [{
189 filePath: "foo.js",
190 source: "const foo = 1\n",
191 messages: [{
192 message: "Missing semicolon.",
193 severity: 2,
194 line: 1,
195 column: 14,
196 ruleId: "semi"
197 }, {
198 message: "'foo' is assigned a value but never used.",
199 severity: 2,
200 line: 1,
201 column: 7,
202 ruleId: "no-unused-vars"
203 }],
204 errorCount: 2,
205 warningCount: 0
206 }];
207
208 it("should return a string with multiple entries", () => {
209 const result = formatter(code);
210
211 assert.strictEqual(stripAnsi(result), [
212 "error: Missing semicolon (semi) at foo.js:1:14:",
213 "> 1 | const foo = 1",
214 " | ^",
215 " 2 | ",
216 "\n",
217 "error: 'foo' is assigned a value but never used (no-unused-vars) at foo.js:1:7:",
218 "> 1 | const foo = 1",
219 " | ^",
220 " 2 | ",
221 "\n",
222 "2 errors found."
223 ].join("\n"));
224 });
225
226 it("should return bold red summary when at least 1 of the messages is an error", () => {
227 sinon.spy(chalkStub.yellow, "bold");
228 sinon.spy(chalkStub.red, "bold");
229 code[0].messages[0].severity = 1;
230 code[0].warningCount = 1;
231 code[0].errorCount = 1;
232
233 formatter(code);
234
235 assert.strictEqual(chalkStub.yellow.bold.callCount, 0);
236 assert.strictEqual(chalkStub.red.bold.callCount, 1);
237 });
238 });
239
240 describe("when passed one file with 1 message and fixes applied", () => {
241 const code = [{
242 filePath: "foo.js",
243 messages: [{
244 ruleId: "no-unused-vars",
245 severity: 2,
246 message: "'foo' is assigned a value but never used.",
247 line: 4,
248 column: 11,
249 source: " const foo = 1;"
250 }],
251 errorCount: 1,
252 warningCount: 0,
253 output: "function foo() {\n\n // a comment\n const foo = 1;\n}\n\n"
254 }];
255
256 it("should return a string with code preview pointing to the correct location after fixes", () => {
257 const result = formatter(code);
258
259 assert.strictEqual(stripAnsi(result), [
260 "error: 'foo' is assigned a value but never used (no-unused-vars) at foo.js:4:11:",
261 " 2 | ",
262 " 3 | // a comment",
263 "> 4 | const foo = 1;",
264 " | ^",
265 " 5 | }",
266 " 6 | ",
267 " 7 | ",
268 "\n",
269 "1 error found."
270 ].join("\n"));
271 });
272 });
273
274 describe("when passed multiple files with 1 message each", () => {
275 const code = [{
276 filePath: "foo.js",
277 source: "const foo = 1\n",
278 messages: [{
279 message: "Missing semicolon.",
280 severity: 2,
281 line: 1,
282 column: 14,
283 ruleId: "semi"
284 }],
285 errorCount: 1,
286 warningCount: 0
287 }, {
288 filePath: "bar.js",
289 source: "const bar = 2\n",
290 messages: [{
291 message: "Missing semicolon.",
292 severity: 2,
293 line: 1,
294 column: 14,
295 ruleId: "semi"
296 }],
297 errorCount: 1,
298 warningCount: 0
299 }];
300
301 it("should return a string with multiple entries", () => {
302 const result = formatter(code);
303
304 assert.strictEqual(stripAnsi(result), [
305 "error: Missing semicolon (semi) at foo.js:1:14:",
306 "> 1 | const foo = 1",
307 " | ^",
308 " 2 | ",
309 "\n",
310 "error: Missing semicolon (semi) at bar.js:1:14:",
311 "> 1 | const bar = 2",
312 " | ^",
313 " 2 | ",
314 "\n",
315 "2 errors found."
316 ].join("\n"));
317 });
318 });
319
320 describe("when passed a fatal error message", () => {
321 const code = [{
322 filePath: "foo.js",
323 source: "e{}\n",
324 messages: [{
325 ruleId: null,
326 fatal: true,
327 severity: 2,
328 source: "e{}",
329 message: "Parsing error: Unexpected token {",
330 line: 1,
331 column: 2
332 }],
333 errorCount: 1,
334 warningCount: 0
335 }];
336
337 it("should return a string in the correct format", () => {
338 const result = formatter(code);
339
340 assert.strictEqual(stripAnsi(result), [
341 "error: Parsing error: Unexpected token { at foo.js:1:2:",
342 "> 1 | e{}",
343 " | ^",
344 " 2 | ",
345 "\n",
346 "1 error found."
347 ].join("\n"));
348 });
349 });
350
351 describe("when passed one file not found message", () => {
352 const code = [{
353 filePath: "foo.js",
354 messages: [{
355 fatal: true,
356 message: "Couldn't find foo.js."
357 }],
358 errorCount: 1,
359 warningCount: 0
360 }];
361
362 it("should return a string without code preview (codeframe)", () => {
363 const result = formatter(code);
364
365 assert.strictEqual(stripAnsi(result), "error: Couldn't find foo.js at foo.js\n\n\n1 error found.");
366 });
367 });
368
369 describe("when passed a single message with no line or column", () => {
370 const code = [{
371 filePath: "foo.js",
372 messages: [{
373 ruleId: "foo",
374 message: "Unexpected foo.",
375 severity: 2,
376 source: "foo"
377 }],
378 errorCount: 1,
379 warningCount: 0
380 }];
381
382 it("should return a string without code preview (codeframe)", () => {
383 const result = formatter(code);
384
385 assert.strictEqual(stripAnsi(result), "error: Unexpected foo (foo) at foo.js\n\n\n1 error found.");
386 });
387
388 it("should output filepath but without 'line:column' appended", () => {
389 const result = formatter(code);
390
391 assert.strictEqual(stripAnsi(result), "error: Unexpected foo (foo) at foo.js\n\n\n1 error found.");
392 });
393 });
394
395
396 describe("fixable problems", () => {
397 it("should not output fixable problems message when no errors or warnings are fixable", () => {
398 const code = [{
399 filePath: "foo.js",
400 errorCount: 1,
401 warningCount: 0,
402 fixableErrorCount: 0,
403 fixableWarningCount: 0,
404 messages: [{
405 message: "Unexpected foo.",
406 severity: 2,
407 line: 5,
408 column: 10,
409 ruleId: "foo"
410 }]
411 }];
412
413 const result = formatter(code);
414
415 assert.notInclude(result, "potentially fixable");
416 });
417
418 it("should output the fixable problems message when errors are fixable", () => {
419 const code = [{
420 filePath: "foo.js",
421 errorCount: 1,
422 warningCount: 0,
423 fixableErrorCount: 1,
424 fixableWarningCount: 0,
425 messages: [{
426 message: "Unexpected foo.",
427 severity: 2,
428 line: 5,
429 column: 10,
430 ruleId: "foo"
431 }]
432 }];
433
434 const result = formatter(code);
435
436 assert.include(result, "1 error potentially fixable with the `--fix` option.");
437 });
438
439 it("should output fixable problems message when warnings are fixable", () => {
440 const code = [{
441 filePath: "foo.js",
442 errorCount: 0,
443 warningCount: 3,
444 fixableErrorCount: 0,
445 fixableWarningCount: 2,
446 messages: [{
447 message: "Unexpected foo."
448 }]
449 }];
450
451 const result = formatter(code);
452
453 assert.include(result, "2 warnings potentially fixable with the `--fix` option.");
454 });
455
456 it("should output the total number of fixable errors and warnings", () => {
457 const code = [{
458 filePath: "foo.js",
459 errorCount: 5,
460 warningCount: 3,
461 fixableErrorCount: 5,
462 fixableWarningCount: 2,
463 messages: [{
464 message: "Unexpected foo."
465 }]
466 }, {
467 filePath: "bar.js",
468 errorCount: 4,
469 warningCount: 2,
470 fixableErrorCount: 4,
471 fixableWarningCount: 1,
472 messages: [{
473 message: "Unexpected bar."
474 }]
475 }];
476
477 const result = formatter(code);
478
479 assert.include(result, "9 errors and 3 warnings potentially fixable with the `--fix` option.");
480 });
481 });
482
483 });