2 * @fileoverview Tests for configInitializer.
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const assert
= require("chai").assert
,
14 path
= require("path"),
16 sinon
= require("sinon"),
17 sh
= require("shelljs"),
18 espree
= require("espree"),
19 autoconfig
= require("../../../lib/init/autoconfig"),
20 npmUtils
= require("../../../lib/init/npm-utils");
22 const originalDir
= process
.cwd();
23 const proxyquire
= require("proxyquire").noPreserveCache();
25 //------------------------------------------------------------------------------
27 //------------------------------------------------------------------------------
31 describe("configInitializer", () => {
36 npmFetchPeerDependenciesStub
,
38 localESLintVersion
= null;
44 const requireStubs
= {
45 "../shared/logging": log
,
46 "../shared/relative-module-resolver": {
48 if (localESLintVersion
) {
49 return `local-eslint-${localESLintVersion}`;
51 throw new Error("Cannot find module");
54 "local-eslint-3.18.0": { linter
: { version
: "3.18.0" }, "@noCallThru": true },
55 "local-eslint-3.19.0": { linter
: { version
: "3.19.0" }, "@noCallThru": true },
56 "local-eslint-4.0.0": { linter
: { version
: "4.0.0" }, "@noCallThru": true }
60 * Returns the path inside of the fixture directory.
61 * @param {...string} args file path segments.
62 * @returns {string} The path inside the fixture directory.
65 function getFixturePath(...args
) {
66 const filepath
= path
.join(fixtureDir
, ...args
);
69 return fs
.realpathSync(filepath
);
75 // copy into clean area so as not to get "infected" by this project's .eslintrc files
77 fixtureDir
= path
.join(os
.tmpdir(), "eslint/fixtures/config-initializer");
78 sh
.mkdir("-p", fixtureDir
);
79 sh
.cp("-r", "./tests/fixtures/config-initializer/.", fixtureDir
);
80 fixtureDir
= fs
.realpathSync(fixtureDir
);
84 npmInstallStub
= sinon
.stub(npmUtils
, "installSyncSaveDev");
85 npmCheckStub
= sinon
.stub(npmUtils
, "checkDevDeps").callsFake(packages
=> packages
.reduce((status
, pkg
) => {
89 npmFetchPeerDependenciesStub
= sinon
90 .stub(npmUtils
, "fetchPeerDependencies")
93 "eslint-plugin-jsx-a11y": "^5.0.1",
94 "eslint-plugin-import": "^2.2.0",
95 "eslint-plugin-react": "^7.0.1"
97 init
= proxyquire("../../../lib/init/config-initializer", requireStubs
);
101 log
.info
.resetHistory();
102 log
.error
.resetHistory();
103 npmInstallStub
.restore();
104 npmCheckStub
.restore();
105 npmFetchPeerDependenciesStub
.restore();
109 sh
.rm("-r", fixtureDir
);
112 describe("processAnswers()", () => {
114 describe("prompt", () => {
132 it("should create default config", () => {
133 const config
= init
.processAnswers(answers
);
135 assert
.deepStrictEqual(config
.rules
.indent
, ["error", 2]);
136 assert
.deepStrictEqual(config
.rules
.quotes
, ["error", "single"]);
137 assert
.deepStrictEqual(config
.rules
["linebreak-style"], ["error", "unix"]);
138 assert
.deepStrictEqual(config
.rules
.semi
, ["error", "always"]);
139 assert
.strictEqual(config
.env
.es6
, true);
140 assert
.strictEqual(config
.globals
.Atomics
, "readonly");
141 assert
.strictEqual(config
.globals
.SharedArrayBuffer
, "readonly");
142 assert
.strictEqual(config
.parserOptions
.ecmaVersion
, espree
.latestEcmaVersion
);
143 assert
.strictEqual(config
.parserOptions
.sourceType
, "module");
144 assert
.strictEqual(config
.env
.browser
, true);
145 assert
.strictEqual(config
.extends, "eslint:recommended");
148 it("should disable semi", () => {
149 answers
.semi
= false;
150 const config
= init
.processAnswers(answers
);
152 assert
.deepStrictEqual(config
.rules
.semi
, ["error", "never"]);
155 it("should enable react plugin", () => {
156 answers
.framework
= "react";
157 const config
= init
.processAnswers(answers
);
159 assert
.strictEqual(config
.parserOptions
.ecmaFeatures
.jsx
, true);
160 assert
.strictEqual(config
.parserOptions
.ecmaVersion
, espree
.latestEcmaVersion
);
161 assert
.deepStrictEqual(config
.plugins
, ["react"]);
164 it("should enable vue plugin", () => {
165 answers
.framework
= "vue";
166 const config
= init
.processAnswers(answers
);
168 assert
.strictEqual(config
.parserOptions
.ecmaVersion
, espree
.latestEcmaVersion
);
169 assert
.deepStrictEqual(config
.plugins
, ["vue"]);
170 assert
.deepStrictEqual(config
.extends, ["eslint:recommended", "plugin:vue/essential"]);
173 it("should enable typescript parser and plugin", () => {
174 answers
.typescript
= true;
175 const config
= init
.processAnswers(answers
);
177 assert
.strictEqual(config
.parser
, "@typescript-eslint/parser");
178 assert
.deepStrictEqual(config
.plugins
, ["@typescript-eslint"]);
179 assert
.deepStrictEqual(config
.extends, ["eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended"]);
182 it("should enable typescript parser and plugin with vue", () => {
183 answers
.framework
= "vue";
184 answers
.typescript
= true;
185 const config
= init
.processAnswers(answers
);
187 assert
.deepStrictEqual(config
.extends, ["eslint:recommended", "plugin:vue/essential", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended"]);
188 assert
.strictEqual(config
.parserOptions
.parser
, "@typescript-eslint/parser");
189 assert
.deepStrictEqual(config
.plugins
, ["vue", "@typescript-eslint"]);
192 it("should extend eslint:recommended", () => {
193 const config
= init
.processAnswers(answers
);
195 assert
.strictEqual(config
.extends, "eslint:recommended");
198 it("should not use commonjs by default", () => {
199 const config
= init
.processAnswers(answers
);
201 assert
.isUndefined(config
.env
.commonjs
);
204 it("should use commonjs when set", () => {
205 answers
.moduleType
= "commonjs";
206 const config
= init
.processAnswers(answers
);
208 assert
.isTrue(config
.env
.commonjs
);
212 describe("guide", () => {
213 it("should support the google style guide", () => {
214 const config
= { extends: "google" };
215 const modules
= init
.getModulesList(config
);
217 assert
.deepStrictEqual(config
, { extends: "google", installedESLint
: true });
218 assert
.include(modules
, "eslint-config-google@latest");
221 it("should support the airbnb style guide", () => {
222 const config
= { extends: "airbnb" };
223 const modules
= init
.getModulesList(config
);
225 assert
.deepStrictEqual(config
, { extends: "airbnb", installedESLint
: true });
226 assert
.include(modules
, "eslint-config-airbnb@latest");
229 it("should support the airbnb base style guide", () => {
230 const config
= { extends: "airbnb-base" };
231 const modules
= init
.getModulesList(config
);
233 assert
.deepStrictEqual(config
, { extends: "airbnb-base", installedESLint
: true });
234 assert
.include(modules
, "eslint-config-airbnb-base@latest");
237 it("should support the standard style guide", () => {
238 const config
= { extends: "standard" };
239 const modules
= init
.getModulesList(config
);
241 assert
.deepStrictEqual(config
, { extends: "standard", installedESLint
: true });
242 assert
.include(modules
, "eslint-config-standard@latest");
245 it("should install required sharable config", () => {
246 const config
= { extends: "google" };
248 init
.installModules(init
.getModulesList(config
));
249 assert(npmInstallStub
.calledOnce
);
250 assert(npmInstallStub
.firstCall
.args
[0].some(name
=> name
.startsWith("eslint-config-google@")));
253 it("should install ESLint if not installed locally", () => {
254 const config
= { extends: "google" };
256 init
.installModules(init
.getModulesList(config
));
257 assert(npmInstallStub
.calledOnce
);
258 assert(npmInstallStub
.firstCall
.args
[0].some(name
=> name
.startsWith("eslint@")));
261 it("should install peerDependencies of the sharable config", () => {
262 const config
= { extends: "airbnb" };
264 init
.installModules(init
.getModulesList(config
));
266 assert(npmFetchPeerDependenciesStub
.calledOnce
);
267 assert(npmFetchPeerDependenciesStub
.firstCall
.args
[0] === "eslint-config-airbnb@latest");
268 assert(npmInstallStub
.calledOnce
);
269 assert
.deepStrictEqual(
270 npmInstallStub
.firstCall
.args
[0],
272 "eslint-config-airbnb@latest",
274 "eslint-plugin-jsx-a11y@^5.0.1",
275 "eslint-plugin-import@^2.2.0",
276 "eslint-plugin-react@^7.0.1"
281 describe("hasESLintVersionConflict (Note: peerDependencies always `eslint: \"^3.19.0\"` by stubs)", () => {
282 describe("if local ESLint is not found,", () => {
284 localESLintVersion
= null;
287 it("should return false.", () => {
288 const result
= init
.hasESLintVersionConflict({ styleguide
: "airbnb" });
290 assert
.strictEqual(result
, false);
294 describe("if local ESLint is 3.19.0,", () => {
296 localESLintVersion
= "3.19.0";
299 it("should return false.", () => {
300 const result
= init
.hasESLintVersionConflict({ styleguide
: "airbnb" });
302 assert
.strictEqual(result
, false);
306 describe("if local ESLint is 4.0.0,", () => {
308 localESLintVersion
= "4.0.0";
311 it("should return true.", () => {
312 const result
= init
.hasESLintVersionConflict({ styleguide
: "airbnb" });
314 assert
.strictEqual(result
, true);
318 describe("if local ESLint is 3.18.0,", () => {
320 localESLintVersion
= "3.18.0";
323 it("should return true.", () => {
324 const result
= init
.hasESLintVersionConflict({ styleguide
: "airbnb" });
326 assert
.strictEqual(result
, true);
331 it("should support the standard style guide with Vue.js", () => {
334 extends: ["plugin:vue/essential", "standard"]
336 const modules
= init
.getModulesList(config
);
338 assert
.include(modules
, "eslint-plugin-vue@latest");
339 assert
.include(modules
, "eslint-config-standard@latest");
342 it("should support custom parser", () => {
344 parser
: "@typescript-eslint/parser"
346 const modules
= init
.getModulesList(config
);
348 assert
.include(modules
, "@typescript-eslint/parser@latest");
351 it("should support custom parser with Vue.js", () => {
354 // We should declare the parser at `parserOptions` when using with `eslint-plugin-vue`.
356 parser
: "@typescript-eslint/parser"
359 const modules
= init
.getModulesList(config
);
361 assert
.include(modules
, "@typescript-eslint/parser@latest");
365 describe("auto", () => {
366 const completeSpy
= sinon
.spy();
371 getFixturePath("lib"),
372 getFixturePath("tests")
383 sinon
.stub(console
, "log"); // necessary to replace, because of progress bar
385 process
.chdir(fixtureDir
);
386 config
= init
.processAnswers(answers
);
395 process
.chdir(originalDir
);
399 it("should create a config", () => {
400 assert
.isTrue(completeSpy
.notCalled
);
404 it("should create the config based on examined files", () => {
405 assert
.deepStrictEqual(config
.rules
.quotes
, ["error", "double"]);
406 assert
.strictEqual(config
.rules
.semi
, "off");
409 it("should extend and not disable recommended rules", () => {
410 assert
.strictEqual(config
.extends, "eslint:recommended");
411 assert
.notProperty(config
.rules
, "no-debugger");
414 it("should support new ES features if using later ES version", () => {
415 const filename
= getFixturePath("new-es-features");
417 answers
.patterns
= filename
;
418 answers
.ecmaVersion
= 2017;
419 process
.chdir(fixtureDir
);
420 config
= init
.processAnswers(answers
);
423 it("should throw on fatal parsing error", () => {
424 const filename
= getFixturePath("parse-error");
426 sinon
.stub(autoconfig
, "extendFromRecommended");
427 answers
.patterns
= filename
;
428 process
.chdir(fixtureDir
);
429 assert
.throws(() => {
430 config
= init
.processAnswers(answers
);
431 }, "Parsing error: Unexpected token ;");
434 it("should throw if no files are matched from patterns", () => {
435 sinon
.stub(autoconfig
, "extendFromRecommended");
436 answers
.patterns
= "not-a-real-filename";
437 process
.chdir(fixtureDir
);
438 assert
.throws(() => {
439 config
= init
.processAnswers(answers
);
440 }, "No files matching 'not-a-real-filename' were found.");