Skip to content

Commit c292ac2

Browse files
committed
feat(reactivity): add tests for dev mode computed optimization
Add test cases to verify dev mode optimization prevents unnecessary computed recomputations when dependencies remain unchanged, while ensuring correct behavior for actual dependency changes and nested computed properties.
1 parent 675707a commit c292ac2

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed

packages/reactivity/__tests__/computed.spec.ts

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,4 +1150,168 @@ describe('reactivity/computed', () => {
11501150
const t2 = performance.now()
11511151
expect(t2 - t1).toBeLessThan(process.env.CI ? 100 : 30)
11521152
})
1153+
1154+
describe('dev mode optimization', () => {
1155+
// Mock __DEV__ for testing
1156+
const originalDev = (globalThis as any).__DEV__
1157+
beforeEach(() => {
1158+
;(globalThis as any).__DEV__ = true
1159+
})
1160+
afterEach(() => {
1161+
;(globalThis as any).__DEV__ = originalDev
1162+
})
1163+
1164+
test('should prevent unnecessary recomputations when dependencies have not actually changed', () => {
1165+
const getter = vi.fn()
1166+
const base = ref(1)
1167+
const comp = computed(() => {
1168+
getter()
1169+
return base.value
1170+
})
1171+
1172+
// Initial computation
1173+
expect(comp.value).toBe(1)
1174+
expect(getter).toHaveBeenCalledTimes(1)
1175+
1176+
// Trigger dependency tracking but without actual value change
1177+
// This simulates the scenario where globalVersion changes but actual dep values don't
1178+
const impl = comp as any as ComputedRefImpl
1179+
impl.globalVersion = -1 // Force a version mismatch
1180+
1181+
// Access computed again - should not recompute due to dev mode optimization
1182+
expect(comp.value).toBe(1)
1183+
expect(getter).toHaveBeenCalledTimes(1) // Should not have called getter again
1184+
1185+
// Now actually change the value
1186+
base.value = 2
1187+
expect(comp.value).toBe(2)
1188+
expect(getter).toHaveBeenCalledTimes(2) // Should recompute when value actually changes
1189+
})
1190+
1191+
test('should refresh nested computed dependencies correctly', () => {
1192+
const getterA = vi.fn()
1193+
const getterB = vi.fn()
1194+
const getterC = vi.fn()
1195+
1196+
const base = ref(1)
1197+
const compA = computed(() => {
1198+
getterA()
1199+
return base.value * 2
1200+
})
1201+
const compB = computed(() => {
1202+
getterB()
1203+
return compA.value + 1
1204+
})
1205+
const compC = computed(() => {
1206+
getterC()
1207+
return compB.value * 3
1208+
})
1209+
1210+
// Initial computation
1211+
expect(compC.value).toBe(9) // (1 * 2 + 1) * 3 = 9
1212+
expect(getterA).toHaveBeenCalledTimes(1)
1213+
expect(getterB).toHaveBeenCalledTimes(1)
1214+
expect(getterC).toHaveBeenCalledTimes(1)
1215+
1216+
// Force version mismatch to trigger dev mode optimization path
1217+
const implA = compA as any as ComputedRefImpl
1218+
const implB = compB as any as ComputedRefImpl
1219+
const implC = compC as any as ComputedRefImpl
1220+
implA.globalVersion = -1
1221+
implB.globalVersion = -1
1222+
implC.globalVersion = -1
1223+
1224+
// Access computed again - should not recompute any level
1225+
expect(compC.value).toBe(9)
1226+
expect(getterA).toHaveBeenCalledTimes(1)
1227+
expect(getterB).toHaveBeenCalledTimes(1)
1228+
expect(getterC).toHaveBeenCalledTimes(1)
1229+
1230+
// Change base value
1231+
base.value = 2
1232+
expect(compC.value).toBe(15) // (2 * 2 + 1) * 3 = 15
1233+
expect(getterA).toHaveBeenCalledTimes(2)
1234+
expect(getterB).toHaveBeenCalledTimes(2)
1235+
expect(getterC).toHaveBeenCalledTimes(2)
1236+
})
1237+
1238+
test('should recompute when at least one dependency actually changes', () => {
1239+
const getter = vi.fn()
1240+
const base1 = ref(1)
1241+
const base2 = ref(2)
1242+
const comp = computed(() => {
1243+
getter()
1244+
return base1.value + base2.value
1245+
})
1246+
1247+
// Initial computation
1248+
expect(comp.value).toBe(3)
1249+
expect(getter).toHaveBeenCalledTimes(1)
1250+
1251+
// Force version mismatch
1252+
const impl = comp as any as ComputedRefImpl
1253+
impl.globalVersion = -1
1254+
1255+
// Change one dependency
1256+
base1.value = 5
1257+
1258+
// Should recompute because at least one dependency changed
1259+
expect(comp.value).toBe(7)
1260+
expect(getter).toHaveBeenCalledTimes(2)
1261+
})
1262+
1263+
test('should handle mixed changed and unchanged dependencies', () => {
1264+
const getter = vi.fn()
1265+
const unchanged = ref(1)
1266+
const changed = ref(2)
1267+
const comp = computed(() => {
1268+
getter()
1269+
return unchanged.value + changed.value
1270+
})
1271+
1272+
// Initial computation
1273+
expect(comp.value).toBe(3)
1274+
expect(getter).toHaveBeenCalledTimes(1)
1275+
1276+
// Access unchanged ref to establish dependency tracking
1277+
unchanged.value
1278+
1279+
// Force version mismatch
1280+
const impl = comp as any as ComputedRefImpl
1281+
impl.globalVersion = -1
1282+
1283+
// Change only one dependency
1284+
changed.value = 5
1285+
1286+
// Should recompute because at least one dependency changed
1287+
expect(comp.value).toBe(6) // 1 + 5
1288+
expect(getter).toHaveBeenCalledTimes(2)
1289+
})
1290+
1291+
test('should not affect production mode behavior', () => {
1292+
// Set to production mode
1293+
;(globalThis as any).__DEV__ = false
1294+
1295+
const getter = vi.fn()
1296+
const base = ref(1)
1297+
const comp = computed(() => {
1298+
getter()
1299+
return base.value
1300+
})
1301+
1302+
// Initial computation
1303+
expect(comp.value).toBe(1)
1304+
expect(getter).toHaveBeenCalledTimes(1)
1305+
1306+
// Force version mismatch - in production this should still follow normal path
1307+
const impl = comp as any as ComputedRefImpl
1308+
impl.globalVersion = -1
1309+
1310+
// In production mode, the optimization should not apply
1311+
// The behavior should be determined by the normal computed logic
1312+
expect(comp.value).toBe(1)
1313+
// In production, without the dev optimization, the call count behavior
1314+
// depends on the normal computed implementation
1315+
})
1316+
})
11531317
})

0 commit comments

Comments
 (0)