From 215e9c19a3e43ff6acdb560e3490b3abb62eb5a2 Mon Sep 17 00:00:00 2001 From: Raphael Oliveira <1087109+RaphaelDDL@users.noreply.github.com> Date: Tue, 16 May 2023 21:01:46 -0300 Subject: [PATCH 1/2] feat(css-modules): added multiple modules support; re-write tests & add more css module scenarios --- src/cssModules.ts | 11 +- test/advanced.spec.ts | 2 +- test/fixtures/css-modules.vue | 20 - .../default-extend-composes-css.vue | 16 + .../css-modules/default-extend-diffclass.vue | 17 + .../default-extend.vue} | 6 +- .../fixtures/css-modules/default-multiple.vue | 19 + .../default.vue} | 4 + .../named-multiple-diffnamediffclass.vue | 19 + .../named-multiple-diffnamesameclass.vue | 19 + test/fixtures/css-modules/named-multiple.vue | 19 + test/fixtures/css-modules/named.vue | 13 + test/fixtures/css-modules/red.css | 3 + test/style.spec.ts | 419 +++++++++++++++--- 14 files changed, 493 insertions(+), 94 deletions(-) delete mode 100644 test/fixtures/css-modules.vue create mode 100644 test/fixtures/css-modules/default-extend-composes-css.vue create mode 100644 test/fixtures/css-modules/default-extend-diffclass.vue rename test/fixtures/{css-modules-extend.vue => css-modules/default-extend.vue} (56%) create mode 100644 test/fixtures/css-modules/default-multiple.vue rename test/fixtures/{css-modules-simple.vue => css-modules/default.vue} (62%) create mode 100644 test/fixtures/css-modules/named-multiple-diffnamediffclass.vue create mode 100644 test/fixtures/css-modules/named-multiple-diffnamesameclass.vue create mode 100644 test/fixtures/css-modules/named-multiple.vue create mode 100644 test/fixtures/css-modules/named.vue create mode 100644 test/fixtures/css-modules/red.css diff --git a/src/cssModules.ts b/src/cssModules.ts index e95a27e91..c15252173 100644 --- a/src/cssModules.ts +++ b/src/cssModules.ts @@ -10,13 +10,20 @@ export function genCSSModulesCode( // inject variable const name = typeof moduleName === 'string' ? moduleName : '$style' - code += `\ncssModules["${name}"] = ${styleVar}` + + const moduleAdd = ` + if(cssModules["${name}"]){ + Object.assign(cssModules["${name}"], ${styleVar}); + } else { + cssModules["${name}"] = ${styleVar}; + }` + code += `${moduleAdd}` if (needsHotReload) { code += ` if (module.hot) { module.hot.accept(${request}, () => { - cssModules["${name}"] = ${styleVar} + ${moduleAdd} __VUE_HMR_RUNTIME__.rerender("${id}") }) }` diff --git a/test/advanced.spec.ts b/test/advanced.spec.ts index 9fee7e833..286820b4f 100644 --- a/test/advanced.spec.ts +++ b/test/advanced.spec.ts @@ -190,7 +190,7 @@ test('support rules with oneOf', async () => { const { window, instance } = await run('css-modules-simple.vue') const className = instance.$style.red - expect(className).toMatch(/^red_\w{5}/) + expect(className).toMatch(/^red_[\w-]{5}/) style = normalizeNewline(window.document.querySelector('style')!.textContent!) expect(style).toContain('.' + className + ' {\n color: red;\n}') }) diff --git a/test/fixtures/css-modules.vue b/test/fixtures/css-modules.vue deleted file mode 100644 index 473f90ce9..000000000 --- a/test/fixtures/css-modules.vue +++ /dev/null @@ -1,20 +0,0 @@ - - - - - diff --git a/test/fixtures/css-modules/default-extend-composes-css.vue b/test/fixtures/css-modules/default-extend-composes-css.vue new file mode 100644 index 000000000..46cd247cf --- /dev/null +++ b/test/fixtures/css-modules/default-extend-composes-css.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/test/fixtures/css-modules/default-extend-diffclass.vue b/test/fixtures/css-modules/default-extend-diffclass.vue new file mode 100644 index 000000000..fbf2fa3fa --- /dev/null +++ b/test/fixtures/css-modules/default-extend-diffclass.vue @@ -0,0 +1,17 @@ + + + + + diff --git a/test/fixtures/css-modules-extend.vue b/test/fixtures/css-modules/default-extend.vue similarity index 56% rename from test/fixtures/css-modules-extend.vue rename to test/fixtures/css-modules/default-extend.vue index de95d1a25..88831f959 100644 --- a/test/fixtures/css-modules-extend.vue +++ b/test/fixtures/css-modules/default-extend.vue @@ -5,7 +5,7 @@ \ No newline at end of file +
{{ $style.red }}
+ diff --git a/test/fixtures/css-modules/default-multiple.vue b/test/fixtures/css-modules/default-multiple.vue new file mode 100644 index 000000000..26a70eea6 --- /dev/null +++ b/test/fixtures/css-modules/default-multiple.vue @@ -0,0 +1,19 @@ + + + + + + + diff --git a/test/fixtures/css-modules-simple.vue b/test/fixtures/css-modules/default.vue similarity index 62% rename from test/fixtures/css-modules-simple.vue rename to test/fixtures/css-modules/default.vue index f677aa29c..79fcedbf5 100644 --- a/test/fixtures/css-modules-simple.vue +++ b/test/fixtures/css-modules/default.vue @@ -7,3 +7,7 @@ + + diff --git a/test/fixtures/css-modules/named-multiple-diffnamediffclass.vue b/test/fixtures/css-modules/named-multiple-diffnamediffclass.vue new file mode 100644 index 000000000..358a4292b --- /dev/null +++ b/test/fixtures/css-modules/named-multiple-diffnamediffclass.vue @@ -0,0 +1,19 @@ + + + + + + + diff --git a/test/fixtures/css-modules/named-multiple-diffnamesameclass.vue b/test/fixtures/css-modules/named-multiple-diffnamesameclass.vue new file mode 100644 index 000000000..c61fb15c9 --- /dev/null +++ b/test/fixtures/css-modules/named-multiple-diffnamesameclass.vue @@ -0,0 +1,19 @@ + + + + + + + diff --git a/test/fixtures/css-modules/named-multiple.vue b/test/fixtures/css-modules/named-multiple.vue new file mode 100644 index 000000000..ffd5852d0 --- /dev/null +++ b/test/fixtures/css-modules/named-multiple.vue @@ -0,0 +1,19 @@ + + + + + + + diff --git a/test/fixtures/css-modules/named.vue b/test/fixtures/css-modules/named.vue new file mode 100644 index 000000000..bca461115 --- /dev/null +++ b/test/fixtures/css-modules/named.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/test/fixtures/css-modules/red.css b/test/fixtures/css-modules/red.css new file mode 100644 index 000000000..c6dd2c88f --- /dev/null +++ b/test/fixtures/css-modules/red.css @@ -0,0 +1,3 @@ +.red { + color: red; +} diff --git a/test/style.spec.ts b/test/style.spec.ts index 94a04eb0e..5eec8c576 100644 --- a/test/style.spec.ts +++ b/test/style.spec.ts @@ -86,10 +86,14 @@ test('postcss', async () => { expect(style).toContain(`h1[${id}] {\n color: red;\n font-size: 14px\n}`) }) -test('CSS Modules', async () => { +describe('CSS Modules', () => { + const fixtureFolder = 'css-modules/' + const defaultIdent = [undefined, /^[\w-+]{21,}/, /^[\w-+]{21,}/] // pass w/ apply + const customIdent = '[path][name]---[local]---[hash:base64:5]' + const testWithIdent = async ( - localIdentName: string | undefined, - regexToMatch: RegExp + entry: string, + localIdentName: string | undefined ) => { const baseLoaders = [ 'style-loader', @@ -102,9 +106,8 @@ test('CSS Modules', async () => { }, }, ] - - const { window, instance } = await mockBundleAndRun({ - entry: 'css-modules.vue', + const mockResult = await mockBundleAndRun({ + entry: fixtureFolder + entry, modify: (config: any) => { config!.module!.rules = [ { @@ -122,75 +125,355 @@ test('CSS Modules', async () => { ] }, }) - - // get local class name - const className = instance.$style.red - expect(className).toMatch(regexToMatch) - - // class name in style - let style = [].slice - .call(window.document.querySelectorAll('style')) - .map((style: any) => { - return style!.textContent - }) - .join('\n') - style = normalizeNewline(style) - expect(style).toContain('.' + className + ' {\n color: red;\n}') - - // animation name - const match = style.match(/@keyframes\s+(\S+)\s+{/) - expect(match).toHaveLength(2) - const animationName = match[1] - expect(animationName).not.toBe('fade') - expect(style).toContain('animation: ' + animationName + ' 1s;') - - // default module + pre-processor + scoped - const anotherClassName = instance.$style.red - expect(anotherClassName).toMatch(regexToMatch) - const id = 'data-v-' + genId('css-modules.vue') - expect(style).toContain('.' + anotherClassName + '[' + id + ']') + return mockResult } - // default ident - await testWithIdent(undefined, /^\w{21,}/) + test('default/nameless module ($style)', async () => { + const ENTRY = 'default.vue' - // custom ident - await testWithIdent( - '[path][name]---[local]---[hash:base64:5]', - /css-modules---red---\w{5}/ - ) -}) + const expectations = async ( + localIdentName: string | undefined, + regexToMatch: RegExp + ) => { + const { window, instance } = await testWithIdent(ENTRY, localIdentName) + // get local class name + const className = instance.$style.red + expect(className).toMatch(regexToMatch) -test('CSS Modules Extend', async () => { - const baseLoaders = [ - 'style-loader', - { - loader: 'css-loader', - options: { - modules: true, - }, - }, - ] + // class name in style + let style = [].slice + .call(window.document.querySelectorAll('style')) + .map((style: any) => { + return style!.textContent + }) + .join('\n') + style = normalizeNewline(style) + expect(style).toContain('.' + className + ' {\n color: red;\n}') + } - const { window, instance } = await mockBundleAndRun({ - entry: 'css-modules-extend.vue', - modify: (config: any) => { - config!.module!.rules = [ - { - test: /\.vue$/, - loader: 'vue-loader', - }, - { - test: /\.css$/, - use: baseLoaders, - }, - ] - }, + await expectations.apply(undefined, defaultIdent) + await expectations( + customIdent, + /test-fixtures-css-modules-default---red---[\w-+]{5}/ + ) + }) + + test('named module (module="named")', async () => { + const ENTRY = 'named.vue' + + const expectations = async ( + localIdentName: string | undefined, + regexToMatch: RegExp + ) => { + const { window, instance } = await testWithIdent(ENTRY, localIdentName) + // get local class name + const className = instance.named.red + expect(className).toMatch(regexToMatch) + + // class name in style + let style = [].slice + .call(window.document.querySelectorAll('style')) + .map((style: any) => { + return style!.textContent + }) + .join('\n') + style = normalizeNewline(style) + expect(style).toContain('.' + className + ' {\n color: red;\n}') + } + + await expectations.apply(undefined, defaultIdent) + await expectations( + customIdent, + /test-fixtures-css-modules-named---red---[\w-+]{5}/ + ) + }) + + test('multiple default/multiple modules', async () => { + const ENTRY = 'default-multiple.vue' + + const expectations = async ( + localIdentName: string | undefined, + regexToMatchA: RegExp, + regexToMatchB: RegExp + ) => { + const { window, instance } = await testWithIdent(ENTRY, localIdentName) + // get local class name + const classNameA = instance.$style.red + const classNameB = instance.$style.blue + expect(classNameA).toMatch(regexToMatchA) + expect(classNameB).toMatch(regexToMatchB) + + // class name in style + let style = [].slice + .call(window.document.querySelectorAll('style')) + .map((style: any) => { + return style!.textContent + }) + .join('\n') + style = normalizeNewline(style) + expect(style).toContain('.' + classNameA + ' {\n color: red;\n}') + expect(style).toContain('.' + classNameB + ' {\n color: blue;\n}') + } + + await expectations.apply(undefined, defaultIdent) + await expectations( + customIdent, + /test-fixtures-css-modules-default-multiple---red---[\w-+]{5}/, + /test-fixtures-css-modules-default-multiple---blue---[\w-+]{5}/ + ) + }) + + test('multiple named modules (same module names, different class names)', async () => { + const ENTRY = 'named-multiple.vue' + + const expectations = async ( + localIdentName: string | undefined, + regexToMatchA: RegExp, + regexToMatchB: RegExp + ) => { + const { window, instance } = await testWithIdent(ENTRY, localIdentName) + // get local class name + const classNameA = instance.named.red + const classNameB = instance.named.blue + expect(classNameA).toMatch(regexToMatchA) + expect(classNameB).toMatch(regexToMatchB) + + // class name in style + let style = [].slice + .call(window.document.querySelectorAll('style')) + .map((style: any) => { + return style!.textContent + }) + .join('\n') + style = normalizeNewline(style) + expect(style).toContain('.' + classNameA + ' {\n color: red;\n}') + expect(style).toContain('.' + classNameB + ' {\n color: blue;\n}') + } + + await expectations.apply(undefined, defaultIdent) + await expectations( + customIdent, + /test-fixtures-css-modules-named-multiple---red---[\w-+]{5}/, + /test-fixtures-css-modules-named-multiple---blue---[\w-+]{5}/ + ) + }) + + test('multiple named modules (different module names, different class names)', async () => { + const ENTRY = 'named-multiple-diffnamediffclass.vue' + + const expectations = async ( + localIdentName: string | undefined, + regexToMatchA: RegExp, + regexToMatchB: RegExp + ) => { + const { window, instance } = await testWithIdent(ENTRY, localIdentName) + // get local class name + const classNameA = instance.name1.red + const classNameB = instance.name2.blue + expect(classNameA).toMatch(regexToMatchA) + expect(classNameB).toMatch(regexToMatchB) + + // class name in style + let style = [].slice + .call(window.document.querySelectorAll('style')) + .map((style: any) => { + return style!.textContent + }) + .join('\n') + style = normalizeNewline(style) + expect(style).toContain('.' + classNameA + ' {\n color: red;\n}') + expect(style).toContain('.' + classNameB + ' {\n color: blue;\n}') + } + + await expectations.apply(undefined, defaultIdent) + await expectations( + customIdent, + /test-fixtures-css-modules-named-multiple-diffnamediffclass---red---[\w-+]{5}/, + /test-fixtures-css-modules-named-multiple-diffnamediffclass---blue---[\w-+]{5}/ + ) }) - expect(instance.$el.className).toBe(instance.$style.red) - const style = window.document.querySelectorAll('style')![1]!.textContent - expect(style).toContain(`.${instance.$style.red} {\n color: #FF0000;\n}`) + test('multiple named modules (different module names, same class name)', async () => { + const ENTRY = 'named-multiple-diffnamesameclass.vue' + + const expectations = async ( + localIdentName: string | undefined, + regexToMatchA: RegExp, + regexToMatchB: RegExp + ) => { + const { window, instance } = await testWithIdent(ENTRY, localIdentName) + // get local class name + const classNameA = instance.name1.red + const classNameB = instance.name2.red + expect(classNameA).toMatch(regexToMatchA) + expect(classNameB).toMatch(regexToMatchB) + + /* + !!BROKEN!!, classes have same name+hash + hash not taking module name into account + vue-loader needs to pass to css-loader too! + */ + expect(classNameA).not.toMatch(classNameB) + + // class name in style + let style = [].slice + .call(window.document.querySelectorAll('style')) + .map((style: any) => { + return style!.textContent + }) + .join('\n') + style = normalizeNewline(style) + expect(style).toContain('.' + classNameA + ' {\n color: red;\n}') + expect(style).toContain('.' + classNameB + ' {\n color: red;\n}') + } + + await expectations.apply(undefined, defaultIdent) + await expectations( + customIdent, + /test-fixtures-css-modules-named-multiple-diffnamesameclass---red---[\w-+]{5}/, + /test-fixtures-css-modules-named-multiple-diffnamesameclass---blue---[\w-+]{5}/ + ) + }) + + test('default/nameless extend (same class name)', async () => { + const ENTRY = 'default-extend.vue' + + const expectations = async ( + localIdentName: string | undefined, + regexToMatch: RegExp + ) => { + const { window, instance } = await testWithIdent(ENTRY, localIdentName) + // get local class name + const className = instance.$style.red // extended + expect(className).toMatch(regexToMatch) + // class name in style + let style = [].slice + .call(window.document.querySelectorAll('style')) + .map((style: any) => { + return style!.textContent + }) + .join('\n') + style = normalizeNewline(style) + /* + !!BROKEN!!, + extend is adding both classes to style + but instance.$style.red className points + to the file's original style (hexcolor) + (a677feb62ef42886b712f1b16b71e851-vue) + and not the extended version (red keyword) + e.g. + + ._7ef3af38102f7bc2284518b4f9dda8d9-vue { + color: red; + } + .a677feb62ef42886b712f1b16b71e851-vue { + color: #FF0000; + } + */ + expect(style).toContain('.' + className + ' {\n color: red;\n}') + } + + await expectations.apply(undefined, defaultIdent) + await expectations( + customIdent, + /test-fixtures-css-modules-default-extend---red---[\w-+]{5}/ + ) + }) + + test('default/nameless extend (different classes)', async () => { + const ENTRY = 'default-extend-diffclass.vue' + + const expectations = async ( + localIdentName: string | undefined, + regexToMatchA: RegExp, + regexToMatchB: RegExp + ) => { + const { window, instance } = await testWithIdent(ENTRY, localIdentName) + // get local class name + const classNameA = instance.$style.black // own style + const classNameB = instance.$style.red // extended + + expect(classNameA).toMatch(regexToMatchA) + expect(classNameB).toMatch(regexToMatchB) + /* + !!BROKEN!!, + styles for both own file's style tag and the + extended file are being added to style tags + in document BUT instance.$style has not received the + `red` in the hashmap so instance.$style does't exist + + instance.$style + { black: "dd07afd7f1529b35227b9b3bc7609e28-vue" } + + + styles + + ._7ef3af38102f7bc2284518b4f9dda8d9-vue { + color: red; + } + + + .dd07afd7f1529b35227b9b3bc7609e28-vue { + color: #000000; + } + */ + // class name in style + let style = [].slice + .call(window.document.querySelectorAll('style')) + .map((style: any) => { + return style!.textContent + }) + .join('\n') + style = normalizeNewline(style) + expect(style).toContain('.' + classNameA + ' {\n color: #000000;\n}') + expect(style).toContain('.' + classNameB + ' {\n color: red;\n}') + } + + await expectations.apply(undefined, defaultIdent) + await expectations( + customIdent, + /test-fixtures-css-modules-default-extend-diffclass---black---[\w-+]{5}/, + /test-fixtures-css-modules-default-extend-diffclass---red---[\w-+]{5}/ + ) + }) + + test('default/nameless extend w/ compose importing css file', async () => { + const ENTRY = 'default-extend-composes-css.vue' + + const expectations = async ( + localIdentName: string | undefined, + regexToMatchA: RegExp, + regexToMatchB: RegExp + ) => { + const { window, instance } = await testWithIdent(ENTRY, localIdentName) + // get local class name + const className = instance.$style.black // own style + const classList = className.split(' ') + expect(classList[0]).toMatch(regexToMatchA) + expect(classList[1]).toMatch(regexToMatchB) + + let style = [].slice + .call(window.document.querySelectorAll('style')) + .map((style: any) => { + return style!.textContent + }) + .join('\n') + style = normalizeNewline(style) + // own style, w/ font-weight + expect(style).toContain( + '.' + classList[0] + ' {\n font-weight: bold;\n}' + ) + // composed style, w/ red + expect(style).toContain('.' + classList[1] + ' {\n color: red;\n}') + } + + await expectations.apply(undefined, defaultIdent) + await expectations( + customIdent, + /test-fixtures-css-modules-default-extend-composes-css---black---[\w-+]{5}/, + /test-fixtures-css-modules-red---red---[\w-+]{5}/ + ) + }) }) test.todo('experimental + + + + + + diff --git a/test/style.spec.ts b/test/style.spec.ts index 5eec8c576..9fddbc2f4 100644 --- a/test/style.spec.ts +++ b/test/style.spec.ts @@ -1,4 +1,9 @@ -import { mockBundleAndRun, genId, normalizeNewline } from './utils' +import { + mockBundleAndRun, + genId, + normalizeNewline, + normalizeEscapedHash, +} from './utils' test('scoped style', async () => { const { window, instance, componentModule } = await mockBundleAndRun({ @@ -147,7 +152,7 @@ describe('CSS Modules', () => { return style!.textContent }) .join('\n') - style = normalizeNewline(style) + style = normalizeEscapedHash(normalizeNewline(style)) expect(style).toContain('.' + className + ' {\n color: red;\n}') } @@ -177,7 +182,7 @@ describe('CSS Modules', () => { return style!.textContent }) .join('\n') - style = normalizeNewline(style) + style = normalizeEscapedHash(normalizeNewline(style)) expect(style).toContain('.' + className + ' {\n color: red;\n}') } @@ -210,7 +215,7 @@ describe('CSS Modules', () => { return style!.textContent }) .join('\n') - style = normalizeNewline(style) + style = normalizeEscapedHash(normalizeNewline(style)) expect(style).toContain('.' + classNameA + ' {\n color: red;\n}') expect(style).toContain('.' + classNameB + ' {\n color: blue;\n}') } @@ -224,7 +229,7 @@ describe('CSS Modules', () => { }) test('multiple named modules (same module names, different class names)', async () => { - const ENTRY = 'named-multiple.vue' + const ENTRY = 'named-multiple-samename-diffclass.vue' const expectations = async ( localIdentName: string | undefined, @@ -245,7 +250,7 @@ describe('CSS Modules', () => { return style!.textContent }) .join('\n') - style = normalizeNewline(style) + style = normalizeEscapedHash(normalizeNewline(style)) expect(style).toContain('.' + classNameA + ' {\n color: red;\n}') expect(style).toContain('.' + classNameB + ' {\n color: blue;\n}') } @@ -253,13 +258,43 @@ describe('CSS Modules', () => { await expectations.apply(undefined, defaultIdent) await expectations( customIdent, - /test-fixtures-css-modules-named-multiple---red---[\w-+]{5}/, - /test-fixtures-css-modules-named-multiple---blue---[\w-+]{5}/ + /test-fixtures-css-modules-named-multiple-samename-diffclass---red---[\w-+]{5}/, + /test-fixtures-css-modules-named-multiple-samename-diffclass---blue---[\w-+]{5}/ + ) + }) + + test('multiple named modules (same module names, same class names)', async () => { + const ENTRY = 'named-multiple-samename-sameclass.vue' + + const expectations = async ( + localIdentName: string | undefined, + regexToMatch: RegExp + ) => { + const { window, instance } = await testWithIdent(ENTRY, localIdentName) + // get local class name + const className = instance.named.red + expect(className).toMatch(regexToMatch) + + // class name in style + let style = [].slice + .call(window.document.querySelectorAll('style')) + .map((style: any) => { + return style!.textContent + }) + .join('\n') + style = normalizeEscapedHash(normalizeNewline(style)) + expect(style).toContain('.' + className + ' {\n color: blue;\n}') + } + + await expectations.apply(undefined, defaultIdent) + await expectations( + customIdent, + /test-fixtures-css-modules-named-multiple-samename-sameclass---red---[\w-+]{5}/ ) }) test('multiple named modules (different module names, different class names)', async () => { - const ENTRY = 'named-multiple-diffnamediffclass.vue' + const ENTRY = 'named-multiple-diffname-diffclass.vue' const expectations = async ( localIdentName: string | undefined, @@ -280,7 +315,7 @@ describe('CSS Modules', () => { return style!.textContent }) .join('\n') - style = normalizeNewline(style) + style = normalizeEscapedHash(normalizeNewline(style)) expect(style).toContain('.' + classNameA + ' {\n color: red;\n}') expect(style).toContain('.' + classNameB + ' {\n color: blue;\n}') } @@ -288,13 +323,13 @@ describe('CSS Modules', () => { await expectations.apply(undefined, defaultIdent) await expectations( customIdent, - /test-fixtures-css-modules-named-multiple-diffnamediffclass---red---[\w-+]{5}/, - /test-fixtures-css-modules-named-multiple-diffnamediffclass---blue---[\w-+]{5}/ + /test-fixtures-css-modules-named-multiple-diffname-diffclass---red---[\w-+]{5}/, + /test-fixtures-css-modules-named-multiple-diffname-diffclass---blue---[\w-+]{5}/ ) }) test('multiple named modules (different module names, same class name)', async () => { - const ENTRY = 'named-multiple-diffnamesameclass.vue' + const ENTRY = 'named-multiple-diffname-sameclass.vue' const expectations = async ( localIdentName: string | undefined, @@ -308,12 +343,12 @@ describe('CSS Modules', () => { expect(classNameA).toMatch(regexToMatchA) expect(classNameB).toMatch(regexToMatchB) - /* - !!BROKEN!!, classes have same name+hash + expect(classNameA).not.toMatch(classNameB) + /* ^!BROKEN!^ + classes have same name+hash hash not taking module name into account vue-loader needs to pass to css-loader too! */ - expect(classNameA).not.toMatch(classNameB) // class name in style let style = [].slice @@ -322,7 +357,7 @@ describe('CSS Modules', () => { return style!.textContent }) .join('\n') - style = normalizeNewline(style) + style = normalizeEscapedHash(normalizeNewline(style)) expect(style).toContain('.' + classNameA + ' {\n color: red;\n}') expect(style).toContain('.' + classNameB + ' {\n color: red;\n}') } @@ -330,8 +365,8 @@ describe('CSS Modules', () => { await expectations.apply(undefined, defaultIdent) await expectations( customIdent, - /test-fixtures-css-modules-named-multiple-diffnamesameclass---red---[\w-+]{5}/, - /test-fixtures-css-modules-named-multiple-diffnamesameclass---blue---[\w-+]{5}/ + /test-fixtures-css-modules-named-multiple-diffname-sameclass---red---[\w-+]{5}/, + /test-fixtures-css-modules-named-multiple-diffname-sameclass---blue---[\w-+]{5}/ ) }) @@ -353,9 +388,10 @@ describe('CSS Modules', () => { return style!.textContent }) .join('\n') - style = normalizeNewline(style) - /* - !!BROKEN!!, + style = normalizeEscapedHash(normalizeNewline(style)) + + expect(style).toContain('.' + className + ' {\n color: red;\n}') + /* ^!BROKEN!^ extend is adding both classes to style but instance.$style.red className points to the file's original style (hexcolor) @@ -370,7 +406,6 @@ describe('CSS Modules', () => { color: #FF0000; } */ - expect(style).toContain('.' + className + ' {\n color: red;\n}') } await expectations.apply(undefined, defaultIdent) @@ -394,20 +429,19 @@ describe('CSS Modules', () => { const classNameB = instance.$style.red // extended expect(classNameA).toMatch(regexToMatchA) + expect(classNameB).toMatch(regexToMatchB) - /* - !!BROKEN!!, + /* ^!BROKEN!^, styles for both own file's style tag and the extended file are being added to style tags in document BUT instance.$style has not received the - `red` in the hashmap so instance.$style does't exist + `red` in the hashmap so instance.$style.red does't exist instance.$style { black: "dd07afd7f1529b35227b9b3bc7609e28-vue" } styles - ._7ef3af38102f7bc2284518b4f9dda8d9-vue { color: red; } @@ -424,7 +458,7 @@ describe('CSS Modules', () => { return style!.textContent }) .join('\n') - style = normalizeNewline(style) + style = normalizeEscapedHash(normalizeNewline(style)) expect(style).toContain('.' + classNameA + ' {\n color: #000000;\n}') expect(style).toContain('.' + classNameB + ' {\n color: red;\n}') } @@ -458,7 +492,7 @@ describe('CSS Modules', () => { return style!.textContent }) .join('\n') - style = normalizeNewline(style) + style = normalizeEscapedHash(normalizeNewline(style)) // own style, w/ font-weight expect(style).toContain( '.' + classList[0] + ' {\n font-weight: bold;\n}' diff --git a/test/utils.ts b/test/utils.ts index 628d24da8..05c403c17 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -174,6 +174,10 @@ export function normalizeNewline(input: string): string { return input.replace(new RegExp('\r\n', 'g'), '\n') } +export function normalizeEscapedHash(input: string): string { + return input.replace(new RegExp('\\\\', 'g'), '') +} + // see the logic at src/index.ts // in non-production environment, shortFilePath is used to generate scope id export function genId(fixtureName: string): string {