import { range , Viewport } from "adapter/viewport" ; import { chance } from "_/helpers" ; import { mockViewportConfiguration , mockViewportContext } from "_/mocks/adapter/viewport" ; import { mockQuerySelector } from "_/mocks/vendor/document" ; describe ( "Viewport" , ( ) => { const config = mockViewportConfiguration ( ) ; let context ; beforeAll ( ( ) => { fixture . setBase ( "fixtures" ) ; } ) ; beforeEach ( ( ) => { context = mockViewportContext ( ) ; document . body . appendChild ( context ) ; context . contentDocument ! . write ( "<body></body>" ) ; } ) ; afterEach ( ( ) => { document . body . removeChild ( context ) ; } ) ; describe ( "range" , ( ) => { it ( "should return first breakpoint" , ( ) => { const breakpoints = range ( config . breakpoints , "mobile" ) ; expect ( breakpoints ) . toEqual ( jasmine . any ( Array ) ) ; expect ( breakpoints . length ) . toEqual ( 1 ) ; expect ( breakpoints [ 0 ] ) . toEqual ( config . breakpoints [ 0 ] ) ; } ) ; it ( "should return middle breakpoint" , ( ) => { const breakpoints = range ( config . breakpoints , "tablet" ) ; expect ( breakpoints ) . toEqual ( jasmine . any ( Array ) ) ; expect ( breakpoints . length ) . toEqual ( 1 ) ; expect ( breakpoints [ 0 ] ) . toEqual ( config . breakpoints [ 1 ] ) ; } ) ; it ( "should return last breakpoint" , ( ) => { const breakpoints = range ( config . breakpoints , "screen" ) ; expect ( breakpoints ) . toEqual ( jasmine . any ( Array ) ) ; expect ( breakpoints . length ) . toEqual ( 1 ) ; expect ( breakpoints [ 0 ] ) . toEqual ( config . breakpoints [ 2 ] ) ; } ) ; it ( "should return first to first breakpoint" , ( ) => { const breakpoints = range ( config . breakpoints , "mobile" , "mobile" ) ; expect ( breakpoints ) . toEqual ( jasmine . any ( Array ) ) ; expect ( breakpoints . length ) . toEqual ( 1 ) ; expect ( breakpoints [ 0 ] ) . toEqual ( config . breakpoints [ 0 ] ) ; } ) ; it ( "should return first to last breakpoint" , ( ) => { const breakpoints = range ( config . breakpoints , "mobile" , "screen" ) ; expect ( breakpoints ) . toEqual ( jasmine . any ( Array ) ) ; expect ( breakpoints . length ) . toEqual ( 3 ) ; expect ( breakpoints ) . toEqual ( config . breakpoints ) ; } ) ; it ( "should return last to last breakpoint" , ( ) => { const breakpoints = range ( config . breakpoints , "screen" , "screen" ) ; expect ( breakpoints ) . toEqual ( jasmine . any ( Array ) ) ; expect ( breakpoints . length ) . toEqual ( 1 ) ; expect ( breakpoints [ 0 ] ) . toEqual ( config . breakpoints [ 2 ] ) ; } ) ; it ( "should throw on invalid breakpoint" , ( ) => { expect ( ( ) => { range ( [ ] , "invalid" ) ; } ) . toThrow ( new ReferenceError ( "Invalid breakpoint: 'invalid'" ) ) ; } ) ; } ) ; describe ( "#constructor" , ( ) => { it ( "should set configuration" , ( ) => { const viewport = new Viewport ( config , window ) ; expect ( viewport . config ) . toBe ( config ) ; } ) ; it ( "should resolve context" , ( ) => { const querySelector = mockQuerySelector ( context ) ; const viewport = new Viewport ( config , window ) ; expect ( viewport . context ) . toBe ( context ) ; expect ( querySelector ) . toHaveBeenCalledWith ( config . context ) ; } ) ; it ( "should throw on missing context" , ( ) => { mockQuerySelector ( null ) ; expect ( ( ) => { new Viewport ( config , window ) ; } ) . toThrow ( new TypeError ( `No match for selector: '${ config . context }'` ) ) ; } ) ; } ) ; describe ( "#load" , ( ) => { it ( "should set context source" , done => { const viewport = new Viewport ( config , window ) ; viewport . load ( "/debug.html" , ( ) => { expect ( context . src ) . toContain ( "/debug.html" ) ; done ( ) ; } ) ; } ) ; it ( "should set context source and return promise" , done => { const viewport = new Viewport ( config , window ) ; viewport . load ( "/debug.html" ) . then ( ( ) => { expect ( context . src ) . toContain ( "/debug.html" ) ; done ( ) ; } ) ; } ) ; } ) ; describe ( "#offset" , ( ) => { it ( "should set horizontal offset" , ( ) => { const viewport = new Viewport ( config , window ) ; const x = chance . integer ( { min : 10 , max : 100 } ) ; context . contentDocument ! . body . style . width = `${ context . contentWindow ! . innerWidth + x }px` ; context . contentDocument ! . body . style . height = `${ context . contentWindow ! . innerHeight }px` ; viewport . offset ( x ) ; expect ( viewport . context . contentWindow ! . pageXOffset ) . toEqual ( x ) ; } ) ; it ( "should set horizontal and vertical offset" , ( ) => { const viewport = new Viewport ( config , window ) ; const x = chance . integer ( { min : 10 , max : 100 } ) ; const y = chance . integer ( { min : 10 , max : 100 } ) ; context . contentDocument ! . body . style . width = `${ context . contentWindow ! . innerWidth + x }px` ; context . contentDocument ! . body . style . height = `${ context . contentWindow ! . innerHeight + y }px` ; viewport . offset ( x , y ) ; expect ( viewport . context . contentWindow ! . pageXOffset ) . toEqual ( x ) ; expect ( viewport . context . contentWindow ! . pageYOffset ) . toEqual ( y ) ; } ) ; } ) ; describe ( "#set" , ( ) => { it ( "should set width" , ( ) => { const viewport = new Viewport ( config , window ) ; const width = chance . integer ( { min : 100 , max : 400 } ) ; viewport . set ( width ) ; expect ( context . style . width ) . toEqual ( `${ width }px` ) ; expect ( context . style . height ) . toEqual ( "" ) ; } ) ; it ( "should set width and height" , ( ) => { const viewport = new Viewport ( config , window ) ; const width = chance . integer ( { min : 100 , max : 400 } ) ; const height = chance . integer ( { min : 100 , max : 400 } ) ; viewport . set ( width , height ) ; expect ( context . style . width ) . toEqual ( `${ width }px` ) ; expect ( context . style . height ) . toEqual ( `${ height }px` ) ; } ) ; it ( "should set width and height of breakpoint" , ( ) => { const viewport = new Viewport ( config , window ) ; viewport . set ( "tablet" ) ; expect ( context . style . width ) . toEqual ( `${ config . breakpoints [ 1 ] . size . width }px` ) ; expect ( context . style . height ) . toEqual ( `${ config . breakpoints [ 1 ] . size . height }px` ) ; } ) ; it ( "should force layout" , ( ) => { spyOn ( context . contentDocument ! . body , "getBoundingClientRect" ) ; const viewport = new Viewport ( config , window ) ; const width = chance . integer ( { min : 100 , max : 400 } ) ; viewport . set ( width ) ; expect ( context . contentDocument ! . body . getBoundingClientRect ) . toHaveBeenCalled ( ) ; } ) ; it ( "should throw on invalid breakpoint" , ( ) => { const viewport = new Viewport ( config , window ) ; expect ( ( ) => { viewport . set ( "invalid" ) ; } ) . toThrow ( new ReferenceError ( "Invalid breakpoint: 'invalid'" ) ) ; } ) ; it ( "should throw on invalid width" , ( ) => { const viewport = new Viewport ( config , window ) ; const width = chance . integer ( { min : - 400 , max : - 100 } ) ; expect ( ( ) => { viewport . set ( width ) ; } ) . toThrow ( new TypeError ( `Invalid breakpoint width: ${ width }` ) ) ; } ) ; it ( "should throw on invalid width and height" , ( ) => { const viewport = new Viewport ( config , window ) ; const width = chance . integer ( { min : - 400 , max : - 100 } ) ; const height = chance . integer ( { min : - 400 , max : - 100 } ) ; expect ( ( ) => { viewport . set ( width , height ) ; } ) . toThrow ( new TypeError ( `Invalid breakpoint width: ${ width }` ) ) ; } ) ; it ( "should throw on invalid height" , ( ) => { const viewport = new Viewport ( config , window ) ; const width = chance . integer ( { min : 100 , max : 400 } ) ; const height = chance . integer ( { min : - 400 , max : - 100 } ) ; expect ( ( ) => { viewport . set ( width , height ) ; } ) . toThrow ( new TypeError ( `Invalid breakpoint height: ${ height }` ) ) ; } ) ; } ) ; describe ( "#reset" , ( ) => { it ( "should reset offset" , ( ) => { const viewport = new Viewport ( config , window ) ; const x = chance . integer ( { min : 10 , max : 100 } ) ; const y = chance . integer ( { min : 10 , max : 100 } ) ; context . contentDocument ! . body . style . width = `${ context . contentWindow ! . innerWidth + x }` ; context . contentDocument ! . body . style . height = `${ context . contentWindow ! . innerHeight + y }` ; viewport . offset ( x , y ) ; viewport . reset ( ) ; expect ( viewport . context . contentWindow ! . pageXOffset ) . toEqual ( 0 ) ; expect ( viewport . context . contentWindow ! . pageYOffset ) . toEqual ( 0 ) ; } ) ; it ( "should reset width and height" , ( ) => { const viewport = new Viewport ( config , window ) ; const width = chance . integer ( { min : 100 , max : 400 } ) ; const height = chance . integer ( { min : 100 , max : 400 } ) ; viewport . set ( width , height ) ; viewport . reset ( ) ; expect ( context . style . width ) . toEqual ( "" ) ; expect ( context . style . height ) . toEqual ( "" ) ; } ) ; it ( "should force layout" , ( ) => { spyOn ( context . contentDocument ! . body , "getBoundingClientRect" ) ; const viewport = new Viewport ( config , window ) ; viewport . reset ( ) ; expect ( context . contentDocument ! . body . getBoundingClientRect ) . toHaveBeenCalled ( ) ; } ) ; } ) ; describe ( "#between" , ( ) => { it ( "should invoke callback on breakpoints" , ( ) => { const cb = jasmine . createSpy ( "callback" ) ; const viewport = new Viewport ( config , window ) ; viewport . between ( "mobile" , "tablet" , cb ) ; expect ( cb ) . toHaveBeenCalledWith ( "mobile" ) ; expect ( cb ) . toHaveBeenCalledWith ( "tablet" ) ; expect ( cb ) . not . toHaveBeenCalledWith ( "screen" ) ; } ) ; it ( "should invoke callback returning promise on breakpoints" , async ( ) => { const cb = jasmine . createSpy ( "callback" ) . and . returnValue ( Promise . resolve ( ) ) ; const viewport = new Viewport ( config , window ) ; await viewport . between ( "tablet" , "screen" , cb ) ; expect ( cb ) . not . toHaveBeenCalledWith ( "mobile" ) ; expect ( cb ) . toHaveBeenCalledWith ( "tablet" ) ; expect ( cb ) . toHaveBeenCalledWith ( "screen" ) ; } ) ; } ) ; describe ( "#each" , ( ) => { beforeEach ( ( ) => { fixture . load ( "default.html" ) ; } ) ; it ( "should invoke callback on breakpoints" , ( ) => { const cb = jasmine . createSpy ( "callback" ) ; const viewport = new Viewport ( config , window ) ; viewport . each ( cb ) ; expect ( cb ) . toHaveBeenCalledWith ( "mobile" ) ; expect ( cb ) . toHaveBeenCalledWith ( "tablet" ) ; expect ( cb ) . toHaveBeenCalledWith ( "screen" ) ; } ) ; it ( "should set width and height of breakpoint" , ( ) => { const cb = jasmine . createSpy ( "callback" ) . and . callFake ( ( name ) => { const style = window . getComputedStyle ( document . body ) ; switch ( name ) { case "mobile" : expect ( style . fontSize ) . toEqual ( "16px" ) ; break ; case "tablet" : expect ( style . fontSize ) . toEqual ( "14px" ) ; break ; case "screen" : expect ( style . fontSize ) . toEqual ( "12px" ) ; break ; } } ) ; const viewport = new Viewport ( { ... config , context : "#context" } , window ) ; viewport . each ( cb ) ; expect ( cb . calls . count ( ) ) . toEqual ( 3 ) ; } ) ; } ) ; describe ( "#from" , ( ) => { it ( "should invoke callback on breakpoints" , ( ) => { const cb = jasmine . createSpy ( "callback" ) ; const viewport = new Viewport ( config , window ) ; viewport . from ( "tablet" , cb ) ; expect ( cb ) . not . toHaveBeenCalledWith ( "mobile" ) ; expect ( cb ) . toHaveBeenCalledWith ( "tablet" ) ; expect ( cb ) . toHaveBeenCalledWith ( "screen" ) ; } ) ; } ) ; describe ( "#to" , ( ) => { it ( "should invoke callback on breakpoints" , ( ) => { const cb = jasmine . createSpy ( "callback" ) ; const viewport = new Viewport ( config , window ) ; viewport . to ( "tablet" , cb ) ; expect ( cb ) . toHaveBeenCalledWith ( "mobile" ) ; expect ( cb ) . toHaveBeenCalledWith ( "tablet" ) ; expect ( cb ) . not . toHaveBeenCalledWith ( "screen" ) ; } ) ; } ) ; } ) ;