mirror of
https://git.proxmox.com/git/pve-eslint
synced 2025-10-04 20:48:29 +00:00
443 lines
16 KiB
JavaScript
443 lines
16 KiB
JavaScript
/**
|
|
* @fileoverview Tests for configInitializer.
|
|
* @author Ilya Volodin
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Requirements
|
|
//------------------------------------------------------------------------------
|
|
|
|
const assert = require("chai").assert,
|
|
fs = require("fs"),
|
|
path = require("path"),
|
|
os = require("os"),
|
|
sinon = require("sinon"),
|
|
sh = require("shelljs"),
|
|
espree = require("espree"),
|
|
autoconfig = require("../../../lib/init/autoconfig"),
|
|
npmUtils = require("../../../lib/init/npm-utils");
|
|
|
|
const originalDir = process.cwd();
|
|
const proxyquire = require("proxyquire").noPreserveCache();
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Tests
|
|
//------------------------------------------------------------------------------
|
|
|
|
let answers = {};
|
|
|
|
describe("configInitializer", () => {
|
|
|
|
let fixtureDir,
|
|
npmCheckStub,
|
|
npmInstallStub,
|
|
npmFetchPeerDependenciesStub,
|
|
init,
|
|
localESLintVersion = null;
|
|
|
|
const log = {
|
|
info: sinon.spy(),
|
|
error: sinon.spy()
|
|
};
|
|
const requireStubs = {
|
|
"../shared/logging": log,
|
|
"../shared/relative-module-resolver": {
|
|
resolve() {
|
|
if (localESLintVersion) {
|
|
return `local-eslint-${localESLintVersion}`;
|
|
}
|
|
throw new Error("Cannot find module");
|
|
}
|
|
},
|
|
"local-eslint-3.18.0": { linter: { version: "3.18.0" }, "@noCallThru": true },
|
|
"local-eslint-3.19.0": { linter: { version: "3.19.0" }, "@noCallThru": true },
|
|
"local-eslint-4.0.0": { linter: { version: "4.0.0" }, "@noCallThru": true }
|
|
};
|
|
|
|
/**
|
|
* Returns the path inside of the fixture directory.
|
|
* @param {...string} args file path segments.
|
|
* @returns {string} The path inside the fixture directory.
|
|
* @private
|
|
*/
|
|
function getFixturePath(...args) {
|
|
const filepath = path.join(fixtureDir, ...args);
|
|
|
|
try {
|
|
return fs.realpathSync(filepath);
|
|
} catch {
|
|
return filepath;
|
|
}
|
|
}
|
|
|
|
// copy into clean area so as not to get "infected" by this project's .eslintrc files
|
|
before(() => {
|
|
fixtureDir = path.join(os.tmpdir(), "eslint/fixtures/config-initializer");
|
|
sh.mkdir("-p", fixtureDir);
|
|
sh.cp("-r", "./tests/fixtures/config-initializer/.", fixtureDir);
|
|
fixtureDir = fs.realpathSync(fixtureDir);
|
|
});
|
|
|
|
beforeEach(() => {
|
|
npmInstallStub = sinon.stub(npmUtils, "installSyncSaveDev");
|
|
npmCheckStub = sinon.stub(npmUtils, "checkDevDeps").callsFake(packages => packages.reduce((status, pkg) => {
|
|
status[pkg] = false;
|
|
return status;
|
|
}, {}));
|
|
npmFetchPeerDependenciesStub = sinon
|
|
.stub(npmUtils, "fetchPeerDependencies")
|
|
.returns({
|
|
eslint: "^3.19.0",
|
|
"eslint-plugin-jsx-a11y": "^5.0.1",
|
|
"eslint-plugin-import": "^2.2.0",
|
|
"eslint-plugin-react": "^7.0.1"
|
|
});
|
|
init = proxyquire("../../../lib/init/config-initializer", requireStubs);
|
|
});
|
|
|
|
afterEach(() => {
|
|
log.info.resetHistory();
|
|
log.error.resetHistory();
|
|
npmInstallStub.restore();
|
|
npmCheckStub.restore();
|
|
npmFetchPeerDependenciesStub.restore();
|
|
});
|
|
|
|
after(() => {
|
|
sh.rm("-r", fixtureDir);
|
|
});
|
|
|
|
describe("processAnswers()", () => {
|
|
|
|
describe("prompt", () => {
|
|
|
|
beforeEach(() => {
|
|
answers = {
|
|
purpose: "style",
|
|
source: "prompt",
|
|
extendDefault: true,
|
|
indent: 2,
|
|
quotes: "single",
|
|
linebreak: "unix",
|
|
semi: true,
|
|
moduleType: "esm",
|
|
es6Globals: true,
|
|
env: ["browser"],
|
|
format: "JSON"
|
|
};
|
|
});
|
|
|
|
it("should create default config", () => {
|
|
const config = init.processAnswers(answers);
|
|
|
|
assert.deepStrictEqual(config.rules.indent, ["error", 2]);
|
|
assert.deepStrictEqual(config.rules.quotes, ["error", "single"]);
|
|
assert.deepStrictEqual(config.rules["linebreak-style"], ["error", "unix"]);
|
|
assert.deepStrictEqual(config.rules.semi, ["error", "always"]);
|
|
assert.strictEqual(config.env.es2020, true);
|
|
assert.strictEqual(config.parserOptions.ecmaVersion, espree.latestEcmaVersion);
|
|
assert.strictEqual(config.parserOptions.sourceType, "module");
|
|
assert.strictEqual(config.env.browser, true);
|
|
assert.strictEqual(config.extends, "eslint:recommended");
|
|
});
|
|
|
|
it("should disable semi", () => {
|
|
answers.semi = false;
|
|
const config = init.processAnswers(answers);
|
|
|
|
assert.deepStrictEqual(config.rules.semi, ["error", "never"]);
|
|
});
|
|
|
|
it("should enable react plugin", () => {
|
|
answers.framework = "react";
|
|
const config = init.processAnswers(answers);
|
|
|
|
assert.strictEqual(config.parserOptions.ecmaFeatures.jsx, true);
|
|
assert.strictEqual(config.parserOptions.ecmaVersion, espree.latestEcmaVersion);
|
|
assert.deepStrictEqual(config.plugins, ["react"]);
|
|
});
|
|
|
|
it("should enable vue plugin", () => {
|
|
answers.framework = "vue";
|
|
const config = init.processAnswers(answers);
|
|
|
|
assert.strictEqual(config.parserOptions.ecmaVersion, espree.latestEcmaVersion);
|
|
assert.deepStrictEqual(config.plugins, ["vue"]);
|
|
assert.deepStrictEqual(config.extends, ["eslint:recommended", "plugin:vue/essential"]);
|
|
});
|
|
|
|
it("should enable typescript parser and plugin", () => {
|
|
answers.typescript = true;
|
|
const config = init.processAnswers(answers);
|
|
|
|
assert.strictEqual(config.parser, "@typescript-eslint/parser");
|
|
assert.deepStrictEqual(config.plugins, ["@typescript-eslint"]);
|
|
assert.deepStrictEqual(config.extends, ["eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended"]);
|
|
});
|
|
|
|
it("should enable typescript parser and plugin with vue", () => {
|
|
answers.framework = "vue";
|
|
answers.typescript = true;
|
|
const config = init.processAnswers(answers);
|
|
|
|
assert.deepStrictEqual(config.extends, ["eslint:recommended", "plugin:vue/essential", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended"]);
|
|
assert.strictEqual(config.parserOptions.parser, "@typescript-eslint/parser");
|
|
assert.deepStrictEqual(config.plugins, ["vue", "@typescript-eslint"]);
|
|
});
|
|
|
|
it("should extend eslint:recommended", () => {
|
|
const config = init.processAnswers(answers);
|
|
|
|
assert.strictEqual(config.extends, "eslint:recommended");
|
|
});
|
|
|
|
it("should not use commonjs by default", () => {
|
|
const config = init.processAnswers(answers);
|
|
|
|
assert.isUndefined(config.env.commonjs);
|
|
});
|
|
|
|
it("should use commonjs when set", () => {
|
|
answers.moduleType = "commonjs";
|
|
const config = init.processAnswers(answers);
|
|
|
|
assert.isTrue(config.env.commonjs);
|
|
});
|
|
});
|
|
|
|
describe("guide", () => {
|
|
it("should support the google style guide", () => {
|
|
const config = { extends: "google" };
|
|
const modules = init.getModulesList(config);
|
|
|
|
assert.deepStrictEqual(config, { extends: "google", installedESLint: true });
|
|
assert.include(modules, "eslint-config-google@latest");
|
|
});
|
|
|
|
it("should support the airbnb style guide", () => {
|
|
const config = { extends: "airbnb" };
|
|
const modules = init.getModulesList(config);
|
|
|
|
assert.deepStrictEqual(config, { extends: "airbnb", installedESLint: true });
|
|
assert.include(modules, "eslint-config-airbnb@latest");
|
|
});
|
|
|
|
it("should support the airbnb base style guide", () => {
|
|
const config = { extends: "airbnb-base" };
|
|
const modules = init.getModulesList(config);
|
|
|
|
assert.deepStrictEqual(config, { extends: "airbnb-base", installedESLint: true });
|
|
assert.include(modules, "eslint-config-airbnb-base@latest");
|
|
});
|
|
|
|
it("should support the standard style guide", () => {
|
|
const config = { extends: "standard" };
|
|
const modules = init.getModulesList(config);
|
|
|
|
assert.deepStrictEqual(config, { extends: "standard", installedESLint: true });
|
|
assert.include(modules, "eslint-config-standard@latest");
|
|
});
|
|
|
|
it("should install required sharable config", () => {
|
|
const config = { extends: "google" };
|
|
|
|
init.installModules(init.getModulesList(config));
|
|
assert(npmInstallStub.calledOnce);
|
|
assert(npmInstallStub.firstCall.args[0].some(name => name.startsWith("eslint-config-google@")));
|
|
});
|
|
|
|
it("should install ESLint if not installed locally", () => {
|
|
const config = { extends: "google" };
|
|
|
|
init.installModules(init.getModulesList(config));
|
|
assert(npmInstallStub.calledOnce);
|
|
assert(npmInstallStub.firstCall.args[0].some(name => name.startsWith("eslint@")));
|
|
});
|
|
|
|
it("should install peerDependencies of the sharable config", () => {
|
|
const config = { extends: "airbnb" };
|
|
|
|
init.installModules(init.getModulesList(config));
|
|
|
|
assert(npmFetchPeerDependenciesStub.calledOnce);
|
|
assert(npmFetchPeerDependenciesStub.firstCall.args[0] === "eslint-config-airbnb@latest");
|
|
assert(npmInstallStub.calledOnce);
|
|
assert.deepStrictEqual(
|
|
npmInstallStub.firstCall.args[0],
|
|
[
|
|
"eslint-config-airbnb@latest",
|
|
"eslint@^3.19.0",
|
|
"eslint-plugin-jsx-a11y@^5.0.1",
|
|
"eslint-plugin-import@^2.2.0",
|
|
"eslint-plugin-react@^7.0.1"
|
|
]
|
|
);
|
|
});
|
|
|
|
describe("hasESLintVersionConflict (Note: peerDependencies always `eslint: \"^3.19.0\"` by stubs)", () => {
|
|
describe("if local ESLint is not found,", () => {
|
|
before(() => {
|
|
localESLintVersion = null;
|
|
});
|
|
|
|
it("should return false.", () => {
|
|
const result = init.hasESLintVersionConflict({ styleguide: "airbnb" });
|
|
|
|
assert.strictEqual(result, false);
|
|
});
|
|
});
|
|
|
|
describe("if local ESLint is 3.19.0,", () => {
|
|
before(() => {
|
|
localESLintVersion = "3.19.0";
|
|
});
|
|
|
|
it("should return false.", () => {
|
|
const result = init.hasESLintVersionConflict({ styleguide: "airbnb" });
|
|
|
|
assert.strictEqual(result, false);
|
|
});
|
|
});
|
|
|
|
describe("if local ESLint is 4.0.0,", () => {
|
|
before(() => {
|
|
localESLintVersion = "4.0.0";
|
|
});
|
|
|
|
it("should return true.", () => {
|
|
const result = init.hasESLintVersionConflict({ styleguide: "airbnb" });
|
|
|
|
assert.strictEqual(result, true);
|
|
});
|
|
});
|
|
|
|
describe("if local ESLint is 3.18.0,", () => {
|
|
before(() => {
|
|
localESLintVersion = "3.18.0";
|
|
});
|
|
|
|
it("should return true.", () => {
|
|
const result = init.hasESLintVersionConflict({ styleguide: "airbnb" });
|
|
|
|
assert.strictEqual(result, true);
|
|
});
|
|
});
|
|
});
|
|
|
|
it("should support the standard style guide with Vue.js", () => {
|
|
const config = {
|
|
plugins: ["vue"],
|
|
extends: ["plugin:vue/essential", "standard"]
|
|
};
|
|
const modules = init.getModulesList(config);
|
|
|
|
assert.include(modules, "eslint-plugin-vue@latest");
|
|
assert.include(modules, "eslint-config-standard@latest");
|
|
});
|
|
|
|
it("should support custom parser", () => {
|
|
const config = {
|
|
parser: "@typescript-eslint/parser"
|
|
};
|
|
const modules = init.getModulesList(config);
|
|
|
|
assert.include(modules, "@typescript-eslint/parser@latest");
|
|
});
|
|
|
|
it("should support custom parser with Vue.js", () => {
|
|
const config = {
|
|
|
|
// We should declare the parser at `parserOptions` when using with `eslint-plugin-vue`.
|
|
parserOptions: {
|
|
parser: "@typescript-eslint/parser"
|
|
}
|
|
};
|
|
const modules = init.getModulesList(config);
|
|
|
|
assert.include(modules, "@typescript-eslint/parser@latest");
|
|
});
|
|
});
|
|
|
|
describe("auto", () => {
|
|
const completeSpy = sinon.spy();
|
|
let config;
|
|
|
|
before(() => {
|
|
const patterns = [
|
|
getFixturePath("lib"),
|
|
getFixturePath("tests")
|
|
].join(" ");
|
|
|
|
answers = {
|
|
purpose: "style",
|
|
source: "auto",
|
|
patterns,
|
|
env: ["browser"],
|
|
format: "JSON"
|
|
};
|
|
|
|
sinon.stub(console, "log"); // necessary to replace, because of progress bar
|
|
|
|
process.chdir(fixtureDir);
|
|
config = init.processAnswers(answers);
|
|
sinon.restore();
|
|
});
|
|
|
|
after(() => {
|
|
sinon.restore();
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.chdir(originalDir);
|
|
sinon.restore();
|
|
});
|
|
|
|
it("should create a config", () => {
|
|
assert.isTrue(completeSpy.notCalled);
|
|
assert.ok(config);
|
|
});
|
|
|
|
it("should create the config based on examined files", () => {
|
|
assert.deepStrictEqual(config.rules.quotes, ["error", "double"]);
|
|
assert.strictEqual(config.rules.semi, "off");
|
|
});
|
|
|
|
it("should extend and not disable recommended rules", () => {
|
|
assert.strictEqual(config.extends, "eslint:recommended");
|
|
assert.notProperty(config.rules, "no-debugger");
|
|
});
|
|
|
|
it("should support new ES features if using later ES version", () => {
|
|
const filename = getFixturePath("new-es-features");
|
|
|
|
answers.patterns = filename;
|
|
answers.ecmaVersion = 2017;
|
|
process.chdir(fixtureDir);
|
|
config = init.processAnswers(answers);
|
|
});
|
|
|
|
it("should throw on fatal parsing error", () => {
|
|
const filename = getFixturePath("parse-error");
|
|
|
|
sinon.stub(autoconfig, "extendFromRecommended");
|
|
answers.patterns = filename;
|
|
process.chdir(fixtureDir);
|
|
assert.throws(() => {
|
|
config = init.processAnswers(answers);
|
|
}, "Parsing error: Unexpected token ;");
|
|
});
|
|
|
|
it("should throw if no files are matched from patterns", () => {
|
|
sinon.stub(autoconfig, "extendFromRecommended");
|
|
answers.patterns = "not-a-real-filename";
|
|
process.chdir(fixtureDir);
|
|
assert.throws(() => {
|
|
config = init.processAnswers(answers);
|
|
}, "No files matching 'not-a-real-filename' were found.");
|
|
});
|
|
});
|
|
});
|
|
});
|