compileStyle.spec.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import { compileStyle } from '../src/compileStyle'
  2. import { mockWarn } from '@vue/shared'
  3. function compile(source: string): string {
  4. const res = compileStyle({
  5. source,
  6. filename: 'test.css',
  7. id: 'test'
  8. })
  9. if (res.errors.length) {
  10. res.errors.forEach(err => {
  11. console.error(err)
  12. })
  13. expect(res.errors.length).toBe(0)
  14. }
  15. return res.code
  16. }
  17. describe('SFC scoped CSS', () => {
  18. mockWarn()
  19. test('simple selectors', () => {
  20. expect(compile(`h1 { color: red; }`)).toMatch(`h1[test] { color: red;`)
  21. expect(compile(`.foo { color: red; }`)).toMatch(`.foo[test] { color: red;`)
  22. })
  23. test('descendent selector', () => {
  24. expect(compile(`h1 .foo { color: red; }`)).toMatch(
  25. `h1 .foo[test] { color: red;`
  26. )
  27. })
  28. test('multiple selectors', () => {
  29. expect(compile(`h1 .foo, .bar, .baz { color: red; }`)).toMatch(
  30. `h1 .foo[test], .bar[test], .baz[test] { color: red;`
  31. )
  32. })
  33. test('pseudo class', () => {
  34. expect(compile(`.foo:after { color: red; }`)).toMatch(
  35. `.foo[test]:after { color: red;`
  36. )
  37. })
  38. test('pseudo element', () => {
  39. expect(compile(`::selection { display: none; }`)).toMatch(
  40. '[test]::selection {'
  41. )
  42. })
  43. test('spaces before pseudo element', () => {
  44. const code = compile(`.abc, ::selection { color: red; }`)
  45. expect(code).toMatch('.abc[test],')
  46. expect(code).toMatch('[test]::selection {')
  47. })
  48. test('::v-deep', () => {
  49. expect(compile(`::v-deep(.foo) { color: red; }`)).toMatchInlineSnapshot(`
  50. "[test] .foo { color: red;
  51. }"
  52. `)
  53. expect(compile(`::v-deep(.foo .bar) { color: red; }`))
  54. .toMatchInlineSnapshot(`
  55. "[test] .foo .bar { color: red;
  56. }"
  57. `)
  58. expect(compile(`.baz .qux ::v-deep(.foo .bar) { color: red; }`))
  59. .toMatchInlineSnapshot(`
  60. ".baz .qux[test] .foo .bar { color: red;
  61. }"
  62. `)
  63. })
  64. test('::v-slotted', () => {
  65. expect(compile(`::v-slotted(.foo) { color: red; }`)).toMatchInlineSnapshot(`
  66. ".foo[test-s] { color: red;
  67. }"
  68. `)
  69. expect(compile(`::v-slotted(.foo .bar) { color: red; }`))
  70. .toMatchInlineSnapshot(`
  71. ".foo .bar[test-s] { color: red;
  72. }"
  73. `)
  74. expect(compile(`.baz .qux ::v-slotted(.foo .bar) { color: red; }`))
  75. .toMatchInlineSnapshot(`
  76. ".baz .qux .foo .bar[test-s] { color: red;
  77. }"
  78. `)
  79. })
  80. test('::v-global', () => {
  81. expect(compile(`::v-global(.foo) { color: red; }`)).toMatchInlineSnapshot(`
  82. ".foo { color: red;
  83. }"
  84. `)
  85. expect(compile(`::v-global(.foo .bar) { color: red; }`))
  86. .toMatchInlineSnapshot(`
  87. ".foo .bar { color: red;
  88. }"
  89. `)
  90. // global ignores anything before it
  91. expect(compile(`.baz .qux ::v-global(.foo .bar) { color: red; }`))
  92. .toMatchInlineSnapshot(`
  93. ".foo .bar { color: red;
  94. }"
  95. `)
  96. })
  97. test('media query', () => {
  98. expect(compile(`@media print { .foo { color: red }}`))
  99. .toMatchInlineSnapshot(`
  100. "@media print {
  101. .foo[test] { color: red
  102. }}"
  103. `)
  104. })
  105. test('supports query', () => {
  106. expect(compile(`@supports(display: grid) { .foo { display: grid }}`))
  107. .toMatchInlineSnapshot(`
  108. "@supports(display: grid) {
  109. .foo[test] { display: grid
  110. }}"
  111. `)
  112. })
  113. test('scoped keyframes', () => {
  114. const style = compile(`
  115. .anim {
  116. animation: color 5s infinite, other 5s;
  117. }
  118. .anim-2 {
  119. animation-name: color;
  120. animation-duration: 5s;
  121. }
  122. .anim-3 {
  123. animation: 5s color infinite, 5s other;
  124. }
  125. .anim-multiple {
  126. animation: color 5s infinite, opacity 2s;
  127. }
  128. .anim-multiple-2 {
  129. animation-name: color, opacity;
  130. animation-duration: 5s, 2s;
  131. }
  132. @keyframes color {
  133. from { color: red; }
  134. to { color: green; }
  135. }
  136. @-webkit-keyframes color {
  137. from { color: red; }
  138. to { color: green; }
  139. }
  140. @keyframes opacity {
  141. from { opacity: 0; }
  142. to { opacity: 1; }
  143. }
  144. @-webkit-keyframes opacity {
  145. from { opacity: 0; }
  146. to { opacity: 1; }
  147. }
  148. `)
  149. expect(style).toContain(
  150. `.anim[test] {\n animation: color-test 5s infinite, other 5s;`
  151. )
  152. expect(style).toContain(`.anim-2[test] {\n animation-name: color-test`)
  153. expect(style).toContain(
  154. `.anim-3[test] {\n animation: 5s color-test infinite, 5s other;`
  155. )
  156. expect(style).toContain(`@keyframes color-test {`)
  157. expect(style).toContain(`@-webkit-keyframes color-test {`)
  158. expect(style).toContain(
  159. `.anim-multiple[test] {\n animation: color-test 5s infinite,opacity-test 2s;`
  160. )
  161. expect(style).toContain(
  162. `.anim-multiple-2[test] {\n animation-name: color-test,opacity-test;`
  163. )
  164. expect(style).toContain(`@keyframes opacity-test {`)
  165. expect(style).toContain(`@-webkit-keyframes opacity-test {`)
  166. })
  167. // vue-loader/#1370
  168. test('spaces after selector', () => {
  169. const { code } = compileStyle({
  170. source: `.foo , .bar { color: red; }`,
  171. filename: 'test.css',
  172. id: 'test'
  173. })
  174. expect(code).toMatchInlineSnapshot(`
  175. ".foo[test], .bar[test] { color: red;
  176. }"
  177. `)
  178. })
  179. describe('deprecated syntax', () => {
  180. test('::v-deep as combinator', () => {
  181. expect(compile(`::v-deep .foo { color: red; }`)).toMatchInlineSnapshot(`
  182. "[test] .foo { color: red;
  183. }"
  184. `)
  185. expect(compile(`.bar ::v-deep .foo { color: red; }`))
  186. .toMatchInlineSnapshot(`
  187. ".bar[test] .foo { color: red;
  188. }"
  189. `)
  190. expect(
  191. `::v-deep usage as a combinator has been deprecated.`
  192. ).toHaveBeenWarned()
  193. })
  194. test('>>> (deprecated syntax)', () => {
  195. const code = compile(`>>> .foo { color: red; }`)
  196. expect(code).toMatchInlineSnapshot(`
  197. "[test] .foo { color: red;
  198. }"
  199. `)
  200. expect(
  201. `the >>> and /deep/ combinators have been deprecated.`
  202. ).toHaveBeenWarned()
  203. })
  204. test('/deep/ (deprecated syntax)', () => {
  205. const code = compile(`/deep/ .foo { color: red; }`)
  206. expect(code).toMatchInlineSnapshot(`
  207. "[test] .foo { color: red;
  208. }"
  209. `)
  210. expect(
  211. `the >>> and /deep/ combinators have been deprecated.`
  212. ).toHaveBeenWarned()
  213. })
  214. })
  215. })