import path from "path"; import fs from "fs"; import { compile, getCompiler, getErrors, getExecutedCode, getModuleSource, getWarnings, } from "./helpers/index"; const testCasesPath = path.join(__dirname, "fixtures/modules/tests-cases"); const testCases = fs.readdirSync(testCasesPath); jest.setTimeout(60000); describe('"modules" option', () => { [ true, false, "local", "global", { mode: "local" }, { mode: "global" }, ].forEach((modulesValue) => { testCases.forEach((name) => { it(`should work with case \`${name}\` (\`modules\` value is \`${ modulesValue.mode ? `object with mode ${modulesValue.mode}` : modulesValue })\``, async () => { const pathToTest = `./modules/tests-cases/${name}/source.js`; const moduleId = `./modules/tests-cases/${name}/source.css`; const compiler = getCompiler(pathToTest, { modules: modulesValue.mode ? { mode: modulesValue.mode, localIdentName: "_[local]" } : modulesValue, }); const stats = await compile(compiler); expect(getModuleSource(moduleId, stats)).toMatchSnapshot("module"); expect( getExecutedCode("main.bundle.js", compiler, stats) ).toMatchSnapshot("result"); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); }); }); it('should work and support "pure" mode', async () => { const compiler = getCompiler("./modules/pure/pure.js", { modules: "pure" }); const stats = await compile(compiler); expect(getModuleSource("./modules/pure/pure.css", stats)).toMatchSnapshot( "module" ); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and support "pure" mode #2', async () => { const compiler = getCompiler("./modules/pure/pure.js", { modules: { mode: "pure" }, }); const stats = await compile(compiler); expect(getModuleSource("./modules/pure/pure.css", stats)).toMatchSnapshot( "module" ); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with the "[local]" placeholder for the "localIdentName" option', async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "[local]" }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and respect the "localIdentName" option', async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "[name]--[local]--[hash:base64:5]", localIdentContext: path.resolve(__dirname), }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and respect the "context" option', async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "[hash:base64:8]", localIdentContext: path.resolve(__dirname), }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and respect the "path" placeholder', async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "[path][name]__[local]", localIdentContext: path.resolve(__dirname), }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and respect the "hashPrefix" option', async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "[local]--[hash]", localIdentHashPrefix: "x", }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should work and prefix leading hyphen when digit is first", async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "-1[local]" }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should should work with two leading hyphens", async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "--[local]" }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should should work with two leading underscore", async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "__[local]" }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should work and correctly replace escaped symbols", async () => { const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentName: "[local]--[hash:base64:4]" }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and respect the "getLocalIdent" option', async () => { expect.assertions(382); const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { localIdentRegExp: "regExp", localIdentContext: "context", localIdentHashPrefix: "hash", getLocalIdent(loaderContext, localIdentName, localName, options) { expect(loaderContext).toBeDefined(); expect(typeof localIdentName).toBe("string"); expect(typeof localName).toBe("string"); expect(options).toBeDefined(); expect(options.regExp).toBe("regExp"); expect(options.context).toBe("context"); expect(options.hashPrefix).toBe("hash"); return "foo"; }, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and has "undefined" context if no context was given', async () => { expect.assertions(58); const compiler = getCompiler("./modules/localIdentName/localIdentName.js", { modules: { getLocalIdent(loaderContext, localIdentName, localName, options) { expect(options.context).toBeDefined(); return "foo"; }, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/localIdentName/localIdentName.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should support resolving in composes", async () => { const compiler = getCompiler("./modules/composes/composes.js", { modules: true, }); const stats = await compile(compiler); expect( getModuleSource("./modules/composes/composes.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should resolve absolute path in composes", async () => { // Create the file with absolute path const fileDirectory = path.resolve( __dirname, "fixtures", "modules", "composes" ); const file = path.resolve(fileDirectory, "composes-absolute.css"); const absolutePath = path.resolve(fileDirectory, "imported-simple.css"); fs.writeFileSync( file, `.simple { color: red; composes: imported-simple from '${absolutePath}'; }` ); const compiler = getCompiler("./modules/composes/composes-absolute.js", { modules: true, }); const stats = await compile(compiler); expect( getModuleSource("./modules/composes/composes-absolute.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should support resolving in composes preprocessor files with extensions", async () => { const compiler = getCompiler( "./modules/composes/composes-preprocessors.js", { modules: { mode: "local", exportGlobals: true, }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/composes/composes-preprocessors.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #286", async () => { const compiler = getCompiler( "./modules/issue-286/source.js", {}, { module: { rules: [ { test: /source\.css$/, loader: path.resolve(__dirname, "../src"), options: { importLoaders: false, modules: { localIdentName: "b--[local]", }, }, }, { test: /dep\.css$/, loader: path.resolve(__dirname, "../src"), options: { importLoaders: false, modules: { localIdentName: "a--[local]", }, }, }, ], }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-286/source.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #636", async () => { const compiler = getCompiler( "./modules/issue-636/source.js", {}, { module: { rules: [ { test: /\.s[ca]ss$/i, use: [ { loader: path.resolve(__dirname, "../src"), options: { modules: { localIdentName: "[local]", getLocalIdent: (context, localIdentName, localName) => `prefix-${localName}`, }, importLoaders: 1, }, }, { loader: "sass-loader", options: { // eslint-disable-next-line global-require implementation: require("sass"), }, }, ], }, ], }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-636/source.scss", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #861", async () => { const compiler = getCompiler( "./modules/issue-861/resolving-from-node_modules.js", { modules: true, } ); const stats = await compile(compiler); expect( getModuleSource( "./modules/issue-861/resolving-from-node_modules.css", stats ) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #966", async () => { const compiler = getCompiler("./modules/issue-966/button.js", { modules: { getLocalIdent: (ctx, localIdentName, localName) => `${localName}.hey`, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-966/button.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #966 - values in selectors aren't escaped properly", async () => { const compiler = getCompiler("./modules/issue-966/issue-966.js", { modules: { getLocalIdent: (loaderContext, localIdentName, localName) => { if (localName === "foo-class") { return `7-${localName}`; } if (localName === "bar-class") { return `>-${localName}`; } if (localName === "baz-class") { return `\u0000-${localName}`; } if (localName === "fooBaz-class") { return `${localName}.continuation`; } return null; }, localIdentName: "[local]", }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-966/issue-966.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #967", async () => { const compiler = getCompiler("./modules/issue-967/path-placeholder.js", { modules: { mode: "local", localIdentName: '[path][name]__[local]__/-sep-?-sep-<-sep->-sep-\\\\-sep-:-sep-*-sep-|-sep-"-sep-:', }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-967/path-placeholder.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #980", async () => { const compiler = getCompiler( "./modules/issue-980/file.with.many.dots.in.name.js", { modules: { localIdentName: "[name]_[local]_[hash:base64:5]", }, } ); const stats = await compile(compiler); expect( getModuleSource( "./modules/issue-980/file.with.many.dots.in.name.css", stats ) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #995", async () => { const compiler = getCompiler("./modules/issue-995/issue-995.js", { modules: { mode: "global", localIdentName: "😀", }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-995/issue-995.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should avoid unnecessary "require"', async () => { const compiler = getCompiler("./modules/composes/composes-duplicate.js", { modules: true, }); const stats = await compile(compiler); expect( getModuleSource("./modules/composes/composes-duplicate.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should keep order", async () => { const compiler = getCompiler("./modules/order/index.js", { modules: true }); const stats = await compile(compiler); expect(getModuleSource("./modules/order/index.css", stats)).toMatchSnapshot( "module" ); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should dedupe same modules in one module (issue #1037)", async () => { const compiler = getCompiler("./modules/dedupe/source.js", { modules: true, }); const stats = await compile(compiler); expect( getModuleSource("./modules/dedupe/source.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #1063", async () => { const compiler = getCompiler("./modules/issue-1063/issue-1063.js", { modules: { mode: (resourcePath) => { if (/pure.css$/i.test(resourcePath)) { return "pure"; } if (/global.css$/i.test(resourcePath)) { return "global"; } return "local"; }, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-1063/local.css", stats) ).toMatchSnapshot("module with the `local` mode"); expect( getModuleSource("./modules/issue-1063/global.css", stats) ).toMatchSnapshot("module with the `global` mode"); expect( getModuleSource("./modules/issue-1063/pure.css", stats) ).toMatchSnapshot("module with the `pure` mode"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #1063 throw error", async () => { const compiler = getCompiler("./modules/issue-1063/issue-1063.js", { modules: { mode: () => { return "not local, global or pure"; }, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-1063/local.css", stats) ).toMatchSnapshot("module"); expect( getModuleSource("./modules/issue-1063/global.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("issue #1191 - fallback to default getLocalIdent", async () => { const compiler = getCompiler("./modules/issue-1191/issue-1191.js", { modules: { getLocalIdent: (ctx, localIdentName, localName) => ctx.resourcePath.includes("custom") ? `custom-${localName}` : null, localIdentName: "[local]", }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-1191/issue-1191.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should work with the `exportGlobals` option (the `mode` option is `global`)", async () => { const compiler = getCompiler( "./modules/exportGlobals-global/exportGlobals.js", { modules: { mode: "local", exportGlobals: true, }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/exportGlobals-global/exportGlobals.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should work with the `exportGlobals` option (the `mode` option is `local`)", async () => { const compiler = getCompiler( "./modules/exportGlobals-local/exportGlobals.js", { modules: { mode: "global", exportGlobals: true, }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/exportGlobals-local/exportGlobals.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should work with the `exportGlobals` option (the `mode` option is `pure`)", async () => { const compiler = getCompiler( "./modules/exportGlobals-pure/exportGlobals.js", { modules: { mode: "pure", exportGlobals: true, }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/exportGlobals-pure/exportGlobals.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with the "auto" by default', async () => { const compiler = getCompiler("./modules/mode/modules.js"); const stats = await compile(compiler); expect( getModuleSource("./modules/mode/relative.module.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with the "auto" by default with "modules" filename', async () => { const compiler = getCompiler("./modules/mode/modules-2.js"); const stats = await compile(compiler); expect( getModuleSource("./modules/mode/relative.modules.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with the "auto" by default for icss', async () => { const compiler = getCompiler("./modules/mode/icss/icss.js"); const stats = await compile(compiler); expect( getModuleSource("./modules/mode/icss/relative.icss.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with the "auto" when it is "false"', async () => { const compiler = getCompiler("./modules/mode/modules.js", { modules: { auto: false, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/mode/relative.module.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with the "auto" when it is "true"', async () => { const compiler = getCompiler("./modules/mode/modules.js", { modules: { auto: true, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/mode/relative.module.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with a modules.auto RegExp that returns "true"', async () => { const compiler = getCompiler("./modules/mode/modules.js", { modules: { auto: /relative\.module\.css$/, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/mode/relative.module.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with a modules.auto RegExp that returns "false"', async () => { const compiler = getCompiler("./modules/mode/modules.js", { modules: { auto: /will no pass/, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/mode/relative.module.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with a modules.auto Function that returns "true"', async () => { const compiler = getCompiler("./modules/mode/modules.js", { modules: { auto: (relativePath) => relativePath.endsWith("module.css"), }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/mode/relative.module.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with a modules.auto Function that returns "false"', async () => { const compiler = getCompiler("./modules/mode/modules.js", { modules: { auto: (relativePath) => relativePath.endsWith("will no pass"), }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/mode/relative.module.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should resolve package from node_modules with and without tilde", async () => { const compiler = getCompiler("./modules/issue-914/source.js", { modules: true, }); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-914/source.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should throw an error on unresolved import", async () => { const compiler = getCompiler("./modules/unresolved/source.js", { modules: true, }); const stats = await compile(compiler); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats, true)).toMatchSnapshot("errors"); }); it('should work and respect the "localConvention" option with the "asIs" value', async () => { const compiler = getCompiler( "./modules/localsConvention/localsConvention.js", { modules: { mode: "local", exportLocalsConvention: "asIs", }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/localsConvention/localsConvention.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and respect the "localConvention" option with the "camelCase" value', async () => { const compiler = getCompiler( "./modules/localsConvention/localsConvention.js", { modules: { mode: "local", exportLocalsConvention: "camelCase", }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/localsConvention/localsConvention.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and respect the "localConvention" option with the "camelCaseOnly" value', async () => { const compiler = getCompiler( "./modules/localsConvention/localsConvention.js", { modules: { mode: "local", exportLocalsConvention: "camelCaseOnly", }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/localsConvention/localsConvention.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and respect the "localConvention" option with the "dashes" value', async () => { const compiler = getCompiler( "./modules/localsConvention/localsConvention.js", { modules: { mode: "local", exportLocalsConvention: "dashes", }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/localsConvention/localsConvention.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and respect the "localConvention" option with the "dashesOnly" value', async () => { const compiler = getCompiler( "./modules/localsConvention/localsConvention.js", { modules: { mode: "local", exportLocalsConvention: "dashesOnly", }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/localsConvention/localsConvention.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work and respect the "exportOnlyLocals" option', async () => { const compiler = getCompiler("./modules/composes/composes.js", { modules: { mode: "local", localIdentName: "_[local]", exportOnlyLocals: true, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/composes/composes.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with "exportOnlyLocals" and "esModule" with "true" value options', async () => { const compiler = getCompiler("./modules/composes/composes.js", { modules: { mode: "local", localIdentName: "_[local]", exportOnlyLocals: true, }, esModule: true, }); const stats = await compile(compiler); expect( getModuleSource("./modules/composes/composes.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with "exportOnlyLocals" and "esModule" with "false" value options', async () => { const compiler = getCompiler("./modules/composes/composes.js", { modules: { mode: "local", localIdentName: "_[local]", exportOnlyLocals: true, }, esModule: false, }); const stats = await compile(compiler); expect( getModuleSource("./modules/composes/composes.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should work with an empty object value", async () => { const compiler = getCompiler("./modules/pure/pure.js", { modules: {} }); const stats = await compile(compiler); expect(getModuleSource("./modules/pure/pure.css", stats)).toMatchSnapshot( "module" ); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with the "namedExport" option', async () => { const compiler = getCompiler("./modules/namedExport/base/index.js", { modules: { namedExport: true, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/namedExport/base/index.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with the "namedExport" option with nested import', async () => { const compiler = getCompiler("./modules/namedExport/nested/index.js", { esModule: true, modules: { namedExport: true, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/namedExport/nested/index.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work js template with "namedExport" option', async () => { const compiler = getCompiler("./modules/namedExport/template/index.js", { esModule: true, modules: { localIdentName: "[local]", namedExport: true, }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/namedExport/template/index.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work when the "namedExport" is enabled and the "exportLocalsConvention" options has "dashesOnly" value', async () => { const compiler = getCompiler("./modules/namedExport/dashesOnly/index.js", { modules: { localIdentName: "[local]", namedExport: true, exportLocalsConvention: "dashesOnly", }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/namedExport/dashesOnly/index.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats, true)).toMatchSnapshot("errors"); }); it('should work with composes when the "namedExport" is enabled and "exportLocalsConvention" options has "dashesOnly" value', async () => { const compiler = getCompiler("./modules/namedExport/composes/composes.js", { modules: { localIdentName: "_[local]", namedExport: true, exportLocalsConvention: "dashesOnly", }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/namedExport/composes/composes.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should throw error with composes when the "namedExport" is enabled and "exportLocalsConvention" options has invalid value', async () => { const compiler = getCompiler("./modules/namedExport/composes/composes.js", { modules: { localIdentName: "_[local]", namedExport: true, exportLocalsConvention: "dashes", }, }); const stats = await compile(compiler); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats, true)).toMatchSnapshot("errors"); }); it('should throw an error when the "namedExport" option is "true", but the "esModule" is "false"', async () => { const compiler = getCompiler("./modules/namedExport/base/index.js", { esModule: false, modules: { namedExport: true, }, }); const stats = await compile(compiler); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats, true)).toMatchSnapshot("errors"); }); it('should throw an error when the "namedExport" is enabled and the "exportLocalsConvention" options has not "camelCaseOnly" value', async () => { const compiler = getCompiler("./modules/namedExport/broken/index.js", { esModule: true, modules: { namedExport: true, exportLocalsConvention: "dashes", }, }); const stats = await compile(compiler); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats, true)).toMatchSnapshot("errors"); }); it("should throw an error when class has unsupported name (JavaScript reserved words)", async () => { const compiler = getCompiler("./modules/namedExport/broken/index.js", { esModule: true, modules: { namedExport: true, }, }); const stats = await compile(compiler); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats, true)).toMatchSnapshot("errors"); }); it('should work with "exportOnlyLocals" and "namedExport" option', async () => { const compiler = getCompiler("./modules/composes/composes-named.js", { modules: { mode: "local", localIdentName: "_[local]", namedExport: true, exportOnlyLocals: true, }, esModule: true, }); const stats = await compile(compiler); expect( getModuleSource("./modules/composes/composes.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with "url" and "namedExport"', async () => { const compiler = getCompiler("./modules/url/source.js", { modules: { namedExport: true, }, }); const stats = await compile(compiler); expect(getModuleSource("./modules/url/source.css", stats)).toMatchSnapshot( "module" ); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with "url"', async () => { const compiler = getCompiler("./modules/url/source.js", { modules: true, }); const stats = await compile(compiler); expect(getModuleSource("./modules/url/source.css", stats)).toMatchSnapshot( "module" ); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); const icssTestCasesPath = path.join( __dirname, "fixtures/modules/icss/tests-cases" ); const icssTestCases = fs.readdirSync(icssTestCasesPath); icssTestCases.forEach((name) => { it(`show work with the "compileType" option, case "${name}"`, async () => { const compiler = getCompiler( `./modules/icss/tests-cases/${name}/source.js`, { modules: { compileType: "icss", }, } ); const stats = await compile(compiler); expect( getModuleSource(`./modules/icss/tests-cases/${name}/source.css`, stats) ).toMatchSnapshot("module"); expect( getExecutedCode("main.bundle.js", compiler, stats) ).toMatchSnapshot("result"); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); }); it('show work with the "compileType" and "exportOnlyLocals" options', async () => { const compiler = getCompiler( "./modules/icss/tests-cases/import/source.js", { modules: { compileType: "icss", exportOnlyLocals: true, }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/icss/tests-cases/import/source.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('show work with the "compileType" and "namedExport" options', async () => { const compiler = getCompiler( "./modules/icss/tests-cases/import/source.js", { modules: { compileType: "icss", namedExport: true, }, } ); const stats = await compile(compiler); expect( getModuleSource("./modules/icss/tests-cases/import/source.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('show work with the "compileType" option using the "module" value', async () => { const compiler = getCompiler("./modules/composes/composes.js", { modules: { compileType: "module", }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/composes/composes.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should emit warning when localIdentName is emoji", async () => { const compiler = getCompiler("./modules/pure/pure.js", { modules: { localIdentName: "[emoji:0]", }, }); const stats = await compile(compiler); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it("should work with `@` character in scoped packages", async () => { const compiler = getCompiler("./modules/issue-1223/issue-1223.js", { modules: { localIdentName: "[path]-[local]", }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-1223/@foo/bar/index.module.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); it('should work with the "animation" ', async () => { const compiler = getCompiler("./modules/issue-1228/source.js", { modules: { mode: "local" }, }); const stats = await compile(compiler); expect( getModuleSource("./modules/issue-1228/source.css", stats) ).toMatchSnapshot("module"); expect(getExecutedCode("main.bundle.js", compiler, stats)).toMatchSnapshot( "result" ); expect(getWarnings(stats)).toMatchSnapshot("warnings"); expect(getErrors(stats)).toMatchSnapshot("errors"); }); });