/** * @fileoverview Tests for options. * @author Sindre Sorhus */ "use strict"; //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ const assert = require("chai").assert, chalk = require("chalk"), proxyquire = require("proxyquire"), sinon = require("sinon"); //----------------------------------------------------------------------------- // Helpers //----------------------------------------------------------------------------- /* * Chalk protects its methods so we need to inherit from it * for Sinon to work. */ const chalkStub = Object.create(chalk, { reset: { value(str) { return chalk.reset(str); }, writable: true }, yellow: { value(str) { return chalk.yellow(str); }, writable: true }, red: { value(str) { return chalk.red(str); }, writable: true } }); chalkStub.yellow.bold = chalk.yellow.bold; chalkStub.red.bold = chalk.red.bold; const formatter = proxyquire("../../../../lib/cli-engine/formatters/stylish", { chalk: chalkStub }); //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ describe("formatter:stylish", () => { const originalColorLevel = chalk.level; beforeEach(() => { chalk.level = 0; sinon.spy(chalkStub, "reset"); sinon.spy(chalkStub.yellow, "bold"); sinon.spy(chalkStub.red, "bold"); }); afterEach(() => { sinon.verifyAndRestore(); chalk.level = originalColorLevel; }); describe("when passed no messages", () => { const code = [{ filePath: "foo.js", messages: [], errorCount: 0, warningCount: 0 }]; it("should not return message", () => { const result = formatter(code); assert.strictEqual(result, ""); assert.strictEqual(chalkStub.reset.callCount, 0); assert.strictEqual(chalkStub.yellow.bold.callCount, 0); assert.strictEqual(chalkStub.red.bold.callCount, 0); }); }); describe("when passed a single error message", () => { const code = [{ filePath: "foo.js", errorCount: 1, warningCount: 0, fixableErrorCount: 0, fixableWarningCount: 0, messages: [{ message: "Unexpected foo.", severity: 2, line: 5, column: 10, ruleId: "foo" }] }]; it("should return a string in the correct format", () => { const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 5:10 error Unexpected foo foo\n\n\u2716 1 problem (1 error, 0 warnings)\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 0); assert.strictEqual(chalkStub.red.bold.callCount, 1); }); describe("when the error is fixable", () => { beforeEach(() => { code[0].fixableErrorCount = 1; }); it("should return a string in the correct format", () => { const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 5:10 error Unexpected foo foo\n\n\u2716 1 problem (1 error, 0 warnings)\n 1 error and 0 warnings potentially fixable with the `--fix` option.\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 0); assert.strictEqual(chalkStub.red.bold.callCount, 2); }); }); }); describe("when passed a single warning message", () => { const code = [{ filePath: "foo.js", errorCount: 0, warningCount: 1, fixableErrorCount: 0, fixableWarningCount: 0, messages: [{ message: "Unexpected foo.", severity: 1, line: 5, column: 10, ruleId: "foo" }] }]; it("should return a string in the correct format", () => { const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 5:10 warning Unexpected foo foo\n\n\u2716 1 problem (0 errors, 1 warning)\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 1); assert.strictEqual(chalkStub.red.bold.callCount, 0); }); describe("when the error is fixable", () => { beforeEach(() => { code[0].fixableWarningCount = 1; }); it("should return a string in the correct format", () => { const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 5:10 warning Unexpected foo foo\n\n\u2716 1 problem (0 errors, 1 warning)\n 0 errors and 1 warning potentially fixable with the `--fix` option.\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 2); assert.strictEqual(chalkStub.red.bold.callCount, 0); }); }); }); describe("when passed a message that ends with ' .'", () => { const code = [{ filePath: "foo.js", errorCount: 0, warningCount: 1, fixableErrorCount: 0, fixableWarningCount: 0, messages: [{ message: "Unexpected .", severity: 1, line: 5, column: 10, ruleId: "foo" }] }]; it("should return a string in the correct format (retaining the ' .')", () => { const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 5:10 warning Unexpected . foo\n\n\u2716 1 problem (0 errors, 1 warning)\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 1); assert.strictEqual(chalkStub.red.bold.callCount, 0); }); }); describe("when passed a fatal error message", () => { const code = [{ filePath: "foo.js", errorCount: 1, warningCount: 0, messages: [{ fatal: true, message: "Unexpected foo.", line: 5, column: 10, ruleId: "foo" }] }]; it("should return a string in the correct format", () => { const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 5:10 error Unexpected foo foo\n\n\u2716 1 problem (1 error, 0 warnings)\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 0); assert.strictEqual(chalkStub.red.bold.callCount, 1); }); }); describe("when passed multiple messages", () => { const code = [{ filePath: "foo.js", errorCount: 1, warningCount: 1, messages: [{ message: "Unexpected foo.", severity: 2, line: 5, column: 10, ruleId: "foo" }, { message: "Unexpected bar.", severity: 1, line: 6, column: 11, ruleId: "bar" }] }]; it("should return a string with multiple entries", () => { const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 5:10 error Unexpected foo foo\n 6:11 warning Unexpected bar bar\n\n\u2716 2 problems (1 error, 1 warning)\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 0); assert.strictEqual(chalkStub.red.bold.callCount, 1); }); }); describe("when passed multiple files with 1 message each", () => { const code = [{ filePath: "foo.js", errorCount: 1, warningCount: 0, messages: [{ message: "Unexpected foo.", severity: 2, line: 5, column: 10, ruleId: "foo" }] }, { errorCount: 0, warningCount: 1, filePath: "bar.js", messages: [{ message: "Unexpected bar.", severity: 1, line: 6, column: 11, ruleId: "bar" }] }]; it("should return a string with multiple entries", () => { const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 5:10 error Unexpected foo foo\n\nbar.js\n 6:11 warning Unexpected bar bar\n\n\u2716 2 problems (1 error, 1 warning)\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 0); assert.strictEqual(chalkStub.red.bold.callCount, 1); }); it("should add errorCount", () => { code.forEach(c => { c.errorCount = 1; c.warningCount = 0; }); const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 5:10 error Unexpected foo foo\n\nbar.js\n 6:11 warning Unexpected bar bar\n\n\u2716 2 problems (2 errors, 0 warnings)\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 0); assert.strictEqual(chalkStub.red.bold.callCount, 1); }); it("should add warningCount", () => { code.forEach(c => { c.errorCount = 0; c.warningCount = 1; }); const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 5:10 error Unexpected foo foo\n\nbar.js\n 6:11 warning Unexpected bar bar\n\n\u2716 2 problems (0 errors, 2 warnings)\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 0); assert.strictEqual(chalkStub.red.bold.callCount, 1); }); }); describe("when passed one file not found message", () => { const code = [{ filePath: "foo.js", errorCount: 1, warningCount: 0, messages: [{ fatal: true, message: "Couldn't find foo.js." }] }]; it("should return a string without line and column", () => { const result = formatter(code); assert.strictEqual(result, "\nfoo.js\n 0:0 error Couldn't find foo.js\n\n\u2716 1 problem (1 error, 0 warnings)\n"); assert.strictEqual(chalkStub.reset.callCount, 1); assert.strictEqual(chalkStub.yellow.bold.callCount, 0); assert.strictEqual(chalkStub.red.bold.callCount, 1); }); }); describe("fixable problems", () => { it("should not output fixable problems message when no errors or warnings are fixable", () => { const code = [{ filePath: "foo.js", errorCount: 1, warningCount: 0, fixableErrorCount: 0, fixableWarningCount: 0, messages: [{ message: "Unexpected foo.", severity: 2, line: 5, column: 10, ruleId: "foo" }] }]; const result = formatter(code); assert.notInclude(result, "potentially fixable"); }); it("should output the fixable problems message when errors are fixable", () => { const code = [{ filePath: "foo.js", errorCount: 1, warningCount: 0, fixableErrorCount: 1, fixableWarningCount: 0, messages: [{ message: "Unexpected foo.", severity: 2, line: 5, column: 10, ruleId: "foo" }] }]; const result = formatter(code); assert.include(result, " 1 error and 0 warnings potentially fixable with the `--fix` option.\n"); }); it("should output fixable problems message when warnings are fixable", () => { const code = [{ filePath: "foo.js", errorCount: 0, warningCount: 3, fixableErrorCount: 0, fixableWarningCount: 2, messages: [{ message: "Unexpected foo." }] }]; const result = formatter(code); assert.include(result, " 0 errors and 2 warnings potentially fixable with the `--fix` option.\n"); }); it("should output the total number of fixable errors and warnings", () => { const code = [{ filePath: "foo.js", errorCount: 5, warningCount: 3, fixableErrorCount: 5, fixableWarningCount: 2, messages: [{ message: "Unexpected foo." }] }, { filePath: "bar.js", errorCount: 4, warningCount: 2, fixableErrorCount: 4, fixableWarningCount: 1, messages: [{ message: "Unexpected bar." }] }]; const result = formatter(code); assert.include(result, " 9 errors and 3 warnings potentially fixable with the `--fix` option.\n"); }); }); });