import * as isCI from 'is-ci' ; import { launch , Browser , Frame , Page , Target } from 'puppeteer' ; import test from 'ava' ; import { delay } from '@hint/utils' ; import { Server } from '@hint/utils-create-server' ; import { Events , Results } from '../src/shared/types' ; import { readFixture } from './helpers/fixtures' ; const pathToExtension = `${ __dirname }/../bundle` ; const getPageFromTarget = async ( target ) => { ( target as any ) . _targetInfo . type = 'page' ; return await target . page ( ) ; } ; param browser returns const findBackgroundScriptPage = async ( browser ) : Promise < Page > => { const targets = await browser . targets ( ) ; const bgTargets = targets . filter ( ( t ) => { return t . type ( ) === 'background_page' ; } ) ; const matches = await Promise . all ( bgTargets . map ( async ( t ) => { const page = await t . page ( ) ; if ( ! page ) { return null ; } return await page . $ ( 'script[src="background-script.js"]' ) ; } ) ) ; const bgTarget = bgTargets . filter ( ( t , i ) => { return matches [ i ] ; } ) [ 0 ] ; return await bgTarget . page ( ) as Page ; } ; param browser returns const findWebhintDevtoolsPanel = async ( browser ) : Promise < Frame > => { const targets = await browser . targets ( ) ; const devtoolsTarget = targets . filter ( ( t ) => { return t . type ( ) === 'other' && t . url ( ) . startsWith ( 'chrome-devtools://' ) ; } ) [ 0 ] ; const devtoolsPage = await getPageFromTarget ( devtoolsTarget ) as Page ; await delay ( 500 ) ; await devtoolsPage . keyboard . down ( 'Control' ) ; await devtoolsPage . keyboard . press ( '[' ) ; await devtoolsPage . keyboard . up ( 'Control' ) ; await delay ( 500 ) ; const webhintTarget = ( await browser . targets ( ) ) . filter ( ( target ) => { return target . url ( ) . startsWith ( 'chrome-extension://' ) && target . url ( ) . endsWith ( '/panel.html' ) ; } ) [ 0 ] ; const webhintPanelPage = await getPageFromTarget ( webhintTarget ) as Page ; const webhintPanelFrame = webhintPanelPage . frames ( ) [ 0 ] ; return webhintPanelFrame ; } ; test ( 'It runs end-to-end in a page' , async ( t ) => { const content = await readFixture ( 'missing-lang.html' ) ; const server = await Server . create ( { configuration : content } ) ; const url = `http://localhost:${ server . port }/` ; const browser = await launch ( ) ; const page = ( await browser . pages ( ) ) [ 0 ] ; await page . goto ( url ) ; page . on ( 'pageerror' , ( e ) => { console . log ( 'Page Error: ' , e ) ; } ) ; const resultsPromise = page . evaluate ( ( content , url ) => { return new Promise < Results > ( ( resolve ) => { const listeners = [ ] ; const onMessage = ( events ) => { for ( const listener of listeners ) { listener ( events ) ; } } ; window . chrome = { i18n : { getMessage ( key ) { return key ; } } , runtime : { onMessage : { addListener : ( fn ) => { listeners . push ( fn ) ; } , removeListener : ( ) => { } } , sendMessage : ( event ) => { if ( event . evaluate ) { const { code , id } = event . evaluate ; setTimeout ( ( ) => { try { const value = eval ( code ) ; onMessage ( { evaluateResult : { id , value } } ) ; } catch ( err ) { onMessage ( { evaluateResult : { err , id } } ) ; } } , 0 ) ; } if ( event . requestConfig ) { onMessage ( { config : { } } ) ; } if ( event . ready ) { setTimeout ( ( ) => { onMessage ( { fetchEnd : { element : null , request : { headers : { } , url } , resource : url , response : { body : { content , rawContent : null as any , rawResponse : null as any } , charset : '' , headers : { 'content-type' : 'text/html; charset=utf-8' } , hops : [ ] , mediaType : '' , statusCode : 200 , url } } } ) ; } , 0 ) ; } if ( event . results ) { resolve ( event . results ) ; } } } } as any ; } ) ; } , content , url ) ; await page . addScriptTag ( { path : `${ __dirname }/../bundle/content-script/webhint.js` } ) ; const results = await resultsPromise ; t . not ( results . categories . length , 0 ) ; t . true ( results . categories . some ( ( category ) => { return category . hints . some ( ( hint ) => { return hint . problems . some ( ( problem ) => { return problem . message . startsWith ( '<html> element must have a lang attribute' ) ; } ) ; } ) ; } ) , 'Missing `lang` attribute was not reported' ) ; await browser . close ( ) ; server . stop ( ) ; } ) ; if ( ! isCI ) { test . skip ( 'It runs end-to-end as an extension' , async ( t ) => { const server = await Server . create ( { configuration : await readFixture ( 'missing-lang.html' ) } ) ; const url = `http://localhost:${ server . port }/` ; const browser = await launch ( { args : [ `--disable-extensions-except=${ pathToExtension }` , `--load-extension=${ pathToExtension }` ] , defaultViewport : undefined , devtools : true , headless : false } ) ; const pages = await browser . pages ( ) ; await pages [ 0 ] . goto ( url ) ; await delay ( 500 ) ; const backgroundPage = await findBackgroundScriptPage ( browser ) ; const webhintPanel = await findWebhintDevtoolsPanel ( browser ) ; await delay ( 500 ) ; await webhintPanel . click ( 'button[type="submit"]' ) ; const results = await backgroundPage . evaluate ( ( ) => { return new Promise < Results > ( ( resolve ) => { chrome . runtime . onMessage . addListener ( ( message ) => { if ( message . results ) { resolve ( message . results ) ; } } ) ; } ) ; } ) ; t . not ( results . categories . length , 0 ) ; t . true ( results . categories . some ( ( category ) => { return category . hints . some ( ( hint ) => { return hint . problems . some ( ( problem ) => { return problem . message . startsWith ( '<html> element must have a lang attribute' ) ; } ) ; } ) ; } ) , 'Missing `lang` attribute was not reported' ) ; await browser . close ( ) ; server . stop ( ) ; } ) ; }