deferredComputed.spec.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import { computed, effect, ref } from '../src'
  2. describe('deferred computed', () => {
  3. test('should not trigger if value did not change', () => {
  4. const src = ref(0)
  5. const c = computed(() => src.value % 2)
  6. const spy = vi.fn()
  7. effect(() => {
  8. spy(c.value)
  9. })
  10. expect(spy).toHaveBeenCalledTimes(1)
  11. src.value = 2
  12. // should not trigger
  13. expect(spy).toHaveBeenCalledTimes(1)
  14. src.value = 3
  15. src.value = 5
  16. // should trigger because latest value changes
  17. expect(spy).toHaveBeenCalledTimes(2)
  18. })
  19. test('chained computed trigger', () => {
  20. const effectSpy = vi.fn()
  21. const c1Spy = vi.fn()
  22. const c2Spy = vi.fn()
  23. const src = ref(0)
  24. const c1 = computed(() => {
  25. c1Spy()
  26. return src.value % 2
  27. })
  28. const c2 = computed(() => {
  29. c2Spy()
  30. return c1.value + 1
  31. })
  32. effect(() => {
  33. effectSpy(c2.value)
  34. })
  35. expect(c1Spy).toHaveBeenCalledTimes(1)
  36. expect(c2Spy).toHaveBeenCalledTimes(1)
  37. expect(effectSpy).toHaveBeenCalledTimes(1)
  38. src.value = 1
  39. expect(c1Spy).toHaveBeenCalledTimes(2)
  40. expect(c2Spy).toHaveBeenCalledTimes(2)
  41. expect(effectSpy).toHaveBeenCalledTimes(2)
  42. })
  43. test('chained computed avoid re-compute', () => {
  44. const effectSpy = vi.fn()
  45. const c1Spy = vi.fn()
  46. const c2Spy = vi.fn()
  47. const src = ref(0)
  48. const c1 = computed(() => {
  49. c1Spy()
  50. return src.value % 2
  51. })
  52. const c2 = computed(() => {
  53. c2Spy()
  54. return c1.value + 1
  55. })
  56. effect(() => {
  57. effectSpy(c2.value)
  58. })
  59. expect(effectSpy).toHaveBeenCalledTimes(1)
  60. src.value = 2
  61. src.value = 4
  62. src.value = 6
  63. expect(c1Spy).toHaveBeenCalledTimes(4)
  64. // c2 should not have to re-compute because c1 did not change.
  65. expect(c2Spy).toHaveBeenCalledTimes(1)
  66. // effect should not trigger because c2 did not change.
  67. expect(effectSpy).toHaveBeenCalledTimes(1)
  68. })
  69. test('chained computed value invalidation', () => {
  70. const effectSpy = vi.fn()
  71. const c1Spy = vi.fn()
  72. const c2Spy = vi.fn()
  73. const src = ref(0)
  74. const c1 = computed(() => {
  75. c1Spy()
  76. return src.value % 2
  77. })
  78. const c2 = computed(() => {
  79. c2Spy()
  80. return c1.value + 1
  81. })
  82. effect(() => {
  83. effectSpy(c2.value)
  84. })
  85. expect(effectSpy).toHaveBeenCalledTimes(1)
  86. expect(effectSpy).toHaveBeenCalledWith(1)
  87. expect(c2.value).toBe(1)
  88. expect(c1Spy).toHaveBeenCalledTimes(1)
  89. expect(c2Spy).toHaveBeenCalledTimes(1)
  90. src.value = 1
  91. // value should be available sync
  92. expect(c2.value).toBe(2)
  93. expect(c2Spy).toHaveBeenCalledTimes(2)
  94. })
  95. test('sync access of invalidated chained computed should not prevent final effect from running', () => {
  96. const effectSpy = vi.fn()
  97. const c1Spy = vi.fn()
  98. const c2Spy = vi.fn()
  99. const src = ref(0)
  100. const c1 = computed(() => {
  101. c1Spy()
  102. return src.value % 2
  103. })
  104. const c2 = computed(() => {
  105. c2Spy()
  106. return c1.value + 1
  107. })
  108. effect(() => {
  109. effectSpy(c2.value)
  110. })
  111. expect(effectSpy).toHaveBeenCalledTimes(1)
  112. src.value = 1
  113. // sync access c2
  114. c2.value
  115. expect(effectSpy).toHaveBeenCalledTimes(2)
  116. })
  117. test('should not compute if deactivated before scheduler is called', () => {
  118. const c1Spy = vi.fn()
  119. const src = ref(0)
  120. const c1 = computed(() => {
  121. c1Spy()
  122. return src.value % 2
  123. })
  124. effect(() => c1.value)
  125. expect(c1Spy).toHaveBeenCalledTimes(1)
  126. c1.effect.stop()
  127. // trigger
  128. src.value++
  129. expect(c1Spy).toHaveBeenCalledTimes(1)
  130. })
  131. })