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 @@
+
+
+
+
+
+ {{ $style.black }}
+
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 @@
+
+
+
+
+
+ {{ $style.red }} | {{ $style.black }}
+
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 @@
+
+
+
+
+
+
+
+ {{ $style }}
+
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 @@
+
+
+ {{ $style }}
+
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 @@
+
+
+
+
+
+
+
+ {{ name1 }} | {{ name2 }}
+
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 @@
+
+
+
+
+
+
+
+ {{ name1 }} | {{ name2 }}
+
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 @@
+
+
+
+
+
+
+
+ {{ named }}
+
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 @@
+
+
+
+
+
+ {{ named }}
+
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
+
+
+
+
+
+
+ {{ named }}
+
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 {