import { BoundingBox , Browser , ElementHandle , launch , Page } from 'puppeteer' ; import * as path from 'path' ; import { CollectionViewDelegate , GridLayoutParameters , Size as ImportedSize , CollectionView , GridLayout } from '../dist' ; jest . setTimeout ( 10000 ) ; let page ; let browser ; const width = 1024 ; const height = 1024 ; beforeAll ( async ( ) => { if ( process . env . CI === 'true' ) { browser = await launch ( { headless : true , slowMo : 200 , args : [ `--window-size=${ width },${ height }` , '--no-sandbox' , '--disable-setuid-sandbox' ] } ) ; } else { browser = await launch ( { headless : false , slowMo : 300 , args : [ `--window-size=${ width },${ height }` , ] } ) ; } } ) ; afterAll ( async ( ) => { await browser . close ( ) ; } ) ; const collectTraces = false ; let testIndex = 0 ; beforeEach ( async ( ) => { page = await browser . newPage ( ) ; await page . setViewport ( { width , height } ) ; page . once ( 'pageerror' , fail ) ; const envURL = 'file://' + path . resolve ( __dirname , 'env' , 'index.html' ) ; await page . goto ( envURL , { "waitUntil" : "networkidle0" } ) ; if ( collectTraces ) { await page . tracing . start ( { path : `trace-${ testIndex ++ }.json` } ) ; } } ) ; afterEach ( async ( ) => { if ( collectTraces ) { await page . tracing . stop ( ) ; } } ) ; declare const delegate ; declare const collectionView ; declare const wrapperElement ; declare const newGridLayout ; declare const Size ; async function getElements ( ) { return await page . $$ ( '#scroll div' ) ; } async function getBoundingBoxesAndContents ( elements ) { const unsorted = await Promise . all ( elements . map ( element => { return Promise . all ( [ element . boundingBox ( ) as Promise < BoundingBox > , page . evaluate ( element => element . innerText , element ) ] ) ; } ) ) ; return unsorted . sort ( ( a , b ) => { const boxA = a [ 0 ] ; const boxB = b [ 0 ] ; if ( boxA . y < boxB . y ) return - 1 ; if ( boxA . y > boxB . y ) return 1 ; if ( boxA . x < boxB . x ) return - 1 ; if ( boxA . x > boxB . x ) return 1 ; return 0 ; } ) ; } async function expectElements ( expected , size ) { const elements = await getElements ( ) ; const actualBoundingBoxesAndContents = await getBoundingBoxesAndContents ( elements ) ; const expectedBoundingBoxesAndContents = expected . map ( ( [ x , y , content ] ) : [ BoundingBox , string ] => [ { x , y , width : size [ 0 ] , height : size [ 1 ] } , content ] ) ; expect ( actualBoundingBoxesAndContents ) . toEqual ( expectedBoundingBoxesAndContents ) ; } function wait ( ms ) { return new Promise ( resolve => setTimeout ( resolve , ms ) ) ; } describe ( "Collection View with default Grid Layout" , ( ) => { test ( "add elements and scroll" , async ( ) => { await page . evaluate ( ( ) => { const items = Array . from ( Array ( 100 ) . keys ( ) ) ; delegate . items = items ; const addedIndices = items . map ( ( _ , index ) => index ) ; return collectionView . changeIndices ( [ ] , addedIndices , new Map ( ) ) ; } ) ; await expectElements ( [ [ 80 , 10 , '0' ] , [ 300 , 10 , '1' ] , [ 520 , 10 , '2' ] , [ 80 , 230 , '3' ] , [ 300 , 230 , '4' ] , [ 520 , 230 , '5' ] , [ 80 , 450 , '6' ] , [ 300 , 450 , '7' ] , [ 520 , 450 , '8' ] ] , [ 200 , 200 ] ) ; await page . evaluate ( ( ) => { wrapperElement . scrollBy ( 0 , 140 ) ; } ) ; await expectElements ( [ [ 80 , - 130 , '0' ] , [ 300 , - 130 , '1' ] , [ 520 , - 130 , '2' ] , [ 80 , 90 , '3' ] , [ 300 , 90 , '4' ] , [ 520 , 90 , '5' ] , [ 80 , 310 , '6' ] , [ 300 , 310 , '7' ] , [ 520 , 310 , '8' ] , [ 80 , 530 , '9' ] , [ 300 , 530 , '10' ] , [ 520 , 530 , '11' ] ] , [ 200 , 200 ] ) ; await page . evaluate ( ( ) => { wrapperElement . scrollBy ( 0 , 200 ) ; } ) ; await expectElements ( [ [ 80 , - 110 , '3' ] , [ 300 , - 110 , '4' ] , [ 520 , - 110 , '5' ] , [ 80 , 110 , '6' ] , [ 300 , 110 , '7' ] , [ 520 , 110 , '8' ] , [ 80 , 330 , '9' ] , [ 300 , 330 , '10' ] , [ 520 , 330 , '11' ] , [ 80 , 550 , '12' ] , [ 300 , 550 , '13' ] , [ 520 , 550 , '14' ] , ] , [ 200 , 200 ] ) ; } ) ; test ( "change elements" , async ( ) => { await page . evaluate ( ( ) => { const initialElements = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; delegate . items = initialElements . slice ( ) ; const addedIndices = initialElements . map ( ( _ , index ) => index ) ; return collectionView . changeIndices ( [ ] , addedIndices , new Map ( ) ) ; } ) ; await page . evaluate ( ( ) => { delegate . items = [ 1 , 15 , 16 , 3 , 6 , 8 , 4 , 10 , 11 , 12 , 13 , 14 ] ; return collectionView . changeIndices ( [ 1 , 4 , 6 , 8 ] , [ 1 , 2 ] , new Map ( [ [ 3 , 6 ] ] ) ) ; } ) ; await expectElements ( [ [ 80 , 10 , '1' ] , [ 300 , 10 , '15' ] , [ 520 , 10 , '16' ] , [ 80 , 230 , '3' ] , [ 300 , 230 , '6' ] , [ 520 , 230 , '8' ] , [ 80 , 450 , '4' ] , [ 300 , 450 , '10' ] , [ 520 , 450 , '11' ] ] , [ 200 , 200 ] ) ; await page . evaluate ( ( ) => { delegate . items = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; return collectionView . changeIndices ( [ 1 , 2 ] , [ 1 , 4 , 6 , 8 ] , new Map ( [ [ 6 , 3 ] ] ) ) ; } ) ; await expectElements ( [ [ 80 , 10 , '1' ] , [ 300 , 10 , '2' ] , [ 520 , 10 , '3' ] , [ 80 , 230 , '4' ] , [ 300 , 230 , '5' ] , [ 520 , 230 , '6' ] , [ 80 , 450 , '7' ] , [ 300 , 450 , '8' ] , [ 520 , 450 , '9' ] ] , [ 200 , 200 ] ) ; } ) ; test ( "change elements at bottom" , async ( ) => { await page . evaluate ( ( ) => { const initialElements = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; delegate . items = initialElements . slice ( ) ; const addedIndices = initialElements . map ( ( _ , index ) => index ) ; return collectionView . changeIndices ( [ ] , addedIndices , new Map ( ) ) ; } ) ; await page . evaluate ( ( ) => { wrapperElement . scrollTo ( 0 , wrapperElement . scrollHeight ) ; } ) ; await page . evaluate ( ( ) => { delegate . items = [ 1 , 15 , 16 , 3 , 6 , 8 , 4 , 10 , 11 , 12 , 13 , 14 ] ; return collectionView . changeIndices ( [ 1 , 4 , 6 , 8 ] , [ 1 , 2 ] , new Map ( [ [ 3 , 6 ] ] ) ) ; } ) ; await expectElements ( [ [ 80 , - 70 , '3' ] , [ 300 , - 70 , '6' ] , [ 520 , - 70 , '8' ] , [ 80 , 150 , '4' ] , [ 300 , 150 , '10' ] , [ 520 , 150 , '11' ] , [ 80 , 370 , '12' ] , [ 300 , 370 , '13' ] , [ 520 , 370 , '14' ] ] , [ 200 , 200 ] ) ; await page . evaluate ( ( ) => { delegate . items = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; return collectionView . changeIndices ( [ 1 , 2 ] , [ 1 , 4 , 6 , 8 ] , new Map ( [ [ 6 , 3 ] ] ) ) ; } ) ; await expectElements ( [ [ 80 , - 70 , '4' ] , [ 300 , - 70 , '5' ] , [ 520 , - 70 , '6' ] , [ 80 , 150 , '7' ] , [ 300 , 150 , '8' ] , [ 520 , 150 , '9' ] , [ 80 , 370 , '10' ] , [ 300 , 370 , '11' ] , [ 520 , 370 , '12' ] , [ 80 , 590 , '13' ] , [ 300 , 590 , '14' ] ] , [ 200 , 200 ] ) ; } ) ; test ( "change elements, one interruption" , async ( ) => { const animationDuration = await page . evaluate ( ( ) => collectionView . animationDuration ) ; await page . evaluate ( ( ) => { const initialElements = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; delegate . items = initialElements . slice ( ) ; const addedIndices = initialElements . map ( ( _ , index ) => index ) ; return collectionView . changeIndices ( [ ] , addedIndices , new Map ( ) ) ; } ) ; const firstUpdate = page . evaluate ( ( ) => { delegate . items = [ 1 , 15 , 16 , 3 , 6 , 8 , 4 , 10 , 11 , 12 , 13 , 14 ] ; return collectionView . changeIndices ( [ 1 , 4 , 6 , 8 ] , [ 1 , 2 ] , new Map ( [ [ 3 , 6 ] ] ) ) . catch ( ( ) => Promise . resolve ( 'update failed' ) ) ; } ) ; await wait ( animationDuration * 0.5 ) ; await page . evaluate ( ( ) => { delegate . items = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; return collectionView . changeIndices ( [ 1 , 2 ] , [ 1 , 4 , 6 , 8 ] , new Map ( [ [ 6 , 3 ] ] ) ) ; } ) ; await expectElements ( [ [ 80 , 10 , '1' ] , [ 300 , 10 , '2' ] , [ 520 , 10 , '3' ] , [ 80 , 230 , '4' ] , [ 300 , 230 , '5' ] , [ 520 , 230 , '6' ] , [ 80 , 450 , '7' ] , [ 300 , 450 , '8' ] , [ 520 , 450 , '9' ] ] , [ 200 , 200 ] ) ; expect ( await firstUpdate ) . toEqual ( 'update failed' ) ; } ) ; test ( "change elements, multiple interruptions" , async ( ) => { const animationDuration = await page . evaluate ( ( ) => collectionView . animationDuration ) ; await page . evaluate ( ( ) => { const initialElements = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; delegate . items = initialElements . slice ( ) ; const addedIndices = initialElements . map ( ( _ , index ) => index ) ; return collectionView . changeIndices ( [ ] , addedIndices , new Map ( ) ) ; } ) ; const firstUpdate = page . evaluate ( ( ) => { delegate . items = [ 1 , 15 , 16 , 3 , 6 , 8 , 4 , 10 , 11 , 12 , 13 , 14 ] ; return collectionView . changeIndices ( [ 1 , 4 , 6 , 8 ] , [ 1 , 2 ] , new Map ( [ [ 3 , 6 ] ] ) ) . catch ( ( ) => Promise . resolve ( 'first update failed' ) ) ; } ) ; await wait ( animationDuration * 0.5 ) ; const secondUpdate = page . evaluate ( ( ) => { delegate . items = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; return collectionView . changeIndices ( [ 1 , 2 ] , [ 1 , 4 , 6 , 8 ] , new Map ( [ [ 6 , 3 ] ] ) ) . catch ( ( ) => Promise . resolve ( 'second update failed' ) ) ; } ) ; await wait ( animationDuration * 0.5 ) ; await page . evaluate ( ( ) => { delegate . items = [ 1 , 15 , 16 , 3 , 6 , 8 , 4 , 10 , 11 , 12 , 13 , 14 ] ; return collectionView . changeIndices ( [ 1 , 4 , 6 , 8 ] , [ 1 , 2 ] , new Map ( [ [ 3 , 6 ] ] ) ) ; } ) ; await expectElements ( [ [ 80 , 10 , '1' ] , [ 300 , 10 , '15' ] , [ 520 , 10 , '16' ] , [ 80 , 230 , '3' ] , [ 300 , 230 , '6' ] , [ 520 , 230 , '8' ] , [ 80 , 450 , '4' ] , [ 300 , 450 , '10' ] , [ 520 , 450 , '11' ] ] , [ 200 , 200 ] ) ; expect ( await firstUpdate ) . toEqual ( 'first update failed' ) ; expect ( await secondUpdate ) . toEqual ( 'second update failed' ) ; } ) ; test ( "update layout" , async ( ) => { await page . evaluate ( ( ) => { const initialElements = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; delegate . items = initialElements . slice ( ) ; const addedIndices = initialElements . map ( ( _ , index ) => index ) ; return collectionView . changeIndices ( [ ] , addedIndices , new Map ( ) ) ; } ) ; await page . evaluate ( ( ) => { return collectionView . updateLayout ( newGridLayout ( { itemSize : new Size ( 300 , 300 ) } ) ) ; } ) ; await expectElements ( [ [ 90 , 10 , '1' ] , [ 410 , 10 , '2' ] , [ 90 , 330 , '3' ] , [ 410 , 330 , '4' ] ] , [ 300 , 300 ] ) ; await page . evaluate ( ( ) => { return collectionView . updateLayout ( newGridLayout ( { itemSize : new Size ( 200 , 200 ) } ) ) ; } ) ; await expectElements ( [ [ 80 , 10 , '1' ] , [ 300 , 10 , '2' ] , [ 520 , 10 , '3' ] , [ 80 , 230 , '4' ] , [ 300 , 230 , '5' ] , [ 520 , 230 , '6' ] , [ 80 , 450 , '7' ] , [ 300 , 450 , '8' ] , [ 520 , 450 , '9' ] ] , [ 200 , 200 ] ) ; } ) ; test ( "update layout at bottom" , async ( ) => { await page . evaluate ( ( ) => { return collectionView . updateLayout ( newGridLayout ( { itemSize : new Size ( 260 , 260 ) } ) ) ; } ) ; await page . evaluate ( ( ) => { const initialElements = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; delegate . items = initialElements . slice ( ) ; const addedIndices = initialElements . map ( ( _ , index ) => index ) ; return collectionView . changeIndices ( [ ] , addedIndices , new Map ( ) ) ; } ) ; await page . evaluate ( ( ) => { wrapperElement . scrollTo ( 0 , wrapperElement . scrollHeight ) ; } ) ; await page . evaluate ( ( ) => { return collectionView . updateLayout ( newGridLayout ( { itemSize : new Size ( 180 , 180 ) } ) ) ; } ) ; await expectElements ( [ [ 10 , - 10 , '5' ] , [ 210 , - 10 , '6' ] , [ 410 , - 10 , '7' ] , [ 610 , - 10 , '8' ] , [ 10 , 190 , '9' ] , [ 210 , 190 , '10' ] , [ 410 , 190 , '11' ] , [ 610 , 190 , '12' ] , [ 10 , 390 , '13' ] , [ 210 , 390 , '14' ] ] , [ 180 , 180 ] ) ; } ) ; test ( "update layout, one interruption" , async ( ) => { const animationDuration = await page . evaluate ( ( ) => collectionView . animationDuration ) ; await page . evaluate ( ( ) => { const initialElements = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; delegate . items = initialElements . slice ( ) ; const addedIndices = initialElements . map ( ( _ , index ) => index ) ; return collectionView . changeIndices ( [ ] , addedIndices , new Map ( ) ) ; } ) ; const firstUpdate = page . evaluate ( ( ) => { return collectionView . updateLayout ( newGridLayout ( { itemSize : new Size ( 300 , 300 ) } ) ) . catch ( ( ) => Promise . resolve ( 'update failed' ) ) ; } ) ; await wait ( animationDuration * 0.5 ) ; await page . evaluate ( ( ) => { return collectionView . updateLayout ( newGridLayout ( { itemSize : new Size ( 200 , 200 ) } ) ) ; } ) ; await expectElements ( [ [ 80 , 10 , '1' ] , [ 300 , 10 , '2' ] , [ 520 , 10 , '3' ] , [ 80 , 230 , '4' ] , [ 300 , 230 , '5' ] , [ 520 , 230 , '6' ] , [ 80 , 450 , '7' ] , [ 300 , 450 , '8' ] , [ 520 , 450 , '9' ] ] , [ 200 , 200 ] ) ; expect ( await firstUpdate ) . toEqual ( 'update failed' ) ; } ) ; test ( "update layout, multiple interruptions" , async ( ) => { const animationDuration = await page . evaluate ( ( ) => collectionView . animationDuration ) ; await page . evaluate ( ( ) => { const initialElements = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ; delegate . items = initialElements . slice ( ) ; const addedIndices = initialElements . map ( ( _ , index ) => index ) ; return collectionView . changeIndices ( [ ] , addedIndices , new Map ( ) ) ; } ) ; const firstUpdate = page . evaluate ( ( ) => { return collectionView . updateLayout ( newGridLayout ( { itemSize : new Size ( 300 , 300 ) } ) ) . catch ( ( ) => Promise . resolve ( 'first update failed' ) ) ; } ) ; await wait ( animationDuration * 0.5 ) ; const secondUpdate = page . evaluate ( ( ) => { return collectionView . updateLayout ( newGridLayout ( { itemSize : new Size ( 200 , 200 ) } ) ) . catch ( ( ) => Promise . resolve ( 'second update failed' ) ) ; } ) ; await wait ( animationDuration * 0.5 ) ; await page . evaluate ( ( ) => { return collectionView . updateLayout ( newGridLayout ( { itemSize : new Size ( 300 , 300 ) } ) ) ; } ) ; await expectElements ( [ [ 90 , 10 , '1' ] , [ 410 , 10 , '2' ] , [ 90 , 330 , '3' ] , [ 410 , 330 , '4' ] ] , [ 300 , 300 ] ) ; expect ( await firstUpdate ) . toEqual ( 'first update failed' ) ; expect ( await secondUpdate ) . toEqual ( 'second update failed' ) ; } ) ; } ) ;