import test from "blue-tape" ; import { testStrictness , waitForLength , Obs } from "./util" ; import { delay } from "./delay" ; import { observable , runInAction , autorun } from "mobx" ; import { throttledComputed } from "../src/index" ; function getInsideReaction < T > ( getter ) { let result = undefined ! ; const stop = autorun ( ( ) => { result = getter ( ) ; } ) ; stop ( ) ; return result ; } testStrictness ( "throttledComputed - synchronous at first" , async ( assert ) => { const o = observable ( { x : 1 , y : 2 } ) ; const r = throttledComputed ( ( ) => o . x + o . y , 50 ) ; assert . equal ( getInsideReaction ( ( ) => r . get ( ) ) , 3 , "Initial computation is synchronous" ) ; runInAction ( ( ) => o . x = 5 ) ; assert . equal ( getInsideReaction ( ( ) => r . get ( ) ) , 7 , "Subsequent computations outside reactive contexts are also synchronous" ) ; runInAction ( ( ) => o . x = 6 ) ; assert . equal ( getInsideReaction ( ( ) => r . get ( ) ) , 8 , "Ditto" ) ; const results = [ ] ; const stop = autorun ( ( ) => results . push ( r . get ( ) ) ) ; assert . deepEqual ( results , [ 8 ] ) ; runInAction ( ( ) => o . x = 3 ) ; assert . deepEqual ( results , [ 8 ] , "Reactive contexts don't see immediate changes" ) ; await waitForLength ( results , 2 ) ; assert . deepEqual ( results , [ 8 , 5 ] , "But do see delayed changes" ) ; runInAction ( ( ) => o . x = 10 ) ; runInAction ( ( ) => o . x = 20 ) ; await waitForLength ( results , 3 ) ; assert . deepEqual ( results , [ 8 , 5 , 22 ] , "Changes are batched by throttling" ) ; stop ( ) ; } ) ; testStrictness ( "throttledComputed - propagates exceptions" , async ( assert ) => { const o = new Obs ( false ) ; const r = throttledComputed ( ( ) => { if ( o . get ( ) ) { throw new Error ( "Badness" ) ; } return 1 ; } , 50 ) ; assert . equal ( getInsideReaction ( ( ) => r . get ( ) ) , 1 , "Initial computation is synchronous" ) ; const results = [ ] ; const stop = autorun ( ( ) => { try { results . push ( r . get ( ) ) ; } catch ( x ) { results . push ( x . message ) ; } } ) ; assert . deepEqual ( results , [ 1 ] ) ; runInAction ( ( ) => o . set ( true ) ) ; assert . deepEqual ( results , [ 1 ] , "Reactive contexts don't see immediate changes" ) ; await waitForLength ( results , 2 ) ; assert . deepEqual ( results , [ 1 , "Badness" ] , "But do see delayed changes" ) ; runInAction ( ( ) => o . set ( false ) ) ; runInAction ( ( ) => o . set ( true ) ) ; runInAction ( ( ) => o . set ( false ) ) ; await waitForLength ( results , 3 ) ; assert . deepEqual ( results , [ 1 , "Badness" , 1 ] , "Changes are batched by throttling" ) ; runInAction ( ( ) => o . set ( true ) ) ; await delay ( 1 ) ; runInAction ( ( ) => o . set ( false ) ) ; runInAction ( ( ) => o . set ( true ) ) ; await waitForLength ( results , 4 ) ; assert . deepEqual ( results , [ 1 , "Badness" , 1 , "Badness" ] , "Changes are batched again" ) ; stop ( ) ; } ) ; testStrictness ( "throttledComputed - can be refreshed" , async ( assert ) => { let counter = 0 ; const r = throttledComputed ( ( ) => ++ counter , 10 ) ; const trace = [ ] ; const stop = autorun ( ( ) => trace . push ( r . get ( ) ) ) ; assert . deepEqual ( trace , [ 1 ] , "Initial value appears synchronously" ) ; r . refresh ( ) ; assert . deepEqual ( trace , [ 1 , 2 ] , "Second value appears synchronously" ) ; stop ( ) ; } ) ;