ref.spec.ts 3.7 KB

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