compileScriptRefTransform.spec.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import { BindingTypes } from '@vue/compiler-core'
  2. import { compileSFCScript as compile, assertCode } from './utils'
  3. // this file only tests integration with SFC - main test case for the ref
  4. // transform can be found in <root>/packages/reactivity-transform/__tests__
  5. describe('sfc ref transform', () => {
  6. function compileWithReactivityTransform(src: string) {
  7. return compile(src, { reactivityTransform: true })
  8. }
  9. test('$ unwrapping', () => {
  10. const { content, bindings } = compileWithReactivityTransform(`<script setup>
  11. import { ref, shallowRef } from 'vue'
  12. let foo = $(ref())
  13. let a = $(ref(1))
  14. let b = $(shallowRef({
  15. count: 0
  16. }))
  17. let c = () => {}
  18. let d
  19. </script>`)
  20. expect(content).not.toMatch(`$(ref())`)
  21. expect(content).not.toMatch(`$(ref(1))`)
  22. expect(content).not.toMatch(`$(shallowRef({`)
  23. expect(content).toMatch(`let foo = (ref())`)
  24. expect(content).toMatch(`let a = (ref(1))`)
  25. expect(content).toMatch(`
  26. let b = (shallowRef({
  27. count: 0
  28. }))
  29. `)
  30. // normal declarations left untouched
  31. expect(content).toMatch(`let c = () => {}`)
  32. expect(content).toMatch(`let d`)
  33. expect(content).toMatch(
  34. `return { foo, a, b, get c() { return c }, get d() { return d }, ref, shallowRef }`
  35. )
  36. assertCode(content)
  37. expect(bindings).toStrictEqual({
  38. foo: BindingTypes.SETUP_REF,
  39. a: BindingTypes.SETUP_REF,
  40. b: BindingTypes.SETUP_REF,
  41. c: BindingTypes.SETUP_LET,
  42. d: BindingTypes.SETUP_LET,
  43. ref: BindingTypes.SETUP_CONST,
  44. shallowRef: BindingTypes.SETUP_CONST
  45. })
  46. })
  47. test('$ref & $shallowRef declarations', () => {
  48. const { content, bindings } = compileWithReactivityTransform(`<script setup>
  49. let foo = $ref()
  50. let a = $ref(1)
  51. let b = $shallowRef({
  52. count: 0
  53. })
  54. let c = () => {}
  55. let d
  56. </script>`)
  57. expect(content).toMatch(
  58. `import { ref as _ref, shallowRef as _shallowRef } from 'vue'`
  59. )
  60. expect(content).not.toMatch(`$ref()`)
  61. expect(content).not.toMatch(`$ref(1)`)
  62. expect(content).not.toMatch(`$shallowRef({`)
  63. expect(content).toMatch(`let foo = _ref()`)
  64. expect(content).toMatch(`let a = _ref(1)`)
  65. expect(content).toMatch(`
  66. let b = _shallowRef({
  67. count: 0
  68. })
  69. `)
  70. // normal declarations left untouched
  71. expect(content).toMatch(`let c = () => {}`)
  72. expect(content).toMatch(`let d`)
  73. assertCode(content)
  74. expect(bindings).toStrictEqual({
  75. foo: BindingTypes.SETUP_REF,
  76. a: BindingTypes.SETUP_REF,
  77. b: BindingTypes.SETUP_REF,
  78. c: BindingTypes.SETUP_LET,
  79. d: BindingTypes.SETUP_LET
  80. })
  81. })
  82. test('usage in normal <script>', () => {
  83. const { content } = compileWithReactivityTransform(`<script>
  84. export default {
  85. setup() {
  86. let count = $ref(0)
  87. const inc = () => count++
  88. return $$({ count })
  89. }
  90. }
  91. </script>`)
  92. expect(content).not.toMatch(`$ref(0)`)
  93. expect(content).toMatch(`import { ref as _ref } from 'vue'`)
  94. expect(content).toMatch(`let count = _ref(0)`)
  95. expect(content).toMatch(`count.value++`)
  96. expect(content).toMatch(`return ({ count })`)
  97. assertCode(content)
  98. })
  99. test('usage /w typescript', () => {
  100. const { content } = compileWithReactivityTransform(`
  101. <script setup lang="ts">
  102. let msg = $ref<string | number>('foo');
  103. let bar = $ref <string | number>('bar');
  104. </script>
  105. `)
  106. expect(content).toMatch(`import { ref as _ref`)
  107. expect(content).toMatch(`let msg = _ref<string | number>('foo')`)
  108. expect(content).toMatch(`let bar = _ref <string | number>('bar')`)
  109. assertCode(content)
  110. })
  111. test('usage with normal <script> + <script setup>', () => {
  112. const { content, bindings } = compileWithReactivityTransform(`<script>
  113. let a = $ref(0)
  114. let c = $ref(0)
  115. </script>
  116. <script setup>
  117. let b = $ref(0)
  118. let c = 0
  119. function change() {
  120. a++
  121. b++
  122. c++
  123. }
  124. </script>`)
  125. // should dedupe helper imports
  126. expect(content).toMatch(`import { ref as _ref } from 'vue'`)
  127. expect(content).toMatch(`let a = _ref(0)`)
  128. expect(content).toMatch(`let b = _ref(0)`)
  129. // root level ref binding declared in <script> should be inherited in <script setup>
  130. expect(content).toMatch(`a.value++`)
  131. expect(content).toMatch(`b.value++`)
  132. // c shadowed
  133. expect(content).toMatch(`c++`)
  134. assertCode(content)
  135. expect(bindings).toStrictEqual({
  136. a: BindingTypes.SETUP_REF,
  137. b: BindingTypes.SETUP_REF,
  138. c: BindingTypes.SETUP_REF,
  139. change: BindingTypes.SETUP_CONST
  140. })
  141. })
  142. test('usage with normal <script> (has macro usage) + <script setup> (no macro usage)', () => {
  143. const { content } = compileWithReactivityTransform(`
  144. <script>
  145. let data = $ref()
  146. </script>
  147. <script setup>
  148. console.log(data)
  149. </script>
  150. `)
  151. expect(content).toMatch(`console.log(data.value)`)
  152. assertCode(content)
  153. })
  154. describe('errors', () => {
  155. test('defineProps/Emit() referencing ref declarations', () => {
  156. expect(() =>
  157. compile(
  158. `<script setup>
  159. let bar = $ref(1)
  160. defineProps({
  161. bar
  162. })
  163. </script>`,
  164. { reactivityTransform: true }
  165. )
  166. ).toThrow(`cannot reference locally declared variables`)
  167. expect(() =>
  168. compile(
  169. `<script setup>
  170. let bar = $ref(1)
  171. defineEmits({
  172. bar
  173. })
  174. </script>`,
  175. { reactivityTransform: true }
  176. )
  177. ).toThrow(`cannot reference locally declared variables`)
  178. })
  179. })
  180. })