]> git.proxmox.com Git - pve-eslint.git/blame - eslint/tests/lib/cli.js
change from CLIEngine to ESLint
[pve-eslint.git] / eslint / tests / lib / cli.js
CommitLineData
eb39fafa
DC
1/**
2 * @fileoverview Tests for cli.
3 * @author Ian Christian Myers
4 */
5
6"use strict";
7
8/*
56c4a2cb
DC
9 * NOTE: If you are adding new tests for cli.js, use verifyESLintOpts(). The
10 * test only needs to verify that ESLint receives the correct opts.
eb39fafa
DC
11 */
12
13//------------------------------------------------------------------------------
14// Requirements
15//------------------------------------------------------------------------------
16
17const assert = require("chai").assert,
56c4a2cb
DC
18 stdAssert = require("assert"),
19 { ESLint } = require("../../lib/eslint"),
20 BuiltinRules = require("../../lib/rules"),
eb39fafa
DC
21 path = require("path"),
22 sinon = require("sinon"),
23 fs = require("fs"),
24 os = require("os"),
25 sh = require("shelljs");
26
27const proxyquire = require("proxyquire").noCallThru().noPreserveCache();
28
29//------------------------------------------------------------------------------
30// Tests
31//------------------------------------------------------------------------------
32
33describe("cli", () => {
34 let fixtureDir;
35 const log = {
36 info: sinon.spy(),
37 error: sinon.spy()
38 };
39 const RuntimeInfo = {
40 environment: sinon.stub(),
41 version: sinon.stub()
42 };
43 const cli = proxyquire("../../lib/cli", {
44 "./shared/logging": log,
45 "./shared/runtime-info": RuntimeInfo
46 });
47
48 /**
56c4a2cb 49 * Verify that ESLint class receives correct opts via await cli.execute().
eb39fafa 50 * @param {string} cmd CLI command.
56c4a2cb 51 * @param {Object} opts Options hash that should match that received by ESLint class.
eb39fafa
DC
52 * @returns {void}
53 */
56c4a2cb 54 async function verifyESLintOpts(cmd, opts) {
eb39fafa 55
56c4a2cb
DC
56 // create a fake ESLint class to test with
57 const fakeESLint = sinon.mock().withExactArgs(sinon.match(opts));
eb39fafa 58
56c4a2cb
DC
59 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
60 sinon.stub(fakeESLint.prototype, "lintFiles").returns([]);
61 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: sinon.spy() });
eb39fafa
DC
62
63 const localCLI = proxyquire("../../lib/cli", {
56c4a2cb 64 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
65 "./shared/logging": log
66 });
67
56c4a2cb 68 await localCLI.execute(cmd);
eb39fafa
DC
69 sinon.verifyAndRestore();
70 }
71
56c4a2cb 72 // verifyESLintOpts
eb39fafa
DC
73
74 /**
75 * Returns the path inside of the fixture directory.
76 * @param {...string} args file path segments.
77 * @returns {string} The path inside the fixture directory.
78 * @private
79 */
80 function getFixturePath(...args) {
81 return path.join(fixtureDir, ...args);
82 }
83
84 // copy into clean area so as not to get "infected" by this project's .eslintrc files
6f036462
TL
85 before(function() {
86
87 /*
88 * GitHub Actions Windows and macOS runners occasionally exhibit
89 * extremely slow filesystem operations, during which copying fixtures
90 * exceeds the default test timeout, so raise it just for this hook.
91 * Mocha uses `this` to set timeouts on an individual hook level.
92 */
609c276f 93 this.timeout(60 * 1000); // eslint-disable-line no-invalid-this -- Mocha API
eb39fafa
DC
94 fixtureDir = `${os.tmpdir()}/eslint/fixtures`;
95 sh.mkdir("-p", fixtureDir);
96 sh.cp("-r", "./tests/fixtures/.", fixtureDir);
97 });
98
99 afterEach(() => {
100 log.info.resetHistory();
101 log.error.resetHistory();
102 });
103
104 after(() => {
105 sh.rm("-r", fixtureDir);
106 });
107
108 describe("execute()", () => {
56c4a2cb 109 it("should return error when text with incorrect quotes is passed as argument", async () => {
eb39fafa 110 const configFile = getFixturePath("configurations", "quotes-error.json");
56c4a2cb 111 const result = await cli.execute(`-c ${configFile}`, "var foo = 'bar';");
eb39fafa
DC
112
113 assert.strictEqual(result, 1);
114 });
115
56c4a2cb
DC
116 it("should not print debug info when passed the empty string as text", async () => {
117 const result = await cli.execute(["--stdin", "--no-eslintrc"], "");
eb39fafa
DC
118
119 assert.strictEqual(result, 0);
120 assert.isTrue(log.info.notCalled);
121 });
122
56c4a2cb 123 it("should return no error when --ext .js2 is specified", async () => {
eb39fafa 124 const filePath = getFixturePath("files");
56c4a2cb 125 const result = await cli.execute(`--ext .js2 ${filePath}`);
eb39fafa
DC
126
127 assert.strictEqual(result, 0);
128 });
129
56c4a2cb 130 it("should exit with console error when passed unsupported arguments", async () => {
eb39fafa 131 const filePath = getFixturePath("files");
56c4a2cb 132 const result = await cli.execute(`--blah --another ${filePath}`);
eb39fafa
DC
133
134 assert.strictEqual(result, 2);
135 });
136
137 });
138
139 describe("when given a config file", () => {
56c4a2cb 140 it("should load the specified config file", async () => {
eb39fafa
DC
141 const configPath = getFixturePath(".eslintrc");
142 const filePath = getFixturePath("passing.js");
143
56c4a2cb 144 await cli.execute(`--config ${configPath} ${filePath}`);
eb39fafa
DC
145 });
146 });
147
148 describe("when there is a local config file", () => {
149 const code = "lib/cli.js";
150
56c4a2cb 151 it("should load the local config file", async () => {
eb39fafa
DC
152
153 // Mock CWD
154 process.eslintCwd = getFixturePath("configurations", "single-quotes");
155
56c4a2cb 156 await cli.execute(code);
eb39fafa
DC
157
158 process.eslintCwd = null;
159 });
160 });
161
162 describe("when given a config with rules with options and severity level set to error", () => {
56c4a2cb 163 it("should exit with an error status (1)", async () => {
eb39fafa
DC
164 const configPath = getFixturePath("configurations", "quotes-error.json");
165 const filePath = getFixturePath("single-quoted.js");
166 const code = `--no-ignore --config ${configPath} ${filePath}`;
167
56c4a2cb 168 const exitStatus = await cli.execute(code);
eb39fafa
DC
169
170 assert.strictEqual(exitStatus, 1);
171 });
172 });
173
174 describe("when given a config file and a directory of files", () => {
56c4a2cb 175 it("should load and execute without error", async () => {
eb39fafa
DC
176 const configPath = getFixturePath("configurations", "semi-error.json");
177 const filePath = getFixturePath("formatters");
178 const code = `--config ${configPath} ${filePath}`;
179
56c4a2cb 180 const exitStatus = await cli.execute(code);
eb39fafa
DC
181
182 assert.strictEqual(exitStatus, 0);
183 });
184 });
185
186 describe("when given a config with environment set to browser", () => {
56c4a2cb 187 it("should execute without any errors", async () => {
eb39fafa
DC
188 const configPath = getFixturePath("configurations", "env-browser.json");
189 const filePath = getFixturePath("globals-browser.js");
190 const code = `--config ${configPath} ${filePath}`;
191
56c4a2cb 192 const exit = await cli.execute(code);
eb39fafa
DC
193
194 assert.strictEqual(exit, 0);
195 });
196 });
197
198 describe("when given a config with environment set to Node.js", () => {
56c4a2cb 199 it("should execute without any errors", async () => {
eb39fafa
DC
200 const configPath = getFixturePath("configurations", "env-node.json");
201 const filePath = getFixturePath("globals-node.js");
202 const code = `--config ${configPath} ${filePath}`;
203
56c4a2cb 204 const exit = await cli.execute(code);
eb39fafa
DC
205
206 assert.strictEqual(exit, 0);
207 });
208 });
209
210 describe("when given a config with environment set to Nashorn", () => {
56c4a2cb 211 it("should execute without any errors", async () => {
eb39fafa
DC
212 const configPath = getFixturePath("configurations", "env-nashorn.json");
213 const filePath = getFixturePath("globals-nashorn.js");
214 const code = `--config ${configPath} ${filePath}`;
215
56c4a2cb 216 const exit = await cli.execute(code);
eb39fafa
DC
217
218 assert.strictEqual(exit, 0);
219 });
220 });
221
222 describe("when given a config with environment set to WebExtensions", () => {
56c4a2cb 223 it("should execute without any errors", async () => {
eb39fafa
DC
224 const configPath = getFixturePath("configurations", "env-webextensions.json");
225 const filePath = getFixturePath("globals-webextensions.js");
226 const code = `--config ${configPath} ${filePath}`;
227
56c4a2cb 228 const exit = await cli.execute(code);
eb39fafa
DC
229
230 assert.strictEqual(exit, 0);
231 });
232 });
233
234 describe("when given a valid built-in formatter name", () => {
56c4a2cb 235 it("should execute without any errors", async () => {
eb39fafa 236 const filePath = getFixturePath("passing.js");
56c4a2cb 237 const exit = await cli.execute(`-f checkstyle ${filePath}`);
eb39fafa
DC
238
239 assert.strictEqual(exit, 0);
240 });
241 });
242
243 describe("when given a valid built-in formatter name that uses rules meta.", () => {
56c4a2cb 244 it("should execute without any errors", async () => {
eb39fafa 245 const filePath = getFixturePath("passing.js");
56c4a2cb 246 const exit = await cli.execute(`-f json-with-metadata ${filePath} --no-eslintrc`);
eb39fafa
DC
247
248 assert.strictEqual(exit, 0);
249
250 // Check metadata.
251 const { metadata } = JSON.parse(log.info.args[0][0]);
56c4a2cb 252 const expectedMetadata = Array.from(BuiltinRules).reduce((obj, [ruleId, rule]) => {
eb39fafa
DC
253 obj.rulesMeta[ruleId] = rule.meta;
254 return obj;
255 }, { rulesMeta: {} });
256
257 assert.deepStrictEqual(metadata, expectedMetadata);
258 });
259 });
260
261 describe("when given an invalid built-in formatter name", () => {
56c4a2cb 262 it("should execute with error", async () => {
eb39fafa 263 const filePath = getFixturePath("passing.js");
56c4a2cb 264 const exit = await cli.execute(`-f fakeformatter ${filePath}`);
eb39fafa
DC
265
266 assert.strictEqual(exit, 2);
267 });
268 });
269
270 describe("when given a valid formatter path", () => {
56c4a2cb 271 it("should execute without any errors", async () => {
eb39fafa
DC
272 const formatterPath = getFixturePath("formatters", "simple.js");
273 const filePath = getFixturePath("passing.js");
56c4a2cb 274 const exit = await cli.execute(`-f ${formatterPath} ${filePath}`);
eb39fafa
DC
275
276 assert.strictEqual(exit, 0);
277 });
278 });
279
280 describe("when given an invalid formatter path", () => {
56c4a2cb 281 it("should execute with error", async () => {
eb39fafa
DC
282 const formatterPath = getFixturePath("formatters", "file-does-not-exist.js");
283 const filePath = getFixturePath("passing.js");
56c4a2cb 284 const exit = await cli.execute(`-f ${formatterPath} ${filePath}`);
eb39fafa
DC
285
286 assert.strictEqual(exit, 2);
287 });
288 });
289
290 describe("when executing a file with a lint error", () => {
56c4a2cb 291 it("should exit with error", async () => {
eb39fafa
DC
292 const filePath = getFixturePath("undef.js");
293 const code = `--no-ignore --rule no-undef:2 ${filePath}`;
294
56c4a2cb 295 const exit = await cli.execute(code);
eb39fafa
DC
296
297 assert.strictEqual(exit, 1);
298 });
299 });
300
301 describe("when using --fix-type without --fix or --fix-dry-run", () => {
56c4a2cb 302 it("should exit with error", async () => {
eb39fafa
DC
303 const filePath = getFixturePath("passing.js");
304 const code = `--fix-type suggestion ${filePath}`;
305
56c4a2cb 306 const exit = await cli.execute(code);
eb39fafa
DC
307
308 assert.strictEqual(exit, 2);
309 });
310 });
311
312 describe("when executing a file with a syntax error", () => {
56c4a2cb 313 it("should exit with error", async () => {
eb39fafa 314 const filePath = getFixturePath("syntax-error.js");
56c4a2cb 315 const exit = await cli.execute(`--no-ignore ${filePath}`);
eb39fafa
DC
316
317 assert.strictEqual(exit, 1);
318 });
319 });
320
321 describe("when calling execute more than once", () => {
56c4a2cb 322 it("should not print the results from previous execution", async () => {
eb39fafa
DC
323 const filePath = getFixturePath("missing-semicolon.js");
324 const passingPath = getFixturePath("passing.js");
325
56c4a2cb 326 await cli.execute(`--no-ignore --rule semi:2 ${filePath}`);
eb39fafa
DC
327
328 assert.isTrue(log.info.called, "Log should have been called.");
329
330 log.info.resetHistory();
331
56c4a2cb 332 await cli.execute(`--no-ignore --rule semi:2 ${passingPath}`);
eb39fafa
DC
333 assert.isTrue(log.info.notCalled);
334
335 });
336 });
337
338 describe("when executing with version flag", () => {
56c4a2cb
DC
339 it("should print out current version", async () => {
340 assert.strictEqual(await cli.execute("-v"), 0);
eb39fafa
DC
341 assert.strictEqual(log.info.callCount, 1);
342 });
343 });
344
345 describe("when executing with env-info flag", () => {
56c4a2cb
DC
346 it("should print out environment information", async () => {
347 assert.strictEqual(await cli.execute("--env-info"), 0);
eb39fafa
DC
348 assert.strictEqual(log.info.callCount, 1);
349 });
350
56c4a2cb 351 it("should print error message and return error code", async () => {
eb39fafa
DC
352 RuntimeInfo.environment.throws("There was an error!");
353
56c4a2cb 354 assert.strictEqual(await cli.execute("--env-info"), 2);
eb39fafa
DC
355 assert.strictEqual(log.error.callCount, 1);
356 });
357 });
358
359 describe("when executing without no-error-on-unmatched-pattern flag", () => {
56c4a2cb 360 it("should throw an error on unmatched glob pattern", async () => {
eb39fafa
DC
361 const filePath = getFixturePath("unmatched-patterns");
362 const globPattern = "*.js3";
363
56c4a2cb
DC
364 await stdAssert.rejects(async () => {
365 await cli.execute(`"${filePath}/${globPattern}"`);
366 }, new Error(`No files matching '${filePath}/${globPattern}' were found.`));
eb39fafa
DC
367 });
368
56c4a2cb 369 it("should throw an error on unmatched --ext", async () => {
eb39fafa
DC
370 const filePath = getFixturePath("unmatched-patterns");
371 const extension = ".js3";
372
56c4a2cb
DC
373 await stdAssert.rejects(async () => {
374 await cli.execute(`--ext ${extension} ${filePath}`);
eb39fafa
DC
375 }, `No files matching '${filePath}' were found`);
376 });
377 });
378
379 describe("when executing with no-error-on-unmatched-pattern flag", () => {
56c4a2cb 380 it("should not throw an error on unmatched node glob syntax patterns", async () => {
eb39fafa 381 const filePath = getFixturePath("unmatched-patterns");
56c4a2cb 382 const exit = await cli.execute(`--no-error-on-unmatched-pattern "${filePath}/*.js3"`);
eb39fafa
DC
383
384 assert.strictEqual(exit, 0);
385 });
386
56c4a2cb 387 it("should not throw an error on unmatched --ext", async () => {
eb39fafa 388 const filePath = getFixturePath("unmatched-patterns");
56c4a2cb 389 const exit = await cli.execute(`--no-error-on-unmatched-pattern --ext .js3 ${filePath}`);
eb39fafa
DC
390
391 assert.strictEqual(exit, 0);
392 });
393 });
394
395 describe("when executing with no-error-on-unmatched-pattern flag and multiple patterns", () => {
56c4a2cb 396 it("should not throw an error on multiple unmatched node glob syntax patterns", async () => {
eb39fafa 397 const filePath = getFixturePath("unmatched-patterns");
56c4a2cb 398 const exit = await cli.execute(`--no-error-on-unmatched-pattern ${filePath}/*.js3 ${filePath}/*.js4`);
eb39fafa
DC
399
400 assert.strictEqual(exit, 0);
401 });
402
56c4a2cb 403 it("should still throw an error on when a matched pattern has lint errors", async () => {
eb39fafa 404 const filePath = getFixturePath("unmatched-patterns");
56c4a2cb 405 const exit = await cli.execute(`--no-error-on-unmatched-pattern ${filePath}/*.js3 ${filePath}/*.js`);
eb39fafa
DC
406
407 assert.strictEqual(exit, 1);
408 });
409 });
410
411 describe("when executing with no-error-on-unmatched-pattern flag and multiple --ext arguments", () => {
56c4a2cb 412 it("should not throw an error on multiple unmatched --ext arguments", async () => {
eb39fafa 413 const filePath = getFixturePath("unmatched-patterns");
56c4a2cb 414 const exit = await cli.execute(`--no-error-on-unmatched-pattern --ext .js3 --ext .js4 ${filePath}`);
eb39fafa
DC
415
416 assert.strictEqual(exit, 0);
417 });
418
56c4a2cb 419 it("should still throw an error on when a matched pattern has lint errors", async () => {
eb39fafa 420 const filePath = getFixturePath("unmatched-patterns");
56c4a2cb 421 const exit = await cli.execute(`--no-error-on-unmatched-pattern --ext .js3 --ext .js ${filePath}`);
eb39fafa
DC
422
423 assert.strictEqual(exit, 1);
424 });
425 });
426
427 describe("when executing with help flag", () => {
56c4a2cb
DC
428 it("should print out help", async () => {
429 assert.strictEqual(await cli.execute("-h"), 0);
eb39fafa
DC
430 assert.strictEqual(log.info.callCount, 1);
431 });
432 });
433
434 describe("when given a directory with eslint excluded files in the directory", () => {
56c4a2cb 435 it("should throw an error and not process any files", async () => {
eb39fafa
DC
436 const ignorePath = getFixturePath(".eslintignore");
437 const filePath = getFixturePath("cli");
438
56c4a2cb
DC
439 await stdAssert.rejects(async () => {
440 await cli.execute(`--ignore-path ${ignorePath} ${filePath}`);
441 }, new Error(`All files matched by '${filePath}' are ignored.`));
eb39fafa
DC
442 });
443 });
444
445 describe("when given a file in excluded files list", () => {
56c4a2cb 446 it("should not process the file", async () => {
eb39fafa
DC
447 const ignorePath = getFixturePath(".eslintignore");
448 const filePath = getFixturePath("passing.js");
56c4a2cb 449 const exit = await cli.execute(`--ignore-path ${ignorePath} ${filePath}`);
eb39fafa
DC
450
451 // a warning about the ignored file
452 assert.isTrue(log.info.called);
453 assert.strictEqual(exit, 0);
454 });
455
56c4a2cb 456 it("should process the file when forced", async () => {
eb39fafa
DC
457 const ignorePath = getFixturePath(".eslintignore");
458 const filePath = getFixturePath("passing.js");
56c4a2cb 459 const exit = await cli.execute(`--ignore-path ${ignorePath} --no-ignore ${filePath}`);
eb39fafa
DC
460
461 // no warnings
462 assert.isFalse(log.info.called);
463 assert.strictEqual(exit, 0);
464 });
465 });
466
467 describe("when given a pattern to ignore", () => {
56c4a2cb 468 it("should not process any files", async () => {
eb39fafa
DC
469 const ignoredFile = getFixturePath("cli/syntax-error.js");
470 const filePath = getFixturePath("cli/passing.js");
56c4a2cb 471 const exit = await cli.execute(`--ignore-pattern cli/ ${ignoredFile} ${filePath}`);
eb39fafa
DC
472
473 // warnings about the ignored files
474 assert.isTrue(log.info.called);
475 assert.strictEqual(exit, 0);
476 });
477 });
478
479 describe("when given patterns to ignore", () => {
56c4a2cb 480 it("should not process any matching files", async () => {
eb39fafa
DC
481 const ignorePaths = ["a", "b"];
482
483 const cmd = ignorePaths.map(ignorePath => `--ignore-pattern ${ignorePath}`).concat(".").join(" ");
484
485 const opts = {
56c4a2cb
DC
486 overrideConfig: {
487 ignorePatterns: ignorePaths
488 }
eb39fafa
DC
489 };
490
56c4a2cb 491 await verifyESLintOpts(cmd, opts);
eb39fafa
DC
492 });
493 });
494
495 describe("when executing a file with a shebang", () => {
56c4a2cb 496 it("should execute without error", async () => {
eb39fafa 497 const filePath = getFixturePath("shebang.js");
56c4a2cb 498 const exit = await cli.execute(`--no-ignore ${filePath}`);
eb39fafa
DC
499
500 assert.strictEqual(exit, 0);
501 });
502 });
503
504 describe("when loading a custom rule", () => {
56c4a2cb 505 it("should return an error when rule isn't found", async () => {
eb39fafa
DC
506 const rulesPath = getFixturePath("rules", "wrong");
507 const configPath = getFixturePath("rules", "eslint.json");
508 const filePath = getFixturePath("rules", "test", "test-custom-rule.js");
509 const code = `--rulesdir ${rulesPath} --config ${configPath} --no-ignore ${filePath}`;
510
56c4a2cb
DC
511 await stdAssert.rejects(async () => {
512 const exit = await cli.execute(code);
eb39fafa
DC
513
514 assert.strictEqual(exit, 2);
609c276f 515 }, /Error while loading rule 'custom-rule': Boom!/u);
eb39fafa
DC
516 });
517
56c4a2cb 518 it("should return a warning when rule is matched", async () => {
eb39fafa
DC
519 const rulesPath = getFixturePath("rules");
520 const configPath = getFixturePath("rules", "eslint.json");
521 const filePath = getFixturePath("rules", "test", "test-custom-rule.js");
522 const code = `--rulesdir ${rulesPath} --config ${configPath} --no-ignore ${filePath}`;
523
56c4a2cb 524 await cli.execute(code);
eb39fafa
DC
525
526 assert.isTrue(log.info.calledOnce);
527 assert.isTrue(log.info.neverCalledWith(""));
528 });
529
56c4a2cb 530 it("should return warnings from multiple rules in different directories", async () => {
eb39fafa
DC
531 const rulesPath = getFixturePath("rules", "dir1");
532 const rulesPath2 = getFixturePath("rules", "dir2");
533 const configPath = getFixturePath("rules", "multi-rulesdirs.json");
534 const filePath = getFixturePath("rules", "test-multi-rulesdirs.js");
535 const code = `--rulesdir ${rulesPath} --rulesdir ${rulesPath2} --config ${configPath} --no-ignore ${filePath}`;
56c4a2cb 536 const exit = await cli.execute(code);
eb39fafa
DC
537
538 const call = log.info.getCall(0);
539
540 assert.isTrue(log.info.calledOnce);
541 assert.isTrue(call.args[0].indexOf("String!") > -1);
542 assert.isTrue(call.args[0].indexOf("Literal!") > -1);
543 assert.isTrue(call.args[0].indexOf("2 problems") > -1);
544 assert.isTrue(log.info.neverCalledWith(""));
545 assert.strictEqual(exit, 1);
546 });
547
548
549 });
550
551 describe("when executing with no-eslintrc flag", () => {
56c4a2cb 552 it("should ignore a local config file", async () => {
eb39fafa 553 const filePath = getFixturePath("eslintrc", "quotes.js");
56c4a2cb 554 const exit = await cli.execute(`--no-eslintrc --no-ignore ${filePath}`);
eb39fafa
DC
555
556 assert.isTrue(log.info.notCalled);
557 assert.strictEqual(exit, 0);
558 });
559 });
560
561 describe("when executing without no-eslintrc flag", () => {
56c4a2cb 562 it("should load a local config file", async () => {
eb39fafa 563 const filePath = getFixturePath("eslintrc", "quotes.js");
56c4a2cb 564 const exit = await cli.execute(`--no-ignore ${filePath}`);
eb39fafa
DC
565
566 assert.isTrue(log.info.calledOnce);
567 assert.strictEqual(exit, 1);
568 });
569 });
570
571 describe("when executing without env flag", () => {
56c4a2cb 572 it("should not define environment-specific globals", async () => {
eb39fafa
DC
573 const files = [
574 getFixturePath("globals-browser.js"),
575 getFixturePath("globals-node.js")
576 ];
577
56c4a2cb 578 await cli.execute(`--no-eslintrc --config ./conf/eslint-recommended.js --no-ignore ${files.join(" ")}`);
eb39fafa
DC
579
580 assert.strictEqual(log.info.args[0][0].split("\n").length, 10);
581 });
582 });
583
584 describe("when executing with global flag", () => {
56c4a2cb 585 it("should default defined variables to read-only", async () => {
eb39fafa 586 const filePath = getFixturePath("undef.js");
56c4a2cb 587 const exit = await cli.execute(`--global baz,bat --no-ignore --rule no-global-assign:2 ${filePath}`);
eb39fafa
DC
588
589 assert.isTrue(log.info.calledOnce);
590 assert.strictEqual(exit, 1);
591 });
592
56c4a2cb 593 it("should allow defining writable global variables", async () => {
eb39fafa 594 const filePath = getFixturePath("undef.js");
56c4a2cb 595 const exit = await cli.execute(`--global baz:false,bat:true --no-ignore ${filePath}`);
eb39fafa
DC
596
597 assert.isTrue(log.info.notCalled);
598 assert.strictEqual(exit, 0);
599 });
600
56c4a2cb 601 it("should allow defining variables with multiple flags", async () => {
eb39fafa 602 const filePath = getFixturePath("undef.js");
56c4a2cb 603 const exit = await cli.execute(`--global baz --global bat:true --no-ignore ${filePath}`);
eb39fafa
DC
604
605 assert.isTrue(log.info.notCalled);
606 assert.strictEqual(exit, 0);
607 });
608 });
609
610 describe("when supplied with rule flag and severity level set to error", () => {
56c4a2cb 611 it("should exit with an error status (2)", async () => {
eb39fafa
DC
612 const filePath = getFixturePath("single-quoted.js");
613 const code = `--no-ignore --rule 'quotes: [2, double]' ${filePath}`;
56c4a2cb 614 const exitStatus = await cli.execute(code);
eb39fafa
DC
615
616 assert.strictEqual(exitStatus, 1);
617 });
618 });
619
620 describe("when the quiet option is enabled", () => {
621
56c4a2cb 622 it("should only print error", async () => {
eb39fafa
DC
623 const filePath = getFixturePath("single-quoted.js");
624 const cliArgs = `--no-ignore --quiet -f compact --rule 'quotes: [2, double]' --rule 'no-unused-vars: 1' ${filePath}`;
625
56c4a2cb 626 await cli.execute(cliArgs);
eb39fafa
DC
627
628 sinon.assert.calledOnce(log.info);
629
630 const formattedOutput = log.info.firstCall.args[0];
631
632 assert.include(formattedOutput, "Error");
633 assert.notInclude(formattedOutput, "Warning");
634 });
635
56c4a2cb 636 it("should print nothing if there are no errors", async () => {
eb39fafa
DC
637 const filePath = getFixturePath("single-quoted.js");
638 const cliArgs = `--quiet -f compact --rule 'quotes: [1, double]' --rule 'no-unused-vars: 1' ${filePath}`;
639
56c4a2cb 640 await cli.execute(cliArgs);
eb39fafa
DC
641
642 sinon.assert.notCalled(log.info);
643 });
644 });
645
646 describe("when supplied with report output file path", () => {
647 afterEach(() => {
648 sh.rm("-rf", "tests/output");
649 });
650
56c4a2cb 651 it("should write the file and create dirs if they don't exist", async () => {
eb39fafa
DC
652 const filePath = getFixturePath("single-quoted.js");
653 const code = `--no-ignore --rule 'quotes: [1, double]' --o tests/output/eslint-output.txt ${filePath}`;
654
56c4a2cb 655 await cli.execute(code);
eb39fafa
DC
656
657 assert.include(fs.readFileSync("tests/output/eslint-output.txt", "utf8"), filePath);
658 assert.isTrue(log.info.notCalled);
659 });
660
56c4a2cb 661 it("should return an error if the path is a directory", async () => {
eb39fafa
DC
662 const filePath = getFixturePath("single-quoted.js");
663 const code = `--no-ignore --rule 'quotes: [1, double]' --o tests/output ${filePath}`;
664
665 fs.mkdirSync("tests/output");
666
56c4a2cb 667 const exit = await cli.execute(code);
eb39fafa
DC
668
669 assert.strictEqual(exit, 2);
670 assert.isTrue(log.info.notCalled);
671 assert.isTrue(log.error.calledOnce);
672 });
673
56c4a2cb 674 it("should return an error if the path could not be written to", async () => {
eb39fafa
DC
675 const filePath = getFixturePath("single-quoted.js");
676 const code = `--no-ignore --rule 'quotes: [1, double]' --o tests/output/eslint-output.txt ${filePath}`;
677
678 fs.writeFileSync("tests/output", "foo");
679
56c4a2cb 680 const exit = await cli.execute(code);
eb39fafa
DC
681
682 assert.strictEqual(exit, 2);
683 assert.isTrue(log.info.notCalled);
684 assert.isTrue(log.error.calledOnce);
685 });
686 });
687
688 describe("when supplied with a plugin", () => {
56c4a2cb 689 it("should pass plugins to ESLint", async () => {
eb39fafa
DC
690 const examplePluginName = "eslint-plugin-example";
691
56c4a2cb
DC
692 await verifyESLintOpts(`--no-ignore --plugin ${examplePluginName} foo.js`, {
693 overrideConfig: {
694 plugins: [examplePluginName]
695 }
eb39fafa
DC
696 });
697 });
698
699 });
700
701 describe("when supplied with a plugin-loading path", () => {
56c4a2cb 702 it("should pass the option to ESLint", async () => {
eb39fafa
DC
703 const examplePluginDirPath = "foo/bar";
704
56c4a2cb 705 await verifyESLintOpts(`--resolve-plugins-relative-to ${examplePluginDirPath} foo.js`, {
eb39fafa
DC
706 resolvePluginsRelativeTo: examplePluginDirPath
707 });
708 });
709 });
710
711 describe("when given an parser name", () => {
56c4a2cb 712 it("should exit with a fatal error if parser is invalid", async () => {
eb39fafa
DC
713 const filePath = getFixturePath("passing.js");
714
56c4a2cb 715 await stdAssert.rejects(async () => await cli.execute(`--no-ignore --parser test111 ${filePath}`), "Cannot find module 'test111'");
eb39fafa
DC
716 });
717
56c4a2cb 718 it("should exit with no error if parser is valid", async () => {
eb39fafa 719 const filePath = getFixturePath("passing.js");
56c4a2cb 720 const exit = await cli.execute(`--no-ignore --parser espree ${filePath}`);
eb39fafa
DC
721
722 assert.strictEqual(exit, 0);
723 });
724 });
725
726 describe("when given parser options", () => {
56c4a2cb 727 it("should exit with error if parser options are invalid", async () => {
eb39fafa 728 const filePath = getFixturePath("passing.js");
56c4a2cb 729 const exit = await cli.execute(`--no-ignore --parser-options test111 ${filePath}`);
eb39fafa
DC
730
731 assert.strictEqual(exit, 2);
732 });
733
56c4a2cb 734 it("should exit with no error if parser is valid", async () => {
eb39fafa 735 const filePath = getFixturePath("passing.js");
56c4a2cb 736 const exit = await cli.execute(`--no-ignore --parser-options=ecmaVersion:6 ${filePath}`);
eb39fafa
DC
737
738 assert.strictEqual(exit, 0);
739 });
740
56c4a2cb 741 it("should exit with an error on ecmaVersion 7 feature in ecmaVersion 6", async () => {
eb39fafa 742 const filePath = getFixturePath("passing-es7.js");
56c4a2cb 743 const exit = await cli.execute(`--no-ignore --parser-options=ecmaVersion:6 ${filePath}`);
eb39fafa
DC
744
745 assert.strictEqual(exit, 1);
746 });
747
56c4a2cb 748 it("should exit with no error on ecmaVersion 7 feature in ecmaVersion 7", async () => {
eb39fafa 749 const filePath = getFixturePath("passing-es7.js");
56c4a2cb 750 const exit = await cli.execute(`--no-ignore --parser-options=ecmaVersion:7 ${filePath}`);
eb39fafa
DC
751
752 assert.strictEqual(exit, 0);
753 });
754
56c4a2cb 755 it("should exit with no error on ecmaVersion 7 feature with config ecmaVersion 6 and command line ecmaVersion 7", async () => {
eb39fafa
DC
756 const configPath = getFixturePath("configurations", "es6.json");
757 const filePath = getFixturePath("passing-es7.js");
56c4a2cb 758 const exit = await cli.execute(`--no-ignore --config ${configPath} --parser-options=ecmaVersion:7 ${filePath}`);
eb39fafa
DC
759
760 assert.strictEqual(exit, 0);
761 });
762 });
763
764 describe("when given the max-warnings flag", () => {
56c4a2cb 765 it("should not change exit code if warning count under threshold", async () => {
eb39fafa 766 const filePath = getFixturePath("max-warnings");
56c4a2cb 767 const exitCode = await cli.execute(`--no-ignore --max-warnings 10 ${filePath}`);
eb39fafa
DC
768
769 assert.strictEqual(exitCode, 0);
770 });
771
56c4a2cb 772 it("should exit with exit code 1 if warning count exceeds threshold", async () => {
eb39fafa 773 const filePath = getFixturePath("max-warnings");
56c4a2cb 774 const exitCode = await cli.execute(`--no-ignore --max-warnings 5 ${filePath}`);
eb39fafa
DC
775
776 assert.strictEqual(exitCode, 1);
777 assert.ok(log.error.calledOnce);
778 assert.include(log.error.getCall(0).args[0], "ESLint found too many warnings");
779 });
780
5422a9cc
TL
781 it("should exit with exit code 1 without printing warnings if the quiet option is enabled and warning count exceeds threshold", async () => {
782 const filePath = getFixturePath("max-warnings");
783 const exitCode = await cli.execute(`--no-ignore --quiet --max-warnings 5 ${filePath}`);
784
785 assert.strictEqual(exitCode, 1);
786 assert.ok(log.error.calledOnce);
787 assert.include(log.error.getCall(0).args[0], "ESLint found too many warnings");
788 assert.ok(log.info.notCalled); // didn't print warnings
789 });
790
56c4a2cb 791 it("should not change exit code if warning count equals threshold", async () => {
eb39fafa 792 const filePath = getFixturePath("max-warnings");
56c4a2cb 793 const exitCode = await cli.execute(`--no-ignore --max-warnings 6 ${filePath}`);
eb39fafa
DC
794
795 assert.strictEqual(exitCode, 0);
796 });
797
56c4a2cb 798 it("should not change exit code if flag is not specified and there are warnings", async () => {
eb39fafa 799 const filePath = getFixturePath("max-warnings");
56c4a2cb 800 const exitCode = await cli.execute(filePath);
eb39fafa
DC
801
802 assert.strictEqual(exitCode, 0);
803 });
804 });
805
609c276f
TL
806 describe("when given the exit-on-fatal-error flag", () => {
807 it("should not change exit code if no fatal errors are reported", async () => {
808 const filePath = getFixturePath("exit-on-fatal-error", "no-fatal-error.js");
809 const exitCode = await cli.execute(`--no-ignore --exit-on-fatal-error ${filePath}`);
810
811 assert.strictEqual(exitCode, 0);
812 });
813
814 it("should exit with exit code 1 if no fatal errors are found, but rule violations are found", async () => {
815 const filePath = getFixturePath("exit-on-fatal-error", "no-fatal-error-rule-violation.js");
816 const exitCode = await cli.execute(`--no-ignore --exit-on-fatal-error ${filePath}`);
817
818 assert.strictEqual(exitCode, 1);
819 });
820
821 it("should exit with exit code 2 if fatal error is found", async () => {
822 const filePath = getFixturePath("exit-on-fatal-error", "fatal-error.js");
823 const exitCode = await cli.execute(`--no-ignore --exit-on-fatal-error ${filePath}`);
824
825 assert.strictEqual(exitCode, 2);
826 });
827
828 it("should exit with exit code 2 if fatal error is found in any file", async () => {
829 const filePath = getFixturePath("exit-on-fatal-error");
830 const exitCode = await cli.execute(`--no-ignore --exit-on-fatal-error ${filePath}`);
831
832 assert.strictEqual(exitCode, 2);
833 });
834
835
836 });
837
eb39fafa
DC
838 describe("when passed --no-inline-config", () => {
839 let localCLI;
840
841 afterEach(() => {
842 sinon.verifyAndRestore();
843 });
844
56c4a2cb 845 it("should pass allowInlineConfig:false to ESLint when --no-inline-config is used", async () => {
eb39fafa 846
56c4a2cb
DC
847 // create a fake ESLint class to test with
848 const fakeESLint = sinon.mock().withExactArgs(sinon.match({ allowInlineConfig: false }));
eb39fafa 849
56c4a2cb
DC
850 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
851 sinon.stub(fakeESLint.prototype, "lintFiles").returns([{
852 filePath: "./foo.js",
853 output: "bar",
854 messages: [
855 {
856 severity: 2,
857 message: "Fake message"
858 }
859 ],
eb39fafa 860 errorCount: 1,
56c4a2cb
DC
861 warningCount: 0
862 }]);
863 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: () => "done" });
864 fakeESLint.outputFixes = sinon.stub();
eb39fafa
DC
865
866 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 867 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
868 "./shared/logging": log
869 });
870
56c4a2cb 871 await localCLI.execute("--no-inline-config .");
eb39fafa
DC
872 });
873
56c4a2cb 874 it("should not error and allowInlineConfig should be true by default", async () => {
eb39fafa 875
56c4a2cb
DC
876 // create a fake ESLint class to test with
877 const fakeESLint = sinon.mock().withExactArgs(sinon.match({ allowInlineConfig: true }));
eb39fafa 878
56c4a2cb
DC
879 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
880 sinon.stub(fakeESLint.prototype, "lintFiles").returns([]);
881 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: () => "done" });
882 fakeESLint.outputFixes = sinon.stub();
eb39fafa
DC
883
884 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 885 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
886 "./shared/logging": log
887 });
888
56c4a2cb 889 const exitCode = await localCLI.execute(".");
eb39fafa
DC
890
891 assert.strictEqual(exitCode, 0);
892
893 });
894
895 });
896
897 describe("when passed --fix", () => {
898 let localCLI;
899
900 afterEach(() => {
901 sinon.verifyAndRestore();
902 });
903
56c4a2cb 904 it("should pass fix:true to ESLint when executing on files", async () => {
eb39fafa 905
56c4a2cb
DC
906 // create a fake ESLint class to test with
907 const fakeESLint = sinon.mock().withExactArgs(sinon.match({ fix: true }));
eb39fafa 908
56c4a2cb
DC
909 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
910 sinon.stub(fakeESLint.prototype, "lintFiles").returns([]);
911 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: () => "done" });
912 fakeESLint.outputFixes = sinon.mock().once();
eb39fafa
DC
913
914 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 915 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
916 "./shared/logging": log
917 });
918
56c4a2cb 919 const exitCode = await localCLI.execute("--fix .");
eb39fafa
DC
920
921 assert.strictEqual(exitCode, 0);
922
923 });
924
925
56c4a2cb 926 it("should rewrite files when in fix mode", async () => {
eb39fafa 927
56c4a2cb
DC
928 const report = [{
929 filePath: "./foo.js",
930 output: "bar",
931 messages: [
932 {
933 severity: 2,
934 message: "Fake message"
935 }
936 ],
eb39fafa 937 errorCount: 1,
56c4a2cb
DC
938 warningCount: 0
939 }];
eb39fafa 940
56c4a2cb
DC
941 // create a fake ESLint class to test with
942 const fakeESLint = sinon.mock().withExactArgs(sinon.match({ fix: true }));
eb39fafa 943
56c4a2cb
DC
944 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
945 sinon.stub(fakeESLint.prototype, "lintFiles").returns(report);
946 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: () => "done" });
947 fakeESLint.outputFixes = sinon.mock().withExactArgs(report);
eb39fafa
DC
948
949 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 950 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
951 "./shared/logging": log
952 });
953
56c4a2cb 954 const exitCode = await localCLI.execute("--fix .");
eb39fafa
DC
955
956 assert.strictEqual(exitCode, 1);
957
958 });
959
56c4a2cb 960 it("should provide fix predicate and rewrite files when in fix mode and quiet mode", async () => {
eb39fafa 961
56c4a2cb
DC
962 const report = [{
963 filePath: "./foo.js",
964 output: "bar",
965 messages: [
966 {
967 severity: 1,
968 message: "Fake message"
969 }
970 ],
eb39fafa 971 errorCount: 0,
56c4a2cb
DC
972 warningCount: 1
973 }];
eb39fafa 974
56c4a2cb
DC
975 // create a fake ESLint class to test with
976 const fakeESLint = sinon.mock().withExactArgs(sinon.match({ fix: sinon.match.func }));
eb39fafa 977
56c4a2cb
DC
978 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
979 sinon.stub(fakeESLint.prototype, "lintFiles").returns(report);
980 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: () => "done" });
981 fakeESLint.getErrorResults = sinon.stub().returns([]);
982 fakeESLint.outputFixes = sinon.mock().withExactArgs(report);
eb39fafa
DC
983
984 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 985 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
986 "./shared/logging": log
987 });
988
56c4a2cb 989 const exitCode = await localCLI.execute("--fix --quiet .");
eb39fafa
DC
990
991 assert.strictEqual(exitCode, 0);
992
993 });
994
56c4a2cb 995 it("should not call ESLint and return 2 when executing on text", async () => {
eb39fafa 996
56c4a2cb
DC
997 // create a fake ESLint class to test with
998 const fakeESLint = sinon.mock().never();
eb39fafa
DC
999
1000 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 1001 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
1002 "./shared/logging": log
1003 });
1004
56c4a2cb 1005 const exitCode = await localCLI.execute("--fix .", "foo = bar;");
eb39fafa
DC
1006
1007 assert.strictEqual(exitCode, 2);
1008 });
1009
1010 });
1011
1012 describe("when passed --fix-dry-run", () => {
1013 let localCLI;
1014
1015 afterEach(() => {
1016 sinon.verifyAndRestore();
1017 });
1018
56c4a2cb 1019 it("should pass fix:true to ESLint when executing on files", async () => {
eb39fafa 1020
56c4a2cb
DC
1021 // create a fake ESLint class to test with
1022 const fakeESLint = sinon.mock().withExactArgs(sinon.match({ fix: true }));
eb39fafa 1023
56c4a2cb
DC
1024 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
1025 sinon.stub(fakeESLint.prototype, "lintFiles").returns([]);
1026 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: () => "done" });
1027 fakeESLint.outputFixes = sinon.mock().never();
eb39fafa
DC
1028
1029 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 1030 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
1031 "./shared/logging": log
1032 });
1033
56c4a2cb 1034 const exitCode = await localCLI.execute("--fix-dry-run .");
eb39fafa
DC
1035
1036 assert.strictEqual(exitCode, 0);
1037
1038 });
1039
56c4a2cb 1040 it("should pass fixTypes to ESLint when --fix-type is passed", async () => {
eb39fafa 1041
56c4a2cb 1042 const expectedESLintOptions = {
eb39fafa
DC
1043 fix: true,
1044 fixTypes: ["suggestion"]
1045 };
1046
56c4a2cb
DC
1047 // create a fake ESLint class to test with
1048 const fakeESLint = sinon.mock().withExactArgs(sinon.match(expectedESLintOptions));
eb39fafa 1049
56c4a2cb
DC
1050 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
1051 sinon.stub(fakeESLint.prototype, "lintFiles").returns([]);
1052 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: () => "done" });
1053 fakeESLint.outputFixes = sinon.stub();
eb39fafa
DC
1054
1055 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 1056 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
1057 "./shared/logging": log
1058 });
1059
56c4a2cb 1060 const exitCode = await localCLI.execute("--fix-dry-run --fix-type suggestion .");
eb39fafa
DC
1061
1062 assert.strictEqual(exitCode, 0);
1063 });
1064
56c4a2cb 1065 it("should not rewrite files when in fix-dry-run mode", async () => {
eb39fafa 1066
56c4a2cb
DC
1067 const report = [{
1068 filePath: "./foo.js",
1069 output: "bar",
1070 messages: [
1071 {
1072 severity: 2,
1073 message: "Fake message"
1074 }
1075 ],
eb39fafa 1076 errorCount: 1,
56c4a2cb
DC
1077 warningCount: 0
1078 }];
eb39fafa 1079
56c4a2cb
DC
1080 // create a fake ESLint class to test with
1081 const fakeESLint = sinon.mock().withExactArgs(sinon.match({ fix: true }));
eb39fafa 1082
56c4a2cb
DC
1083 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
1084 sinon.stub(fakeESLint.prototype, "lintFiles").returns(report);
1085 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: () => "done" });
1086 fakeESLint.outputFixes = sinon.mock().never();
eb39fafa
DC
1087
1088 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 1089 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
1090 "./shared/logging": log
1091 });
1092
56c4a2cb 1093 const exitCode = await localCLI.execute("--fix-dry-run .");
eb39fafa
DC
1094
1095 assert.strictEqual(exitCode, 1);
1096
1097 });
1098
56c4a2cb 1099 it("should provide fix predicate when in fix-dry-run mode and quiet mode", async () => {
eb39fafa 1100
56c4a2cb
DC
1101 const report = [{
1102 filePath: "./foo.js",
1103 output: "bar",
1104 messages: [
1105 {
1106 severity: 1,
1107 message: "Fake message"
1108 }
1109 ],
eb39fafa 1110 errorCount: 0,
56c4a2cb
DC
1111 warningCount: 1
1112 }];
eb39fafa 1113
56c4a2cb
DC
1114 // create a fake ESLint class to test with
1115 const fakeESLint = sinon.mock().withExactArgs(sinon.match({ fix: sinon.match.func }));
eb39fafa 1116
56c4a2cb
DC
1117 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
1118 sinon.stub(fakeESLint.prototype, "lintFiles").returns(report);
1119 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: () => "done" });
1120 fakeESLint.getErrorResults = sinon.stub().returns([]);
1121 fakeESLint.outputFixes = sinon.mock().never();
eb39fafa
DC
1122
1123 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 1124 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
1125 "./shared/logging": log
1126 });
1127
56c4a2cb 1128 const exitCode = await localCLI.execute("--fix-dry-run --quiet .");
eb39fafa
DC
1129
1130 assert.strictEqual(exitCode, 0);
1131
1132 });
1133
56c4a2cb 1134 it("should allow executing on text", async () => {
eb39fafa 1135
56c4a2cb
DC
1136 const report = [{
1137 filePath: "./foo.js",
1138 output: "bar",
1139 messages: [
1140 {
1141 severity: 2,
1142 message: "Fake message"
1143 }
1144 ],
eb39fafa 1145 errorCount: 1,
56c4a2cb
DC
1146 warningCount: 0
1147 }];
eb39fafa 1148
56c4a2cb
DC
1149 // create a fake ESLint class to test with
1150 const fakeESLint = sinon.mock().withExactArgs(sinon.match({ fix: true }));
eb39fafa 1151
56c4a2cb
DC
1152 Object.defineProperties(fakeESLint.prototype, Object.getOwnPropertyDescriptors(ESLint.prototype));
1153 sinon.stub(fakeESLint.prototype, "lintText").returns(report);
1154 sinon.stub(fakeESLint.prototype, "loadFormatter").returns({ format: () => "done" });
1155 fakeESLint.outputFixes = sinon.mock().never();
eb39fafa
DC
1156
1157 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 1158 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
1159 "./shared/logging": log
1160 });
1161
56c4a2cb 1162 const exitCode = await localCLI.execute("--fix-dry-run .", "foo = bar;");
eb39fafa
DC
1163
1164 assert.strictEqual(exitCode, 1);
1165 });
1166
56c4a2cb 1167 it("should not call ESLint and return 2 when used with --fix", async () => {
eb39fafa 1168
56c4a2cb
DC
1169 // create a fake ESLint class to test with
1170 const fakeESLint = sinon.mock().never();
eb39fafa
DC
1171
1172 localCLI = proxyquire("../../lib/cli", {
56c4a2cb 1173 "./eslint": { ESLint: fakeESLint },
eb39fafa
DC
1174 "./shared/logging": log
1175 });
1176
56c4a2cb 1177 const exitCode = await localCLI.execute("--fix --fix-dry-run .", "foo = bar;");
eb39fafa
DC
1178
1179 assert.strictEqual(exitCode, 2);
1180 });
1181 });
1182
1183 describe("when passing --print-config", () => {
56c4a2cb 1184 it("should print out the configuration", async () => {
eb39fafa
DC
1185 const filePath = getFixturePath("xxxx");
1186
56c4a2cb 1187 const exitCode = await cli.execute(`--print-config ${filePath}`);
eb39fafa
DC
1188
1189 assert.isTrue(log.info.calledOnce);
1190 assert.strictEqual(exitCode, 0);
1191 });
1192
56c4a2cb 1193 it("should error if any positional file arguments are passed", async () => {
eb39fafa
DC
1194 const filePath1 = getFixturePath("files", "bar.js");
1195 const filePath2 = getFixturePath("files", "foo.js");
1196
56c4a2cb 1197 const exitCode = await cli.execute(`--print-config ${filePath1} ${filePath2}`);
eb39fafa
DC
1198
1199 assert.isTrue(log.info.notCalled);
1200 assert.isTrue(log.error.calledOnce);
1201 assert.strictEqual(exitCode, 2);
1202 });
1203
56c4a2cb
DC
1204 it("should error out when executing on text", async () => {
1205 const exitCode = await cli.execute("--print-config=myFile.js", "foo = bar;");
eb39fafa
DC
1206
1207 assert.isTrue(log.info.notCalled);
1208 assert.isTrue(log.error.calledOnce);
1209 assert.strictEqual(exitCode, 2);
1210 });
1211 });
1212
1213});