From c8f0071c4f5336dfe0efc5d3c218ab49f2401264 Mon Sep 17 00:00:00 2001 From: Elena Vilchik Date: Wed, 18 Dec 2019 17:10:10 +0100 Subject: Rely on NodeJS API of Stylelint to execute CSS rules (#221) --- .../css-bundle/tests/fixtures/file-bom.css | 2 + .../css-bundle/tests/fixtures/file.css | 1 + .../css-bundle/tests/fixtures/file.html | 12 ++ .../css-bundle/tests/fixtures/file.php | 13 ++ .../css-bundle/tests/fixtures/stylelintconfig.json | 5 + .../css-bundle/tests/server-mock-stylelint.test.ts | 51 +++++++ sonar-css-plugin/css-bundle/tests/server.test.ts | 153 +++++++++++++++++++++ sonar-css-plugin/css-bundle/tests/utils.ts | 36 +++++ 8 files changed, 273 insertions(+) create mode 100644 sonar-css-plugin/css-bundle/tests/fixtures/file-bom.css create mode 100644 sonar-css-plugin/css-bundle/tests/fixtures/file.css create mode 100644 sonar-css-plugin/css-bundle/tests/fixtures/file.html create mode 100644 sonar-css-plugin/css-bundle/tests/fixtures/file.php create mode 100644 sonar-css-plugin/css-bundle/tests/fixtures/stylelintconfig.json create mode 100644 sonar-css-plugin/css-bundle/tests/server-mock-stylelint.test.ts create mode 100644 sonar-css-plugin/css-bundle/tests/server.test.ts create mode 100644 sonar-css-plugin/css-bundle/tests/utils.ts (limited to 'sonar-css-plugin/css-bundle/tests') diff --git a/sonar-css-plugin/css-bundle/tests/fixtures/file-bom.css b/sonar-css-plugin/css-bundle/tests/fixtures/file-bom.css new file mode 100644 index 0000000..0ecd9c3 --- /dev/null +++ b/sonar-css-plugin/css-bundle/tests/fixtures/file-bom.css @@ -0,0 +1,2 @@ +p { +} diff --git a/sonar-css-plugin/css-bundle/tests/fixtures/file.css b/sonar-css-plugin/css-bundle/tests/fixtures/file.css new file mode 100644 index 0000000..802e4f0 --- /dev/null +++ b/sonar-css-plugin/css-bundle/tests/fixtures/file.css @@ -0,0 +1 @@ +p { } diff --git a/sonar-css-plugin/css-bundle/tests/fixtures/file.html b/sonar-css-plugin/css-bundle/tests/fixtures/file.html new file mode 100644 index 0000000..02e014f --- /dev/null +++ b/sonar-css-plugin/css-bundle/tests/fixtures/file.html @@ -0,0 +1,12 @@ + + + + Page Title + + + + + diff --git a/sonar-css-plugin/css-bundle/tests/fixtures/file.php b/sonar-css-plugin/css-bundle/tests/fixtures/file.php new file mode 100644 index 0000000..54d36ee --- /dev/null +++ b/sonar-css-plugin/css-bundle/tests/fixtures/file.php @@ -0,0 +1,13 @@ + + + + Index + + + + + + diff --git a/sonar-css-plugin/css-bundle/tests/fixtures/stylelintconfig.json b/sonar-css-plugin/css-bundle/tests/fixtures/stylelintconfig.json new file mode 100644 index 0000000..44d0932 --- /dev/null +++ b/sonar-css-plugin/css-bundle/tests/fixtures/stylelintconfig.json @@ -0,0 +1,5 @@ +{ + "rules": { + "block-no-empty": true + } +} \ No newline at end of file diff --git a/sonar-css-plugin/css-bundle/tests/server-mock-stylelint.test.ts b/sonar-css-plugin/css-bundle/tests/server-mock-stylelint.test.ts new file mode 100644 index 0000000..f7df176 --- /dev/null +++ b/sonar-css-plugin/css-bundle/tests/server-mock-stylelint.test.ts @@ -0,0 +1,51 @@ +import { start, setLogHandlersForTests } from "../src/server"; +import { Server } from "http"; +import * as path from "path"; +import { promisify } from "util"; +import * as stylelint from "stylelint"; +import { postToServer } from "./utils"; + +const filePath = path.join(__dirname, "fixtures", "file.css"); + +const request = JSON.stringify({ + filePath, + configFile: path.join(__dirname, "fixtures", "stylelintconfig.json") +}); + +jest.mock("stylelint"); + +describe("server", () => { + let server: Server; + let close: () => Promise; + const logSpy = jest.fn(); + const errorSpy = jest.fn(); + + beforeAll(async () => { + setLogHandlersForTests(logSpy, errorSpy); + server = await start(); + close = promisify(server.close.bind(server)); + }); + + afterAll(async () => { + jest.restoreAllMocks(); + await close(); + }); + + it("should not return issues for not original file", async () => { + (stylelint.lint as any).mockResolvedValue({ + results: [{ source: "foo.bar" }] + }); + const response = await postToServer(request, "/analyze", server); + expect(JSON.parse(response)).toEqual([]); + expect(logSpy).toHaveBeenCalledWith( + `DEBUG For file [${filePath}] received issues with [foo.bar] as a source. They will not be reported.` + ); + }); + + it("should not return issues when failed promise returned", async () => { + (stylelint.lint as any).mockRejectedValue("some reason"); + const response = await postToServer(request, "/analyze", server); + expect(JSON.parse(response)).toEqual([]); + expect(errorSpy).toHaveBeenCalledWith("some reason"); + }); +}); diff --git a/sonar-css-plugin/css-bundle/tests/server.test.ts b/sonar-css-plugin/css-bundle/tests/server.test.ts new file mode 100644 index 0000000..8465810 --- /dev/null +++ b/sonar-css-plugin/css-bundle/tests/server.test.ts @@ -0,0 +1,153 @@ +import { start, setLogHandlersForTests } from "../src/server"; +import * as http from "http"; +import { Server } from "http"; +import { promisify } from "util"; +import { AddressInfo } from "net"; +import { postToServer } from "./utils"; +import * as path from "path"; + +const configFile = path.join(__dirname, "fixtures", "stylelintconfig.json"); + +describe("server", () => { + let server: Server; + let close: () => Promise; + const logSpy = jest.fn(); + const errorSpy = jest.fn(); + + beforeAll(async () => { + setLogHandlersForTests(logSpy, errorSpy); + server = await start(); + close = promisify(server.close.bind(server)); + }); + + afterAll(async () => { + jest.restoreAllMocks(); + await close(); + }); + + it("should log with debug server start", async () => { + expect(server.listening).toEqual(true); + expect(logSpy).toBeCalledTimes(2); + expect(logSpy).toBeCalledWith( + "DEBUG starting stylelint-bridge server at port", + 0 + ); + expect(logSpy).toBeCalledWith( + "DEBUG stylelint-bridge server is running at port", + (server.address()).port + ); + expect(errorSpy).toBeCalledTimes(0); + }); + + it("should respond to analysis request", async () => { + const request = JSON.stringify({ + filePath: path.join(__dirname, "fixtures", "file.css"), + configFile + }); + const response = await post(request, "/analyze"); + expect(JSON.parse(response)).toEqual([ + { + line: 1, + rule: "block-no-empty", + text: "Unexpected empty block (block-no-empty)" + } + ]); + }); + + it("should respond to analysis request for php", async () => { + const requestPhp = JSON.stringify({ + filePath: path.join(__dirname, "fixtures", "file.php"), + configFile + }); + const responsePhp = await post(requestPhp, "/analyze"); + expect(JSON.parse(responsePhp)).toEqual([ + { + line: 7, + rule: "block-no-empty", + text: "Unexpected empty block (block-no-empty)" + } + ]); + }); + + it("should respond to analysis request for html", async () => { + const requestHtml = JSON.stringify({ + filePath: path.join(__dirname, "fixtures", "file.html"), + configFile + }); + const responseHtml = await post(requestHtml, "/analyze"); + expect(JSON.parse(responseHtml)).toEqual([ + { + line: 6, + rule: "block-no-empty", + text: "Unexpected empty block (block-no-empty)" + } + ]); + }); + + it("should cut BOM", async () => { + const response = await post( + JSON.stringify({ + filePath: path.join(__dirname, "fixtures", "file-bom.css"), + configFile + }), + "/analyze" + ); + expect(JSON.parse(response)).toEqual([ + { + line: 1, + rule: "block-no-empty", + text: "Unexpected empty block (block-no-empty)" + } + ]); + }); + + it("should respond OK! when started", done => { + const req = http.request( + { + host: "localhost", + port: (server.address()).port, + path: "/status", + method: "GET" + }, + res => { + let data = ""; + res.on("data", chunk => { + data += chunk; + }); + res.on("end", () => { + expect(data).toEqual("OK!"); + done(); + }); + } + ); + req.end(); + }); + + it("should return empty list of issues when request not json", async () => { + const response = await post("invalid json", "/analyze"); + expect(JSON.parse(response)).toEqual([]); + expect(errorSpy).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.stringContaining( + "Unexpected token i in JSON at position 0" + ) + }) + ); + }); + + it("should return empty list of issues when invalid request", async () => { + const response = await post("{}", "/analyze"); + expect(JSON.parse(response)).toEqual([]); + expect(errorSpy).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.stringContaining( + "Unexpected token i in JSON at position 0" + ) + }) + ); + }); + + function post(data: string, endpoint: string): Promise { + return postToServer(data, endpoint, server); + } +}); diff --git a/sonar-css-plugin/css-bundle/tests/utils.ts b/sonar-css-plugin/css-bundle/tests/utils.ts new file mode 100644 index 0000000..0be132b --- /dev/null +++ b/sonar-css-plugin/css-bundle/tests/utils.ts @@ -0,0 +1,36 @@ +import * as http from "http"; +import { Server } from "http"; +import { AddressInfo } from "net"; + +export function postToServer( + data: string, + endpoint: string, + server: Server +): Promise { + const options = { + host: "localhost", + port: (server.address()).port, + path: endpoint, + method: "POST", + headers: { + "Content-Type": "application/json" + } + }; + + return new Promise((resolve, reject) => { + let response = ""; + + const req = http.request(options, res => { + res.on("data", chunk => { + response += chunk; + }); + + res.on("end", () => resolve(response)); + }); + + req.on("error", reject); + + req.write(data); + req.end(); + }); +} -- cgit v1.2.3