ref.spec.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import { ref, effect, reactive, isRef, toRefs, Ref } from '../src/index'
  2. import { computed } from '@vue/runtime-dom'
  3. describe('reactivity/ref', () => {
  4. it('should hold a value', () => {
  5. const a = ref(1)
  6. expect(a.value).toBe(1)
  7. a.value = 2
  8. expect(a.value).toBe(2)
  9. })
  10. it('should be reactive', () => {
  11. const a = ref(1)
  12. let dummy
  13. effect(() => {
  14. dummy = a.value
  15. })
  16. expect(dummy).toBe(1)
  17. a.value = 2
  18. expect(dummy).toBe(2)
  19. })
  20. it('should make nested properties reactive', () => {
  21. const a = ref({
  22. count: 1
  23. })
  24. let dummy
  25. effect(() => {
  26. dummy = a.value.count
  27. })
  28. expect(dummy).toBe(1)
  29. a.value.count = 2
  30. expect(dummy).toBe(2)
  31. })
  32. it('should work like a normal property when nested in a reactive object', () => {
  33. const a = ref(1)
  34. const obj = reactive({
  35. a,
  36. b: {
  37. c: a,
  38. d: [a]
  39. }
  40. })
  41. let dummy1
  42. let dummy2
  43. let dummy3
  44. effect(() => {
  45. dummy1 = obj.a
  46. dummy2 = obj.b.c
  47. dummy3 = obj.b.d[0]
  48. })
  49. expect(dummy1).toBe(1)
  50. expect(dummy2).toBe(1)
  51. expect(dummy3).toBe(1)
  52. a.value++
  53. expect(dummy1).toBe(2)
  54. expect(dummy2).toBe(2)
  55. expect(dummy3).toBe(2)
  56. obj.a++
  57. expect(dummy1).toBe(3)
  58. expect(dummy2).toBe(3)
  59. expect(dummy3).toBe(3)
  60. obj.b.c++
  61. expect(dummy1).toBe(4)
  62. expect(dummy2).toBe(4)
  63. expect(dummy3).toBe(4)
  64. obj.b.d[0]++
  65. expect(dummy1).toBe(5)
  66. expect(dummy2).toBe(5)
  67. expect(dummy3).toBe(5)
  68. })
  69. it('should unwrap nested ref in types', () => {
  70. const a = ref(0)
  71. const b = ref(a)
  72. expect(typeof (b.value + 1)).toBe('number')
  73. })
  74. it('should unwrap nested values in types', () => {
  75. const a = {
  76. b: ref(0)
  77. }
  78. const c = ref(a)
  79. expect(typeof (c.value.b + 1)).toBe('number')
  80. })
  81. it('should properly unwrap ref types nested inside arrays', () => {
  82. const arr = ref([1, ref(1)]).value
  83. // should unwrap to number[]
  84. arr[0]++
  85. arr[1]++
  86. const arr2 = ref([1, new Map<string, any>(), ref('1')]).value
  87. const value = arr2[0]
  88. if (typeof value === 'string') {
  89. value + 'foo'
  90. } else if (typeof value === 'number') {
  91. value + 1
  92. } else {
  93. // should narrow down to Map type
  94. // and not contain any Ref type
  95. value.has('foo')
  96. }
  97. })
  98. it('should keep tuple types', () => {
  99. const tuple: [number, string, { a: number }, () => number, Ref<number>] = [
  100. 0,
  101. '1',
  102. { a: 1 },
  103. () => 0,
  104. ref(0)
  105. ]
  106. const tupleRef = ref(tuple)
  107. tupleRef.value[0]++
  108. expect(tupleRef.value[0]).toBe(1)
  109. tupleRef.value[1] += '1'
  110. expect(tupleRef.value[1]).toBe('11')
  111. tupleRef.value[2].a++
  112. expect(tupleRef.value[2].a).toBe(2)
  113. expect(tupleRef.value[3]()).toBe(0)
  114. tupleRef.value[4]++
  115. expect(tupleRef.value[4]).toBe(1)
  116. })
  117. test('isRef', () => {
  118. expect(isRef(ref(1))).toBe(true)
  119. expect(isRef(computed(() => 1))).toBe(true)
  120. expect(isRef(0)).toBe(false)
  121. expect(isRef(1)).toBe(false)
  122. // an object that looks like a ref isn't necessarily a ref
  123. expect(isRef({ value: 0 })).toBe(false)
  124. })
  125. test('toRefs', () => {
  126. const a = reactive({
  127. x: 1,
  128. y: 2
  129. })
  130. const { x, y } = toRefs(a)
  131. expect(isRef(x)).toBe(true)
  132. expect(isRef(y)).toBe(true)
  133. expect(x.value).toBe(1)
  134. expect(y.value).toBe(2)
  135. // source -> proxy
  136. a.x = 2
  137. a.y = 3
  138. expect(x.value).toBe(2)
  139. expect(y.value).toBe(3)
  140. // proxy -> source
  141. x.value = 3
  142. y.value = 4
  143. expect(a.x).toBe(3)
  144. expect(a.y).toBe(4)
  145. // reactivity
  146. let dummyX, dummyY
  147. effect(() => {
  148. dummyX = x.value
  149. dummyY = y.value
  150. })
  151. expect(dummyX).toBe(x.value)
  152. expect(dummyY).toBe(y.value)
  153. // mutating source should trigger effect using the proxy refs
  154. a.x = 4
  155. a.y = 5
  156. expect(dummyX).toBe(4)
  157. expect(dummyY).toBe(5)
  158. })
  159. })