2021-04-30 17:40:22 +03:00
/ * *
* Copyright ( c ) Microsoft Corporation .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2021-12-10 04:21:17 +03:00
import fs from 'fs' ;
2022-04-19 06:20:49 +03:00
import { jpegjs } from 'playwright-core/lib/utilsBundle' ;
2021-10-25 21:49:59 +03:00
import path from 'path' ;
2022-03-26 02:05:50 +03:00
import { browserTest , contextTest as test , expect } from '../config/browserTest' ;
2023-05-06 01:12:18 +03:00
import { parseTraceRaw } from '../config/utils' ;
2023-02-23 08:08:47 +03:00
import type { StackFrame } from '@protocol/channels' ;
2023-02-28 02:29:20 +03:00
import type { ActionTraceEvent } from '../../packages/trace/src/trace' ;
2023-05-17 04:44:27 +03:00
import { artifactsFolderName } from '../../packages/playwright-test/src/isomorphic/folders' ;
2021-04-30 17:40:22 +03:00
2021-10-26 23:45:53 +03:00
test . skip ( ( { trace } ) = > trace === 'on' ) ;
2021-08-20 05:09:19 +03:00
2021-08-03 23:05:58 +03:00
test ( 'should collect trace with resources, but no js' , async ( { context , page , server } , testInfo ) = > {
2021-07-15 04:43:51 +03:00
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
2021-08-03 23:05:58 +03:00
await page . goto ( server . PREFIX + '/frames/frame.html' ) ;
2021-04-30 17:40:22 +03:00
await page . setContent ( '<button>Click</button>' ) ;
await page . click ( '"Click"' ) ;
2021-09-07 23:48:30 +03:00
await page . mouse . move ( 20 , 20 ) ;
await page . mouse . dblclick ( 30 , 30 ) ;
await page . keyboard . insertText ( 'abc' ) ;
2021-06-15 02:01:18 +03:00
await page . waitForTimeout ( 2000 ) ; // Give it some time to produce screenshots.
2021-04-30 17:40:22 +03:00
await page . close ( ) ;
2021-06-02 20:04:25 +03:00
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ;
2021-04-30 17:40:22 +03:00
2023-05-06 01:12:18 +03:00
const { events , actions } = await parseTraceRaw ( testInfo . outputPath ( 'trace.zip' ) ) ;
2021-05-14 08:36:34 +03:00
expect ( events [ 0 ] . type ) . toBe ( 'context-options' ) ;
2023-01-04 04:30:36 +03:00
expect ( actions ) . toEqual ( [
2022-07-15 23:31:58 +03:00
'page.goto' ,
'page.setContent' ,
'page.click' ,
'mouse.move' ,
'mouse.dblclick' ,
'keyboard.insertText' ,
'page.waitForTimeout' ,
'page.close' ,
] ) ;
2021-04-30 17:40:22 +03:00
expect ( events . some ( e = > e . type === 'frame-snapshot' ) ) . toBeTruthy ( ) ;
2021-05-08 21:35:36 +03:00
expect ( events . some ( e = > e . type === 'screencast-frame' ) ) . toBeTruthy ( ) ;
2021-09-08 01:23:13 +03:00
const style = events . find ( e = > e . type === 'resource-snapshot' && e . snapshot . request . url . endsWith ( 'style.css' ) ) ;
expect ( style ) . toBeTruthy ( ) ;
expect ( style . snapshot . response . content . _sha1 ) . toBeTruthy ( ) ;
const script = events . find ( e = > e . type === 'resource-snapshot' && e . snapshot . request . url . endsWith ( 'script.js' ) ) ;
expect ( script ) . toBeTruthy ( ) ;
expect ( script . snapshot . response . content . _sha1 ) . toBe ( undefined ) ;
2021-04-30 17:40:22 +03:00
} ) ;
2022-07-15 23:31:58 +03:00
test ( 'should use the correct apiName for event driven callbacks' , async ( { context , page , server } , testInfo ) = > {
await context . tracing . start ( ) ;
await page . route ( '**/empty.html' , route = > route . continue ( ) ) ;
// page.goto -> page.route should be included in the trace since its handled.
await page . goto ( server . PREFIX + '/empty.html' ) ;
// page.route -> internalContinue should not be included in the trace since it was handled by Playwright internally.
await page . goto ( server . PREFIX + '/grid.html' ) ;
// The default internal dialog handler should not provide an action.
await page . evaluate ( ( ) = > alert ( 'yo' ) ) ;
await page . reload ( ) ;
// now we do it again with a dialog event listener attached which should produce an action.
page . on ( 'dialog' , dialog = > {
2023-06-02 22:59:12 +03:00
void dialog . accept ( 'answer!' ) ;
2022-07-15 23:31:58 +03:00
} ) ;
await page . evaluate ( ( ) = > alert ( 'yo' ) ) ;
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ;
2023-05-06 01:12:18 +03:00
const { events , actions } = await parseTraceRaw ( testInfo . outputPath ( 'trace.zip' ) ) ;
2022-07-15 23:31:58 +03:00
expect ( events [ 0 ] . type ) . toBe ( 'context-options' ) ;
2023-01-04 04:30:36 +03:00
expect ( actions ) . toEqual ( [
2022-07-15 23:31:58 +03:00
'page.route' ,
'page.goto' ,
'route.continue' ,
'page.goto' ,
'page.evaluate' ,
'page.reload' ,
'page.evaluate' ,
'dialog.accept' ,
] ) ;
} ) ;
2021-06-05 00:52:16 +03:00
test ( 'should not collect snapshots by default' , async ( { context , page , server } , testInfo ) = > {
2021-06-02 20:04:25 +03:00
await context . tracing . start ( ) ;
2021-04-30 17:40:22 +03:00
await page . goto ( server . EMPTY_PAGE ) ;
await page . setContent ( '<button>Click</button>' ) ;
await page . click ( '"Click"' ) ;
await page . close ( ) ;
2021-06-02 20:04:25 +03:00
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ;
2021-04-30 17:40:22 +03:00
2023-05-06 01:12:18 +03:00
const { events } = await parseTraceRaw ( testInfo . outputPath ( 'trace.zip' ) ) ;
2021-04-30 17:40:22 +03:00
expect ( events . some ( e = > e . type === 'frame-snapshot' ) ) . toBeFalsy ( ) ;
expect ( events . some ( e = > e . type === 'resource-snapshot' ) ) . toBeFalsy ( ) ;
} ) ;
2022-10-20 20:19:42 +03:00
test ( 'should not include buffers in the trace' , async ( { context , page , server , mode } , testInfo ) = > {
test . skip ( mode !== 'default' , 'no buffers with remote connections' ) ;
2022-10-18 02:17:25 +03:00
await context . tracing . start ( { snapshots : true } ) ;
await page . goto ( server . PREFIX + '/empty.html' ) ;
await page . screenshot ( ) ;
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ;
2023-07-08 03:16:26 +03:00
const { actionObjects } = await parseTraceRaw ( testInfo . outputPath ( 'trace.zip' ) ) ;
const screenshotEvent = actionObjects . find ( a = > a . apiName === 'page.screenshot' ) ;
2023-03-16 08:33:40 +03:00
expect ( screenshotEvent . beforeSnapshot ) . toBeTruthy ( ) ;
expect ( screenshotEvent . afterSnapshot ) . toBeTruthy ( ) ;
2023-02-28 02:29:20 +03:00
expect ( screenshotEvent . result ) . toEqual ( { } ) ;
2022-10-18 02:17:25 +03:00
} ) ;
2021-05-29 04:20:49 +03:00
test ( 'should exclude internal pages' , async ( { browserName , context , page , server } , testInfo ) = > {
await page . goto ( server . EMPTY_PAGE ) ;
2021-06-02 20:04:25 +03:00
await context . tracing . start ( ) ;
2021-05-29 04:20:49 +03:00
await context . storageState ( ) ;
await page . close ( ) ;
2021-06-02 20:04:25 +03:00
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ;
2021-05-29 04:20:49 +03:00
2023-05-06 01:12:18 +03:00
const trace = await parseTraceRaw ( testInfo . outputPath ( 'trace.zip' ) ) ;
2021-05-29 04:20:49 +03:00
const pageIds = new Set ( ) ;
trace . events . forEach ( e = > {
2023-02-28 02:29:20 +03:00
const pageId = e . pageId ;
2021-05-29 04:20:49 +03:00
if ( pageId )
pageIds . add ( pageId ) ;
} ) ;
expect ( pageIds . size ) . toBe ( 1 ) ;
} ) ;
2021-12-03 02:53:47 +03:00
test ( 'should include context API requests' , async ( { browserName , context , page , server } , testInfo ) = > {
await context . tracing . start ( { snapshots : true } ) ;
await page . request . post ( server . PREFIX + '/simple.json' , { data : { foo : 'bar' } } ) ;
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ;
2023-05-06 01:12:18 +03:00
const { events } = await parseTraceRaw ( testInfo . outputPath ( 'trace.zip' ) ) ;
2023-02-28 02:29:20 +03:00
const postEvent = events . find ( e = > e . apiName === 'apiRequestContext.post' ) ;
2021-12-03 02:53:47 +03:00
expect ( postEvent ) . toBeTruthy ( ) ;
const harEntry = events . find ( e = > e . type === 'resource-snapshot' ) ;
expect ( harEntry ) . toBeTruthy ( ) ;
expect ( harEntry . snapshot . request . url ) . toBe ( server . PREFIX + '/simple.json' ) ;
expect ( harEntry . snapshot . response . status ) . toBe ( 200 ) ;
} ) ;
2021-04-30 17:40:22 +03:00
test ( 'should collect two traces' , async ( { context , page , server } , testInfo ) = > {
2021-06-02 20:04:25 +03:00
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
2021-04-30 17:40:22 +03:00
await page . goto ( server . EMPTY_PAGE ) ;
await page . setContent ( '<button>Click</button>' ) ;
await page . click ( '"Click"' ) ;
2021-06-02 20:04:25 +03:00
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace1.zip' ) } ) ;
2021-04-30 17:40:22 +03:00
2021-06-02 20:04:25 +03:00
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
2021-04-30 17:40:22 +03:00
await page . dblclick ( '"Click"' ) ;
await page . close ( ) ;
2021-06-02 20:04:25 +03:00
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace2.zip' ) } ) ;
2021-04-30 17:40:22 +03:00
{
2023-05-06 01:12:18 +03:00
const { events , actions } = await parseTraceRaw ( testInfo . outputPath ( 'trace1.zip' ) ) ;
2021-05-14 08:36:34 +03:00
expect ( events [ 0 ] . type ) . toBe ( 'context-options' ) ;
2023-01-04 04:30:36 +03:00
expect ( actions ) . toEqual ( [
2022-07-15 23:31:58 +03:00
'page.goto' ,
'page.setContent' ,
'page.click' ,
] ) ;
2021-04-30 17:40:22 +03:00
}
{
2023-05-06 01:12:18 +03:00
const { events , actions } = await parseTraceRaw ( testInfo . outputPath ( 'trace2.zip' ) ) ;
2021-05-14 08:36:34 +03:00
expect ( events [ 0 ] . type ) . toBe ( 'context-options' ) ;
2023-01-04 04:30:36 +03:00
expect ( actions ) . toEqual ( [
2022-07-15 23:31:58 +03:00
'page.dblclick' ,
'page.close' ,
] ) ;
2021-04-30 17:40:22 +03:00
}
} ) ;
2023-05-31 20:52:29 +03:00
test ( 'should respect tracesDir and name' , async ( { browserType , server , mode } , testInfo ) = > {
2023-07-26 02:47:04 +03:00
test . skip ( mode . startsWith ( 'service' ) , 'Service ignores tracesDir' ) ;
2023-05-31 20:52:29 +03:00
2023-03-16 03:34:56 +03:00
const tracesDir = testInfo . outputPath ( 'traces' ) ;
const browser = await browserType . launch ( { tracesDir } ) ;
const context = await browser . newContext ( ) ;
const page = await context . newPage ( ) ;
await context . tracing . start ( { name : 'name1' , snapshots : true } ) ;
await page . goto ( server . PREFIX + '/one-style.html' ) ;
await context . tracing . stopChunk ( { path : testInfo.outputPath ( 'trace1.zip' ) } ) ;
expect ( fs . existsSync ( path . join ( tracesDir , 'name1.trace' ) ) ) . toBe ( true ) ;
expect ( fs . existsSync ( path . join ( tracesDir , 'name1.network' ) ) ) . toBe ( true ) ;
await context . tracing . startChunk ( { name : 'name2' } ) ;
await page . goto ( server . PREFIX + '/har.html' ) ;
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace2.zip' ) } ) ;
expect ( fs . existsSync ( path . join ( tracesDir , 'name2.trace' ) ) ) . toBe ( true ) ;
expect ( fs . existsSync ( path . join ( tracesDir , 'name2.network' ) ) ) . toBe ( true ) ;
await browser . close ( ) ;
function resourceNames ( resources : Map < string , Buffer > ) {
return [ . . . resources . keys ( ) ] . map ( file = > {
return file . replace ( /^resources\/.*\.(html|css)$/ , 'resources/XXX.$1' ) ;
} ) . sort ( ) ;
}
{
2023-05-06 01:12:18 +03:00
const { resources , actions } = await parseTraceRaw ( testInfo . outputPath ( 'trace1.zip' ) ) ;
2023-03-16 03:34:56 +03:00
expect ( actions ) . toEqual ( [ 'page.goto' ] ) ;
expect ( resourceNames ( resources ) ) . toEqual ( [
'resources/XXX.css' ,
'resources/XXX.html' ,
'trace.network' ,
'trace.stacks' ,
'trace.trace' ,
] ) ;
}
{
2023-05-06 01:12:18 +03:00
const { resources , actions } = await parseTraceRaw ( testInfo . outputPath ( 'trace2.zip' ) ) ;
2023-03-16 03:34:56 +03:00
expect ( actions ) . toEqual ( [ 'page.goto' ] ) ;
expect ( resourceNames ( resources ) ) . toEqual ( [
'resources/XXX.css' ,
'resources/XXX.html' ,
'resources/XXX.html' ,
'trace.network' ,
'trace.stacks' ,
'trace.trace' ,
] ) ;
}
} ) ;
2023-07-31 21:24:04 +03:00
test ( 'should not include trace resources from the previous chunks' , async ( { context , page , server , browserName , mode } , testInfo ) = > {
2021-12-16 04:40:34 +03:00
test . skip ( browserName !== 'chromium' , 'The number of screenshots is flaky in non-Chromium' ) ;
2023-07-31 21:24:04 +03:00
test . skip ( mode . startsWith ( 'service' ) , 'The number of screenshots is flaky' ) ;
2021-12-11 01:07:22 +03:00
await context . tracing . start ( { screenshots : true , snapshots : true , sources : true } ) ;
await context . tracing . startChunk ( ) ;
await page . goto ( server . EMPTY_PAGE ) ;
await page . setContent ( '<button>Click</button>' ) ;
await page . click ( '"Click"' ) ;
2021-12-14 01:37:44 +03:00
// Give it enough time for both screenshots to get into the trace.
2022-11-08 02:35:21 +03:00
await new Promise ( f = > setTimeout ( f , 3000 ) ) ;
2021-12-11 01:07:22 +03:00
await context . tracing . stopChunk ( { path : testInfo.outputPath ( 'trace1.zip' ) } ) ;
await context . tracing . startChunk ( ) ;
await context . tracing . stopChunk ( { path : testInfo.outputPath ( 'trace2.zip' ) } ) ;
{
2023-05-06 01:12:18 +03:00
const { resources } = await parseTraceRaw ( testInfo . outputPath ( 'trace1.zip' ) ) ;
2021-12-11 01:07:22 +03:00
const names = Array . from ( resources . keys ( ) ) ;
expect ( names . filter ( n = > n . endsWith ( '.html' ) ) . length ) . toBe ( 1 ) ;
2021-12-15 21:40:18 +03:00
expect ( names . filter ( n = > n . endsWith ( '.jpeg' ) ) . length ) . toBeGreaterThan ( 0 ) ;
2021-12-11 01:07:22 +03:00
// 1 source file for the test.
expect ( names . filter ( n = > n . endsWith ( '.txt' ) ) . length ) . toBe ( 1 ) ;
}
{
2023-05-06 01:12:18 +03:00
const { resources } = await parseTraceRaw ( testInfo . outputPath ( 'trace2.zip' ) ) ;
2021-12-11 01:07:22 +03:00
const names = Array . from ( resources . keys ( ) ) ;
// 1 network resource should be preserved.
expect ( names . filter ( n = > n . endsWith ( '.html' ) ) . length ) . toBe ( 1 ) ;
expect ( names . filter ( n = > n . endsWith ( '.jpeg' ) ) . length ) . toBe ( 0 ) ;
2023-02-23 08:08:47 +03:00
// 0 source file for the second test.
expect ( names . filter ( n = > n . endsWith ( '.txt' ) ) . length ) . toBe ( 0 ) ;
2021-12-11 01:07:22 +03:00
}
} ) ;
test ( 'should overwrite existing file' , async ( { context , page , server } , testInfo ) = > {
await context . tracing . start ( { screenshots : true , snapshots : true , sources : true } ) ;
await page . goto ( server . EMPTY_PAGE ) ;
await page . setContent ( '<button>Click</button>' ) ;
await page . click ( '"Click"' ) ;
const path = testInfo . outputPath ( 'trace1.zip' ) ;
await context . tracing . stop ( { path } ) ;
{
2023-05-06 01:12:18 +03:00
const { resources } = await parseTraceRaw ( path ) ;
2021-12-11 01:07:22 +03:00
const names = Array . from ( resources . keys ( ) ) ;
expect ( names . filter ( n = > n . endsWith ( '.html' ) ) . length ) . toBe ( 1 ) ;
}
await context . tracing . start ( { screenshots : true , snapshots : true , sources : true } ) ;
await context . tracing . stop ( { path } ) ;
{
2023-05-06 01:12:18 +03:00
const { resources } = await parseTraceRaw ( path ) ;
2021-12-11 01:07:22 +03:00
const names = Array . from ( resources . keys ( ) ) ;
expect ( names . filter ( n = > n . endsWith ( '.html' ) ) . length ) . toBe ( 0 ) ;
}
} ) ;
2021-12-10 04:21:17 +03:00
test ( 'should collect sources' , async ( { context , page , server } , testInfo ) = > {
await context . tracing . start ( { sources : true } ) ;
await page . goto ( server . EMPTY_PAGE ) ;
await page . setContent ( '<button>Click</button>' ) ;
await page . click ( '"Click"' ) ;
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace1.zip' ) } ) ;
2023-05-06 01:12:18 +03:00
const { resources } = await parseTraceRaw ( testInfo . outputPath ( 'trace1.zip' ) ) ;
2021-12-10 04:21:17 +03:00
const sourceNames = Array . from ( resources . keys ( ) ) . filter ( k = > k . endsWith ( '.txt' ) ) ;
expect ( sourceNames . length ) . toBe ( 1 ) ;
const sourceFile = resources . get ( sourceNames [ 0 ] ) ;
const thisFile = await fs . promises . readFile ( __filename ) ;
expect ( sourceFile ) . toEqual ( thisFile ) ;
} ) ;
2022-01-07 22:22:01 +03:00
test ( 'should record network failures' , async ( { context , page , server } , testInfo ) = > {
await context . tracing . start ( { snapshots : true } ) ;
await page . route ( '**/*' , route = > route . abort ( 'connectionaborted' ) ) ;
await page . goto ( server . EMPTY_PAGE ) . catch ( e = > { } ) ;
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace1.zip' ) } ) ;
2023-05-06 01:12:18 +03:00
const { events } = await parseTraceRaw ( testInfo . outputPath ( 'trace1.zip' ) ) ;
2022-01-07 22:22:01 +03:00
const requestEvent = events . find ( e = > e . type === 'resource-snapshot' && ! ! e . snapshot . response . _failureText ) ;
expect ( requestEvent ) . toBeTruthy ( ) ;
} ) ;
2023-07-27 03:31:00 +03:00
test ( 'should not crash when browser closes mid-trace' , async ( { browserType , server } , testInfo ) = > {
const browser = await browserType . launch ( ) ;
const page = await browser . newPage ( ) ;
await page . context ( ) . tracing . start ( { snapshots : true , screenshots : true } ) ;
await page . goto ( server . EMPTY_PAGE ) ;
await browser . close ( ) ;
await new Promise ( f = > setTimeout ( f , 1000 ) ) ; // Give it some time to throw errors
} ) ;
test ( 'should survive browser.close with auto-created traces dir' , async ( { browserType } , testInfo ) = > {
const oldTracesDir = ( browserType as any ) . _defaultLaunchOptions . tracesDir ;
( browserType as any ) . _defaultLaunchOptions . tracesDir = undefined ;
const browser = await browserType . launch ( ) ;
const page = await browser . newPage ( ) ;
await page . context ( ) . tracing . start ( ) ;
const done = { value : false } ;
async function go() {
while ( ! done . value ) {
// Produce a lot of operations to make sure tracing operations are enqueued.
for ( let i = 0 ; i < 100 ; i ++ )
page . evaluate ( '1 + 1' ) . catch ( ( ) = > { } ) ;
2023-07-28 06:20:31 +03:00
await new Promise ( f = > setTimeout ( f , 250 ) ) ;
2023-07-27 03:31:00 +03:00
}
}
void go ( ) ;
2023-07-28 06:20:31 +03:00
await new Promise ( f = > setTimeout ( f , 1000 ) ) ;
2023-07-27 03:31:00 +03:00
// Close the browser and give it some time to fail.
await Promise . all ( [
browser . close ( ) ,
new Promise ( f = > setTimeout ( f , 500 ) ) ,
] ) ;
done . value = true ;
( browserType as any ) . _defaultLaunchOptions . tracesDir = oldTracesDir ;
} ) ;
2021-06-11 08:24:04 +03:00
test ( 'should not stall on dialogs' , async ( { page , context , server } ) = > {
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
await page . goto ( server . EMPTY_PAGE ) ;
page . on ( 'dialog' , async dialog = > {
await dialog . accept ( ) ;
} ) ;
await page . evaluate ( ( ) = > {
confirm ( 'are you sure' ) ;
} ) ;
await context . tracing . stop ( ) ;
} ) ;
2021-05-11 23:21:01 +03:00
for ( const params of [
{
id : 'fit' ,
width : 500 ,
height : 500 ,
2021-05-12 18:35:19 +03:00
} ,
{
2021-05-11 23:21:01 +03:00
id : 'crop' ,
width : 400 , // Less than 450 to test firefox
height : 800 ,
2021-05-12 18:35:19 +03:00
} ,
{
2021-05-11 23:21:01 +03:00
id : 'scale' ,
width : 1024 ,
height : 768 ,
2021-05-12 18:35:19 +03:00
}
] ) {
2021-06-04 00:33:33 +03:00
browserTest ( ` should produce screencast frames ${ params . id } ` , async ( { video , contextFactory , browserName , platform , headless } , testInfo ) = > {
2023-01-28 08:52:34 +03:00
browserTest . skip ( browserName === 'chromium' && video === 'on' , 'Same screencast resolution conflicts' ) ;
2023-06-02 21:40:12 +03:00
browserTest . fixme ( browserName === 'chromium' && ( ! headless || ! ! process . env . PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW ) , 'Chromium screencast on headed has a min width issue' ) ;
2021-05-12 18:35:19 +03:00
browserTest . fixme ( params . id === 'fit' && browserName === 'chromium' && platform === 'darwin' , 'High DPI maxes image at 600x600' ) ;
2021-05-17 22:06:18 +03:00
browserTest . fixme ( params . id === 'fit' && browserName === 'webkit' && platform === 'linux' , 'Image size is flaky' ) ;
2023-01-28 08:52:34 +03:00
browserTest . fixme ( browserName === 'firefox' && ! headless , 'Image size is different' ) ;
2021-05-12 18:35:19 +03:00
2021-05-11 23:21:01 +03:00
const scale = Math . min ( 800 / params . width , 600 / params . height , 1 ) ;
const previewWidth = params . width * scale ;
const previewHeight = params . height * scale ;
2021-09-27 19:58:08 +03:00
const context = await contextFactory ( { viewport : { width : params.width , height : params.height } } ) ;
2021-06-02 20:04:25 +03:00
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
2021-05-11 23:21:01 +03:00
const page = await context . newPage ( ) ;
// Make sure we have a chance to paint.
2021-05-12 18:35:19 +03:00
for ( let i = 0 ; i < 10 ; ++ i ) {
await page . setContent ( '<body style="box-sizing: border-box; width: 100%; height: 100%; margin:0; background: red; border: 50px solid blue"></body>' ) ;
2021-05-11 23:21:01 +03:00
await page . evaluate ( ( ) = > new Promise ( requestAnimationFrame ) ) ;
2021-05-12 18:35:19 +03:00
}
2021-06-02 20:04:25 +03:00
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ;
2021-05-11 23:21:01 +03:00
2023-05-06 01:12:18 +03:00
const { events , resources } = await parseTraceRaw ( testInfo . outputPath ( 'trace.zip' ) ) ;
2021-05-11 23:21:01 +03:00
const frames = events . filter ( e = > e . type === 'screencast-frame' ) ;
2021-05-12 18:35:19 +03:00
// Check all frame sizes.
2021-05-11 23:21:01 +03:00
for ( const frame of frames ) {
expect ( frame . width ) . toBe ( params . width ) ;
expect ( frame . height ) . toBe ( params . height ) ;
const buffer = resources . get ( 'resources/' + frame . sha1 ) ;
2022-04-19 06:20:49 +03:00
const image = jpegjs . decode ( buffer ) ;
2021-05-11 23:21:01 +03:00
expect ( image . width ) . toBe ( previewWidth ) ;
expect ( image . height ) . toBe ( previewHeight ) ;
}
const frame = frames [ frames . length - 1 ] ; // pick last frame.
const buffer = resources . get ( 'resources/' + frame . sha1 ) ;
2022-04-19 06:20:49 +03:00
const image = jpegjs . decode ( buffer ) ;
2021-05-11 23:21:01 +03:00
expect ( image . data . byteLength ) . toBe ( previewWidth * previewHeight * 4 ) ;
expectRed ( image . data , previewWidth * previewHeight * 4 / 2 + previewWidth * 4 / 2 ) ; // center is red
expectBlue ( image . data , previewWidth * 5 * 4 + previewWidth * 4 / 2 ) ; // top
expectBlue ( image . data , previewWidth * ( previewHeight - 5 ) * 4 + previewWidth * 4 / 2 ) ; // bottom
expectBlue ( image . data , previewWidth * previewHeight * 4 / 2 + 5 * 4 ) ; // left
expectBlue ( image . data , previewWidth * previewHeight * 4 / 2 + ( previewWidth - 5 ) * 4 ) ; // right
} ) ;
}
2021-06-26 03:14:19 +03:00
test ( 'should include interrupted actions' , async ( { context , page , server } , testInfo ) = > {
2021-07-15 04:43:51 +03:00
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
2021-06-26 03:14:19 +03:00
await page . goto ( server . EMPTY_PAGE ) ;
await page . setContent ( '<button>Click</button>' ) ;
page . click ( '"ClickNoButton"' ) . catch ( ( ) = > { } ) ;
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ;
await context . close ( ) ;
2023-05-06 01:12:18 +03:00
const { events } = await parseTraceRaw ( testInfo . outputPath ( 'trace.zip' ) ) ;
2023-02-28 02:29:20 +03:00
const clickEvent = events . find ( e = > e . apiName === 'page.click' ) ;
2021-06-26 03:14:19 +03:00
expect ( clickEvent ) . toBeTruthy ( ) ;
} ) ;
2021-09-01 03:03:31 +03:00
test ( 'should throw when starting with different options' , async ( { context } ) = > {
2021-08-04 02:08:06 +03:00
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
2021-09-01 03:03:31 +03:00
const error = await context . tracing . start ( { screenshots : false , snapshots : false } ) . catch ( e = > e ) ;
2023-07-14 16:19:54 +03:00
expect ( error . message ) . toContain ( 'Tracing has been already started' ) ;
2021-09-01 03:03:31 +03:00
} ) ;
2021-08-04 02:08:06 +03:00
2021-09-01 03:03:31 +03:00
test ( 'should throw when stopping without start' , async ( { context } , testInfo ) = > {
const error = await context . tracing . stop ( { path : testInfo.outputPath ( 'trace.zip' ) } ) . catch ( e = > e ) ;
expect ( error . message ) . toContain ( 'Must start tracing before stopping' ) ;
} ) ;
2021-08-04 02:08:06 +03:00
2021-09-01 03:03:31 +03:00
test ( 'should not throw when stopping without start but not exporting' , async ( { context } , testInfo ) = > {
await context . tracing . stop ( ) ;
2021-08-04 02:08:06 +03:00
} ) ;
2021-09-01 03:03:31 +03:00
test ( 'should work with multiple chunks' , async ( { context , page , server } , testInfo ) = > {
2021-08-05 07:11:35 +03:00
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
await page . goto ( server . PREFIX + '/frames/frame.html' ) ;
2021-09-01 03:03:31 +03:00
await context . tracing . startChunk ( ) ;
2021-08-05 07:11:35 +03:00
await page . setContent ( '<button>Click</button>' ) ;
await page . click ( '"Click"' ) ;
2023-03-20 22:52:52 +03:00
page . click ( '"ClickNoButton"' , { timeout : 0 } ) . catch ( ( ) = > { } ) ;
2021-09-01 03:03:31 +03:00
await context . tracing . stopChunk ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ;
2021-08-05 07:11:35 +03:00
2021-09-01 03:03:31 +03:00
await context . tracing . startChunk ( ) ;
2021-08-05 07:11:35 +03:00
await page . hover ( '"Click"' ) ;
2021-09-01 03:03:31 +03:00
await context . tracing . stopChunk ( { path : testInfo.outputPath ( 'trace2.zip' ) } ) ;
2021-08-05 07:11:35 +03:00
2021-10-19 07:05:59 +03:00
await context . tracing . startChunk ( ) ;
await page . click ( '"Click"' ) ;
await context . tracing . stopChunk ( ) ; // Should stop without a path.
2023-05-06 01:12:18 +03:00
const trace1 = await parseTraceRaw ( testInfo . outputPath ( 'trace.zip' ) ) ;
2021-08-05 07:11:35 +03:00
expect ( trace1 . events [ 0 ] . type ) . toBe ( 'context-options' ) ;
2023-01-04 04:30:36 +03:00
expect ( trace1 . actions ) . toEqual ( [
2022-07-15 23:31:58 +03:00
'page.setContent' ,
'page.click' ,
'page.click' ,
] ) ;
2021-08-05 07:11:35 +03:00
expect ( trace1 . events . some ( e = > e . type === 'frame-snapshot' ) ) . toBeTruthy ( ) ;
2021-08-24 23:17:58 +03:00
expect ( trace1 . events . some ( e = > e . type === 'resource-snapshot' && e . snapshot . request . url . endsWith ( 'style.css' ) ) ) . toBeTruthy ( ) ;
2021-08-05 07:11:35 +03:00
2023-05-06 01:12:18 +03:00
const trace2 = await parseTraceRaw ( testInfo . outputPath ( 'trace2.zip' ) ) ;
2021-08-05 07:11:35 +03:00
expect ( trace2 . events [ 0 ] . type ) . toBe ( 'context-options' ) ;
2023-01-04 04:30:36 +03:00
expect ( trace2 . actions ) . toEqual ( [
2022-07-15 23:31:58 +03:00
'page.hover' ,
] ) ;
2021-08-05 07:11:35 +03:00
expect ( trace2 . events . some ( e = > e . type === 'frame-snapshot' ) ) . toBeTruthy ( ) ;
2021-09-01 03:03:31 +03:00
expect ( trace2 . events . some ( e = > e . type === 'resource-snapshot' && e . snapshot . request . url . endsWith ( 'style.css' ) ) ) . toBeTruthy ( ) ;
2021-08-05 07:11:35 +03:00
} ) ;
2021-06-26 03:14:19 +03:00
2021-08-19 17:26:24 +03:00
test ( 'should export trace concurrently to second navigation' , async ( { context , page , server } , testInfo ) = > {
for ( let timeout = 0 ; timeout < 200 ; timeout += 20 ) {
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
await page . goto ( server . PREFIX + '/grid.html' ) ;
// Navigate to the same page to produce the same trace resources
// that might be concurrently exported.
const promise = page . goto ( server . PREFIX + '/grid.html' ) ;
await page . waitForTimeout ( timeout ) ;
await Promise . all ( [
promise ,
context . tracing . stop ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ,
] ) ;
}
} ) ;
2021-08-20 04:20:15 +03:00
test ( 'should not hang for clicks that open dialogs' , async ( { context , page } ) = > {
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
const dialogPromise = page . waitForEvent ( 'dialog' ) ;
await page . setContent ( ` <div onclick='window.alert(123)'>Click me</div> ` ) ;
await page . click ( 'div' , { timeout : 2000 } ) . catch ( ( ) = > { } ) ;
const dialog = await dialogPromise ;
await dialog . dismiss ( ) ;
await context . tracing . stop ( ) ;
} ) ;
2022-02-16 20:09:15 +03:00
test ( 'should ignore iframes in head' , async ( { context , page , server } , testInfo ) = > {
await page . goto ( server . PREFIX + '/input/button.html' ) ;
await page . evaluate ( ( ) = > {
document . head . appendChild ( document . createElement ( 'iframe' ) ) ;
// Add iframe in a shadow tree.
const div = document . createElement ( 'div' ) ;
document . head . appendChild ( div ) ;
const shadow = div . attachShadow ( { mode : 'open' } ) ;
shadow . appendChild ( document . createElement ( 'iframe' ) ) ;
} ) ;
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
await page . click ( 'button' ) ;
await context . tracing . stopChunk ( { path : testInfo.outputPath ( 'trace.zip' ) } ) ;
2023-05-06 01:12:18 +03:00
const trace = await parseTraceRaw ( testInfo . outputPath ( 'trace.zip' ) ) ;
2023-01-04 04:30:36 +03:00
expect ( trace . actions ) . toEqual ( [
2022-07-15 23:31:58 +03:00
'page.click' ,
] ) ;
2022-02-16 20:09:15 +03:00
expect ( trace . events . find ( e = > e . type === 'frame-snapshot' ) ) . toBeTruthy ( ) ;
expect ( trace . events . find ( e = > e . type === 'frame-snapshot' && JSON . stringify ( e . snapshot . html ) . includes ( 'IFRAME' ) ) ) . toBeFalsy ( ) ;
} ) ;
2021-10-25 21:49:59 +03:00
test ( 'should hide internal stack frames' , async ( { context , page } , testInfo ) = > {
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
let evalPromise ;
page . on ( 'dialog' , dialog = > {
evalPromise = page . evaluate ( '2+2' ) ;
2023-06-02 22:59:12 +03:00
void dialog . dismiss ( ) ;
2021-10-25 21:49:59 +03:00
} ) ;
await page . setContent ( ` <div onclick='window.alert(123)'>Click me</div> ` ) ;
await page . click ( 'div' ) ;
await evalPromise ;
const tracePath = testInfo . outputPath ( 'trace.zip' ) ;
await context . tracing . stop ( { path : tracePath } ) ;
2023-05-06 01:12:18 +03:00
const trace = await parseTraceRaw ( tracePath ) ;
2023-07-08 03:16:26 +03:00
const actions = trace . actionObjects . filter ( a = > ! a . apiName . startsWith ( 'tracing.' ) ) ;
2021-10-25 21:49:59 +03:00
expect ( actions ) . toHaveLength ( 4 ) ;
for ( const action of actions )
2023-02-23 08:08:47 +03:00
expect ( relativeStack ( action , trace . stacks ) ) . toEqual ( [ 'tracing.spec.ts' ] ) ;
2021-10-25 21:49:59 +03:00
} ) ;
test ( 'should hide internal stack frames in expect' , async ( { context , page } , testInfo ) = > {
await context . tracing . start ( { screenshots : true , snapshots : true } ) ;
let expectPromise ;
page . on ( 'dialog' , dialog = > {
expectPromise = expect ( page ) . toHaveTitle ( 'Hello' ) ;
2023-06-02 22:59:12 +03:00
void dialog . dismiss ( ) ;
2021-10-25 21:49:59 +03:00
} ) ;
await page . setContent ( ` <title>Hello</title><div onclick='window.alert(123)'>Click me</div> ` ) ;
await page . click ( 'div' ) ;
await expect ( page . locator ( 'div' ) ) . toBeVisible ( ) ;
await expectPromise ;
const tracePath = testInfo . outputPath ( 'trace.zip' ) ;
await context . tracing . stop ( { path : tracePath } ) ;
2023-05-06 01:12:18 +03:00
const trace = await parseTraceRaw ( tracePath ) ;
2023-07-08 03:16:26 +03:00
const actions = trace . actionObjects . filter ( a = > ! a . apiName . startsWith ( 'tracing.' ) ) ;
2021-10-25 21:49:59 +03:00
expect ( actions ) . toHaveLength ( 5 ) ;
for ( const action of actions )
2023-02-23 08:08:47 +03:00
expect ( relativeStack ( action , trace . stacks ) ) . toEqual ( [ 'tracing.spec.ts' ] ) ;
2021-10-25 21:49:59 +03:00
} ) ;
2022-01-25 23:04:03 +03:00
test ( 'should record global request trace' , async ( { request , context , server } , testInfo ) = > {
await ( request as any ) . _tracing . start ( { snapshots : true } ) ;
const url = server . PREFIX + '/simple.json' ;
await request . get ( url ) ;
const tracePath = testInfo . outputPath ( 'trace.zip' ) ;
await ( request as any ) . _tracing . stop ( { path : tracePath } ) ;
2023-05-06 01:12:18 +03:00
const trace = await parseTraceRaw ( tracePath ) ;
2022-01-25 23:04:03 +03:00
const actions = trace . events . filter ( e = > e . type === 'resource-snapshot' ) ;
expect ( actions ) . toHaveLength ( 1 ) ;
expect ( actions [ 0 ] . snapshot . request ) . toEqual ( expect . objectContaining ( {
method : 'GET' ,
url
} ) ) ;
expect ( actions [ 0 ] . snapshot . response ) . toEqual ( expect . objectContaining ( {
status : 200 ,
statusText : 'OK' ,
headers : expect.arrayContaining ( [
expect . objectContaining ( {
'name' : 'Content-Length' ,
'value' : '15'
} )
] )
} ) ) ;
} ) ;
2023-05-18 03:54:34 +03:00
test ( 'should store global request traces separately' , async ( { request , server , playwright , browserName , mode } , testInfo ) = > {
2022-01-25 23:04:03 +03:00
const request2 = await playwright . request . newContext ( ) ;
await Promise . all ( [
( request as any ) . _tracing . start ( { snapshots : true } ) ,
( request2 as any ) . _tracing . start ( { snapshots : true } )
] ) ;
const url = server . PREFIX + '/simple.json' ;
await Promise . all ( [
request . get ( url ) ,
request2 . post ( url )
] ) ;
const tracePath = testInfo . outputPath ( 'trace.zip' ) ;
const trace2Path = testInfo . outputPath ( 'trace2.zip' ) ;
await Promise . all ( [
( request as any ) . _tracing . stop ( { path : tracePath } ) ,
( request2 as any ) . _tracing . stop ( { path : trace2Path } )
] ) ;
{
2023-05-06 01:12:18 +03:00
const trace = await parseTraceRaw ( tracePath ) ;
2022-01-25 23:04:03 +03:00
const actions = trace . events . filter ( e = > e . type === 'resource-snapshot' ) ;
expect ( actions ) . toHaveLength ( 1 ) ;
expect ( actions [ 0 ] . snapshot . request ) . toEqual ( expect . objectContaining ( {
method : 'GET' ,
url
} ) ) ;
}
{
2023-05-06 01:12:18 +03:00
const trace = await parseTraceRaw ( trace2Path ) ;
2022-01-25 23:04:03 +03:00
const actions = trace . events . filter ( e = > e . type === 'resource-snapshot' ) ;
expect ( actions ) . toHaveLength ( 1 ) ;
expect ( actions [ 0 ] . snapshot . request ) . toEqual ( expect . objectContaining ( {
method : 'POST' ,
url
} ) ) ;
}
} ) ;
2022-06-22 19:13:29 +03:00
test ( 'should store postData for global request' , async ( { request , server } , testInfo ) = > {
testInfo . annotations . push ( { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/15031' } ) ;
await ( request as any ) . _tracing . start ( { snapshots : true } ) ;
const url = server . PREFIX + '/simple.json' ;
await request . post ( url , {
data : 'test'
} ) ;
const tracePath = testInfo . outputPath ( 'trace.zip' ) ;
await ( request as any ) . _tracing . stop ( { path : tracePath } ) ;
2023-05-06 01:12:18 +03:00
const trace = await parseTraceRaw ( tracePath ) ;
2022-06-22 19:13:29 +03:00
const actions = trace . events . filter ( e = > e . type === 'resource-snapshot' ) ;
expect ( actions ) . toHaveLength ( 1 ) ;
const req = actions [ 0 ] . snapshot . request ;
expect ( req . postData ? . _sha1 ) . toBeTruthy ( ) ;
expect ( req ) . toEqual ( expect . objectContaining ( {
method : 'POST' ,
url
} ) ) ;
} ) ;
2023-06-07 02:55:53 +03:00
test ( 'should not flush console events' , async ( { context , page , mode } , testInfo ) = > {
2023-07-26 02:47:04 +03:00
test . skip ( mode . startsWith ( 'service' ) , 'Uses artifactsFolderName' ) ;
2023-06-05 22:19:25 +03:00
const testId = test . info ( ) . testId ;
await context . tracing . start ( { name : testId } ) ;
2023-05-17 04:44:27 +03:00
const promise = new Promise < void > ( f = > {
let counter = 0 ;
page . on ( 'console' , ( ) = > {
if ( ++ counter === 100 )
f ( ) ;
} ) ;
} ) ;
await page . evaluate ( ( ) = > {
setTimeout ( ( ) = > {
for ( let i = 0 ; i < 100 ; ++ i )
console . log ( 'hello ' + i ) ;
} , 10 ) ;
return 31415926 ;
} ) ;
await promise ;
const dir = path . join ( testInfo . project . outputDir , artifactsFolderName ( testInfo . workerIndex ) , 'traces' ) ;
let content : string ;
await expect ( async ( ) = > {
2023-06-05 22:19:25 +03:00
const traceName = fs . readdirSync ( dir ) . find ( name = > name . endsWith ( testId + '.trace' ) ) ;
2023-05-17 04:44:27 +03:00
content = await fs . promises . readFile ( path . join ( dir , traceName ) , 'utf8' ) ;
expect ( content ) . toContain ( 'page.evaluate' ) ;
expect ( content ) . toContain ( '31415926' ) ;
} ) . toPass ( ) ;
expect ( content ) . not . toContain ( 'hello 0' ) ;
await page . evaluate ( ( ) = > 42 ) ;
await expect ( async ( ) = > {
2023-06-05 22:19:25 +03:00
const traceName = fs . readdirSync ( dir ) . find ( name = > name . endsWith ( testId + '.trace' ) ) ;
2023-05-17 04:44:27 +03:00
const content = await fs . promises . readFile ( path . join ( dir , traceName ) , 'utf8' ) ;
expect ( content ) . toContain ( 'hello 0' ) ;
expect ( content ) . toContain ( 'hello 99' ) ;
} ) . toPass ( ) ;
} ) ;
test ( 'should flush console events on tracing stop' , async ( { context , page } , testInfo ) = > {
await context . tracing . start ( ) ;
const promise = new Promise < void > ( f = > {
let counter = 0 ;
page . on ( 'console' , ( ) = > {
if ( ++ counter === 100 )
f ( ) ;
} ) ;
} ) ;
await page . evaluate ( ( ) = > {
setTimeout ( ( ) = > {
for ( let i = 0 ; i < 100 ; ++ i )
console . log ( 'hello ' + i ) ;
} ) ;
} ) ;
await promise ;
const tracePath = testInfo . outputPath ( 'trace.zip' ) ;
await context . tracing . stop ( { path : tracePath } ) ;
const trace = await parseTraceRaw ( tracePath ) ;
const events = trace . events . filter ( e = > e . method === 'console' ) ;
expect ( events ) . toHaveLength ( 100 ) ;
} ) ;
2022-06-22 19:13:29 +03:00
2023-07-08 03:16:26 +03:00
test ( 'should not emit after w/o before' , async ( { browserType , mode } , testInfo ) = > {
2023-07-26 02:47:04 +03:00
test . skip ( mode . startsWith ( 'service' ) , 'Service ignores tracesDir' ) ;
2023-07-08 03:16:26 +03:00
const tracesDir = testInfo . outputPath ( 'traces' ) ;
const browser = await browserType . launch ( { tracesDir } ) ;
const context = await browser . newContext ( ) ;
const page = await context . newPage ( ) ;
await context . tracing . start ( { name : 'name1' , snapshots : true } ) ;
2023-07-26 16:50:38 +03:00
const evaluatePromise = page . evaluate ( ( ) = > {
console . log ( 'started' ) ;
return new Promise ( f = > ( window as any ) . callback = f ) ;
} ) . catch ( ( ) = > { } ) ;
await page . waitForEvent ( 'console' ) ;
2023-07-08 03:16:26 +03:00
await context . tracing . stopChunk ( { path : testInfo.outputPath ( 'trace1.zip' ) } ) ;
expect ( fs . existsSync ( path . join ( tracesDir , 'name1.trace' ) ) ) . toBe ( true ) ;
await context . tracing . startChunk ( { name : 'name2' } ) ;
await page . evaluateHandle ( ( ) = > ( window as any ) . callback ( ) ) ;
await evaluatePromise ;
await context . tracing . stop ( { path : testInfo.outputPath ( 'trace2.zip' ) } ) ;
expect ( fs . existsSync ( path . join ( tracesDir , 'name2.trace' ) ) ) . toBe ( true ) ;
await browser . close ( ) ;
let minCallId = 100000 ;
const sanitize = ( e : any ) = > {
if ( e . type === 'after' || e . type === 'before' ) {
minCallId = Math . min ( minCallId , + e . callId . split ( '@' ) [ 1 ] ) ;
return {
type : e . type ,
callId : + e . callId . split ( '@' ) [ 1 ] - minCallId ,
apiName : e.apiName ,
} ;
}
} ;
2023-07-11 04:36:15 +03:00
let call1 : number ;
2023-07-08 03:16:26 +03:00
{
const { events } = await parseTraceRaw ( testInfo . outputPath ( 'trace1.zip' ) ) ;
2023-07-26 16:50:38 +03:00
const sanitized = events . map ( sanitize ) . filter ( Boolean ) ;
expect ( sanitized ) . toEqual ( [
2023-07-08 03:16:26 +03:00
{
type : 'before' ,
2023-07-11 04:36:15 +03:00
callId : expect.any ( Number ) ,
2023-07-08 03:16:26 +03:00
apiName : 'page.evaluate'
2023-07-26 16:50:38 +03:00
} ,
{
type : 'before' ,
callId : expect.any ( Number ) ,
apiName : 'page.waitForEvent'
} ,
{
type : 'after' ,
callId : expect.any ( Number ) ,
apiName : undefined ,
} ,
2023-07-08 03:16:26 +03:00
] ) ;
2023-07-26 16:50:38 +03:00
call1 = sanitized [ 0 ] . callId ;
expect ( sanitized [ 1 ] . callId ) . toBe ( sanitized [ 2 ] . callId ) ;
2023-07-08 03:16:26 +03:00
}
2023-07-11 04:36:15 +03:00
let call2before : number ;
let call2after : number ;
2023-07-08 03:16:26 +03:00
{
const { events } = await parseTraceRaw ( testInfo . outputPath ( 'trace2.zip' ) ) ;
2023-07-26 16:50:38 +03:00
const sanitized = events . map ( sanitize ) . filter ( Boolean ) ;
expect ( sanitized ) . toEqual ( [
2023-07-08 03:16:26 +03:00
{
type : 'before' ,
2023-07-11 04:36:15 +03:00
callId : expect.any ( Number ) ,
2023-07-08 03:16:26 +03:00
apiName : 'page.evaluateHandle'
} ,
{
type : 'after' ,
2023-07-11 04:36:15 +03:00
callId : expect.any ( Number ) ,
2023-07-08 03:16:26 +03:00
apiName : undefined
}
] ) ;
2023-07-26 16:50:38 +03:00
call2before = sanitized [ 0 ] . callId ;
call2after = sanitized [ 1 ] . callId ;
2023-07-08 03:16:26 +03:00
}
2023-07-11 04:36:15 +03:00
expect ( call2before ) . toBeGreaterThan ( call1 ) ;
expect ( call2after ) . toBe ( call2before ) ;
2023-07-08 03:16:26 +03:00
} ) ;
2021-05-11 23:21:01 +03:00
function expectRed ( pixels : Buffer , offset : number ) {
const r = pixels . readUInt8 ( offset ) ;
const g = pixels . readUInt8 ( offset + 1 ) ;
const b = pixels . readUInt8 ( offset + 2 ) ;
const a = pixels . readUInt8 ( offset + 3 ) ;
expect ( r ) . toBeGreaterThan ( 200 ) ;
expect ( g ) . toBeLessThan ( 70 ) ;
expect ( b ) . toBeLessThan ( 70 ) ;
expect ( a ) . toBe ( 255 ) ;
}
function expectBlue ( pixels : Buffer , offset : number ) {
const r = pixels . readUInt8 ( offset ) ;
const g = pixels . readUInt8 ( offset + 1 ) ;
const b = pixels . readUInt8 ( offset + 2 ) ;
const a = pixels . readUInt8 ( offset + 3 ) ;
expect ( r ) . toBeLessThan ( 70 ) ;
expect ( g ) . toBeLessThan ( 70 ) ;
expect ( b ) . toBeGreaterThan ( 200 ) ;
expect ( a ) . toBe ( 255 ) ;
}
2021-10-25 21:49:59 +03:00
2023-02-28 02:29:20 +03:00
function relativeStack ( action : ActionTraceEvent , stacks : Map < string , StackFrame [ ] > ) : string [ ] {
const stack = stacks . get ( action . callId ) || [ ] ;
2023-02-23 08:08:47 +03:00
return stack . map ( f = > f . file . replace ( __dirname + path . sep , '' ) ) ;
2021-10-25 21:49:59 +03:00
}