| 
									
										
										
										
											2021-06-29 22:35:50 -07: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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-06 13:57:14 -08:00
										 |  |  | import type { TraceViewerFixtures } from '../config/traceViewerFixtures'; | 
					
						
							|  |  |  | import { traceViewerFixtures } from '../config/traceViewerFixtures'; | 
					
						
							| 
									
										
										
										
											2021-11-08 18:03:10 -08:00
										 |  |  | import fs from 'fs'; | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  | import path from 'path'; | 
					
						
							| 
									
										
										
										
											2022-04-05 15:10:12 -08:00
										 |  |  | import { expect, playwrightTest } from '../config/browserTest'; | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  | import type { FrameLocator } from '@playwright/test'; | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-05 15:10:12 -08:00
										 |  |  | const test = playwrightTest.extend<TraceViewerFixtures>(traceViewerFixtures); | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-26 12:45:53 -08:00
										 |  |  | test.skip(({ trace }) => trace === 'on'); | 
					
						
							| 
									
										
										
										
											2023-08-04 14:59:48 -07:00
										 |  |  | test.skip(({ mode }) => mode.startsWith('service')); | 
					
						
							| 
									
										
										
										
											2021-12-22 11:17:43 -08:00
										 |  |  | test.slow(); | 
					
						
							| 
									
										
										
										
											2021-10-13 19:32:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  | let traceFile: string; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:23:13 -07:00
										 |  |  | test.beforeAll(async function recordTrace({ browser, browserName, browserType, server }, workerInfo) { | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  |   const context = await browser.newContext(); | 
					
						
							| 
									
										
										
										
											2021-11-01 18:57:29 -08:00
										 |  |  |   await context.tracing.start({ name: 'test', screenshots: true, snapshots: true, sources: true }); | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  |   const page = await context.newPage(); | 
					
						
							| 
									
										
										
										
											2023-07-10 12:56:56 -07:00
										 |  |  |   await page.goto(`data:text/html,<!DOCTYPE html><html>Hello world</html>`); | 
					
						
							|  |  |  |   await page.setContent('<!DOCTYPE html><button>Click</button>'); | 
					
						
							| 
									
										
										
										
											2021-09-28 16:02:34 -07:00
										 |  |  |   await expect(page.locator('button')).toHaveText('Click'); | 
					
						
							| 
									
										
										
										
											2023-05-30 17:45:48 +02:00
										 |  |  |   await expect(page.getByTestId('amazing-btn')).toBeHidden(); | 
					
						
							|  |  |  |   await expect(page.getByTestId(/amazing-btn-regex/)).toBeHidden(); | 
					
						
							| 
									
										
										
										
											2021-07-02 16:45:09 -07:00
										 |  |  |   await page.evaluate(({ a }) => { | 
					
						
							| 
									
										
										
										
											2021-07-01 14:31:20 -07:00
										 |  |  |     console.log('Info'); | 
					
						
							|  |  |  |     console.warn('Warning'); | 
					
						
							|  |  |  |     console.error('Error'); | 
					
						
							| 
									
										
										
										
											2021-08-31 21:49:08 -07:00
										 |  |  |     return new Promise(f => { | 
					
						
							|  |  |  |       // Generate exception.
 | 
					
						
							|  |  |  |       setTimeout(() => { | 
					
						
							|  |  |  |         // And then resolve.
 | 
					
						
							|  |  |  |         setTimeout(() => f('return ' + a), 0); | 
					
						
							|  |  |  |         throw new Error('Unhandled exception'); | 
					
						
							|  |  |  |       }, 0); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2021-07-02 16:45:09 -07:00
										 |  |  |   }, { a: 'paramA', b: 4 }); | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-17 22:12:42 +01:00
										 |  |  |   await page.evaluate(() => 1 + 1, null); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  |   async function doClick() { | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  |     await page.getByText('Click').click(); | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  |   } | 
					
						
							|  |  |  |   await doClick(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-30 17:56:48 -07:00
										 |  |  |   await Promise.all([ | 
					
						
							|  |  |  |     page.waitForNavigation(), | 
					
						
							| 
									
										
										
										
											2022-09-08 11:31:02 -07:00
										 |  |  |     page.waitForResponse(server.PREFIX + '/frames/frame.html'), | 
					
						
							| 
									
										
										
										
											2021-09-07 15:23:13 -07:00
										 |  |  |     page.waitForTimeout(200).then(() => page.goto(server.PREFIX + '/frames/frame.html')) | 
					
						
							| 
									
										
										
										
											2021-06-30 17:56:48 -07:00
										 |  |  |   ]); | 
					
						
							| 
									
										
										
										
											2021-08-05 16:04:09 -07:00
										 |  |  |   await page.setViewportSize({ width: 500, height: 600 }); | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Go through instrumentation to exercise reentrant stack traces.
 | 
					
						
							| 
									
										
										
										
											2023-04-28 08:57:43 -07:00
										 |  |  |   const csi = { | 
					
						
							|  |  |  |     onWillCloseBrowserContext: async () => { | 
					
						
							|  |  |  |       await page.hover('body'); | 
					
						
							|  |  |  |       await page.close(); | 
					
						
							|  |  |  |       traceFile = path.join(workerInfo.project.outputDir, String(workerInfo.workerIndex), browserName, 'trace.zip'); | 
					
						
							|  |  |  |       await context.tracing.stop({ path: traceFile }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2023-04-28 08:57:43 -07:00
										 |  |  |   (browserType as any)._instrumentation.addListener(csi); | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  |   await context.close(); | 
					
						
							| 
									
										
										
										
											2023-04-28 08:57:43 -07:00
										 |  |  |   (browserType as any)._instrumentation.removeListener(csi); | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test('should show empty trace viewer', async ({ showTraceViewer }, testInfo) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([testInfo.outputPath()]); | 
					
						
							| 
									
										
										
										
											2021-11-03 10:44:50 -07:00
										 |  |  |   await expect(traceViewer.page).toHaveTitle('Playwright Trace Viewer'); | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 12:45:42 -07:00
										 |  |  | test('should open two trace viewers', async ({ showTraceViewer }, testInfo) => { | 
					
						
							| 
									
										
										
										
											2023-01-27 23:20:25 +01:00
										 |  |  |   const port = testInfo.workerIndex + 48321; | 
					
						
							|  |  |  |   const traceViewer1 = await showTraceViewer([testInfo.outputPath()], { host: 'localhost', port }); | 
					
						
							| 
									
										
										
										
											2022-09-27 12:45:42 -07:00
										 |  |  |   await expect(traceViewer1.page).toHaveTitle('Playwright Trace Viewer'); | 
					
						
							| 
									
										
										
										
											2023-01-27 23:20:25 +01:00
										 |  |  |   const traceViewer2 = await showTraceViewer([testInfo.outputPath()], { host: 'localhost', port }); | 
					
						
							| 
									
										
										
										
											2022-09-27 12:45:42 -07:00
										 |  |  |   await expect(traceViewer2.page).toHaveTitle('Playwright Trace Viewer'); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 23:20:25 +01:00
										 |  |  | test('should open trace viewer on specific host', async ({ showTraceViewer }, testInfo) => { | 
					
						
							|  |  |  |   const traceViewer = await showTraceViewer([testInfo.outputPath()], { host: '127.0.0.1' }); | 
					
						
							|  |  |  |   await expect(traceViewer.page).toHaveTitle('Playwright Trace Viewer'); | 
					
						
							|  |  |  |   await expect(traceViewer.page).toHaveURL(/127.0.0.1/); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  | test('should open simple trace viewer', async ({ showTraceViewer }) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							| 
									
										
										
										
											2021-09-03 12:34:47 -07:00
										 |  |  |   await expect(traceViewer.actionTitles).toHaveText([ | 
					
						
							| 
									
										
										
										
											2021-11-02 11:16:12 -08:00
										 |  |  |     /browserContext.newPage/, | 
					
						
							| 
									
										
										
										
											2023-07-10 12:56:56 -07:00
										 |  |  |     /page.gotodata:text\/html,<!DOCTYPE html><html>Hello world<\/html>/, | 
					
						
							| 
									
										
										
										
											2021-11-02 11:16:12 -08:00
										 |  |  |     /page.setContent/, | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  |     /expect.toHaveTextlocator\('button'\)/, | 
					
						
							| 
									
										
										
										
											2023-05-30 17:45:48 +02:00
										 |  |  |     /expect.toBeHiddengetByTestId\('amazing-btn'\)/, | 
					
						
							|  |  |  |     /expect.toBeHiddengetByTestId\(\/amazing-btn-regex\/\)/, | 
					
						
							| 
									
										
										
										
											2021-11-02 11:16:12 -08:00
										 |  |  |     /page.evaluate/, | 
					
						
							| 
									
										
										
										
											2022-02-17 22:12:42 +01:00
										 |  |  |     /page.evaluate/, | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  |     /locator.clickgetByText\('Click'\)/, | 
					
						
							| 
									
										
										
										
											2021-11-02 11:16:12 -08:00
										 |  |  |     /page.waitForNavigation/, | 
					
						
							| 
									
										
										
										
											2022-09-08 11:31:02 -07:00
										 |  |  |     /page.waitForResponse/, | 
					
						
							| 
									
										
										
										
											2021-11-02 11:16:12 -08:00
										 |  |  |     /page.waitForTimeout/, | 
					
						
							|  |  |  |     /page.gotohttp:\/\/localhost:\d+\/frames\/frame.html/, | 
					
						
							|  |  |  |     /page.setViewportSize/, | 
					
						
							| 
									
										
										
										
											2021-06-30 17:56:48 -07:00
										 |  |  |   ]); | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-02 14:33:38 -07:00
										 |  |  | test('should contain action info', async ({ showTraceViewer }) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  |   await traceViewer.selectAction('locator.click'); | 
					
						
							| 
									
										
										
										
											2023-09-01 20:12:05 -07:00
										 |  |  |   await traceViewer.page.getByText('Log', { exact: true }).click(); | 
					
						
							| 
									
										
										
										
											2023-10-26 14:45:15 -07:00
										 |  |  |   await expect(traceViewer.logLines).toContainText([ | 
					
						
							|  |  |  |     /\d+m?sattempting click action/, | 
					
						
							|  |  |  |     /\d+m?s  click action done/, | 
					
						
							|  |  |  |   ]); | 
					
						
							| 
									
										
										
										
											2021-06-29 22:35:50 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-06-30 17:56:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-16 16:30:17 -07:00
										 |  |  | test('should render network bars', async ({ page, runAndTrace, server }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await expect(traceViewer.page.locator('.timeline-bar.network')).toHaveCount(1); | 
					
						
							| 
									
										
										
										
											2021-06-30 17:56:48 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-07-01 14:31:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should render console', async ({ showTraceViewer, browserName }) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  |   await traceViewer.showConsoleTab(); | 
					
						
							| 
									
										
										
										
											2021-07-01 14:31:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-31 11:24:04 -07:00
										 |  |  |   await expect(traceViewer.consoleLineMessages.nth(0)).toHaveText('Info'); | 
					
						
							|  |  |  |   await expect(traceViewer.consoleLineMessages.nth(1)).toHaveText('Warning'); | 
					
						
							|  |  |  |   await expect(traceViewer.consoleLineMessages.nth(2)).toHaveText('Error'); | 
					
						
							|  |  |  |   await expect(traceViewer.consoleLineMessages.nth(3)).toHaveText('Unhandled exception'); | 
					
						
							| 
									
										
										
										
											2023-10-10 09:14:58 -07:00
										 |  |  |   // Browsers can insert more messages between these two.
 | 
					
						
							|  |  |  |   await expect(traceViewer.consoleLineMessages.filter({ hasText: 'Cheers!' })).toBeVisible(); | 
					
						
							| 
									
										
										
										
											2023-07-31 11:24:04 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const icons = traceViewer.consoleLines.locator('.codicon'); | 
					
						
							| 
									
										
										
										
											2023-08-21 16:05:27 -07:00
										 |  |  |   await expect.soft(icons.nth(0)).toHaveClass('codicon codicon-browser status-none'); | 
					
						
							|  |  |  |   await expect.soft(icons.nth(1)).toHaveClass('codicon codicon-browser status-warning'); | 
					
						
							|  |  |  |   await expect.soft(icons.nth(2)).toHaveClass('codicon codicon-browser status-error'); | 
					
						
							|  |  |  |   await expect.soft(icons.nth(3)).toHaveClass('codicon codicon-browser status-error'); | 
					
						
							| 
									
										
										
										
											2023-10-10 09:14:58 -07:00
										 |  |  |   // Browsers can insert more messages between these two.
 | 
					
						
							|  |  |  |   await expect.soft(traceViewer.consoleLines.filter({ hasText: 'Cheers!' }).locator('.codicon')).toHaveClass('codicon codicon-browser status-none'); | 
					
						
							| 
									
										
										
										
											2021-08-31 21:49:08 -07:00
										 |  |  |   await expect(traceViewer.consoleStacks.first()).toContainText('Error: Unhandled exception'); | 
					
						
							| 
									
										
										
										
											2023-07-10 12:56:56 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   await traceViewer.selectAction('page.evaluate'); | 
					
						
							| 
									
										
										
										
											2023-07-31 11:24:04 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const listViews = traceViewer.page.locator('.console-tab').locator('.list-view-entry'); | 
					
						
							| 
									
										
										
										
											2023-08-16 16:30:17 -07:00
										 |  |  |   await expect(listViews.nth(0)).toHaveClass('list-view-entry'); | 
					
						
							|  |  |  |   await expect(listViews.nth(1)).toHaveClass('list-view-entry warning'); | 
					
						
							|  |  |  |   await expect(listViews.nth(2)).toHaveClass('list-view-entry error'); | 
					
						
							|  |  |  |   await expect(listViews.nth(3)).toHaveClass('list-view-entry error'); | 
					
						
							| 
									
										
										
										
											2023-10-10 09:14:58 -07:00
										 |  |  |   // Browsers can insert more messages between these two.
 | 
					
						
							|  |  |  |   await expect(listViews.filter({ hasText: 'Cheers!' })).toHaveClass('list-view-entry'); | 
					
						
							| 
									
										
										
										
											2021-07-01 14:31:20 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-07-01 20:46:56 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should open console errors on click', async ({ showTraceViewer, browserName }) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							| 
									
										
										
										
											2021-07-01 20:46:56 -07:00
										 |  |  |   expect(await traceViewer.actionIconsText('page.evaluate')).toEqual(['2', '1']); | 
					
						
							| 
									
										
										
										
											2021-08-05 16:04:09 -07:00
										 |  |  |   expect(await traceViewer.page.isHidden('.console-tab')).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2021-07-01 20:46:56 -07:00
										 |  |  |   await (await traceViewer.actionIcons('page.evaluate')).click(); | 
					
						
							| 
									
										
										
										
											2021-08-05 16:04:09 -07:00
										 |  |  |   expect(await traceViewer.page.waitForSelector('.console-tab')).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2021-07-01 20:46:56 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-07-02 16:45:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-16 07:59:21 -08:00
										 |  |  | test('should show params and return value', async ({ showTraceViewer }) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							| 
									
										
										
										
											2021-08-05 16:04:09 -07:00
										 |  |  |   await traceViewer.selectAction('page.evaluate'); | 
					
						
							| 
									
										
										
										
											2021-09-03 12:34:47 -07:00
										 |  |  |   await expect(traceViewer.callLines).toHaveText([ | 
					
						
							| 
									
										
										
										
											2021-11-02 11:16:12 -08:00
										 |  |  |     /page.evaluate/, | 
					
						
							| 
									
										
										
										
											2023-02-16 07:59:21 -08:00
										 |  |  |     /wall time:[0-9/:,APM ]+/, | 
					
						
							|  |  |  |     /duration:[\d]+ms/, | 
					
						
							|  |  |  |     /expression:"\({↵    a↵  }\) => {↵    console\.log\(\'Info\'\);↵    console\.warn\(\'Warning\'\);↵    console/, | 
					
						
							|  |  |  |     'isFunction:true', | 
					
						
							|  |  |  |     'arg:{"a":"paramA","b":4}', | 
					
						
							|  |  |  |     'value:"return paramA"' | 
					
						
							| 
									
										
										
										
											2021-07-02 16:45:09 -07:00
										 |  |  |   ]); | 
					
						
							| 
									
										
										
										
											2023-01-05 16:59:50 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   await traceViewer.selectAction(`locator('button')`); | 
					
						
							|  |  |  |   await expect(traceViewer.callLines).toContainText([ | 
					
						
							|  |  |  |     /expect.toHaveText/, | 
					
						
							| 
									
										
										
										
											2023-02-16 07:59:21 -08:00
										 |  |  |     /wall time:[0-9/:,APM ]+/, | 
					
						
							|  |  |  |     /duration:[\d]+ms/, | 
					
						
							|  |  |  |     /locator:locator\('button'\)/, | 
					
						
							|  |  |  |     /expression:"to.have.text"/, | 
					
						
							|  |  |  |     /timeout:10000/, | 
					
						
							|  |  |  |     /matches:true/, | 
					
						
							|  |  |  |     /received:"Click"/, | 
					
						
							| 
									
										
										
										
											2023-01-05 16:59:50 -08:00
										 |  |  |   ]); | 
					
						
							| 
									
										
										
										
											2021-07-02 16:45:09 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-08-05 16:04:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-17 22:12:42 +01:00
										 |  |  | test('should show null as a param', async ({ showTraceViewer, browserName }) => { | 
					
						
							|  |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							|  |  |  |   await traceViewer.selectAction('page.evaluate', 1); | 
					
						
							|  |  |  |   await expect(traceViewer.callLines).toHaveText([ | 
					
						
							|  |  |  |     /page.evaluate/, | 
					
						
							| 
									
										
										
										
											2023-02-16 07:59:21 -08:00
										 |  |  |     /wall time:[0-9/:,APM ]+/, | 
					
						
							|  |  |  |     /duration:[\d]+ms/, | 
					
						
							|  |  |  |     'expression:"() => 1 + 1"', | 
					
						
							|  |  |  |     'isFunction:true', | 
					
						
							|  |  |  |     'arg:null', | 
					
						
							|  |  |  |     'value:2' | 
					
						
							| 
									
										
										
										
											2022-02-17 22:12:42 +01:00
										 |  |  |   ]); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-23 11:40:55 -07:00
										 |  |  | test('should have correct snapshot size', async ({ showTraceViewer }, testInfo) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							| 
									
										
										
										
											2021-08-05 16:04:09 -07:00
										 |  |  |   await traceViewer.selectAction('page.setViewport'); | 
					
						
							|  |  |  |   await traceViewer.selectSnapshot('Before'); | 
					
						
							| 
									
										
										
										
											2021-09-23 11:40:55 -07:00
										 |  |  |   await expect(traceViewer.snapshotContainer).toHaveCSS('width', '1280px'); | 
					
						
							|  |  |  |   await expect(traceViewer.snapshotContainer).toHaveCSS('height', '720px'); | 
					
						
							| 
									
										
										
										
											2021-08-05 16:04:09 -07:00
										 |  |  |   await traceViewer.selectSnapshot('After'); | 
					
						
							| 
									
										
										
										
											2021-09-23 11:40:55 -07:00
										 |  |  |   await expect(traceViewer.snapshotContainer).toHaveCSS('width', '500px'); | 
					
						
							|  |  |  |   await expect(traceViewer.snapshotContainer).toHaveCSS('height', '600px'); | 
					
						
							| 
									
										
										
										
											2021-08-05 16:04:09 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should have correct stack trace', async ({ showTraceViewer }) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  |   await traceViewer.selectAction('locator.click'); | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  |   await traceViewer.showSourceTab(); | 
					
						
							| 
									
										
										
										
											2021-09-27 11:14:35 -07:00
										 |  |  |   await expect(traceViewer.stackFrames).toContainText([ | 
					
						
							|  |  |  |     /doClick\s+trace-viewer.spec.ts\s+:\d+/, | 
					
						
							|  |  |  |     /recordTrace\s+trace-viewer.spec.ts\s+:\d+/, | 
					
						
							|  |  |  |   ], { useInnerText: true }); | 
					
						
							| 
									
										
										
										
											2021-08-16 17:06:38 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:23:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should have network requests', async ({ showTraceViewer }) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:23:13 -07:00
										 |  |  |   await traceViewer.selectAction('http://localhost'); | 
					
						
							|  |  |  |   await traceViewer.showNetworkTab(); | 
					
						
							| 
									
										
										
										
											2024-01-10 15:28:33 -08:00
										 |  |  |   await expect(traceViewer.networkRequests).toContainText([/frame.htmlGET200text\/html/]); | 
					
						
							|  |  |  |   await expect(traceViewer.networkRequests).toContainText([/style.cssGET200text\/css/]); | 
					
						
							| 
									
										
										
										
											2024-02-01 13:44:26 -08:00
										 |  |  |   await expect(traceViewer.networkRequests).toContainText([/404GET404text\/plain/]); | 
					
						
							| 
									
										
										
										
											2024-01-10 15:28:33 -08:00
										 |  |  |   await expect(traceViewer.networkRequests).toContainText([/script.jsGET200application\/javascript/]); | 
					
						
							| 
									
										
										
										
											2024-02-01 13:44:26 -08:00
										 |  |  |   await expect(traceViewer.networkRequests.filter({ hasText: '404' })).toHaveCSS('background-color', 'rgb(242, 222, 222)'); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:23:13 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-06 16:55:53 -07:00
										 |  |  | test('should have network request overrides', async ({ page, server, runAndTrace }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.route('**/style.css', route => route.abort()); | 
					
						
							|  |  |  |     await page.goto(server.PREFIX + '/frames/frame.html'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await traceViewer.selectAction('http://localhost'); | 
					
						
							|  |  |  |   await traceViewer.showNetworkTab(); | 
					
						
							| 
									
										
										
										
											2024-01-10 15:28:33 -08:00
										 |  |  |   await expect(traceViewer.networkRequests).toContainText([/frame.htmlGET200text\/html/]); | 
					
						
							|  |  |  |   await expect(traceViewer.networkRequests).toContainText([/style.cssGETx-unknown.*aborted/]); | 
					
						
							| 
									
										
										
										
											2023-06-14 09:37:19 -07:00
										 |  |  |   await expect(traceViewer.networkRequests).not.toContainText([/continued/]); | 
					
						
							| 
									
										
										
										
											2023-06-06 16:55:53 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test('should have network request overrides 2', async ({ page, server, runAndTrace }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.route('**/script.js', route => route.continue()); | 
					
						
							|  |  |  |     await page.goto(server.PREFIX + '/frames/frame.html'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await traceViewer.selectAction('http://localhost'); | 
					
						
							|  |  |  |   await traceViewer.showNetworkTab(); | 
					
						
							| 
									
										
										
										
											2024-01-10 15:28:33 -08:00
										 |  |  |   await expect.soft(traceViewer.networkRequests).toContainText([/frame.htmlGET200text\/html.*/]); | 
					
						
							|  |  |  |   await expect.soft(traceViewer.networkRequests).toContainText([/script.jsGET200application\/javascript.*continued/]); | 
					
						
							| 
									
										
										
										
											2023-06-06 16:55:53 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-02 16:35:23 -08:00
										 |  |  | test('should show snapshot URL', async ({ page, runAndTrace, server }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     await page.evaluate('2+2'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await traceViewer.snapshotFrame('page.evaluate'); | 
					
						
							| 
									
										
										
										
											2023-08-18 17:53:03 -07:00
										 |  |  |   await expect(traceViewer.page.locator('.browser-frame-address-bar')).toHaveText(server.EMPTY_PAGE); | 
					
						
							| 
									
										
										
										
											2021-11-02 16:35:23 -08:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-30 19:07:52 -08:00
										 |  |  | test('should popup snapshot', async ({ page, runAndTrace, server }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     await page.setContent('hello'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await traceViewer.snapshotFrame('page.setContent'); | 
					
						
							|  |  |  |   const popupPromise = traceViewer.page.context().waitForEvent('page'); | 
					
						
							|  |  |  |   await traceViewer.page.getByTitle('Open snapshot in a new tab').click(); | 
					
						
							|  |  |  |   const popup = await popupPromise; | 
					
						
							|  |  |  |   await expect(popup.getByText('hello')).toBeVisible(); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-09 17:10:31 -08:00
										 |  |  | test('should capture iframe with sandbox attribute', async ({ page, server, runAndTrace }) => { | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  |   await page.route('**/empty.html', route => { | 
					
						
							| 
									
										
										
										
											2023-06-02 21:59:12 +02:00
										 |  |  |     void route.fulfill({ | 
					
						
							| 
									
										
										
										
											2021-12-09 17:10:31 -08:00
										 |  |  |       body: '<iframe src="iframe.html" sandBOX="allow-scripts"></iframe>', | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  |       contentType: 'text/html' | 
					
						
							|  |  |  |     }).catch(() => {}); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await page.route('**/iframe.html', route => { | 
					
						
							| 
									
										
										
										
											2023-06-02 21:59:12 +02:00
										 |  |  |     void route.fulfill({ | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  |       body: '<html><button>Hello iframe</button></html>', | 
					
						
							|  |  |  |       contentType: 'text/html' | 
					
						
							|  |  |  |     }).catch(() => {}); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     if (page.frames().length < 2) | 
					
						
							|  |  |  |       await page.waitForEvent('frameattached'); | 
					
						
							|  |  |  |     await page.frames()[1].waitForSelector('button'); | 
					
						
							|  |  |  |     // Force snapshot.
 | 
					
						
							|  |  |  |     await page.evaluate('2+2'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render snapshot, check expectations.
 | 
					
						
							|  |  |  |   const snapshotFrame = await traceViewer.snapshotFrame('page.evaluate', 0, true); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |   const button = snapshotFrame.frameLocator('iframe').locator('button'); | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  |   expect(await button.textContent()).toBe('Hello iframe'); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-09 17:10:31 -08:00
										 |  |  | test('should capture data-url svg iframe', async ({ page, server, runAndTrace }) => { | 
					
						
							|  |  |  |   await page.route('**/empty.html', route => { | 
					
						
							| 
									
										
										
										
											2023-06-02 21:59:12 +02:00
										 |  |  |     void route.fulfill({ | 
					
						
							| 
									
										
										
										
											2021-12-09 17:10:31 -08:00
										 |  |  |       body: `<iframe src="data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3e%3cpath d='M0 0h24v24H0z' fill='none'/%3e%3cpath d='M16.5 3c-1.74 0-3.41.81-4.5 2.09C10.91 3.81 9.24 3 7.5 3 4.42 3 2 5.42 2 8.5c0 3.78 3.4 6.86 8.55 11.54L12 21.35l1.45-1.32C18.6 15.36 22 12.28 22 8.5 22 5.42 19.58 3 16.5 3zm-4.4 15.55l-.1.1-.1-.1C7.14 14.24 4 11.39 4 8.5 4 6.5 5.5 5 7.5 5c1.54 0 3.04.99 3.57 2.36h1.87C13.46 5.99 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5 0 2.89-3.14 5.74-7.9 10.05z'/%3e%3c/svg%3e"></iframe>`, | 
					
						
							|  |  |  |       contentType: 'text/html' | 
					
						
							|  |  |  |     }).catch(() => {}); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     if (page.frames().length < 2) | 
					
						
							|  |  |  |       await page.waitForEvent('frameattached'); | 
					
						
							|  |  |  |     await page.frames()[1].waitForSelector('svg'); | 
					
						
							|  |  |  |     // Force snapshot.
 | 
					
						
							|  |  |  |     await page.evaluate('2+2'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render snapshot, check expectations.
 | 
					
						
							|  |  |  |   const snapshotFrame = await traceViewer.snapshotFrame('page.evaluate', 0, true); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |   await expect(snapshotFrame.frameLocator('iframe').locator('svg')).toBeVisible(); | 
					
						
							|  |  |  |   const content = await snapshotFrame.frameLocator('iframe').locator(':root').innerHTML(); | 
					
						
							| 
									
										
										
										
											2021-12-09 17:10:31 -08:00
										 |  |  |   expect(content).toContain(`d="M16.5 3c-1.74 0-3.41.81-4.5 2.09C10.91 3.81 9.24 3 7.5 3 4.42 3 2 5.42 2 8.5c0 3.78 3.4 6.86 8.55 11.54L12 21.35l1.45-1.32C18.6 15.36 22 12.28 22 8.5 22 5.42 19.58 3 16.5 3zm-4.4 15.55l-.1.1-.1-.1C7.14 14.24 4 11.39 4 8.5 4 6.5 5.5 5 7.5 5c1.54 0 3.04.99 3.57 2.36h1.87C13.46 5.99 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5 0 2.89-3.14 5.74-7.9 10.05z"`); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  | test('should contain adopted style sheets', async ({ page, runAndTrace, browserName }) => { | 
					
						
							|  |  |  |   test.skip(browserName !== 'chromium', 'Constructed stylesheets are only in Chromium.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.setContent('<button>Hello</button>'); | 
					
						
							|  |  |  |     await page.evaluate(() => { | 
					
						
							|  |  |  |       const sheet = new CSSStyleSheet(); | 
					
						
							|  |  |  |       sheet.addRule('button', 'color: red'); | 
					
						
							|  |  |  |       (document as any).adoptedStyleSheets = [sheet]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const sheet2 = new CSSStyleSheet(); | 
					
						
							|  |  |  |       sheet2.addRule(':host', 'color: blue'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       for (const element of [document.createElement('div'), document.createElement('span')]) { | 
					
						
							|  |  |  |         const root = element.attachShadow({ | 
					
						
							|  |  |  |           mode: 'open' | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         root.append('foo'); | 
					
						
							|  |  |  |         (root as any).adoptedStyleSheets = [sheet2]; | 
					
						
							|  |  |  |         document.body.appendChild(element); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const frame = await traceViewer.snapshotFrame('page.evaluate'); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |   await expect(frame.locator('button')).toHaveCSS('color', 'rgb(255, 0, 0)'); | 
					
						
							|  |  |  |   await expect(frame.locator('div')).toHaveCSS('color', 'rgb(0, 0, 255)'); | 
					
						
							|  |  |  |   await expect(frame.locator('span')).toHaveCSS('color', 'rgb(0, 0, 255)'); | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test('should work with adopted style sheets and replace/replaceSync', async ({ page, runAndTrace, browserName }) => { | 
					
						
							|  |  |  |   test.skip(browserName !== 'chromium', 'Constructed stylesheets are only in Chromium.'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.setContent('<button>Hello</button>'); | 
					
						
							|  |  |  |     await page.evaluate(() => { | 
					
						
							|  |  |  |       const sheet = new CSSStyleSheet(); | 
					
						
							|  |  |  |       sheet.addRule('button', 'color: red'); | 
					
						
							|  |  |  |       (document as any).adoptedStyleSheets = [sheet]; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     await page.evaluate(() => { | 
					
						
							|  |  |  |       const [sheet] = (document as any).adoptedStyleSheets; | 
					
						
							|  |  |  |       sheet.replaceSync(`button { color: blue }`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     await page.evaluate(() => { | 
					
						
							|  |  |  |       const [sheet] = (document as any).adoptedStyleSheets; | 
					
						
							|  |  |  |       sheet.replace(`button { color: #0F0 }`); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     const frame = await traceViewer.snapshotFrame('page.evaluate', 0); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |     await expect(frame.locator('button')).toHaveCSS('color', 'rgb(255, 0, 0)'); | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  |   } | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     const frame = await traceViewer.snapshotFrame('page.evaluate', 1); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |     await expect(frame.locator('button')).toHaveCSS('color', 'rgb(0, 0, 255)'); | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  |   } | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     const frame = await traceViewer.snapshotFrame('page.evaluate', 2); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |     await expect(frame.locator('button')).toHaveCSS('color', 'rgb(0, 255, 0)'); | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test('should restore scroll positions', async ({ page, runAndTrace, browserName }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.setContent(`
 | 
					
						
							|  |  |  |       <style> | 
					
						
							|  |  |  |         li { height: 20px; margin: 0; padding: 0; } | 
					
						
							|  |  |  |         div { height: 60px; overflow-x: hidden; overflow-y: scroll; background: green; padding: 0; margin: 0; } | 
					
						
							|  |  |  |       </style> | 
					
						
							|  |  |  |       <div> | 
					
						
							|  |  |  |         <ul> | 
					
						
							|  |  |  |           <li>Item 1</li> | 
					
						
							|  |  |  |           <li>Item 2</li> | 
					
						
							|  |  |  |           <li>Item 3</li> | 
					
						
							|  |  |  |           <li>Item 4</li> | 
					
						
							|  |  |  |           <li>Item 5</li> | 
					
						
							|  |  |  |           <li>Item 6</li> | 
					
						
							|  |  |  |           <li>Item 7</li> | 
					
						
							|  |  |  |           <li>Item 8</li> | 
					
						
							|  |  |  |           <li>Item 9</li> | 
					
						
							|  |  |  |           <li>Item 10</li> | 
					
						
							|  |  |  |         </ul> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     `);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     await (await page.$('text=Item 8')).scrollIntoViewIfNeeded(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render snapshot, check expectations.
 | 
					
						
							|  |  |  |   const frame = await traceViewer.snapshotFrame('scrollIntoViewIfNeeded'); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |   expect(await frame.locator('div').evaluate(div => div.scrollTop)).toBe(136); | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-01 09:38:50 -08:00
										 |  |  | test('should restore control values', async ({ page, runAndTrace, asset }) => { | 
					
						
							| 
									
										
										
										
											2022-03-21 18:51:48 -07:00
										 |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.setContent(`
 | 
					
						
							|  |  |  |       <input type=text value=old> | 
					
						
							|  |  |  |       <input type=checkbox checked> | 
					
						
							|  |  |  |       <input type=radio> | 
					
						
							| 
									
										
										
										
											2023-12-01 09:38:50 -08:00
										 |  |  |       <input type=file> | 
					
						
							| 
									
										
										
										
											2022-03-21 18:51:48 -07:00
										 |  |  |       <textarea>old</textarea> | 
					
						
							|  |  |  |       <select multiple> | 
					
						
							|  |  |  |         <option value=opt1>Hi</option> | 
					
						
							|  |  |  |         <option value=opt2 selected>Bye</option> | 
					
						
							|  |  |  |         <option value=opt3>Hello</option> | 
					
						
							|  |  |  |       </select> | 
					
						
							|  |  |  |       <script> | 
					
						
							|  |  |  |         document.querySelector('[type=text]').value = 'hi'; | 
					
						
							|  |  |  |         document.querySelector('[type=checkbox]').checked = false; | 
					
						
							|  |  |  |         document.querySelector('[type=radio]').checked = true; | 
					
						
							|  |  |  |         document.querySelector('textarea').value = 'hello'; | 
					
						
							|  |  |  |         document.querySelector('[value=opt1]').selected = true; | 
					
						
							|  |  |  |         document.querySelector('[value=opt2]').selected = false; | 
					
						
							|  |  |  |         document.querySelector('[value=opt3]').selected = true; | 
					
						
							|  |  |  |       </script> | 
					
						
							|  |  |  |     `);
 | 
					
						
							| 
									
										
										
										
											2023-12-01 09:38:50 -08:00
										 |  |  |     await page.locator('input[type="file"]').setInputFiles(asset('file-to-upload.txt')); | 
					
						
							| 
									
										
										
										
											2022-03-21 18:51:48 -07:00
										 |  |  |     await page.click('input'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render snapshot, check expectations.
 | 
					
						
							|  |  |  |   const frame = await traceViewer.snapshotFrame('page.click'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const text = frame.locator('[type=text]'); | 
					
						
							|  |  |  |   await expect(text).toHaveAttribute('value', 'old'); | 
					
						
							|  |  |  |   await expect(text).toHaveValue('hi'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const checkbox = frame.locator('[type=checkbox]'); | 
					
						
							|  |  |  |   await expect(checkbox).not.toBeChecked(); | 
					
						
							|  |  |  |   expect(await checkbox.evaluate(c => c.hasAttribute('checked'))).toBe(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const radio = frame.locator('[type=radio]'); | 
					
						
							|  |  |  |   await expect(radio).toBeChecked(); | 
					
						
							|  |  |  |   expect(await radio.evaluate(c => c.hasAttribute('checked'))).toBe(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const textarea = frame.locator('textarea'); | 
					
						
							|  |  |  |   await expect(textarea).toHaveText('old'); | 
					
						
							|  |  |  |   await expect(textarea).toHaveValue('hello'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |   expect(await frame.locator('option >> nth=0').evaluate(o => o.hasAttribute('selected'))).toBe(false); | 
					
						
							|  |  |  |   expect(await frame.locator('option >> nth=1').evaluate(o => o.hasAttribute('selected'))).toBe(true); | 
					
						
							|  |  |  |   expect(await frame.locator('option >> nth=2').evaluate(o => o.hasAttribute('selected'))).toBe(false); | 
					
						
							|  |  |  |   await expect(frame.locator('select')).toHaveValues(['opt1', 'opt3']); | 
					
						
							| 
									
										
										
										
											2023-12-01 09:38:50 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   await expect(frame.locator('input[type=file]')).toHaveValue(''); | 
					
						
							| 
									
										
										
										
											2022-03-21 18:51:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  | test('should work with meta CSP', async ({ page, runAndTrace, browserName }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.setContent(`
 | 
					
						
							|  |  |  |       <head> | 
					
						
							|  |  |  |         <meta http-equiv="Content-Security-Policy" content="script-src 'none'"> | 
					
						
							|  |  |  |       </head> | 
					
						
							|  |  |  |       <body> | 
					
						
							|  |  |  |         <div>Hello</div> | 
					
						
							|  |  |  |       </body> | 
					
						
							|  |  |  |     `);
 | 
					
						
							|  |  |  |     await page.$eval('div', div => { | 
					
						
							|  |  |  |       const shadow = div.attachShadow({ mode: 'open' }); | 
					
						
							|  |  |  |       const span = document.createElement('span'); | 
					
						
							|  |  |  |       span.textContent = 'World'; | 
					
						
							|  |  |  |       shadow.appendChild(span); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render snapshot, check expectations.
 | 
					
						
							|  |  |  |   const frame = await traceViewer.snapshotFrame('$eval'); | 
					
						
							|  |  |  |   // Should render shadow dom with post-processing script.
 | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |   await expect(frame.locator('span')).toHaveText('World'); | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test('should handle multiple headers', async ({ page, server, runAndTrace, browserName }) => { | 
					
						
							|  |  |  |   server.setRoute('/foo.css', (req, res) => { | 
					
						
							|  |  |  |     res.statusCode = 200; | 
					
						
							|  |  |  |     res.setHeader('vary', ['accepts-encoding', 'accepts-encoding']); | 
					
						
							|  |  |  |     res.end('body { padding: 42px }'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     await page.setContent(`<head><link rel=stylesheet href="/foo.css"></head><body><div>Hello</div></body>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const frame = await traceViewer.snapshotFrame('setContent'); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |   await frame.locator('div').waitFor(); | 
					
						
							|  |  |  |   await expect(frame.locator('body')).toHaveCSS('padding-left', '42px'); | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test('should handle src=blob', async ({ page, server, runAndTrace, browserName }) => { | 
					
						
							|  |  |  |   test.skip(browserName === 'firefox'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.setViewportSize({ width: 300, height: 300 }); | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     await page.evaluate(async () => { | 
					
						
							|  |  |  |       const dataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAASCAQAAADIvofAAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfhBhAPKSstM+EuAAAAvUlEQVQY05WQIW4CYRgF599gEZgeoAKBWIfCNSmVvQMe3wv0ChhIViKwtTQEAYJwhgpISBA0JSxNIdlB7LIGTJ/8kpeZ7wW5TcT9o/QNBtvOrrWMrtg0sSGOFeELbHlCDsQ+ukeYiHNFJPHBDRKlQKVEbFkLUT3AiAxI6VGCXsWXAoQLBUl5E7HjUFwiyI4zf/wWoB3CFnxX5IeGdY8IGU/iwE9jcZrLy4pnEat+FL4hf/cbqREKo/Cf6W5zASVMeh234UtGAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA2LTE2VDE1OjQxOjQzLTA3OjAwd1xNIQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNi0xNlQxNTo0MTo0My0wNzowMAYB9Z0AAAAASUVORK5CYII='; | 
					
						
							|  |  |  |       const blob = await fetch(dataUrl).then(res => res.blob()); | 
					
						
							|  |  |  |       const url = window.URL.createObjectURL(blob); | 
					
						
							|  |  |  |       const img = document.createElement('img'); | 
					
						
							|  |  |  |       img.src = url; | 
					
						
							|  |  |  |       const loaded = new Promise(f => img.onload = f); | 
					
						
							|  |  |  |       document.body.appendChild(img); | 
					
						
							|  |  |  |       await loaded; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const frame = await traceViewer.snapshotFrame('page.evaluate'); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |   const size = await frame.locator('img').evaluate(e => (e as HTMLImageElement).naturalWidth); | 
					
						
							| 
									
										
										
										
											2021-10-12 13:42:50 -08:00
										 |  |  |   expect(size).toBe(10); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 12:48:07 -07:00
										 |  |  | test('should preserve currentSrc', async ({ browser, server, showTraceViewer }) => { | 
					
						
							|  |  |  |   const traceFile = test.info().outputPath('trace.zip'); | 
					
						
							|  |  |  |   const page = await browser.newPage({ deviceScaleFactor: 3 }); | 
					
						
							|  |  |  |   await page.context().tracing.start({ snapshots: true, screenshots: true, sources: true }); | 
					
						
							|  |  |  |   await page.setViewportSize({ width: 300, height: 300 }); | 
					
						
							|  |  |  |   await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |   await page.setContent(`
 | 
					
						
							|  |  |  |     <picture> | 
					
						
							|  |  |  |       <source srcset="digits/1.png 1x, digits/2.png 2x, digits/3.png 3x"> | 
					
						
							|  |  |  |       <img id=target1 src="digits/0.png"> | 
					
						
							|  |  |  |     </picture> | 
					
						
							|  |  |  |     <img id=target2 srcset="digits/4.png 1x, digits/5.png 2x, digits/6.png 3x"> | 
					
						
							|  |  |  |   `);
 | 
					
						
							|  |  |  |   await page.context().tracing.stop({ path: traceFile }); | 
					
						
							|  |  |  |   await page.close(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							|  |  |  |   const frame = await traceViewer.snapshotFrame('page.setContent'); | 
					
						
							|  |  |  |   await expect(frame.locator('#target1')).toHaveAttribute('src', server.PREFIX + '/digits/3.png'); | 
					
						
							|  |  |  |   await expect(frame.locator('#target2')).toHaveAttribute('src', server.PREFIX + '/digits/6.png'); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 21:53:27 -08:00
										 |  |  | test('should register custom elements', async ({ page, server, runAndTrace }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     await page.evaluate(() => { | 
					
						
							|  |  |  |       customElements.define('my-element', class extends HTMLElement { | 
					
						
							|  |  |  |         constructor() { | 
					
						
							|  |  |  |           super(); | 
					
						
							|  |  |  |           const shadow = this.attachShadow({ mode: 'open' }); | 
					
						
							|  |  |  |           const span = document.createElement('span'); | 
					
						
							|  |  |  |           span.textContent = 'hello'; | 
					
						
							|  |  |  |           shadow.appendChild(span); | 
					
						
							|  |  |  |           shadow.appendChild(document.createElement('slot')); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     await page.setContent(`
 | 
					
						
							|  |  |  |       <style> | 
					
						
							|  |  |  |         :not(:defined) { | 
					
						
							|  |  |  |           visibility: hidden; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       </style> | 
					
						
							|  |  |  |       <MY-element>world</MY-element> | 
					
						
							|  |  |  |     `);
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const frame = await traceViewer.snapshotFrame('page.setContent'); | 
					
						
							|  |  |  |   await expect(frame.getByText('worldhello')).toBeVisible(); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  | test('should highlight target elements', async ({ page, runAndTrace, browserName }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.setContent(`
 | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  |       <div>t1</div> | 
					
						
							|  |  |  |       <div>t2</div> | 
					
						
							|  |  |  |       <div>t3</div> | 
					
						
							|  |  |  |       <div>t4</div> | 
					
						
							|  |  |  |       <div>t5</div> | 
					
						
							|  |  |  |       <div>t6</div> | 
					
						
							|  |  |  |       <div>multi</div> | 
					
						
							|  |  |  |       <div>multi</div> | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  |     `);
 | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  |     await page.click('text=t1'); | 
					
						
							|  |  |  |     await page.innerText('text=t2'); | 
					
						
							|  |  |  |     await (await page.$('text=t3')).click(); | 
					
						
							|  |  |  |     await (await page.$('text=t4')).innerText(); | 
					
						
							|  |  |  |     await page.locator('text=t5').innerText(); | 
					
						
							|  |  |  |     await expect(page.locator('text=t6')).toHaveText(/t6/i); | 
					
						
							|  |  |  |     await expect(page.locator('text=multi')).toHaveText(['a', 'b'], { timeout: 1000 }).catch(() => {}); | 
					
						
							| 
									
										
										
										
											2023-12-07 06:27:49 -08:00
										 |  |  |     await page.mouse.move(123, 234); | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  |   async function highlightedDivs(frameLocator: FrameLocator) { | 
					
						
							|  |  |  |     return frameLocator.locator('div').evaluateAll(divs => { | 
					
						
							|  |  |  |       // See snapshotRenderer.ts for the exact color.
 | 
					
						
							|  |  |  |       return divs.filter(div => getComputedStyle(div).backgroundColor === 'rgba(111, 168, 220, 0.498)').map(div => div.textContent); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  |   const framePageClick = await traceViewer.snapshotFrame('page.click'); | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  |   await expect.poll(() => highlightedDivs(framePageClick)).toEqual(['t1']); | 
					
						
							| 
									
										
										
										
											2023-12-07 06:27:49 -08:00
										 |  |  |   const box1 = await framePageClick.getByText('t1').boundingBox(); | 
					
						
							|  |  |  |   const box2 = await framePageClick.locator('x-pw-pointer').boundingBox(); | 
					
						
							|  |  |  |   const x1 = box1!.x + box1!.width / 2; | 
					
						
							|  |  |  |   const y1 = box1!.y + box1!.height / 2; | 
					
						
							|  |  |  |   const x2 = box2!.x + box2!.width / 2; | 
					
						
							|  |  |  |   const y2 = box2!.y + box2!.height / 2; | 
					
						
							|  |  |  |   expect(Math.abs(x1 - x2) < 2).toBeTruthy(); | 
					
						
							|  |  |  |   expect(Math.abs(y1 - y2) < 2).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const framePageInnerText = await traceViewer.snapshotFrame('page.innerText'); | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  |   await expect.poll(() => highlightedDivs(framePageInnerText)).toEqual(['t2']); | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const frameHandleClick = await traceViewer.snapshotFrame('elementHandle.click'); | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  |   await expect.poll(() => highlightedDivs(frameHandleClick)).toEqual(['t3']); | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const frameHandleInnerText = await traceViewer.snapshotFrame('elementHandle.innerText'); | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  |   await expect.poll(() => highlightedDivs(frameHandleInnerText)).toEqual(['t4']); | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const frameLocatorInnerText = await traceViewer.snapshotFrame('locator.innerText'); | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  |   await expect.poll(() => highlightedDivs(frameLocatorInnerText)).toEqual(['t5']); | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const frameExpect1 = await traceViewer.snapshotFrame('expect.toHaveText', 0); | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  |   await expect.poll(() => highlightedDivs(frameExpect1)).toEqual(['t6']); | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const frameExpect2 = await traceViewer.snapshotFrame('expect.toHaveText', 1); | 
					
						
							| 
									
										
										
										
											2023-06-09 07:18:13 -07:00
										 |  |  |   await expect.poll(() => highlightedDivs(frameExpect2)).toEqual(['multi', 'multi']); | 
					
						
							| 
									
										
										
										
											2023-12-07 06:27:49 -08:00
										 |  |  |   await expect(frameExpect2.locator('x-pw-pointer')).not.toBeVisible(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const frameMouseMove = await traceViewer.snapshotFrame('mouse.move'); | 
					
						
							|  |  |  |   await expect(frameMouseMove.locator('x-pw-pointer')).toBeVisible(); | 
					
						
							| 
									
										
										
										
											2021-10-15 15:07:15 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-10-23 10:23:39 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 12:46:49 -07:00
										 |  |  | test('should highlight target element in shadow dom', async ({ page, server, runAndTrace }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.PREFIX + '/shadow.html'); | 
					
						
							|  |  |  |     await page.locator('button').click(); | 
					
						
							|  |  |  |     await expect(page.locator('h1')).toHaveText('Hellow Shadow DOM v1'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const framePageClick = await traceViewer.snapshotFrame('locator.click'); | 
					
						
							|  |  |  |   await expect(framePageClick.locator('button')).toHaveCSS('background-color', 'rgba(111, 168, 220, 0.498)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const frameExpect = await traceViewer.snapshotFrame('expect.toHaveText'); | 
					
						
							|  |  |  |   await expect(frameExpect.locator('h1')).toHaveCSS('background-color', 'rgba(111, 168, 220, 0.498)'); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-02 16:41:08 -08:00
										 |  |  | test('should highlight expect failure', async ({ page, server, runAndTrace }) => { | 
					
						
							|  |  |  |   test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright-python/issues/2258' }); | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |       await expect(page).toHaveTitle('foo', { timeout: 100 }); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await expect(traceViewer.actionTitles.getByText('expect.toHaveTitle')).toHaveCSS('color', 'rgb(176, 16, 17)'); | 
					
						
							|  |  |  |   await traceViewer.showErrorsTab(); | 
					
						
							|  |  |  |   await expect(traceViewer.errorMessages.nth(0)).toHaveText('Expect failed'); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-23 10:23:39 -08:00
										 |  |  | test('should show action source', async ({ showTraceViewer }) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  |   await traceViewer.selectAction('locator.click'); | 
					
						
							| 
									
										
										
										
											2021-10-23 10:23:39 -08:00
										 |  |  |   const page = traceViewer.page; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await page.click('text=Source'); | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  |   await expect(page.locator('.source-line-running')).toContainText('await page.getByText(\'Click\').click()'); | 
					
						
							| 
									
										
										
										
											2023-09-07 17:14:39 -07:00
										 |  |  |   await expect(page.getByTestId('stack-trace-list').locator('.list-view-entry.selected')).toHaveText(/doClick.*trace-viewer\.spec\.ts:[\d]+/); | 
					
						
							| 
									
										
										
										
											2021-10-23 10:23:39 -08:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-11-08 18:03:10 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-23 12:04:44 -07:00
										 |  |  | test('should follow redirects', async ({ page, runAndTrace, server, asset }) => { | 
					
						
							| 
									
										
										
										
											2021-11-08 18:03:10 -08:00
										 |  |  |   server.setRoute('/empty.html', (req, res) => { | 
					
						
							|  |  |  |     res.writeHead(200, { 'Content-Type': 'text/html' }); | 
					
						
							|  |  |  |     res.end(`<div><img id=img src="image.png"></img></div>`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   server.setRoute('/image.png', (req, res) => { | 
					
						
							|  |  |  |     res.writeHead(301, { location: '/image-301.png' }); | 
					
						
							|  |  |  |     res.end(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   server.setRoute('/image-301.png', (req, res) => { | 
					
						
							|  |  |  |     res.writeHead(302, { location: '/image-302.png' }); | 
					
						
							|  |  |  |     res.end(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   server.setRoute('/image-302.png', (req, res) => { | 
					
						
							|  |  |  |     res.writeHead(200, { 'content-type': 'image/png' }); | 
					
						
							|  |  |  |     res.end(fs.readFileSync(asset('digits/0.png'))); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     expect(await page.evaluate(() => (window as any).img.naturalWidth)).toBe(10); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const snapshotFrame = await traceViewer.snapshotFrame('page.evaluate'); | 
					
						
							|  |  |  |   await expect(snapshotFrame.locator('img')).toHaveJSProperty('naturalWidth', 10); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-11-09 22:13:51 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should include metainfo', async ({ showTraceViewer, browserName }) => { | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							| 
									
										
										
										
											2021-11-09 22:13:51 -08:00
										 |  |  |   await traceViewer.page.locator('text=Metadata').click(); | 
					
						
							| 
									
										
										
										
											2023-03-11 11:43:33 -08:00
										 |  |  |   const callLine = traceViewer.page.locator('.metadata-view .call-line'); | 
					
						
							| 
									
										
										
										
											2023-02-16 07:59:21 -08:00
										 |  |  |   await expect(callLine.getByText('start time')).toHaveText(/start time:[\d/,: ]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('duration')).toHaveText(/duration:[\dms]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('engine')).toHaveText(/engine:[\w]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('platform')).toHaveText(/platform:[\w]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('width')).toHaveText(/width:[\d]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('height')).toHaveText(/height:[\d]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('pages')).toHaveText(/pages:1/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('actions')).toHaveText(/actions:[\d]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('events')).toHaveText(/events:[\d]+/); | 
					
						
							| 
									
										
										
										
											2021-11-09 22:13:51 -08:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should open two trace files', async ({ context, page, request, server, showTraceViewer }, testInfo) => { | 
					
						
							|  |  |  |   await (request as any)._tracing.start({ snapshots: true }); | 
					
						
							| 
									
										
										
										
											2024-03-26 10:25:12 -07:00
										 |  |  |   await context.tracing.start({ snapshots: true, sources: true }); | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   { | 
					
						
							|  |  |  |     const response = await request.get(server.PREFIX + '/simple.json'); | 
					
						
							|  |  |  |     await expect(response).toBeOK(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   await page.goto(server.PREFIX + '/input/button.html'); | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     const response = await request.head(server.PREFIX + '/simplezip.json'); | 
					
						
							|  |  |  |     await expect(response).toBeOK(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  |   await page.locator('button').click(); | 
					
						
							|  |  |  |   await page.locator('button').click(); | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   { | 
					
						
							|  |  |  |     const response = await request.post(server.PREFIX + '/one-style.css'); | 
					
						
							| 
									
										
										
										
											2023-06-02 21:59:12 +02:00
										 |  |  |     await expect(response).toBeOK(); | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |   } | 
					
						
							|  |  |  |   const apiTrace = testInfo.outputPath('api.zip'); | 
					
						
							|  |  |  |   const contextTrace = testInfo.outputPath('context.zip'); | 
					
						
							|  |  |  |   await (request as any)._tracing.stop({ path: apiTrace }); | 
					
						
							|  |  |  |   await context.tracing.stop({ path: contextTrace }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await showTraceViewer([contextTrace, apiTrace]); | 
					
						
							|  |  |  |   await traceViewer.selectAction('apiRequestContext.head'); | 
					
						
							|  |  |  |   await traceViewer.selectAction('apiRequestContext.get'); | 
					
						
							|  |  |  |   await traceViewer.selectAction('apiRequestContext.post'); | 
					
						
							|  |  |  |   await expect(traceViewer.actionTitles).toHaveText([ | 
					
						
							|  |  |  |     `apiRequestContext.get`, | 
					
						
							|  |  |  |     `page.gotohttp://localhost:${server.PORT}/input/button.html`, | 
					
						
							|  |  |  |     `apiRequestContext.head`, | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  |     `locator.clicklocator('button')`, | 
					
						
							|  |  |  |     `locator.clicklocator('button')`, | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  |     `apiRequestContext.post`, | 
					
						
							|  |  |  |   ]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await traceViewer.page.locator('text=Metadata').click(); | 
					
						
							|  |  |  |   const callLine = traceViewer.page.locator('.call-line'); | 
					
						
							|  |  |  |   // Should get metadata from the context trace
 | 
					
						
							| 
									
										
										
										
											2023-02-16 07:59:21 -08:00
										 |  |  |   await expect(callLine.getByText('start time')).toHaveText(/start time:[\d/,: ]+/); | 
					
						
							| 
									
										
										
										
											2023-10-04 22:56:42 -04:00
										 |  |  |   // duration in the metadata section
 | 
					
						
							| 
									
										
										
										
											2023-02-16 07:59:21 -08:00
										 |  |  |   await expect(callLine.getByText('duration').first()).toHaveText(/duration:[\dms]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('engine')).toHaveText(/engine:[\w]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('platform')).toHaveText(/platform:[\w]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('width')).toHaveText(/width:[\d]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('height')).toHaveText(/height:[\d]+/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('pages')).toHaveText(/pages:1/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('actions')).toHaveText(/actions:6/); | 
					
						
							|  |  |  |   await expect(callLine.getByText('events')).toHaveText(/events:[\d]+/); | 
					
						
							| 
									
										
										
										
											2022-02-07 17:05:42 -08:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  | test('should include requestUrl in route.fulfill', async ({ page, runAndTrace, browserName }) => { | 
					
						
							|  |  |  |   await page.route('**/*', route => { | 
					
						
							| 
									
										
										
										
											2023-06-02 21:59:12 +02:00
										 |  |  |     void route.fulfill({ | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  |       status: 200, | 
					
						
							|  |  |  |       headers: { | 
					
						
							|  |  |  |         'content-type': 'text/html' | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       body: 'Hello there!' | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto('http://test.com'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render snapshot, check expectations.
 | 
					
						
							|  |  |  |   await traceViewer.selectAction('route.fulfill'); | 
					
						
							| 
									
										
										
										
											2023-02-17 11:19:53 -08:00
										 |  |  |   await traceViewer.page.locator('.tabbed-pane-tab-label', { hasText: 'Call' }).click(); | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  |   const callLine = traceViewer.page.locator('.call-line'); | 
					
						
							| 
									
										
										
										
											2022-09-27 15:13:56 -08:00
										 |  |  |   await expect(callLine.getByText('status')).toContainText('200'); | 
					
						
							|  |  |  |   await expect(callLine.getByText('requestUrl')).toContainText('http://test.com'); | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 01:52:04 +00:00
										 |  |  | test('should not crash with broken locator', async ({ page, runAndTrace, server }) => { | 
					
						
							|  |  |  |   test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/21832' }); | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       await page.locator('[class*=github-btn] a]').click(); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await expect(traceViewer.page).toHaveTitle('Playwright Trace Viewer'); | 
					
						
							|  |  |  |   const header = traceViewer.page.getByText('Playwright', { exact: true }); | 
					
						
							|  |  |  |   await expect(header).toBeVisible(); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  | test('should include requestUrl in route.continue', async ({ page, runAndTrace, server }) => { | 
					
						
							|  |  |  |   await page.route('**/*', route => { | 
					
						
							| 
									
										
										
										
											2023-06-02 21:59:12 +02:00
										 |  |  |     void route.continue({ url: server.EMPTY_PAGE }); | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto('http://test.com'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render snapshot, check expectations.
 | 
					
						
							|  |  |  |   await traceViewer.selectAction('route.continue'); | 
					
						
							| 
									
										
										
										
											2023-02-17 11:19:53 -08:00
										 |  |  |   await traceViewer.page.locator('.tabbed-pane-tab-label', { hasText: 'Call' }).click(); | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  |   const callLine = traceViewer.page.locator('.call-line'); | 
					
						
							| 
									
										
										
										
											2022-09-27 15:13:56 -08:00
										 |  |  |   await expect(callLine.getByText('requestUrl')).toContainText('http://test.com'); | 
					
						
							| 
									
										
										
										
											2023-02-16 07:59:21 -08:00
										 |  |  |   await expect(callLine.getByText(/^url:.*/)).toContainText(server.EMPTY_PAGE); | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test('should include requestUrl in route.abort', async ({ page, runAndTrace, server }) => { | 
					
						
							|  |  |  |   await page.route('**/*', route => { | 
					
						
							| 
									
										
										
										
											2023-06-02 21:59:12 +02:00
										 |  |  |     void route.abort(); | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto('http://test.com').catch(() => {}); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render snapshot, check expectations.
 | 
					
						
							|  |  |  |   await traceViewer.selectAction('route.abort'); | 
					
						
							| 
									
										
										
										
											2023-02-17 11:19:53 -08:00
										 |  |  |   await traceViewer.page.locator('.tabbed-pane-tab-label', { hasText: 'Call' }).click(); | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  |   const callLine = traceViewer.page.locator('.call-line'); | 
					
						
							| 
									
										
										
										
											2022-09-27 15:13:56 -08:00
										 |  |  |   await expect(callLine.getByText('requestUrl')).toContainText('http://test.com'); | 
					
						
							| 
									
										
										
										
											2022-08-31 12:37:49 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-04 10:52:20 -07:00
										 |  |  | test('should serve overridden request', async ({ page, runAndTrace, server }) => { | 
					
						
							|  |  |  |   server.setRoute('/custom.css', (req, res) => { | 
					
						
							|  |  |  |     res.writeHead(200, { | 
					
						
							|  |  |  |       'Content-Type': 'text/css', | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     res.end(`body { background: red }`); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await page.route('**/one-style.css', route => { | 
					
						
							| 
									
										
										
										
											2023-06-02 21:59:12 +02:00
										 |  |  |     void route.continue({ | 
					
						
							| 
									
										
										
										
											2022-09-04 10:52:20 -07:00
										 |  |  |       url: server.PREFIX + '/custom.css' | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.PREFIX + '/one-style.html'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   // Render snapshot, check expectations.
 | 
					
						
							|  |  |  |   const snapshotFrame = await traceViewer.snapshotFrame('page.goto'); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |   await expect(snapshotFrame.locator('body')).toHaveCSS('background-color', 'rgb(255, 0, 0)'); | 
					
						
							| 
									
										
										
										
											2022-09-04 10:52:20 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-07 11:27:56 -07:00
										 |  |  | test('should display waitForLoadState even if did not wait for it', async ({ runAndTrace, server, page }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     await page.waitForLoadState('load'); | 
					
						
							|  |  |  |     await page.waitForLoadState('load'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await expect(traceViewer.actionTitles).toHaveText([ | 
					
						
							|  |  |  |     /page.goto/, | 
					
						
							|  |  |  |     /page.waitForLoadState/, | 
					
						
							|  |  |  |     /page.waitForLoadState/, | 
					
						
							|  |  |  |   ]); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should display language-specific locators', async ({ runAndTrace, server, page, toImpl }) => { | 
					
						
							| 
									
										
										
										
											2023-06-01 17:54:43 -07:00
										 |  |  |   toImpl(page).attribution.playwright.options.sdkLanguage = 'python'; | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.setContent('<button>Submit</button>'); | 
					
						
							|  |  |  |     await page.getByRole('button', { name: 'Submit' }).click(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await expect(traceViewer.actionTitles).toHaveText([ | 
					
						
							|  |  |  |     /page.setContent/, | 
					
						
							|  |  |  |     /locator.clickget_by_role\("button", name="Submit"\)/, | 
					
						
							|  |  |  |   ]); | 
					
						
							| 
									
										
										
										
											2023-06-01 17:54:43 -07:00
										 |  |  |   toImpl(page).attribution.playwright.options.sdkLanguage = 'javascript'; | 
					
						
							| 
									
										
										
										
											2022-10-18 22:23:40 -04:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2023-02-17 11:19:53 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should pick locator', async ({ page, runAndTrace, server }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     await page.setContent('<button>Submit</button>'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const snapshot = await traceViewer.snapshotFrame('page.setContent'); | 
					
						
							|  |  |  |   await traceViewer.page.getByTitle('Pick locator').click(); | 
					
						
							| 
									
										
										
										
											2023-03-21 07:40:54 -07:00
										 |  |  |   await snapshot.locator('button').click(); | 
					
						
							| 
									
										
										
										
											2023-02-17 11:19:53 -08:00
										 |  |  |   await expect(traceViewer.page.locator('.cm-wrapper')).toContainText(`getByRole('button', { name: 'Submit' })`); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | test('should update highlight when typing', async ({ page, runAndTrace, server }) => { | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     await page.setContent('<button>Submit</button>'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const snapshot = await traceViewer.snapshotFrame('page.setContent'); | 
					
						
							| 
									
										
										
										
											2023-08-18 17:53:03 -07:00
										 |  |  |   await traceViewer.page.getByText('Locator').click(); | 
					
						
							| 
									
										
										
										
											2023-02-17 11:19:53 -08:00
										 |  |  |   await traceViewer.page.locator('.CodeMirror').click(); | 
					
						
							|  |  |  |   await traceViewer.page.keyboard.type('button'); | 
					
						
							|  |  |  |   await expect(snapshot.locator('x-pw-glass')).toBeVisible(); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2023-03-23 12:49:53 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should open trace-1.31', async ({ showTraceViewer }) => { | 
					
						
							|  |  |  |   const traceViewer = await showTraceViewer([path.join(__dirname, '../assets/trace-1.31.zip')]); | 
					
						
							|  |  |  |   const snapshot = await traceViewer.snapshotFrame('locator.click'); | 
					
						
							|  |  |  |   await expect(snapshot.locator('[__playwright_target__]')).toHaveText(['Submit']); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2023-06-17 06:58:16 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-19 16:21:09 -07:00
										 |  |  | test('should open trace-1.37', async ({ showTraceViewer }) => { | 
					
						
							|  |  |  |   const traceViewer = await showTraceViewer([path.join(__dirname, '../assets/trace-1.37.zip')]); | 
					
						
							|  |  |  |   const snapshot = await traceViewer.snapshotFrame('page.goto'); | 
					
						
							|  |  |  |   await expect(snapshot.locator('div')).toHaveCSS('background-color', 'rgb(255, 0, 0)'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await traceViewer.showConsoleTab(); | 
					
						
							|  |  |  |   await expect(traceViewer.consoleLineMessages).toHaveText(['hello {foo: bar}']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await traceViewer.showNetworkTab(); | 
					
						
							| 
									
										
										
										
											2024-01-10 15:28:33 -08:00
										 |  |  |   await expect(traceViewer.networkRequests).toContainText([ | 
					
						
							|  |  |  |     /index.htmlGET200text\/html/, | 
					
						
							|  |  |  |     /style.cssGET200x-unknown/ | 
					
						
							|  |  |  |   ]); | 
					
						
							| 
									
										
										
										
											2023-09-19 16:21:09 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 20:04:48 -07:00
										 |  |  | test('should prefer later resource request with the same method', async ({ page, server, runAndTrace }) => { | 
					
						
							| 
									
										
										
										
											2023-06-17 06:58:16 -07:00
										 |  |  |   const html = `
 | 
					
						
							|  |  |  |     <body> | 
					
						
							|  |  |  |       <script> | 
					
						
							|  |  |  |         const link = document.createElement('link'); | 
					
						
							|  |  |  |         link.rel = 'stylesheet'; | 
					
						
							|  |  |  |         link.href = 'style.css'; | 
					
						
							|  |  |  |         document.head.appendChild(link); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!window.location.href.includes('reloaded')) | 
					
						
							|  |  |  |           window.location.href = window.location.href + '?reloaded'; | 
					
						
							| 
									
										
										
										
											2023-07-10 20:04:48 -07:00
										 |  |  |         else | 
					
						
							|  |  |  |           link.onload = () => fetch('style.css', { method: 'HEAD' }); | 
					
						
							| 
									
										
										
										
											2023-06-17 06:58:16 -07:00
										 |  |  |       </script> | 
					
						
							| 
									
										
										
										
											2023-07-10 20:04:48 -07:00
										 |  |  |       <div>Hello</div> | 
					
						
							| 
									
										
										
										
											2023-06-17 06:58:16 -07:00
										 |  |  |     </body> | 
					
						
							|  |  |  |   `;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let reloadStartedCallback = () => {}; | 
					
						
							|  |  |  |   const reloadStartedPromise = new Promise<void>(f => reloadStartedCallback = f); | 
					
						
							|  |  |  |   server.setRoute('/style.css', async (req, res) => { | 
					
						
							| 
									
										
										
										
											2023-07-10 20:04:48 -07:00
										 |  |  |     if (req.method === 'HEAD') { | 
					
						
							|  |  |  |       res.statusCode = 200; | 
					
						
							|  |  |  |       res.end(''); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-17 06:58:16 -07:00
										 |  |  |     // Make sure reload happens before style arrives.
 | 
					
						
							|  |  |  |     await reloadStartedPromise; | 
					
						
							|  |  |  |     res.end('body { background-color: rgb(123, 123, 123) }'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   server.setRoute('/index.html', (req, res) => res.end(html)); | 
					
						
							|  |  |  |   server.setRoute('/index.html?reloaded', (req, res) => { | 
					
						
							|  |  |  |     reloadStartedCallback(); | 
					
						
							|  |  |  |     res.end(html); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							| 
									
										
										
										
											2023-07-10 20:04:48 -07:00
										 |  |  |     const headRequest = page.waitForRequest(req => req.url() === server.PREFIX + '/style.css' && req.method() === 'HEAD'); | 
					
						
							| 
									
										
										
										
											2023-06-17 06:58:16 -07:00
										 |  |  |     await page.goto(server.PREFIX + '/index.html'); | 
					
						
							| 
									
										
										
										
											2023-07-10 20:04:48 -07:00
										 |  |  |     await headRequest; | 
					
						
							|  |  |  |     await page.locator('div').click(); | 
					
						
							| 
									
										
										
										
											2023-06-17 06:58:16 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2023-07-10 20:04:48 -07:00
										 |  |  |   const frame1 = await traceViewer.snapshotFrame('page.goto'); | 
					
						
							|  |  |  |   await expect(frame1.locator('body')).toHaveCSS('background-color', 'rgb(123, 123, 123)'); | 
					
						
							|  |  |  |   const frame2 = await traceViewer.snapshotFrame('locator.click'); | 
					
						
							|  |  |  |   await expect(frame2.locator('body')).toHaveCSS('background-color', 'rgb(123, 123, 123)'); | 
					
						
							| 
									
										
										
										
											2023-06-17 06:58:16 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2023-07-27 08:06:00 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should ignore 304 responses', async ({ page, server, runAndTrace }) => { | 
					
						
							|  |  |  |   const html = `
 | 
					
						
							|  |  |  |     <head> | 
					
						
							|  |  |  |       <link rel=stylesheet href="style.css" /> | 
					
						
							|  |  |  |     </head> | 
					
						
							|  |  |  |     <body> | 
					
						
							|  |  |  |       <div>Hello</div> | 
					
						
							|  |  |  |     </body> | 
					
						
							|  |  |  |   `;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   server.setRoute('/style.css', async (req, res) => { | 
					
						
							|  |  |  |     if (req.headers['if-modified-since']) { | 
					
						
							|  |  |  |       res.statusCode = 304; // not modified
 | 
					
						
							|  |  |  |       res.end(); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     res.setHeader('Cache-Control', 'public, max-age=31536000, no-cache'); | 
					
						
							|  |  |  |     res.setHeader('Last-Modified', (new Date()).toISOString()); | 
					
						
							|  |  |  |     res.end('body { background-color: rgb(123, 123, 123) }'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   server.setRoute('/index.html', (req, res) => res.end(html)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     const request1 = page.waitForEvent('requestfinished', req => req.url() === server.PREFIX + '/style.css'); | 
					
						
							|  |  |  |     await page.goto(server.PREFIX + '/index.html'); | 
					
						
							|  |  |  |     await request1; | 
					
						
							|  |  |  |     await page.waitForTimeout(1000); | 
					
						
							|  |  |  |     const request2 = page.waitForEvent('requestfinished', req => req.url() === server.PREFIX + '/style.css'); | 
					
						
							|  |  |  |     await page.goto(server.PREFIX + '/index.html'); | 
					
						
							|  |  |  |     await request2; | 
					
						
							|  |  |  |     await page.waitForTimeout(1000); | 
					
						
							|  |  |  |     await page.locator('div').click(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const frame = await traceViewer.snapshotFrame('locator.click'); | 
					
						
							|  |  |  |   await expect(frame.locator('body')).toHaveCSS('background-color', 'rgb(123, 123, 123)'); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2023-09-06 09:44:47 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should pick locator in iframe', async ({ page, runAndTrace, server }) => { | 
					
						
							|  |  |  |   /* | 
					
						
							|  |  |  |     iframe[id=frame1] | 
					
						
							|  |  |  |       div Hello1 | 
					
						
							|  |  |  |       iframe | 
					
						
							|  |  |  |         div Hello2 | 
					
						
							|  |  |  |         iframe[name=one] | 
					
						
							|  |  |  |           div HelloNameOne | 
					
						
							|  |  |  |         iframe[name=two] | 
					
						
							|  |  |  |           dev HelloNameTwo | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     await page.setContent(`<iframe id=frame1 srcdoc="<div>Hello1</div><iframe srcdoc='<div>Hello2</div><iframe name=one></iframe><iframe name=two></iframe><iframe></iframe>'>">`); | 
					
						
							|  |  |  |     const frameOne = page.frame({ name: 'one' }); | 
					
						
							|  |  |  |     await frameOne.setContent(`<div>HelloNameOne</div>`); | 
					
						
							|  |  |  |     const frameTwo = page.frame({ name: 'two' }); | 
					
						
							|  |  |  |     await frameTwo.setContent(`<div>HelloNameTwo</div>`); | 
					
						
							|  |  |  |     await page.evaluate('2+2'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await traceViewer.page.getByTitle('Pick locator').click(); | 
					
						
							|  |  |  |   const cmWrapper = traceViewer.page.locator('.cm-wrapper'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const snapshot = await traceViewer.snapshotFrame('page.evaluate'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await snapshot.frameLocator('#frame1').getByText('Hello1').click(); | 
					
						
							|  |  |  |   await expect.soft(cmWrapper).toContainText(`frameLocator('#frame1').getByText('Hello1')`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await snapshot.frameLocator('#frame1').frameLocator('iframe').getByText('Hello2').click(); | 
					
						
							|  |  |  |   await expect.soft(cmWrapper).toContainText(`frameLocator('#frame1').frameLocator('iframe').getByText('Hello2')`, { timeout: 0 }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await snapshot.frameLocator('#frame1').frameLocator('iframe').frameLocator('[name=one]').getByText('HelloNameOne').click(); | 
					
						
							|  |  |  |   await expect.soft(cmWrapper).toContainText(`frameLocator('#frame1').frameLocator('iframe').frameLocator('iframe[name="one"]').getByText('HelloNameOne')`, { timeout: 0 }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await snapshot.frameLocator('#frame1').frameLocator('iframe').frameLocator('[name=two]').getByText('HelloNameTwo').click(); | 
					
						
							|  |  |  |   await expect.soft(cmWrapper).toContainText(`frameLocator('#frame1').frameLocator('iframe').frameLocator('iframe[name="two"]').getByText('HelloNameTwo')`, { timeout: 0 }); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2023-09-06 16:14:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should highlight locator in iframe while typing', async ({ page, runAndTrace, server, platform }) => { | 
					
						
							|  |  |  |   /* | 
					
						
							|  |  |  |     iframe[id=frame1] | 
					
						
							|  |  |  |       div Hello1 | 
					
						
							|  |  |  |       iframe | 
					
						
							|  |  |  |         div Hello2 | 
					
						
							|  |  |  |         iframe[name=one] | 
					
						
							|  |  |  |           div HelloNameOne | 
					
						
							|  |  |  |         iframe[name=two] | 
					
						
							|  |  |  |           dev HelloNameTwo | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   const traceViewer = await runAndTrace(async () => { | 
					
						
							|  |  |  |     await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |     await page.setContent(`<iframe id=frame1 srcdoc="<div>Hello1</div><iframe srcdoc='<div>Hello2</div><iframe name=one></iframe><iframe name=two></iframe><iframe></iframe>'>">`); | 
					
						
							|  |  |  |     const frameOne = page.frame({ name: 'one' }); | 
					
						
							|  |  |  |     await frameOne.setContent(`<div>HelloNameOne</div>`); | 
					
						
							|  |  |  |     const frameTwo = page.frame({ name: 'two' }); | 
					
						
							|  |  |  |     await frameTwo.setContent(`<div>HelloNameTwo</div>`); | 
					
						
							|  |  |  |     await page.evaluate('2+2'); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const snapshot = await traceViewer.snapshotFrame('page.evaluate'); | 
					
						
							|  |  |  |   await traceViewer.page.getByText('Locator').click(); | 
					
						
							|  |  |  |   await traceViewer.page.locator('.CodeMirror').click(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const locators = [{ | 
					
						
							|  |  |  |     text: `frameLocator('#frame1').getByText('Hello1')`, | 
					
						
							|  |  |  |     element: snapshot.frameLocator('#frame1').locator('div', { hasText: 'Hello1' }), | 
					
						
							|  |  |  |     highlight: snapshot.frameLocator('#frame1').locator('x-pw-highlight'), | 
					
						
							|  |  |  |   }, { | 
					
						
							|  |  |  |     text: `frameLocator('#frame1').frameLocator('iframe').getByText('Hello2')`, | 
					
						
							|  |  |  |     element: snapshot.frameLocator('#frame1').frameLocator('iframe').locator('div', { hasText: 'Hello2' }), | 
					
						
							|  |  |  |     highlight: snapshot.frameLocator('#frame1').frameLocator('iframe').locator('x-pw-highlight'), | 
					
						
							|  |  |  |   }, { | 
					
						
							|  |  |  |     text: `frameLocator('#frame1').frameLocator('iframe').frameLocator('iframe[name="one"]').getByText('HelloNameOne')`, | 
					
						
							|  |  |  |     element: snapshot.frameLocator('#frame1').frameLocator('iframe').frameLocator('iframe[name="one"]').locator('div', { hasText: 'HelloNameOne' }), | 
					
						
							|  |  |  |     highlight: snapshot.frameLocator('#frame1').frameLocator('iframe').frameLocator('iframe[name="one"]').locator('x-pw-highlight'), | 
					
						
							|  |  |  |   }]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (const locator of locators) { | 
					
						
							|  |  |  |     if (platform === 'darwin') | 
					
						
							|  |  |  |       await traceViewer.page.keyboard.press('Meta+a'); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       await traceViewer.page.keyboard.press('Control+a'); | 
					
						
							|  |  |  |     await traceViewer.page.keyboard.press('Backspace'); | 
					
						
							|  |  |  |     await traceViewer.page.keyboard.type(locator.text); | 
					
						
							|  |  |  |     const elementBox = await locator.element.boundingBox(); | 
					
						
							|  |  |  |     const highlightBox = await locator.highlight.boundingBox(); | 
					
						
							|  |  |  |     expect(Math.abs(elementBox.width - highlightBox.width)).toBeLessThan(5); | 
					
						
							|  |  |  |     expect(Math.abs(elementBox.height - highlightBox.height)).toBeLessThan(5); | 
					
						
							|  |  |  |     expect(Math.abs(elementBox.x - highlightBox.x)).toBeLessThan(5); | 
					
						
							|  |  |  |     expect(Math.abs(elementBox.y - highlightBox.y)).toBeLessThan(5); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2024-01-12 12:11:39 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | test('should preserve noscript when javascript is disabled', async ({ browser, server, showTraceViewer }) => { | 
					
						
							|  |  |  |   const traceFile = test.info().outputPath('trace.zip'); | 
					
						
							|  |  |  |   const page = await browser.newPage({ javaScriptEnabled: false }); | 
					
						
							|  |  |  |   await page.context().tracing.start({ snapshots: true, screenshots: true, sources: true }); | 
					
						
							|  |  |  |   await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |   await page.setContent(`
 | 
					
						
							|  |  |  |     <body> | 
					
						
							|  |  |  |       <noscript>javascript is disabled!</noscript> | 
					
						
							|  |  |  |     </body> | 
					
						
							|  |  |  |   `);
 | 
					
						
							|  |  |  |   await page.context().tracing.stop({ path: traceFile }); | 
					
						
							|  |  |  |   await page.close(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const traceViewer = await showTraceViewer([traceFile]); | 
					
						
							|  |  |  |   const frame = await traceViewer.snapshotFrame('page.setContent'); | 
					
						
							|  |  |  |   await expect(frame.getByText('javascript is disabled!')).toBeVisible(); | 
					
						
							|  |  |  | }); |