import { assert } from "chai" ; import { init , h , thunk , VNode } from "../../src/index" ; const patch = init ( [ ] ) ; describe ( "thunk" , function ( ) { let elm , vnode0 ; beforeEach ( function ( ) { elm = vnode0 = document . createElement ( "div" ) ; } ) ; it ( "returns vnode with data and render function" , function ( ) { function numberInSpan ( n ) { return h ( "span" , `Number is ${ n }` ) ; } const vnode = thunk ( "span" , "num" , numberInSpan , [ 22 ] ) ; assert . deepEqual ( vnode . sel , "span" ) ; assert . deepEqual ( vnode . data . key , "num" ) ; assert . deepEqual ( vnode . data . args , [ 22 ] ) ; } ) ; it ( "calls render function once on data change" , function ( ) { let called = 0 ; function numberInSpan ( n ) { called ++ ; return h ( "span" , { key : "num" } , `Number is ${ n }` ) ; } const vnode1 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ] ) ; const vnode2 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 2 ] ) ] ) ; patch ( vnode0 , vnode1 ) ; assert . strictEqual ( called , 1 ) ; patch ( vnode1 , vnode2 ) ; assert . strictEqual ( called , 2 ) ; } ) ; it ( "does not call render function on data unchanged" , function ( ) { let called = 0 ; function numberInSpan ( n ) { called ++ ; return h ( "span" , { key : "num" } , `Number is ${ n }` ) ; } const vnode1 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ] ) ; const vnode2 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ] ) ; patch ( vnode0 , vnode1 ) ; assert . strictEqual ( called , 1 ) ; patch ( vnode1 , vnode2 ) ; assert . strictEqual ( called , 1 ) ; } ) ; it ( "calls render function once on data-length change" , function ( ) { let called = 0 ; function numberInSpan ( n ) { called ++ ; return h ( "span" , { key : "num" } , `Number is ${ n }` ) ; } const vnode1 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ] ) ; const vnode2 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 1 , 2 ] ) ] ) ; patch ( vnode0 , vnode1 ) ; assert . strictEqual ( called , 1 ) ; patch ( vnode1 , vnode2 ) ; assert . strictEqual ( called , 2 ) ; } ) ; it ( "calls render function once on function change" , function ( ) { let called = 0 ; function numberInSpan ( n ) { called ++ ; return h ( "span" , { key : "num" } , `Number is ${ n }` ) ; } function numberInSpan2 ( n ) { called ++ ; return h ( "span" , { key : "num" } , `Number really is ${ n }` ) ; } const vnode1 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ] ) ; const vnode2 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan2 , [ 1 ] ) ] ) ; patch ( vnode0 , vnode1 ) ; assert . strictEqual ( called , 1 ) ; patch ( vnode1 , vnode2 ) ; assert . strictEqual ( called , 2 ) ; } ) ; it ( "renders correctly" , function ( ) { let called = 0 ; function numberInSpan ( n ) { called ++ ; return h ( "span" , { key : "num" } , `Number is ${ n }` ) ; } const vnode1 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ] ) ; const vnode2 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ] ) ; const vnode3 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 2 ] ) ] ) ; elm = patch ( vnode0 , vnode1 ) . elm ; assert . strictEqual ( elm . firstChild . tagName . toLowerCase ( ) , "span" ) ; assert . strictEqual ( elm . firstChild . innerHTML , "Number is 1" ) ; elm = patch ( vnode1 , vnode2 ) . elm ; assert . strictEqual ( elm . firstChild . tagName . toLowerCase ( ) , "span" ) ; assert . strictEqual ( elm . firstChild . innerHTML , "Number is 1" ) ; elm = patch ( vnode2 , vnode3 ) . elm ; assert . strictEqual ( elm . firstChild . tagName . toLowerCase ( ) , "span" ) ; assert . strictEqual ( elm . firstChild . innerHTML , "Number is 2" ) ; assert . strictEqual ( called , 2 ) ; } ) ; it ( "supports leaving out the `key` argument" , function ( ) { function vnodeFn ( s ) { return h ( "span.number" , "Hello " + s ) ; } const vnode1 = thunk ( "span.number" , vnodeFn , [ "World!" ] ) ; elm = patch ( vnode0 , vnode1 ) . elm ; assert . strictEqual ( elm . innerText , "Hello World!" ) ; } ) ; it ( "renders correctly when root" , function ( ) { let called = 0 ; function numberInSpan ( n ) { called ++ ; return h ( "span" , { key : "num" } , `Number is ${ n }` ) ; } const vnode1 = thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ; const vnode2 = thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ; const vnode3 = thunk ( "span" , "num" , numberInSpan , [ 2 ] ) ; elm = patch ( vnode0 , vnode1 ) . elm ; assert . strictEqual ( elm . tagName . toLowerCase ( ) , "span" ) ; assert . strictEqual ( elm . innerHTML , "Number is 1" ) ; elm = patch ( vnode1 , vnode2 ) . elm ; assert . strictEqual ( elm . tagName . toLowerCase ( ) , "span" ) ; assert . strictEqual ( elm . innerHTML , "Number is 1" ) ; elm = patch ( vnode2 , vnode3 ) . elm ; assert . strictEqual ( elm . tagName . toLowerCase ( ) , "span" ) ; assert . strictEqual ( elm . innerHTML , "Number is 2" ) ; assert . strictEqual ( called , 2 ) ; } ) ; it ( "can be replaced and removed" , function ( ) { function numberInSpan ( n ) { return h ( "span" , { key : "num" } , `Number is ${ n }` ) ; } function oddEven ( n ) { const prefix = n % 2 === 0 ? "Even" : "Odd" ; return h ( "div" , { key : oddEven as any } , `${ prefix }: ${ n }` ) ; } const vnode1 = h ( "div" , [ thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ] ) ; const vnode2 = h ( "div" , [ thunk ( "div" , "oddEven" , oddEven , [ 4 ] ) ] ) ; elm = patch ( vnode0 , vnode1 ) . elm ; assert . strictEqual ( elm . firstChild . tagName . toLowerCase ( ) , "span" ) ; assert . strictEqual ( elm . firstChild . innerHTML , "Number is 1" ) ; elm = patch ( vnode1 , vnode2 ) . elm ; assert . strictEqual ( elm . firstChild . tagName . toLowerCase ( ) , "div" ) ; assert . strictEqual ( elm . firstChild . innerHTML , "Even: 4" ) ; } ) ; it ( "can be replaced and removed when root" , function ( ) { function numberInSpan ( n ) { return h ( "span" , { key : "num" } , `Number is ${ n }` ) ; } function oddEven ( n ) { const prefix = n % 2 === 0 ? "Even" : "Odd" ; return h ( "div" , { key : oddEven as any } , `${ prefix }: ${ n }` ) ; } const vnode1 = thunk ( "span" , "num" , numberInSpan , [ 1 ] ) ; const vnode2 = thunk ( "div" , "oddEven" , oddEven , [ 4 ] ) ; elm = patch ( vnode0 , vnode1 ) . elm ; assert . strictEqual ( elm . tagName . toLowerCase ( ) , "span" ) ; assert . strictEqual ( elm . innerHTML , "Number is 1" ) ; elm = patch ( vnode1 , vnode2 ) . elm ; assert . strictEqual ( elm . tagName . toLowerCase ( ) , "div" ) ; assert . strictEqual ( elm . innerHTML , "Even: 4" ) ; } ) ; it ( "invokes destroy hook on thunks" , function ( ) { let called = 0 ; function destroyHook ( ) { called ++ ; } function numberInSpan ( n ) { return h ( "span" , { key : "num" , hook : { destroy : destroyHook } } , `Number is ${ n }` ) ; } const vnode1 = h ( "div" , [ h ( "div" , "Foo" ) , thunk ( "span" , "num" , numberInSpan , [ 1 ] ) , h ( "div" , "Foo" ) , ] ) ; const vnode2 = h ( "div" , [ h ( "div" , "Foo" ) , h ( "div" , "Foo" ) ] ) ; patch ( vnode0 , vnode1 ) ; patch ( vnode1 , vnode2 ) ; assert . strictEqual ( called , 1 ) ; } ) ; it ( "invokes remove hook on thunks" , function ( ) { let called = 0 ; function hook ( ) { called ++ ; } function numberInSpan ( n ) { return h ( "span" , { key : "num" , hook : { remove : hook } } , `Number is ${ n }` ) ; } const vnode1 = h ( "div" , [ h ( "div" , "Foo" ) , thunk ( "span" , "num" , numberInSpan , [ 1 ] ) , h ( "div" , "Foo" ) , ] ) ; const vnode2 = h ( "div" , [ h ( "div" , "Foo" ) , h ( "div" , "Foo" ) ] ) ; patch ( vnode0 , vnode1 ) ; patch ( vnode1 , vnode2 ) ; assert . strictEqual ( called , 1 ) ; } ) ; } ) ;