diff --git a/__mocks__/nonexistent/package.json b/__mocks__/nonexistent/package.json new file mode 100644 index 00000000..0e303acd --- /dev/null +++ b/__mocks__/nonexistent/package.json @@ -0,0 +1,4 @@ +{ + "main": "./wat", + "version": "12.0.0" +} diff --git a/__mocks__/sass-loader/package.json b/__mocks__/sass-loader/package.json new file mode 100644 index 00000000..e926c306 --- /dev/null +++ b/__mocks__/sass-loader/package.json @@ -0,0 +1,4 @@ +{ + "main": "./lib/api.js", + "version": "16.56.81" +} diff --git a/jest.config.js b/jest.config.js index b2c9c58a..a777ee41 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,4 +1,5 @@ module.exports = { roots: ["/test"], - testPathIgnorePatterns: ["/__fixtures__/", "/__utils__/"] + testPathIgnorePatterns: ["/__fixtures__/", "/__utils__/"], + resolver: "/test/resolver" } diff --git a/package/rules/sass.js b/package/rules/sass.js index 4d71234a..a620d679 100644 --- a/package/rules/sass.js +++ b/package/rules/sass.js @@ -1,16 +1,18 @@ /* eslint global-require: 0 */ const getStyleRule = require("../utils/getStyleRule") -const { canProcess } = require("../utils/helpers") -const { additional_paths: includePaths } = require("../config") +const { canProcess, packageMajorVersion } = require("../utils/helpers") +const { additional_paths: extraPaths } = require("../config") -module.exports = canProcess("sass-loader", (resolvedPath) => - getStyleRule(/\.(scss|sass)(\.erb)?$/i, [ +module.exports = canProcess("sass-loader", (resolvedPath) => { + const optionKey = + packageMajorVersion("sass-loader") > 15 ? "loadPaths" : "includePaths" + return getStyleRule(/\.(scss|sass)(\.erb)?$/i, [ { loader: resolvedPath, options: { - sassOptions: { includePaths } + sassOptions: { [optionKey]: extraPaths } } } ]) -) +}) diff --git a/package/utils/helpers.js b/package/utils/helpers.js index d550eb3f..759178a9 100644 --- a/package/utils/helpers.js +++ b/package/utils/helpers.js @@ -41,10 +41,18 @@ const loaderMatches = (configLoader, loaderToCheck, fn) => { return fn() } +const packageMajorVersion = (packageName) => { + // eslint-disable-next-line import/no-dynamic-require + const packageJsonPath = require.resolve(`${packageName}/package.json`) + // eslint-disable-next-line import/no-dynamic-require, global-require + return require(packageJsonPath).version.match(/^\d+/)[0] +} + module.exports = { isBoolean, ensureTrailingSlash, canProcess, moduleExists, - loaderMatches + loaderMatches, + packageMajorVersion } diff --git a/test/package/helpers.test.js b/test/package/helpers.test.js new file mode 100644 index 00000000..b25415f2 --- /dev/null +++ b/test/package/helpers.test.js @@ -0,0 +1,11 @@ +const { packageMajorVersion } = require("../../package/utils/helpers") + +describe("packageMajorVersion", () => { + test("should find that sass-loader is v16", () => { + expect(packageMajorVersion("sass-loader")).toBe("16") + }) + + test("should find that nonexistent is v12", () => { + expect(packageMajorVersion("nonexistent")).toBe("12") + }) +}) diff --git a/test/package/rules/sass.test.js b/test/package/rules/sass.test.js new file mode 100644 index 00000000..28345781 --- /dev/null +++ b/test/package/rules/sass.test.js @@ -0,0 +1,25 @@ +const sass = require("../../../package/rules/sass") + +jest.mock("../../../package/utils/helpers", () => { + const original = jest.requireActual("../../../package/utils/helpers") + const canProcess = (rule, fn) => { + return fn("This path was mocked") + } + const moduleExists = () => true + const packageMajorVersion = () => "15" + return { + ...original, + canProcess, + moduleExists, + packageMajorVersion + } +}) + +jest.mock("../../../package/utils/inliningCss", () => true) + +describe("sass rule", () => { + test("contains loadPaths as the sassOptions key if sass-loader is v15 or earlier", () => { + expect(typeof sass.use[3].options.sassOptions.includePaths).toBe("object") + expect(typeof sass.use[3].options.sassOptions.loadPaths).toBe("undefined") + }) +}) diff --git a/test/package/rules/sass1.test.js b/test/package/rules/sass1.test.js new file mode 100644 index 00000000..da225cea --- /dev/null +++ b/test/package/rules/sass1.test.js @@ -0,0 +1,25 @@ +const sass = require("../../../package/rules/sass") + +jest.mock("../../../package/utils/helpers", () => { + const original = jest.requireActual("../../../package/utils/helpers") + const canProcess = (rule, fn) => { + return fn("This path was mocked") + } + const moduleExists = () => true + return { + ...original, + canProcess, + moduleExists + } +}) + +jest.mock("../../../package/utils/inliningCss", () => true) + +describe("sass rule", () => { + test("contains loadPaths as the sassOptions key if sass-loader is v15 or earlier", () => { + expect(typeof sass.use[3].options.sassOptions.includePaths).toBe( + "undefined" + ) + expect(typeof sass.use[3].options.sassOptions.loadPaths).toBe("object") + }) +}) diff --git a/test/resolver.js b/test/resolver.js new file mode 100644 index 00000000..c0d50017 --- /dev/null +++ b/test/resolver.js @@ -0,0 +1,13 @@ +const mapping = { + "css-loader": "this path was mocked", + "sass-loader/package.json": "../../__mocks__/sass-loader/package.json", + "nonexistent/package.json": "../../__mocks__/nonexistent/package.json" +} + +function resolver(module, options) { + // If the path corresponds to a key in the mapping object, returns the fakely resolved path + // otherwise it calls the Jest's default resolver + return mapping[module] || options.defaultResolver(module, options) +} + +module.exports = resolver