shallowReactive.spec.ts 4.7 KB

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