diff --git a/packages/playwright-core/src/server/recorder.ts b/packages/playwright-core/src/server/recorder.ts index e7d7ea01d4..9fbe4962d2 100644 --- a/packages/playwright-core/src/server/recorder.ts +++ b/packages/playwright-core/src/server/recorder.ts @@ -32,7 +32,7 @@ import type * as actions from '@recorder/actions'; import { stringifySelector } from '../utils/isomorphic/selectorParser'; import type { Frame } from './frames'; import type { AriaTemplateNode } from '@isomorphic/ariaSnapshot'; -import { Page } from './page'; +import type { Page } from './page'; const recorderSymbol = Symbol('recorderSymbol'); @@ -150,30 +150,6 @@ export class Recorder implements InstrumentationListener, IRecorder { this._recorderApp?.close().catch(() => {}); }); - // Report the URL of the first page in the context - let primaryPage: Page | undefined; - const registerNavigationListener = (page: Page) => { - if (primaryPage === undefined) { - primaryPage = page; - recorderApp.setBasePageURL(page.mainFrame().url()); - } - - page.on(Page.Events.InternalFrameNavigatedToNewDocument, (frame: Frame) => { - if (page === primaryPage && page.mainFrame() === frame) - recorderApp.setBasePageURL(frame.url()); - }); - page.on(Page.Events.Close, () => { - if (page === primaryPage) { - primaryPage = this._context.pages()[0]; - if (primaryPage) - recorderApp.setBasePageURL(primaryPage.mainFrame().url()); - } - }); - }; - for (const page of this._context.pages()) - registerNavigationListener(page); - this._context.on(BrowserContext.Events.Page, registerNavigationListener); - this._contextRecorder.on(ContextRecorder.Events.Change, (data: { sources: Source[], actions: actions.ActionInContext[] }) => { this._recorderSources = data.sources; recorderApp.setActions(data.actions, data.sources); @@ -372,7 +348,8 @@ export class Recorder implements InstrumentationListener, IRecorder { } private _pushAllSources() { - this._recorderApp?.setSources([...this._recorderSources, ...this._userSources.values()]); + const primaryPage: Page | undefined = this._context.pages()[0]; + this._recorderApp?.setSources([...this._recorderSources, ...this._userSources.values()], primaryPage?.mainFrame().url()); } async onBeforeInputAction(sdkObject: SdkObject, metadata: CallMetadata) { diff --git a/packages/playwright-core/src/server/recorder/recorderApp.ts b/packages/playwright-core/src/server/recorder/recorderApp.ts index 6842c73730..05ac4cd0dd 100644 --- a/packages/playwright-core/src/server/recorder/recorderApp.ts +++ b/packages/playwright-core/src/server/recorder/recorderApp.ts @@ -37,9 +37,8 @@ export class EmptyRecorderApp extends EventEmitter implements IRecorderApp { async setRunningFile(file: string | undefined): Promise {} async elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise {} async updateCallLogs(callLogs: CallLog[]): Promise {} - async setSources(sources: Source[]): Promise {} + async setSources(sources: Source[], primaryPageURL: string | undefined): Promise {} async setActions(actions: actions.ActionInContext[], sources: Source[]): Promise {} - async setBasePageURL(url: string): Promise {} } export class RecorderApp extends EventEmitter implements IRecorderApp { @@ -144,10 +143,10 @@ export class RecorderApp extends EventEmitter implements IRecorderApp { }).toString(), { isFunction: true }, paused).catch(() => {}); } - async setSources(sources: Source[]): Promise { - await this._page.mainFrame().evaluateExpression(((sources: Source[]) => { - window.playwrightSetSources(sources); - }).toString(), { isFunction: true }, sources).catch(() => {}); + async setSources(sources: Source[], primaryPageURL: string | undefined): Promise { + await this._page.mainFrame().evaluateExpression((({ sources, primaryPageURL }: { sources: Source[], primaryPageURL: string | undefined }) => { + window.playwrightSetSources(sources, primaryPageURL); + }).toString(), { isFunction: true }, { sources, primaryPageURL }).catch(() => {}); // Testing harness for runCLI mode. if (process.env.PWTEST_CLI_IS_UNDER_TEST && sources.length) { @@ -159,12 +158,6 @@ export class RecorderApp extends EventEmitter implements IRecorderApp { async setActions(actions: actions.ActionInContext[], sources: Source[]): Promise { } - async setBasePageURL(url: string): Promise { - await this._page.mainFrame().evaluateExpression(((url: string) => { - window.playwrightSetBasePageURL(url); - }).toString(), { isFunction: true }, url).catch(() => {}); - } - async elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise { if (userGesture) this._page.bringToFront(); diff --git a/packages/playwright-core/src/server/recorder/recorderFrontend.ts b/packages/playwright-core/src/server/recorder/recorderFrontend.ts index acf884696c..c6fb6e0a1c 100644 --- a/packages/playwright-core/src/server/recorder/recorderFrontend.ts +++ b/packages/playwright-core/src/server/recorder/recorderFrontend.ts @@ -32,9 +32,8 @@ export interface IRecorderApp extends EventEmitter { setRunningFile(file: string | undefined): Promise; elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise; updateCallLogs(callLogs: CallLog[]): Promise; - setSources(sources: Source[]): Promise; + setSources(sources: Source[], primaryPageURL: string | undefined): Promise; setActions(actions: actions.ActionInContext[], sources: Source[]): Promise; - setBasePageURL(url: string): Promise; } export type IRecorderAppFactory = (recorder: IRecorder) => Promise; diff --git a/packages/recorder/src/main.tsx b/packages/recorder/src/main.tsx index f94b468464..4ecfc97760 100644 --- a/packages/recorder/src/main.tsx +++ b/packages/recorder/src/main.tsx @@ -19,8 +19,7 @@ import * as React from 'react'; import { Recorder } from './recorder'; import './recorder.css'; -export const Main: React.FC = ({ -}) => { +export const Main: React.FC = ({}) => { const [sources, setSources] = React.useState([]); const [paused, setPaused] = React.useState(false); const [log, setLog] = React.useState(new Map()); @@ -28,9 +27,12 @@ export const Main: React.FC = ({ React.useLayoutEffect(() => { window.playwrightSetMode = setMode; - window.playwrightSetSources = (sources: Source[]) => { + window.playwrightSetSources = (sources, primaryPageURL) => { setSources(sources); window.playwrightSourcesEchoForTest = sources; + document.title = primaryPageURL + ? `Playwright Inspector - ${primaryPageURL}` + : `Playwright Inspector`; }; window.playwrightSetPaused = setPaused; window.playwrightUpdateLogs = callLogs => { @@ -43,14 +45,7 @@ export const Main: React.FC = ({ return newLog; }); }; - window.playwrightSetBasePageURL = (url: string) => { - if (url) - document.title = `Playwright Inspector - ${url}`; - else - document.title = `Playwright Inspector`; - }; }, []); - return ; }; diff --git a/packages/recorder/src/recorderTypes.d.ts b/packages/recorder/src/recorderTypes.d.ts index 9157e92e87..ae4c41f4f7 100644 --- a/packages/recorder/src/recorderTypes.d.ts +++ b/packages/recorder/src/recorderTypes.d.ts @@ -101,9 +101,8 @@ declare global { interface Window { playwrightSetMode: (mode: Mode) => void; playwrightSetPaused: (paused: boolean) => void; - playwrightSetSources: (sources: Source[]) => void; + playwrightSetSources: (sources: Source[], primaryPageURL: string | undefined) => void; playwrightSetOverlayVisible: (visible: boolean) => void; - playwrightSetBasePageURL: (url: string) => void; playwrightUpdateLogs: (callLogs: CallLog[]) => void; playwrightSetRunningFile: (file: string | undefined) => void; playwrightElementPicked: (elementInfo: ElementInfo, userGesture?: boolean) => void; diff --git a/tests/library/inspector/title.spec.ts b/tests/library/inspector/title.spec.ts index cdb259bf95..edd73be21a 100644 --- a/tests/library/inspector/title.spec.ts +++ b/tests/library/inspector/title.spec.ts @@ -16,38 +16,68 @@ import { test, expect } from './inspectorTest'; -test('should reflect formatted URL of the page', async ({ openRecorder, server }) => { +test('should reflect formatted URL of the page', async ({ + openRecorder, + server, +}) => { const { recorder } = await openRecorder(); await recorder.setContentAndWait(''); - await expect(await recorder.recorderPage.title()).toBe('Playwright Inspector - about:blank'); + await expect(recorder.recorderPage).toHaveTitle( + 'Playwright Inspector - about:blank', + ); await recorder.setContentAndWait('', server.EMPTY_PAGE); - await expect(await recorder.recorderPage.title()).toBe(`Playwright Inspector - ${server.EMPTY_PAGE}`); + await expect(recorder.recorderPage).toHaveTitle( + `Playwright Inspector - ${server.EMPTY_PAGE}`, + ); }); -test('should update primary page URL when original primary closes', async ({ context, openRecorder, server }) => { +test('should update primary page URL when original primary closes', async ({ + context, + openRecorder, + server, +}) => { const { recorder } = await openRecorder(); - await recorder.setContentAndWait('', `${server.PREFIX}/background-color.html`); - await expect(await recorder.recorderPage.title()).toBe(`Playwright Inspector - ${server.PREFIX}/background-color.html`); + await recorder.setContentAndWait( + '', + `${server.PREFIX}/background-color.html`, + ); + await expect(recorder.recorderPage).toHaveTitle( + `Playwright Inspector - ${server.PREFIX}/background-color.html`, + ); const page2 = await context.newPage(); await page2.goto(`${server.PREFIX}/empty.html`); - await expect(await recorder.recorderPage.title()).toBe(`Playwright Inspector - ${server.PREFIX}/background-color.html`); + await expect(recorder.recorderPage).toHaveTitle( + `Playwright Inspector - ${server.PREFIX}/background-color.html`, + ); const page3 = await context.newPage(); await page3.goto(`${server.PREFIX}/dom.html`); - await expect(await recorder.recorderPage.title()).toBe(`Playwright Inspector - ${server.PREFIX}/background-color.html`); + await expect(recorder.recorderPage).toHaveTitle( + `Playwright Inspector - ${server.PREFIX}/background-color.html`, + ); const page4 = await context.newPage(); await page4.goto(`${server.PREFIX}/grid.html`); - await expect(await recorder.recorderPage.title()).toBe(`Playwright Inspector - ${server.PREFIX}/background-color.html`); + await expect(recorder.recorderPage).toHaveTitle( + `Playwright Inspector - ${server.PREFIX}/background-color.html`, + ); await page2.close(); - await expect(await recorder.recorderPage.title()).toBe(`Playwright Inspector - ${server.PREFIX}/background-color.html`); + await expect(recorder.recorderPage).toHaveTitle( + `Playwright Inspector - ${server.PREFIX}/background-color.html`, + ); await recorder.page.close(); - await expect(await recorder.recorderPage.title()).toBe(`Playwright Inspector - ${server.PREFIX}/dom.html`); + // URL will not update without performing some action + await page3.getByRole('checkbox').click(); + await expect(recorder.recorderPage).toHaveTitle( + `Playwright Inspector - ${server.PREFIX}/dom.html`, + ); await page3.close(); - await expect(await recorder.recorderPage.title()).toBe(`Playwright Inspector - ${server.PREFIX}/grid.html`); + await expect(recorder.recorderPage).toHaveTitle( + `Playwright Inspector - ${server.PREFIX}/grid.html`, + ); });