ref.spec.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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 without initial value', () => {
  33. const a = ref()
  34. let dummy
  35. effect(() => {
  36. dummy = a.value
  37. })
  38. expect(dummy).toBe(undefined)
  39. a.value = 2
  40. expect(dummy).toBe(2)
  41. })
  42. it('should work like a normal property when nested in a reactive object', () => {
  43. const a = ref(1)
  44. const obj = reactive({
  45. a,
  46. b: {
  47. c: a
  48. }
  49. })
  50. let dummy1: number
  51. let dummy2: number
  52. effect(() => {
  53. dummy1 = obj.a
  54. dummy2 = obj.b.c
  55. })
  56. const assertDummiesEqualTo = (val: number) =>
  57. [dummy1, dummy2].forEach(dummy => expect(dummy).toBe(val))
  58. assertDummiesEqualTo(1)
  59. a.value++
  60. assertDummiesEqualTo(2)
  61. obj.a++
  62. assertDummiesEqualTo(3)
  63. obj.b.c++
  64. assertDummiesEqualTo(4)
  65. })
  66. it('should unwrap nested ref in types', () => {
  67. const a = ref(0)
  68. const b = ref(a)
  69. expect(typeof (b.value + 1)).toBe('number')
  70. })
  71. it('should unwrap nested values in types', () => {
  72. const a = {
  73. b: ref(0)
  74. }
  75. const c = ref(a)
  76. expect(typeof (c.value.b + 1)).toBe('number')
  77. })
  78. it('should NOT unwrap ref types nested inside arrays', () => {
  79. const arr = ref([1, ref(1)]).value
  80. ;(arr[0] as number)++
  81. ;(arr[1] as Ref<number>).value++
  82. const arr2 = ref([1, new Map<string, any>(), ref('1')]).value
  83. const value = arr2[0]
  84. if (isRef(value)) {
  85. value + 'foo'
  86. } else if (typeof value === 'number') {
  87. value + 1
  88. } else {
  89. // should narrow down to Map type
  90. // and not contain any Ref type
  91. value.has('foo')
  92. }
  93. })
  94. it('should keep tuple types', () => {
  95. const tuple: [number, string, { a: number }, () => number, Ref<number>] = [
  96. 0,
  97. '1',
  98. { a: 1 },
  99. () => 0,
  100. ref(0)
  101. ]
  102. const tupleRef = ref(tuple)
  103. tupleRef.value[0]++
  104. expect(tupleRef.value[0]).toBe(1)
  105. tupleRef.value[1] += '1'
  106. expect(tupleRef.value[1]).toBe('11')
  107. tupleRef.value[2].a++
  108. expect(tupleRef.value[2].a).toBe(2)
  109. expect(tupleRef.value[3]()).toBe(0)
  110. tupleRef.value[4].value++
  111. expect(tupleRef.value[4].value).toBe(1)
  112. })
  113. test('isRef', () => {
  114. expect(isRef(ref(1))).toBe(true)
  115. expect(isRef(computed(() => 1))).toBe(true)
  116. expect(isRef(0)).toBe(false)
  117. expect(isRef(1)).toBe(false)
  118. // an object that looks like a ref isn't necessarily a ref
  119. expect(isRef({ value: 0 })).toBe(false)
  120. })
  121. test('toRefs', () => {
  122. const a = reactive({
  123. x: 1,
  124. y: 2
  125. })
  126. const { x, y } = toRefs(a)
  127. expect(isRef(x)).toBe(true)
  128. expect(isRef(y)).toBe(true)
  129. expect(x.value).toBe(1)
  130. expect(y.value).toBe(2)
  131. // source -> proxy
  132. a.x = 2
  133. a.y = 3
  134. expect(x.value).toBe(2)
  135. expect(y.value).toBe(3)
  136. // proxy -> source
  137. x.value = 3
  138. y.value = 4
  139. expect(a.x).toBe(3)
  140. expect(a.y).toBe(4)
  141. // reactivity
  142. let dummyX, dummyY
  143. effect(() => {
  144. dummyX = x.value
  145. dummyY = y.value
  146. })
  147. expect(dummyX).toBe(x.value)
  148. expect(dummyY).toBe(y.value)
  149. // mutating source should trigger effect using the proxy refs
  150. a.x = 4
  151. a.y = 5
  152. expect(dummyX).toBe(4)
  153. expect(dummyY).toBe(5)
  154. })
  155. })