Skip to content

Commit 5c3f483

Browse files
authored
fix(cli): do not extend injected script on same-document navigations (#5002)
Otherwise, the injected script has to be ready for reentrancy.
1 parent a35617d commit 5c3f483

File tree

6 files changed

+57
-7
lines changed

6 files changed

+57
-7
lines changed

src/cli/injected/recorder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ export class Recorder {
372372
if (event.key === '@' && event.code === 'KeyL')
373373
return false;
374374
// Allow and ignore common used shortcut for pasting.
375-
if (process.platform === 'darwin') {
375+
if (navigator.platform.includes('Mac')) {
376376
if (event.key === 'v' && event.metaKey)
377377
return false;
378378
} else {

src/server/browserContext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ export abstract class BrowserContext extends EventEmitter {
382382
async extendInjectedScript(source: string, arg?: any) {
383383
const installInFrame = (frame: frames.Frame) => frame.extendInjectedScript(source, arg).catch(e => {});
384384
const installInPage = (page: Page) => {
385-
page.on(Page.Events.FrameNavigated, installInFrame);
385+
page.on(Page.Events.InternalFrameNavigatedToNewDocument, installInFrame);
386386
return Promise.all(page.frames().map(installInFrame));
387387
};
388388
this.on(BrowserContext.Events.Page, installInPage);

src/server/frames.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ export class FrameManager {
199199
frame.emit(Frame.Events.Navigation, navigationEvent);
200200
if (!initial) {
201201
debugLogger.log('api', ` navigated to "${url}"`);
202-
this._page.frameNavigated(frame);
202+
this._page.frameNavigatedToNewDocument(frame);
203203
}
204204
// Restore pending if any - see comments above about keepPending.
205205
frame._pendingDocument = keepPending;
@@ -213,7 +213,6 @@ export class FrameManager {
213213
const navigationEvent: NavigationEvent = { url, name: frame._name };
214214
frame.emit(Frame.Events.Navigation, navigationEvent);
215215
debugLogger.log('api', ` navigated to "${url}"`);
216-
this._page.frameNavigated(frame);
217216
}
218217

219218
frameAbortedNavigation(frameId: string, errorText: string, documentId?: string) {

src/server/page.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export class Page extends EventEmitter {
110110
RequestFinished: 'requestfinished',
111111
FrameAttached: 'frameattached',
112112
FrameDetached: 'framedetached',
113-
FrameNavigated: 'framenavigated',
113+
InternalFrameNavigatedToNewDocument: 'internalframenavigatedtonewdocument',
114114
Load: 'load',
115115
Popup: 'popup',
116116
WebSocket: 'websocket',
@@ -457,8 +457,8 @@ export class Page extends EventEmitter {
457457
this.emit(Page.Events.VideoStarted, video);
458458
}
459459

460-
frameNavigated(frame: frames.Frame) {
461-
this.emit(Page.Events.FrameNavigated, frame);
460+
frameNavigatedToNewDocument(frame: frames.Frame) {
461+
this.emit(Page.Events.InternalFrameNavigatedToNewDocument, frame);
462462
const url = frame.url();
463463
if (!url.startsWith('http'))
464464
return;

test/browsercontext-expose-function.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,26 @@ it('exposeBindingHandle should work', async ({context}) => {
8282
expect(await target.evaluate(x => x.foo)).toBe(42);
8383
expect(result).toEqual(17);
8484
});
85+
86+
it('extendInjectedScript should work', async ({ context, server }) => {
87+
await (context as any)._extendInjectedScript(`var pwExport = (() => {
88+
class Foo {
89+
constructor() {
90+
window._counter = (window._counter || 0) + 1;
91+
}
92+
}
93+
return Foo;
94+
})()`);
95+
96+
const page = await context.newPage();
97+
await page.waitForFunction(() => (window as any)._counter === 1);
98+
99+
await page.goto(server.EMPTY_PAGE);
100+
await page.waitForFunction(() => (window as any)._counter === 1);
101+
102+
await Promise.all([
103+
page.waitForNavigation(),
104+
page.evaluate(() => history.pushState({}, '', '/url.html'))
105+
]);
106+
expect(await page.evaluate(() => (window as any)._counter)).toBe(1);
107+
});

test/cli/cli-codegen.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,34 @@ describe('cli codegen', (test, { browserName, headful }) => {
4040
expect(message.text()).toBe('click');
4141
});
4242

43+
it('should click after same-document navigation', async ({ page, recorder, httpServer }) => {
44+
httpServer.setHandler((req: http.IncomingMessage, res: http.ServerResponse) => {
45+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
46+
res.end('');
47+
});
48+
await recorder.setContentAndWait(`<button onclick="console.log('click')">Submit</button>`, httpServer.PREFIX + '/foo.html');
49+
await Promise.all([
50+
page.waitForNavigation(),
51+
page.evaluate(() => history.pushState({}, '', '/url.html')),
52+
]);
53+
// This is the only way to give recorder a chance to install
54+
// the second unnecessary copy of the recorder script.
55+
await page.waitForTimeout(1000);
56+
57+
const selector = await recorder.hoverOverElement('button');
58+
expect(selector).toBe('text="Submit"');
59+
60+
const [message] = await Promise.all([
61+
page.waitForEvent('console'),
62+
recorder.waitForOutput('click'),
63+
page.dispatchEvent('button', 'click', { detail: 1 })
64+
]);
65+
expect(recorder.output()).toContain(`
66+
// Click text="Submit"
67+
await page.click('text="Submit"');`);
68+
expect(message.text()).toBe('click');
69+
});
70+
4371
it('should not target selector preview by text regexp', async ({ page, recorder }) => {
4472
await recorder.setContentAndWait(`<span>dummy</span>`);
4573

0 commit comments

Comments
 (0)