]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/tests/lib/cli.js
2 * @fileoverview Tests for cli.
3 * @author Ian Christian Myers
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.
13 //------------------------------------------------------------------------------
15 //------------------------------------------------------------------------------
17 const assert
= require("chai").assert
,
18 stdAssert
= require("assert"),
19 { ESLint
} = require("../../lib/eslint"),
20 BuiltinRules
= require("../../lib/rules"),
21 path
= require("path"),
22 sinon
= require("sinon"),
25 sh
= require("shelljs");
27 const proxyquire
= require("proxyquire").noCallThru().noPreserveCache();
29 //------------------------------------------------------------------------------
31 //------------------------------------------------------------------------------
33 describe("cli", () => {
40 environment
: sinon
.stub(),
43 const cli
= proxyquire("../../lib/cli", {
44 "./shared/logging": log
,
45 "./shared/runtime-info": RuntimeInfo
49 * Verify that ESLint class receives correct opts via await cli.execute().
50 * @param {string} cmd CLI command.
51 * @param {Object} opts Options hash that should match that received by ESLint class.
54 async
function verifyESLintOpts(cmd
, opts
) {
56 // create a fake ESLint class to test with
57 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match(opts
));
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() });
63 const localCLI
= proxyquire("../../lib/cli", {
64 "./eslint": { ESLint
: fakeESLint
},
65 "./shared/logging": log
68 await localCLI
.execute(cmd
);
69 sinon
.verifyAndRestore();
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.
80 function getFixturePath(...args
) {
81 return path
.join(fixtureDir
, ...args
);
84 // copy into clean area so as not to get "infected" by this project's .eslintrc files
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.
93 this.timeout(60 * 1000); // eslint-disable-line no-invalid-this
94 fixtureDir
= `${os.tmpdir()}/eslint/fixtures`;
95 sh
.mkdir("-p", fixtureDir
);
96 sh
.cp("-r", "./tests/fixtures/.", fixtureDir
);
100 log
.info
.resetHistory();
101 log
.error
.resetHistory();
105 sh
.rm("-r", fixtureDir
);
108 describe("execute()", () => {
109 it("should return error when text with incorrect quotes is passed as argument", async () => {
110 const configFile
= getFixturePath("configurations", "quotes-error.json");
111 const result
= await cli
.execute(`-c ${configFile}`, "var foo = 'bar';");
113 assert
.strictEqual(result
, 1);
116 it("should not print debug info when passed the empty string as text", async () => {
117 const result
= await cli
.execute(["--stdin", "--no-eslintrc"], "");
119 assert
.strictEqual(result
, 0);
120 assert
.isTrue(log
.info
.notCalled
);
123 it("should return no error when --ext .js2 is specified", async () => {
124 const filePath
= getFixturePath("files");
125 const result
= await cli
.execute(`--ext .js2 ${filePath}`);
127 assert
.strictEqual(result
, 0);
130 it("should exit with console error when passed unsupported arguments", async () => {
131 const filePath
= getFixturePath("files");
132 const result
= await cli
.execute(`--blah --another ${filePath}`);
134 assert
.strictEqual(result
, 2);
139 describe("when given a config file", () => {
140 it("should load the specified config file", async () => {
141 const configPath
= getFixturePath(".eslintrc");
142 const filePath
= getFixturePath("passing.js");
144 await cli
.execute(`--config ${configPath} ${filePath}`);
148 describe("when there is a local config file", () => {
149 const code
= "lib/cli.js";
151 it("should load the local config file", async () => {
154 process
.eslintCwd
= getFixturePath("configurations", "single-quotes");
156 await cli
.execute(code
);
158 process
.eslintCwd
= null;
162 describe("when given a config with rules with options and severity level set to error", () => {
163 it("should exit with an error status (1)", async () => {
164 const configPath
= getFixturePath("configurations", "quotes-error.json");
165 const filePath
= getFixturePath("single-quoted.js");
166 const code
= `--no-ignore --config ${configPath} ${filePath}`;
168 const exitStatus
= await cli
.execute(code
);
170 assert
.strictEqual(exitStatus
, 1);
174 describe("when given a config file and a directory of files", () => {
175 it("should load and execute without error", async () => {
176 const configPath
= getFixturePath("configurations", "semi-error.json");
177 const filePath
= getFixturePath("formatters");
178 const code
= `--config ${configPath} ${filePath}`;
180 const exitStatus
= await cli
.execute(code
);
182 assert
.strictEqual(exitStatus
, 0);
186 describe("when given a config with environment set to browser", () => {
187 it("should execute without any errors", async () => {
188 const configPath
= getFixturePath("configurations", "env-browser.json");
189 const filePath
= getFixturePath("globals-browser.js");
190 const code
= `--config ${configPath} ${filePath}`;
192 const exit
= await cli
.execute(code
);
194 assert
.strictEqual(exit
, 0);
198 describe("when given a config with environment set to Node.js", () => {
199 it("should execute without any errors", async () => {
200 const configPath
= getFixturePath("configurations", "env-node.json");
201 const filePath
= getFixturePath("globals-node.js");
202 const code
= `--config ${configPath} ${filePath}`;
204 const exit
= await cli
.execute(code
);
206 assert
.strictEqual(exit
, 0);
210 describe("when given a config with environment set to Nashorn", () => {
211 it("should execute without any errors", async () => {
212 const configPath
= getFixturePath("configurations", "env-nashorn.json");
213 const filePath
= getFixturePath("globals-nashorn.js");
214 const code
= `--config ${configPath} ${filePath}`;
216 const exit
= await cli
.execute(code
);
218 assert
.strictEqual(exit
, 0);
222 describe("when given a config with environment set to WebExtensions", () => {
223 it("should execute without any errors", async () => {
224 const configPath
= getFixturePath("configurations", "env-webextensions.json");
225 const filePath
= getFixturePath("globals-webextensions.js");
226 const code
= `--config ${configPath} ${filePath}`;
228 const exit
= await cli
.execute(code
);
230 assert
.strictEqual(exit
, 0);
234 describe("when given a valid built-in formatter name", () => {
235 it("should execute without any errors", async () => {
236 const filePath
= getFixturePath("passing.js");
237 const exit
= await cli
.execute(`-f checkstyle ${filePath}`);
239 assert
.strictEqual(exit
, 0);
243 describe("when given a valid built-in formatter name that uses rules meta.", () => {
244 it("should execute without any errors", async () => {
245 const filePath
= getFixturePath("passing.js");
246 const exit
= await cli
.execute(`-f json-with-metadata ${filePath} --no-eslintrc`);
248 assert
.strictEqual(exit
, 0);
251 const { metadata
} = JSON
.parse(log
.info
.args
[0][0]);
252 const expectedMetadata
= Array
.from(BuiltinRules
).reduce((obj
, [ruleId
, rule
]) => {
253 obj
.rulesMeta
[ruleId
] = rule
.meta
;
255 }, { rulesMeta
: {} });
257 assert
.deepStrictEqual(metadata
, expectedMetadata
);
261 describe("when given an invalid built-in formatter name", () => {
262 it("should execute with error", async () => {
263 const filePath
= getFixturePath("passing.js");
264 const exit
= await cli
.execute(`-f fakeformatter ${filePath}`);
266 assert
.strictEqual(exit
, 2);
270 describe("when given a valid formatter path", () => {
271 it("should execute without any errors", async () => {
272 const formatterPath
= getFixturePath("formatters", "simple.js");
273 const filePath
= getFixturePath("passing.js");
274 const exit
= await cli
.execute(`-f ${formatterPath} ${filePath}`);
276 assert
.strictEqual(exit
, 0);
280 describe("when given an invalid formatter path", () => {
281 it("should execute with error", async () => {
282 const formatterPath
= getFixturePath("formatters", "file-does-not-exist.js");
283 const filePath
= getFixturePath("passing.js");
284 const exit
= await cli
.execute(`-f ${formatterPath} ${filePath}`);
286 assert
.strictEqual(exit
, 2);
290 describe("when executing a file with a lint error", () => {
291 it("should exit with error", async () => {
292 const filePath
= getFixturePath("undef.js");
293 const code
= `--no-ignore --rule no-undef:2 ${filePath}`;
295 const exit
= await cli
.execute(code
);
297 assert
.strictEqual(exit
, 1);
301 describe("when using --fix-type without --fix or --fix-dry-run", () => {
302 it("should exit with error", async () => {
303 const filePath
= getFixturePath("passing.js");
304 const code
= `--fix-type suggestion ${filePath}`;
306 const exit
= await cli
.execute(code
);
308 assert
.strictEqual(exit
, 2);
312 describe("when executing a file with a syntax error", () => {
313 it("should exit with error", async () => {
314 const filePath
= getFixturePath("syntax-error.js");
315 const exit
= await cli
.execute(`--no-ignore ${filePath}`);
317 assert
.strictEqual(exit
, 1);
321 describe("when calling execute more than once", () => {
322 it("should not print the results from previous execution", async () => {
323 const filePath
= getFixturePath("missing-semicolon.js");
324 const passingPath
= getFixturePath("passing.js");
326 await cli
.execute(`--no-ignore --rule semi:2 ${filePath}`);
328 assert
.isTrue(log
.info
.called
, "Log should have been called.");
330 log
.info
.resetHistory();
332 await cli
.execute(`--no-ignore --rule semi:2 ${passingPath}`);
333 assert
.isTrue(log
.info
.notCalled
);
338 describe("when executing with version flag", () => {
339 it("should print out current version", async () => {
340 assert
.strictEqual(await cli
.execute("-v"), 0);
341 assert
.strictEqual(log
.info
.callCount
, 1);
345 describe("when executing with env-info flag", () => {
346 it("should print out environment information", async () => {
347 assert
.strictEqual(await cli
.execute("--env-info"), 0);
348 assert
.strictEqual(log
.info
.callCount
, 1);
351 it("should print error message and return error code", async () => {
352 RuntimeInfo
.environment
.throws("There was an error!");
354 assert
.strictEqual(await cli
.execute("--env-info"), 2);
355 assert
.strictEqual(log
.error
.callCount
, 1);
359 describe("when executing without no-error-on-unmatched-pattern flag", () => {
360 it("should throw an error on unmatched glob pattern", async () => {
361 const filePath
= getFixturePath("unmatched-patterns");
362 const globPattern
= "*.js3";
364 await stdAssert
.rejects(async () => {
365 await cli
.execute(`"${filePath}/${globPattern}"`);
366 }, new Error(`No files matching '${filePath}/${globPattern}' were found.`));
369 it("should throw an error on unmatched --ext", async () => {
370 const filePath
= getFixturePath("unmatched-patterns");
371 const extension
= ".js3";
373 await stdAssert
.rejects(async () => {
374 await cli
.execute(`--ext ${extension} ${filePath}`);
375 }, `No files matching '${filePath}' were found`);
379 describe("when executing with no-error-on-unmatched-pattern flag", () => {
380 it("should not throw an error on unmatched node glob syntax patterns", async () => {
381 const filePath
= getFixturePath("unmatched-patterns");
382 const exit
= await cli
.execute(`--no-error-on-unmatched-pattern "${filePath}/*.js3"`);
384 assert
.strictEqual(exit
, 0);
387 it("should not throw an error on unmatched --ext", async () => {
388 const filePath
= getFixturePath("unmatched-patterns");
389 const exit
= await cli
.execute(`--no-error-on-unmatched-pattern --ext .js3 ${filePath}`);
391 assert
.strictEqual(exit
, 0);
395 describe("when executing with no-error-on-unmatched-pattern flag and multiple patterns", () => {
396 it("should not throw an error on multiple unmatched node glob syntax patterns", async () => {
397 const filePath
= getFixturePath("unmatched-patterns");
398 const exit
= await cli
.execute(`--no-error-on-unmatched-pattern ${filePath}/*.js3 ${filePath}/*.js4`);
400 assert
.strictEqual(exit
, 0);
403 it("should still throw an error on when a matched pattern has lint errors", async () => {
404 const filePath
= getFixturePath("unmatched-patterns");
405 const exit
= await cli
.execute(`--no-error-on-unmatched-pattern ${filePath}/*.js3 ${filePath}/*.js`);
407 assert
.strictEqual(exit
, 1);
411 describe("when executing with no-error-on-unmatched-pattern flag and multiple --ext arguments", () => {
412 it("should not throw an error on multiple unmatched --ext arguments", async () => {
413 const filePath
= getFixturePath("unmatched-patterns");
414 const exit
= await cli
.execute(`--no-error-on-unmatched-pattern --ext .js3 --ext .js4 ${filePath}`);
416 assert
.strictEqual(exit
, 0);
419 it("should still throw an error on when a matched pattern has lint errors", async () => {
420 const filePath
= getFixturePath("unmatched-patterns");
421 const exit
= await cli
.execute(`--no-error-on-unmatched-pattern --ext .js3 --ext .js ${filePath}`);
423 assert
.strictEqual(exit
, 1);
427 describe("when executing with help flag", () => {
428 it("should print out help", async () => {
429 assert
.strictEqual(await cli
.execute("-h"), 0);
430 assert
.strictEqual(log
.info
.callCount
, 1);
434 describe("when given a directory with eslint excluded files in the directory", () => {
435 it("should throw an error and not process any files", async () => {
436 const ignorePath
= getFixturePath(".eslintignore");
437 const filePath
= getFixturePath("cli");
439 await stdAssert
.rejects(async () => {
440 await cli
.execute(`--ignore-path ${ignorePath} ${filePath}`);
441 }, new Error(`All files matched by '${filePath}' are ignored.`));
445 describe("when given a file in excluded files list", () => {
446 it("should not process the file", async () => {
447 const ignorePath
= getFixturePath(".eslintignore");
448 const filePath
= getFixturePath("passing.js");
449 const exit
= await cli
.execute(`--ignore-path ${ignorePath} ${filePath}`);
451 // a warning about the ignored file
452 assert
.isTrue(log
.info
.called
);
453 assert
.strictEqual(exit
, 0);
456 it("should process the file when forced", async () => {
457 const ignorePath
= getFixturePath(".eslintignore");
458 const filePath
= getFixturePath("passing.js");
459 const exit
= await cli
.execute(`--ignore-path ${ignorePath} --no-ignore ${filePath}`);
462 assert
.isFalse(log
.info
.called
);
463 assert
.strictEqual(exit
, 0);
467 describe("when given a pattern to ignore", () => {
468 it("should not process any files", async () => {
469 const ignoredFile
= getFixturePath("cli/syntax-error.js");
470 const filePath
= getFixturePath("cli/passing.js");
471 const exit
= await cli
.execute(`--ignore-pattern cli/ ${ignoredFile} ${filePath}`);
473 // warnings about the ignored files
474 assert
.isTrue(log
.info
.called
);
475 assert
.strictEqual(exit
, 0);
479 describe("when given patterns to ignore", () => {
480 it("should not process any matching files", async () => {
481 const ignorePaths
= ["a", "b"];
483 const cmd
= ignorePaths
.map(ignorePath
=> `--ignore-pattern ${ignorePath}`).concat(".").join(" ");
487 ignorePatterns
: ignorePaths
491 await
verifyESLintOpts(cmd
, opts
);
495 describe("when executing a file with a shebang", () => {
496 it("should execute without error", async () => {
497 const filePath
= getFixturePath("shebang.js");
498 const exit
= await cli
.execute(`--no-ignore ${filePath}`);
500 assert
.strictEqual(exit
, 0);
504 describe("when loading a custom rule", () => {
505 it("should return an error when rule isn't found", async () => {
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}`;
511 await stdAssert
.rejects(async () => {
512 const exit
= await cli
.execute(code
);
514 assert
.strictEqual(exit
, 2);
515 }, /Error while loading rule 'custom-rule': Cannot read property/u);
518 it("should return a warning when rule is matched", async () => {
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}`;
524 await cli
.execute(code
);
526 assert
.isTrue(log
.info
.calledOnce
);
527 assert
.isTrue(log
.info
.neverCalledWith(""));
530 it("should return warnings from multiple rules in different directories", async () => {
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}`;
536 const exit
= await cli
.execute(code
);
538 const call
= log
.info
.getCall(0);
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);
551 describe("when executing with no-eslintrc flag", () => {
552 it("should ignore a local config file", async () => {
553 const filePath
= getFixturePath("eslintrc", "quotes.js");
554 const exit
= await cli
.execute(`--no-eslintrc --no-ignore ${filePath}`);
556 assert
.isTrue(log
.info
.notCalled
);
557 assert
.strictEqual(exit
, 0);
561 describe("when executing without no-eslintrc flag", () => {
562 it("should load a local config file", async () => {
563 const filePath
= getFixturePath("eslintrc", "quotes.js");
564 const exit
= await cli
.execute(`--no-ignore ${filePath}`);
566 assert
.isTrue(log
.info
.calledOnce
);
567 assert
.strictEqual(exit
, 1);
571 describe("when executing without env flag", () => {
572 it("should not define environment-specific globals", async () => {
574 getFixturePath("globals-browser.js"),
575 getFixturePath("globals-node.js")
578 await cli
.execute(`--no-eslintrc --config ./conf/eslint-recommended.js --no-ignore ${files.join(" ")}`);
580 assert
.strictEqual(log
.info
.args
[0][0].split("\n").length
, 10);
584 describe("when executing with global flag", () => {
585 it("should default defined variables to read-only", async () => {
586 const filePath
= getFixturePath("undef.js");
587 const exit
= await cli
.execute(`--global baz,bat --no-ignore --rule no-global-assign:2 ${filePath}`);
589 assert
.isTrue(log
.info
.calledOnce
);
590 assert
.strictEqual(exit
, 1);
593 it("should allow defining writable global variables", async () => {
594 const filePath
= getFixturePath("undef.js");
595 const exit
= await cli
.execute(`--global baz:false,bat:true --no-ignore ${filePath}`);
597 assert
.isTrue(log
.info
.notCalled
);
598 assert
.strictEqual(exit
, 0);
601 it("should allow defining variables with multiple flags", async () => {
602 const filePath
= getFixturePath("undef.js");
603 const exit
= await cli
.execute(`--global baz --global bat:true --no-ignore ${filePath}`);
605 assert
.isTrue(log
.info
.notCalled
);
606 assert
.strictEqual(exit
, 0);
610 describe("when supplied with rule flag and severity level set to error", () => {
611 it("should exit with an error status (2)", async () => {
612 const filePath
= getFixturePath("single-quoted.js");
613 const code
= `--no-ignore --rule 'quotes: [2, double]' ${filePath}`;
614 const exitStatus
= await cli
.execute(code
);
616 assert
.strictEqual(exitStatus
, 1);
620 describe("when the quiet option is enabled", () => {
622 it("should only print error", async () => {
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}`;
626 await cli
.execute(cliArgs
);
628 sinon
.assert
.calledOnce(log
.info
);
630 const formattedOutput
= log
.info
.firstCall
.args
[0];
632 assert
.include(formattedOutput
, "Error");
633 assert
.notInclude(formattedOutput
, "Warning");
636 it("should print nothing if there are no errors", async () => {
637 const filePath
= getFixturePath("single-quoted.js");
638 const cliArgs
= `--quiet -f compact --rule 'quotes: [1, double]' --rule 'no-unused-vars: 1' ${filePath}`;
640 await cli
.execute(cliArgs
);
642 sinon
.assert
.notCalled(log
.info
);
646 describe("when supplied with report output file path", () => {
648 sh
.rm("-rf", "tests/output");
651 it("should write the file and create dirs if they don't exist", async () => {
652 const filePath
= getFixturePath("single-quoted.js");
653 const code
= `--no-ignore --rule 'quotes: [1, double]' --o tests/output/eslint-output.txt ${filePath}`;
655 await cli
.execute(code
);
657 assert
.include(fs
.readFileSync("tests/output/eslint-output.txt", "utf8"), filePath
);
658 assert
.isTrue(log
.info
.notCalled
);
661 it("should return an error if the path is a directory", async () => {
662 const filePath
= getFixturePath("single-quoted.js");
663 const code
= `--no-ignore --rule 'quotes: [1, double]' --o tests/output ${filePath}`;
665 fs
.mkdirSync("tests/output");
667 const exit
= await cli
.execute(code
);
669 assert
.strictEqual(exit
, 2);
670 assert
.isTrue(log
.info
.notCalled
);
671 assert
.isTrue(log
.error
.calledOnce
);
674 it("should return an error if the path could not be written to", async () => {
675 const filePath
= getFixturePath("single-quoted.js");
676 const code
= `--no-ignore --rule 'quotes: [1, double]' --o tests/output/eslint-output.txt ${filePath}`;
678 fs
.writeFileSync("tests/output", "foo");
680 const exit
= await cli
.execute(code
);
682 assert
.strictEqual(exit
, 2);
683 assert
.isTrue(log
.info
.notCalled
);
684 assert
.isTrue(log
.error
.calledOnce
);
688 describe("when supplied with a plugin", () => {
689 it("should pass plugins to ESLint", async () => {
690 const examplePluginName
= "eslint-plugin-example";
692 await
verifyESLintOpts(`--no-ignore --plugin ${examplePluginName} foo.js`, {
694 plugins
: [examplePluginName
]
701 describe("when supplied with a plugin-loading path", () => {
702 it("should pass the option to ESLint", async () => {
703 const examplePluginDirPath
= "foo/bar";
705 await
verifyESLintOpts(`--resolve-plugins-relative-to ${examplePluginDirPath} foo.js`, {
706 resolvePluginsRelativeTo
: examplePluginDirPath
711 describe("when given an parser name", () => {
712 it("should exit with a fatal error if parser is invalid", async () => {
713 const filePath
= getFixturePath("passing.js");
715 await stdAssert
.rejects(async () => await cli
.execute(`--no-ignore --parser test111 ${filePath}`), "Cannot find module 'test111'");
718 it("should exit with no error if parser is valid", async () => {
719 const filePath
= getFixturePath("passing.js");
720 const exit
= await cli
.execute(`--no-ignore --parser espree ${filePath}`);
722 assert
.strictEqual(exit
, 0);
726 describe("when given parser options", () => {
727 it("should exit with error if parser options are invalid", async () => {
728 const filePath
= getFixturePath("passing.js");
729 const exit
= await cli
.execute(`--no-ignore --parser-options test111 ${filePath}`);
731 assert
.strictEqual(exit
, 2);
734 it("should exit with no error if parser is valid", async () => {
735 const filePath
= getFixturePath("passing.js");
736 const exit
= await cli
.execute(`--no-ignore --parser-options=ecmaVersion:6 ${filePath}`);
738 assert
.strictEqual(exit
, 0);
741 it("should exit with an error on ecmaVersion 7 feature in ecmaVersion 6", async () => {
742 const filePath
= getFixturePath("passing-es7.js");
743 const exit
= await cli
.execute(`--no-ignore --parser-options=ecmaVersion:6 ${filePath}`);
745 assert
.strictEqual(exit
, 1);
748 it("should exit with no error on ecmaVersion 7 feature in ecmaVersion 7", async () => {
749 const filePath
= getFixturePath("passing-es7.js");
750 const exit
= await cli
.execute(`--no-ignore --parser-options=ecmaVersion:7 ${filePath}`);
752 assert
.strictEqual(exit
, 0);
755 it("should exit with no error on ecmaVersion 7 feature with config ecmaVersion 6 and command line ecmaVersion 7", async () => {
756 const configPath
= getFixturePath("configurations", "es6.json");
757 const filePath
= getFixturePath("passing-es7.js");
758 const exit
= await cli
.execute(`--no-ignore --config ${configPath} --parser-options=ecmaVersion:7 ${filePath}`);
760 assert
.strictEqual(exit
, 0);
764 describe("when given the max-warnings flag", () => {
765 it("should not change exit code if warning count under threshold", async () => {
766 const filePath
= getFixturePath("max-warnings");
767 const exitCode
= await cli
.execute(`--no-ignore --max-warnings 10 ${filePath}`);
769 assert
.strictEqual(exitCode
, 0);
772 it("should exit with exit code 1 if warning count exceeds threshold", async () => {
773 const filePath
= getFixturePath("max-warnings");
774 const exitCode
= await cli
.execute(`--no-ignore --max-warnings 5 ${filePath}`);
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");
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}`);
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
791 it("should not change exit code if warning count equals threshold", async () => {
792 const filePath
= getFixturePath("max-warnings");
793 const exitCode
= await cli
.execute(`--no-ignore --max-warnings 6 ${filePath}`);
795 assert
.strictEqual(exitCode
, 0);
798 it("should not change exit code if flag is not specified and there are warnings", async () => {
799 const filePath
= getFixturePath("max-warnings");
800 const exitCode
= await cli
.execute(filePath
);
802 assert
.strictEqual(exitCode
, 0);
806 describe("when passed --no-inline-config", () => {
810 sinon
.verifyAndRestore();
813 it("should pass allowInlineConfig:false to ESLint when --no-inline-config is used", async () => {
815 // create a fake ESLint class to test with
816 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match({ allowInlineConfig
: false }));
818 Object
.defineProperties(fakeESLint
.prototype, Object
.getOwnPropertyDescriptors(ESLint
.prototype));
819 sinon
.stub(fakeESLint
.prototype, "lintFiles").returns([{
820 filePath
: "./foo.js",
825 message
: "Fake message"
831 sinon
.stub(fakeESLint
.prototype, "loadFormatter").returns({ format
: () => "done" });
832 fakeESLint
.outputFixes
= sinon
.stub();
834 localCLI
= proxyquire("../../lib/cli", {
835 "./eslint": { ESLint
: fakeESLint
},
836 "./shared/logging": log
839 await localCLI
.execute("--no-inline-config .");
842 it("should not error and allowInlineConfig should be true by default", async () => {
844 // create a fake ESLint class to test with
845 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match({ allowInlineConfig
: true }));
847 Object
.defineProperties(fakeESLint
.prototype, Object
.getOwnPropertyDescriptors(ESLint
.prototype));
848 sinon
.stub(fakeESLint
.prototype, "lintFiles").returns([]);
849 sinon
.stub(fakeESLint
.prototype, "loadFormatter").returns({ format
: () => "done" });
850 fakeESLint
.outputFixes
= sinon
.stub();
852 localCLI
= proxyquire("../../lib/cli", {
853 "./eslint": { ESLint
: fakeESLint
},
854 "./shared/logging": log
857 const exitCode
= await localCLI
.execute(".");
859 assert
.strictEqual(exitCode
, 0);
865 describe("when passed --fix", () => {
869 sinon
.verifyAndRestore();
872 it("should pass fix:true to ESLint when executing on files", async () => {
874 // create a fake ESLint class to test with
875 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match({ fix
: true }));
877 Object
.defineProperties(fakeESLint
.prototype, Object
.getOwnPropertyDescriptors(ESLint
.prototype));
878 sinon
.stub(fakeESLint
.prototype, "lintFiles").returns([]);
879 sinon
.stub(fakeESLint
.prototype, "loadFormatter").returns({ format
: () => "done" });
880 fakeESLint
.outputFixes
= sinon
.mock().once();
882 localCLI
= proxyquire("../../lib/cli", {
883 "./eslint": { ESLint
: fakeESLint
},
884 "./shared/logging": log
887 const exitCode
= await localCLI
.execute("--fix .");
889 assert
.strictEqual(exitCode
, 0);
894 it("should rewrite files when in fix mode", async () => {
897 filePath
: "./foo.js",
902 message
: "Fake message"
909 // create a fake ESLint class to test with
910 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match({ fix
: true }));
912 Object
.defineProperties(fakeESLint
.prototype, Object
.getOwnPropertyDescriptors(ESLint
.prototype));
913 sinon
.stub(fakeESLint
.prototype, "lintFiles").returns(report
);
914 sinon
.stub(fakeESLint
.prototype, "loadFormatter").returns({ format
: () => "done" });
915 fakeESLint
.outputFixes
= sinon
.mock().withExactArgs(report
);
917 localCLI
= proxyquire("../../lib/cli", {
918 "./eslint": { ESLint
: fakeESLint
},
919 "./shared/logging": log
922 const exitCode
= await localCLI
.execute("--fix .");
924 assert
.strictEqual(exitCode
, 1);
928 it("should provide fix predicate and rewrite files when in fix mode and quiet mode", async () => {
931 filePath
: "./foo.js",
936 message
: "Fake message"
943 // create a fake ESLint class to test with
944 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match({ fix
: sinon
.match
.func
}));
946 Object
.defineProperties(fakeESLint
.prototype, Object
.getOwnPropertyDescriptors(ESLint
.prototype));
947 sinon
.stub(fakeESLint
.prototype, "lintFiles").returns(report
);
948 sinon
.stub(fakeESLint
.prototype, "loadFormatter").returns({ format
: () => "done" });
949 fakeESLint
.getErrorResults
= sinon
.stub().returns([]);
950 fakeESLint
.outputFixes
= sinon
.mock().withExactArgs(report
);
952 localCLI
= proxyquire("../../lib/cli", {
953 "./eslint": { ESLint
: fakeESLint
},
954 "./shared/logging": log
957 const exitCode
= await localCLI
.execute("--fix --quiet .");
959 assert
.strictEqual(exitCode
, 0);
963 it("should not call ESLint and return 2 when executing on text", async () => {
965 // create a fake ESLint class to test with
966 const fakeESLint
= sinon
.mock().never();
968 localCLI
= proxyquire("../../lib/cli", {
969 "./eslint": { ESLint
: fakeESLint
},
970 "./shared/logging": log
973 const exitCode
= await localCLI
.execute("--fix .", "foo = bar;");
975 assert
.strictEqual(exitCode
, 2);
980 describe("when passed --fix-dry-run", () => {
984 sinon
.verifyAndRestore();
987 it("should pass fix:true to ESLint when executing on files", async () => {
989 // create a fake ESLint class to test with
990 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match({ fix
: true }));
992 Object
.defineProperties(fakeESLint
.prototype, Object
.getOwnPropertyDescriptors(ESLint
.prototype));
993 sinon
.stub(fakeESLint
.prototype, "lintFiles").returns([]);
994 sinon
.stub(fakeESLint
.prototype, "loadFormatter").returns({ format
: () => "done" });
995 fakeESLint
.outputFixes
= sinon
.mock().never();
997 localCLI
= proxyquire("../../lib/cli", {
998 "./eslint": { ESLint
: fakeESLint
},
999 "./shared/logging": log
1002 const exitCode
= await localCLI
.execute("--fix-dry-run .");
1004 assert
.strictEqual(exitCode
, 0);
1008 it("should pass fixTypes to ESLint when --fix-type is passed", async () => {
1010 const expectedESLintOptions
= {
1012 fixTypes
: ["suggestion"]
1015 // create a fake ESLint class to test with
1016 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match(expectedESLintOptions
));
1018 Object
.defineProperties(fakeESLint
.prototype, Object
.getOwnPropertyDescriptors(ESLint
.prototype));
1019 sinon
.stub(fakeESLint
.prototype, "lintFiles").returns([]);
1020 sinon
.stub(fakeESLint
.prototype, "loadFormatter").returns({ format
: () => "done" });
1021 fakeESLint
.outputFixes
= sinon
.stub();
1023 localCLI
= proxyquire("../../lib/cli", {
1024 "./eslint": { ESLint
: fakeESLint
},
1025 "./shared/logging": log
1028 const exitCode
= await localCLI
.execute("--fix-dry-run --fix-type suggestion .");
1030 assert
.strictEqual(exitCode
, 0);
1033 it("should not rewrite files when in fix-dry-run mode", async () => {
1036 filePath
: "./foo.js",
1041 message
: "Fake message"
1048 // create a fake ESLint class to test with
1049 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match({ fix
: true }));
1051 Object
.defineProperties(fakeESLint
.prototype, Object
.getOwnPropertyDescriptors(ESLint
.prototype));
1052 sinon
.stub(fakeESLint
.prototype, "lintFiles").returns(report
);
1053 sinon
.stub(fakeESLint
.prototype, "loadFormatter").returns({ format
: () => "done" });
1054 fakeESLint
.outputFixes
= sinon
.mock().never();
1056 localCLI
= proxyquire("../../lib/cli", {
1057 "./eslint": { ESLint
: fakeESLint
},
1058 "./shared/logging": log
1061 const exitCode
= await localCLI
.execute("--fix-dry-run .");
1063 assert
.strictEqual(exitCode
, 1);
1067 it("should provide fix predicate when in fix-dry-run mode and quiet mode", async () => {
1070 filePath
: "./foo.js",
1075 message
: "Fake message"
1082 // create a fake ESLint class to test with
1083 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match({ fix
: sinon
.match
.func
}));
1085 Object
.defineProperties(fakeESLint
.prototype, Object
.getOwnPropertyDescriptors(ESLint
.prototype));
1086 sinon
.stub(fakeESLint
.prototype, "lintFiles").returns(report
);
1087 sinon
.stub(fakeESLint
.prototype, "loadFormatter").returns({ format
: () => "done" });
1088 fakeESLint
.getErrorResults
= sinon
.stub().returns([]);
1089 fakeESLint
.outputFixes
= sinon
.mock().never();
1091 localCLI
= proxyquire("../../lib/cli", {
1092 "./eslint": { ESLint
: fakeESLint
},
1093 "./shared/logging": log
1096 const exitCode
= await localCLI
.execute("--fix-dry-run --quiet .");
1098 assert
.strictEqual(exitCode
, 0);
1102 it("should allow executing on text", async () => {
1105 filePath
: "./foo.js",
1110 message
: "Fake message"
1117 // create a fake ESLint class to test with
1118 const fakeESLint
= sinon
.mock().withExactArgs(sinon
.match({ fix
: true }));
1120 Object
.defineProperties(fakeESLint
.prototype, Object
.getOwnPropertyDescriptors(ESLint
.prototype));
1121 sinon
.stub(fakeESLint
.prototype, "lintText").returns(report
);
1122 sinon
.stub(fakeESLint
.prototype, "loadFormatter").returns({ format
: () => "done" });
1123 fakeESLint
.outputFixes
= sinon
.mock().never();
1125 localCLI
= proxyquire("../../lib/cli", {
1126 "./eslint": { ESLint
: fakeESLint
},
1127 "./shared/logging": log
1130 const exitCode
= await localCLI
.execute("--fix-dry-run .", "foo = bar;");
1132 assert
.strictEqual(exitCode
, 1);
1135 it("should not call ESLint and return 2 when used with --fix", async () => {
1137 // create a fake ESLint class to test with
1138 const fakeESLint
= sinon
.mock().never();
1140 localCLI
= proxyquire("../../lib/cli", {
1141 "./eslint": { ESLint
: fakeESLint
},
1142 "./shared/logging": log
1145 const exitCode
= await localCLI
.execute("--fix --fix-dry-run .", "foo = bar;");
1147 assert
.strictEqual(exitCode
, 2);
1151 describe("when passing --print-config", () => {
1152 it("should print out the configuration", async () => {
1153 const filePath
= getFixturePath("xxxx");
1155 const exitCode
= await cli
.execute(`--print-config ${filePath}`);
1157 assert
.isTrue(log
.info
.calledOnce
);
1158 assert
.strictEqual(exitCode
, 0);
1161 it("should error if any positional file arguments are passed", async () => {
1162 const filePath1
= getFixturePath("files", "bar.js");
1163 const filePath2
= getFixturePath("files", "foo.js");
1165 const exitCode
= await cli
.execute(`--print-config ${filePath1} ${filePath2}`);
1167 assert
.isTrue(log
.info
.notCalled
);
1168 assert
.isTrue(log
.error
.calledOnce
);
1169 assert
.strictEqual(exitCode
, 2);
1172 it("should error out when executing on text", async () => {
1173 const exitCode
= await cli
.execute("--print-config=myFile.js", "foo = bar;");
1175 assert
.isTrue(log
.info
.notCalled
);
1176 assert
.isTrue(log
.error
.calledOnce
);
1177 assert
.strictEqual(exitCode
, 2);