import{ describe, it, expect, vi }from'vitest'import{ reactive }from'../src/reactive'import{ effect }from'../src/effect'describe('mini-vue: effect',()=>{it('should re-run effect on dependency change',()=>{const state =reactive({ num:1})let dummyeffect(()=>{dummy = state.num})expect(dummy).toBe(1)state.num++expect(dummy).toBe(2)})it('should allow scheduler',()=>{const state =reactive({ foo:1})const scheduler = vi.fn()const runner =effect(()=> state.foo,{ scheduler })// 不会立即运行 effect,而是执行 schedulerstate.foo++expect(scheduler).toHaveBeenCalled()})})
✅ computed.spec.ts
import{ describe, it, expect, vi }from'vitest'import{ reactive }from'../src/reactive'import{ computed }from'../src/computed'import{ effect }from'../src/effect'describe('mini-vue: computed',()=>{it('should compute lazily and cache',()=>{const state =reactive({ count:1})const getter = vi.fn(()=> state.count +1)const c =computed(getter)// 没访问前不会调用 getterexpect(getter).not.toHaveBeenCalled()// 第一次访问,计算并缓存expect(c.value).toBe(2)expect(getter).toHaveBeenCalledTimes(1)// 第二次访问,走缓存c.valueexpect(getter).toHaveBeenCalledTimes(1)// 修改依赖,缓存失效state.count++expect(c.value).toBe(3)expect(getter).toHaveBeenCalledTimes(2)})it('should work inside effect',()=>{const state =reactive({ count:1})const c =computed(()=> state.count)let dummyeffect(()=>{dummy = c.value})expect(dummy).toBe(1)state.count++expect(dummy).toBe(2)})})
✅ ref.spec.ts
import{ describe, it, expect }from'vitest'import{ ref }from'../src/ref'import{ effect }from'../src/effect'describe('mini-vue: ref',()=>{it('should hold a value',()=>{const r =ref(1)expect(r.value).toBe(1)})it('should be reactive',()=>{const r =ref(1)let dummyeffect(()=>{dummy = r.value})expect(dummy).toBe(1)r.value++expect(dummy).toBe(2)})it('should not trigger if value not changed',()=>{const r =ref(1)let dummy =0let calls =0effect(()=>{calls++dummy = r.value})expect(calls).toBe(1)r.value =1// 设置相同值,effect 不应重新执行expect(calls).toBe(1)})})
✅ toRefs.spec.ts
import{ describe, it, expect }from'vitest'import{ reactive }from'../src/reactive'import{ toRef }from'../src/toRef'import{ toRefs }from'../src/toRefs'import{ effect }from'../src/effect'describe('mini-vue: toRef / toRefs',()=>{it('toRef should convert property to ref',()=>{const obj =reactive({ count:1})const countRef =toRef(obj,'count')let dummyeffect(()=>{dummy = countRef.value})expect(dummy).toBe(1)obj.count++expect(dummy).toBe(2)countRef.value =3expect(obj.count).toBe(3)})it('toRefs should convert all properties to refs',()=>{const obj =reactive({ count:1, name:'vue'})const refs =toRefs(obj)expect(refs.count.value).toBe(1)expect(refs.name.value).toBe('vue')refs.count.value++expect(obj.count).toBe(2)obj.name ='mini-vue'expect(refs.name.value).toBe('mini-vue')})})