import { computed, observable, autorun, stop } from '../src' describe('observer/computed', () => { it('should return updated value', () => { const value: any = observable({}) const cValue = computed(() => value.foo) expect(cValue()).toBe(undefined) value.foo = 1 expect(cValue()).toBe(1) }) it('should compute lazily', () => { const value: any = observable({}) const getter = jest.fn(() => value.foo) const cValue = computed(getter) // lazy expect(getter).not.toHaveBeenCalled() expect(cValue()).toBe(undefined) expect(getter).toHaveBeenCalledTimes(1) // should not compute again cValue() expect(getter).toHaveBeenCalledTimes(1) // should not compute until needed value.foo = 1 expect(getter).toHaveBeenCalledTimes(1) // now it should compute expect(cValue()).toBe(1) expect(getter).toHaveBeenCalledTimes(2) // should not compute again cValue() expect(getter).toHaveBeenCalledTimes(2) }) it('should accept context', () => { const value: any = observable({}) let callCtx, callArg const getter = function(arg: any) { callCtx = this callArg = arg return value.foo } const ctx = {} const cValue = computed(getter, ctx) cValue() expect(callCtx).toBe(ctx) expect(callArg).toBe(ctx) }) it('should trigger autorun', () => { const value: any = observable({}) const cValue = computed(() => value.foo) let dummy autorun(() => { dummy = cValue() }) expect(dummy).toBe(undefined) value.foo = 1 expect(dummy).toBe(1) }) it('should work when chained', () => { const value: any = observable({ foo: 0 }) const c1 = computed(() => value.foo) const c2 = computed(() => c1() + 1) expect(c2()).toBe(1) expect(c1()).toBe(0) value.foo++ expect(c2()).toBe(2) expect(c1()).toBe(1) }) it('should trigger autorun when chained', () => { const value: any = observable({ foo: 0 }) const getter1 = jest.fn(() => value.foo) const getter2 = jest.fn(() => { return c1() + 1 }) const c1 = computed(getter1) const c2 = computed(getter2) let dummy autorun(() => { dummy = c2() }) expect(dummy).toBe(1) expect(getter1).toHaveBeenCalledTimes(1) expect(getter2).toHaveBeenCalledTimes(1) value.foo++ expect(dummy).toBe(2) // should not result in duplicate calls expect(getter1).toHaveBeenCalledTimes(2) expect(getter2).toHaveBeenCalledTimes(2) }) it('should trigger autorun when chained (mixed invocations)', () => { const value: any = observable({ foo: 0 }) const getter1 = jest.fn(() => value.foo) const getter2 = jest.fn(() => { return c1() + 1 }) const c1 = computed(getter1) const c2 = computed(getter2) let dummy autorun(() => { dummy = c1() + c2() }) expect(dummy).toBe(1) expect(getter1).toHaveBeenCalledTimes(1) expect(getter2).toHaveBeenCalledTimes(1) value.foo++ expect(dummy).toBe(3) // should not result in duplicate calls expect(getter1).toHaveBeenCalledTimes(2) expect(getter2).toHaveBeenCalledTimes(2) }) it('should no longer update when stopped', () => { const value: any = observable({}) const cValue = computed(() => value.foo) let dummy autorun(() => { dummy = cValue() }) expect(dummy).toBe(undefined) value.foo = 1 expect(dummy).toBe(1) stop(cValue.runner) value.foo = 2 expect(dummy).toBe(1) }) })