useCssVars.spec.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import {
  2. ref,
  3. render,
  4. useCssVars,
  5. createStaticVNode,
  6. h,
  7. reactive,
  8. nextTick,
  9. ComponentOptions,
  10. Suspense,
  11. FunctionalComponent
  12. } from '@vue/runtime-dom'
  13. describe('useCssVars', () => {
  14. async function assertCssVars(getApp: (state: any) => ComponentOptions) {
  15. const state = reactive({ color: 'red' })
  16. const App = getApp(state)
  17. const root = document.createElement('div')
  18. render(h(App), root)
  19. await nextTick()
  20. for (const c of [].slice.call(root.children as any)) {
  21. expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe(`red`)
  22. }
  23. state.color = 'green'
  24. await nextTick()
  25. for (const c of [].slice.call(root.children as any)) {
  26. expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('green')
  27. }
  28. }
  29. test('basic', async () => {
  30. await assertCssVars(state => ({
  31. setup() {
  32. // test receiving render context
  33. useCssVars((ctx: any) => ({
  34. color: ctx.color
  35. }))
  36. return state
  37. },
  38. render() {
  39. return h('div')
  40. }
  41. }))
  42. })
  43. test('on fragment root', async () => {
  44. await assertCssVars(state => ({
  45. setup() {
  46. useCssVars(() => state)
  47. return () => [h('div'), h('div')]
  48. }
  49. }))
  50. })
  51. test('on HOCs', async () => {
  52. const Child = () => [h('div'), h('div')]
  53. await assertCssVars(state => ({
  54. setup() {
  55. useCssVars(() => state)
  56. return () => h(Child)
  57. }
  58. }))
  59. })
  60. test('on suspense root', async () => {
  61. const state = reactive({ color: 'red' })
  62. const root = document.createElement('div')
  63. let resolveAsync: any
  64. let asyncPromise: any
  65. const AsyncComp = {
  66. setup() {
  67. asyncPromise = new Promise(r => {
  68. resolveAsync = () => {
  69. r(() => h('p', 'default'))
  70. }
  71. })
  72. return asyncPromise
  73. }
  74. }
  75. const App = {
  76. setup() {
  77. useCssVars(() => state)
  78. return () =>
  79. h(Suspense, null, {
  80. default: h(AsyncComp),
  81. fallback: h('div', 'fallback')
  82. })
  83. }
  84. }
  85. render(h(App), root)
  86. await nextTick()
  87. // css vars use with fallback tree
  88. for (const c of [].slice.call(root.children as any)) {
  89. expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe(`red`)
  90. }
  91. // AsyncComp resolve
  92. resolveAsync()
  93. await asyncPromise.then(() => {})
  94. // Suspense effects flush
  95. await nextTick()
  96. // css vars use with default tree
  97. for (const c of [].slice.call(root.children as any)) {
  98. expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe(`red`)
  99. }
  100. state.color = 'green'
  101. await nextTick()
  102. for (const c of [].slice.call(root.children as any)) {
  103. expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('green')
  104. }
  105. })
  106. test('with subTree changed', async () => {
  107. const state = reactive({ color: 'red' })
  108. const value = ref(true)
  109. const root = document.createElement('div')
  110. const App = {
  111. setup() {
  112. useCssVars(() => state)
  113. return () => (value.value ? [h('div')] : [h('div'), h('div')])
  114. }
  115. }
  116. render(h(App), root)
  117. await nextTick()
  118. // css vars use with fallback tree
  119. for (const c of [].slice.call(root.children as any)) {
  120. expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe(`red`)
  121. }
  122. value.value = false
  123. await nextTick()
  124. for (const c of [].slice.call(root.children as any)) {
  125. expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
  126. }
  127. })
  128. // #3894
  129. test('with subTree change inside HOC', async () => {
  130. const state = reactive({ color: 'red' })
  131. const value = ref(true)
  132. const root = document.createElement('div')
  133. const Child: FunctionalComponent = (_, { slots }) => slots.default!()
  134. const App = {
  135. setup() {
  136. useCssVars(() => state)
  137. return () =>
  138. h(Child, null, () =>
  139. value.value ? [h('div')] : [h('div'), h('div')]
  140. )
  141. }
  142. }
  143. render(h(App), root)
  144. await nextTick()
  145. // css vars use with fallback tree
  146. for (const c of [].slice.call(root.children as any)) {
  147. expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe(`red`)
  148. }
  149. value.value = false
  150. await nextTick()
  151. for (const c of [].slice.call(root.children as any)) {
  152. expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
  153. }
  154. })
  155. test('with createStaticVNode', async () => {
  156. const state = reactive({ color: 'red' })
  157. const root = document.createElement('div')
  158. const App = {
  159. setup() {
  160. useCssVars(() => state)
  161. return () => [
  162. h('div'),
  163. createStaticVNode('<div>1</div><div><span>2</span></div>', 2),
  164. h('div')
  165. ]
  166. }
  167. }
  168. render(h(App), root)
  169. await nextTick()
  170. for (const c of [].slice.call(root.children as any)) {
  171. expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
  172. }
  173. })
  174. })