shallowReactive.spec.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import {
  2. isReactive,
  3. isShallow,
  4. reactive,
  5. shallowReactive,
  6. shallowReadonly,
  7. } from '../src/reactive'
  8. import { effect } from '../src/effect'
  9. import { type Ref, isRef, ref } from '../src/ref'
  10. describe('shallowReactive', () => {
  11. test('should not make non-reactive properties reactive', () => {
  12. const props = shallowReactive({ n: { foo: 1 } })
  13. expect(isReactive(props.n)).toBe(false)
  14. })
  15. test('should keep reactive properties reactive', () => {
  16. const props: any = shallowReactive({ n: reactive({ foo: 1 }) })
  17. props.n = reactive({ foo: 2 })
  18. expect(isReactive(props.n)).toBe(true)
  19. })
  20. // #2843
  21. test('should allow shallow and normal reactive for same target', () => {
  22. const original = { foo: {} }
  23. const shallowProxy = shallowReactive(original)
  24. const reactiveProxy = reactive(original)
  25. expect(shallowProxy).not.toBe(reactiveProxy)
  26. expect(isReactive(shallowProxy.foo)).toBe(false)
  27. expect(isReactive(reactiveProxy.foo)).toBe(true)
  28. })
  29. test('isShallow', () => {
  30. expect(isShallow(shallowReactive({}))).toBe(true)
  31. expect(isShallow(shallowReadonly({}))).toBe(true)
  32. })
  33. // #5271
  34. test('should respect shallow reactive nested inside reactive on reset', () => {
  35. const r = reactive({ foo: shallowReactive({ bar: {} }) })
  36. expect(isShallow(r.foo)).toBe(true)
  37. expect(isReactive(r.foo.bar)).toBe(false)
  38. r.foo = shallowReactive({ bar: {} })
  39. expect(isShallow(r.foo)).toBe(true)
  40. expect(isReactive(r.foo.bar)).toBe(false)
  41. })
  42. // vuejs/vue#12597
  43. test('should not unwrap refs', () => {
  44. const foo = shallowReactive({
  45. bar: ref(123),
  46. })
  47. expect(isRef(foo.bar)).toBe(true)
  48. expect(foo.bar.value).toBe(123)
  49. })
  50. // vuejs/vue#12688
  51. test('should not mutate refs', () => {
  52. const original = ref(123)
  53. const foo = shallowReactive<{ bar: Ref<number> | number }>({
  54. bar: original,
  55. })
  56. expect(foo.bar).toBe(original)
  57. foo.bar = 234
  58. expect(foo.bar).toBe(234)
  59. expect(original.value).toBe(123)
  60. })
  61. test('should respect shallow/deep versions of same target on access', () => {
  62. const original = {}
  63. const shallow = shallowReactive(original)
  64. const deep = reactive(original)
  65. const r = reactive({ shallow, deep })
  66. expect(r.shallow).toBe(shallow)
  67. expect(r.deep).toBe(deep)
  68. })
  69. describe('collections', () => {
  70. test('should be reactive', () => {
  71. const shallowSet = shallowReactive(new Set())
  72. const a = {}
  73. let size
  74. effect(() => {
  75. size = shallowSet.size
  76. })
  77. expect(size).toBe(0)
  78. shallowSet.add(a)
  79. expect(size).toBe(1)
  80. shallowSet.delete(a)
  81. expect(size).toBe(0)
  82. })
  83. test('should not observe when iterating', () => {
  84. const shallowSet = shallowReactive(new Set())
  85. const a = {}
  86. shallowSet.add(a)
  87. const spreadA = [...shallowSet][0]
  88. expect(isReactive(spreadA)).toBe(false)
  89. })
  90. test('should not get reactive entry', () => {
  91. const shallowMap = shallowReactive(new Map())
  92. const a = {}
  93. const key = 'a'
  94. shallowMap.set(key, a)
  95. expect(isReactive(shallowMap.get(key))).toBe(false)
  96. })
  97. test('should not get reactive on foreach', () => {
  98. const shallowSet = shallowReactive(new Set())
  99. const a = {}
  100. shallowSet.add(a)
  101. shallowSet.forEach(x => expect(isReactive(x)).toBe(false))
  102. })
  103. test('Setting a reactive object on a shallowReactive map', () => {
  104. const msg = ref('ads')
  105. const bar = reactive({ msg })
  106. const foo = shallowReactive(new Map([['foo1', bar]]))
  107. foo.set('foo2', bar)
  108. expect(isReactive(foo.get('foo2'))).toBe(true)
  109. expect(isReactive(foo.get('foo1'))).toBe(true)
  110. })
  111. test('Setting a reactive object on a shallowReactive set', () => {
  112. const msg = ref(1)
  113. const bar = reactive({ msg })
  114. const foo = reactive({ msg })
  115. const deps = shallowReactive(new Set([bar]))
  116. deps.add(foo)
  117. deps.forEach(dep => {
  118. expect(isReactive(dep)).toBe(true)
  119. })
  120. })
  121. // #1210
  122. test('onTrack on called on objectSpread', () => {
  123. const onTrackFn = vi.fn()
  124. const shallowSet = shallowReactive(new Set())
  125. let a
  126. effect(
  127. () => {
  128. a = Array.from(shallowSet)
  129. },
  130. {
  131. onTrack: onTrackFn,
  132. },
  133. )
  134. expect(a).toMatchObject([])
  135. expect(onTrackFn).toHaveBeenCalled()
  136. })
  137. })
  138. describe('array', () => {
  139. test('should be reactive', () => {
  140. const shallowArray = shallowReactive<unknown[]>([])
  141. const a = {}
  142. let size
  143. effect(() => {
  144. size = shallowArray.length
  145. })
  146. expect(size).toBe(0)
  147. shallowArray.push(a)
  148. expect(size).toBe(1)
  149. shallowArray.pop()
  150. expect(size).toBe(0)
  151. })
  152. test('should not observe when iterating', () => {
  153. const shallowArray = shallowReactive<object[]>([])
  154. const a = {}
  155. shallowArray.push(a)
  156. const spreadA = [...shallowArray][0]
  157. expect(isReactive(spreadA)).toBe(false)
  158. })
  159. test('onTrack on called on objectSpread', () => {
  160. const onTrackFn = vi.fn()
  161. const shallowArray = shallowReactive([])
  162. let a
  163. effect(
  164. () => {
  165. a = Array.from(shallowArray)
  166. },
  167. {
  168. onTrack: onTrackFn,
  169. },
  170. )
  171. expect(a).toMatchObject([])
  172. expect(onTrackFn).toHaveBeenCalled()
  173. })
  174. })
  175. })