Skip to content

Commit 581102e

Browse files
committed
chore(bidi): add support for context locators
1 parent 34a09f3 commit 581102e

File tree

8 files changed

+44
-32
lines changed

8 files changed

+44
-32
lines changed

packages/playwright-core/src/server/bidi/bidiBrowser.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,13 @@ export class BidiBrowser extends Browser {
137137
const page = this._findPageForFrame(parentFrameId);
138138
if (page) {
139139
page._session.addFrameBrowsingContext(event.context);
140-
page._page.frameManager.frameAttached(event.context, parentFrameId);
141-
const frame = page._page.frameManager.frame(event.context);
142-
if (frame)
143-
frame._url = event.url;
140+
const frame = page._page.frameManager.frameAttached(event.context, parentFrameId);
141+
frame._url = event.url;
142+
page._getFrameNode(frame).then(node => {
143+
const attributes = node?.value?.attributes;
144+
frame._name = attributes?.name ?? attributes?.id ?? '';
145+
});
146+
return;
144147
}
145148
return;
146149
}

packages/playwright-core/src/server/bidi/bidiExecutionContext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,11 @@ export class BidiExecutionContext implements js.ExecutionContextDelegate {
141141
};
142142
}
143143

144-
async remoteObjectForNodeId(context: dom.FrameExecutionContext, nodeId: bidi.Script.SharedReference): Promise<js.JSHandle> {
144+
async remoteObjectForNodeId(context: dom.FrameExecutionContext, nodeId: bidi.Script.SharedReference): Promise<dom.ElementHandle> {
145145
const result = await this._remoteValueForReference(nodeId, true);
146146
if (!('handle' in result))
147147
throw new Error('Can\'t get remote object for nodeId');
148-
return createHandle(context, result);
148+
return createHandle(context, result) as dom.ElementHandle;
149149
}
150150

151151
async contentFrameIdForFrame(handle: dom.ElementHandle) {

packages/playwright-core/src/server/bidi/bidiPage.ts

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ export class BidiPage implements PageDelegate {
196196

197197
private _onNavigationCommitted(params: bidi.BrowsingContext.NavigationInfo) {
198198
const frameId = params.context;
199-
this._page.frameManager.frameCommittedNewDocumentNavigation(frameId, params.url, '', params.navigation!, /* initial */ false);
199+
const frame = this._page.frameManager.frame(frameId)!;
200+
this._page.frameManager.frameCommittedNewDocumentNavigation(frameId, params.url, frame._name, params.navigation!, /* initial */ false);
200201
}
201202

202203
private _onDomContentLoaded(params: bidi.BrowsingContext.NavigationInfo) {
@@ -587,24 +588,24 @@ export class BidiPage implements PageDelegate {
587588
const parent = frame.parentFrame();
588589
if (!parent)
589590
throw new Error('Frame has been detached.');
590-
const parentContext = await parent._mainContext();
591-
const list = await parentContext.evaluateHandle(() => { return [...document.querySelectorAll('iframe,frame')]; });
592-
const length = await list.evaluate(list => list.length);
593-
let foundElement = null;
594-
for (let i = 0; i < length; i++) {
595-
const element = await list.evaluateHandle((list, i) => list[i], i);
596-
const candidate = await element.contentFrame();
597-
if (frame === candidate) {
598-
foundElement = element;
599-
break;
600-
} else {
601-
element.dispose();
602-
}
603-
}
604-
list.dispose();
605-
if (!foundElement)
591+
const node = await this._getFrameNode(frame);
592+
if (!node?.sharedId)
606593
throw new Error('Frame has been detached.');
607-
return foundElement;
594+
const parentFrameExecutionContext = await parent._mainContext();
595+
return await toBidiExecutionContext(parentFrameExecutionContext).remoteObjectForNodeId(parentFrameExecutionContext, { sharedId: node.sharedId });
596+
}
597+
598+
async _getFrameNode(frame: frames.Frame): Promise<bidi.Script.NodeRemoteValue | undefined> {
599+
const parent = frame.parentFrame();
600+
if (!parent)
601+
return undefined;
602+
603+
const result = await this._session.send('browsingContext.locateNodes', {
604+
context: parent._id,
605+
locator: { type: 'context', value: { context: frame._id } },
606+
});
607+
const node = result.nodes[0];
608+
return node;
608609
}
609610

610611
shouldToggleStyleSheetToSyncAnimations(): boolean {

tests/library/hit-target.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ it('should click into frame inside closed shadow root', async ({ page, server })
290290
</script>
291291
`);
292292

293-
const frame = page.frame({ name: 'myframe' });
293+
const frame = page.frames()[1];
294294
await frame.locator('text=click me').click();
295295
expect(await page.evaluate('window.__clicked')).toBe(true);
296296
});

tests/page/elementhandle-bounding-box.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ it('should work', async ({ page, server, browserName, headless, isLinux }) => {
3030
it('should handle nested frames', async ({ page, server }) => {
3131
await page.setViewportSize({ width: 616, height: 500 });
3232
await page.goto(server.PREFIX + '/frames/nested-frames.html');
33-
const nestedFrame = page.frames().find(frame => frame.name() === 'dos');
34-
const elementHandle = await nestedFrame.$('div');
33+
const nestedFrame = page.frameLocator('[name="2frames"]').frameLocator('[name=dos]');
34+
const elementHandle = await nestedFrame.locator('div').elementHandle();
3535
const box = await elementHandle.boundingBox();
3636
expect(box).toEqual({ x: 24, y: 224, width: 268, height: 18 });
3737
});

tests/page/frame-frame-element.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ it('should work inside closed shadow root', async ({ page, server, browserName }
7171
</script>
7272
`);
7373

74-
const frame = page.frame({ name: 'myframe' });
74+
const frame = page.frames()[1];
7575
const element = await frame.frameElement();
7676
expect(await element.getAttribute('name')).toBe('myframe');
7777
});
@@ -87,7 +87,7 @@ it('should work inside declarative shadow root', async ({ page, server, browserN
8787
<span>footer</span>
8888
</div>
8989
`);
90-
const frame = page.frame({ name: 'myframe' });
90+
const frame = page.frames()[1];
9191
const element = await frame.frameElement();
9292
expect(await element.getAttribute('name')).toBe('myframe');
9393
});

tests/page/frame-hierarchy.spec.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ function dumpFrames(frame: Frame, indentation: string = ''): string[] {
3535
return result;
3636
}
3737

38-
it('should handle nested frames @smoke', async ({ page, server, isAndroid }) => {
38+
it('should handle nested frames @smoke', async ({ page, server, isAndroid, browserName, channel }) => {
3939
it.skip(isAndroid, 'No cross-process on Android');
40+
it.skip(browserName === 'firefox' && channel?.startsWith('moz-firefox'), 'frame.name() is racy with BiDi');
41+
it.skip(channel?.startsWith('bidi-chrom'), 'frame.name() is racy with BiDi');
4042

4143
await page.goto(server.PREFIX + '/frames/nested-frames.html');
4244
expect(dumpFrames(page.mainFrame())).toEqual([
@@ -154,7 +156,10 @@ it('should report frame from-inside shadow DOM', async ({ page, server }) => {
154156
expect(page.frames()[1].url()).toBe(server.EMPTY_PAGE);
155157
});
156158

157-
it('should report frame.name()', async ({ page, server }) => {
159+
it('should report frame.name()', async ({ page, server, browserName, channel }) => {
160+
it.skip(browserName === 'firefox' && channel?.startsWith('moz-firefox'), 'frame.name() is racy with BiDi');
161+
it.skip(channel?.startsWith('bidi-chrom'), 'frame.name() is racy with BiDi');
162+
158163
await attachFrame(page, 'theFrameId', server.EMPTY_PAGE);
159164
await page.evaluate(url => {
160165
const frame = document.createElement('iframe');

tests/page/page-basic.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ it('page.close should work with window.close', async function({ page }) {
9494
await closedPromise;
9595
});
9696

97-
it('page.frame should respect name', async function({ page }) {
97+
it('page.frame should respect name', async function({ page, browserName, channel }) {
98+
it.skip(browserName === 'firefox' && channel?.startsWith('moz-firefox'), 'page.frame({ name }) is racy with BiDi');
99+
it.skip(channel?.startsWith('bidi-chrom'), 'page.frame({ name }) is racy with BiDi');
100+
98101
await page.setContent(`<iframe name=target></iframe>`);
99102
expect(page.frame({ name: 'bogus' })).toBe(null);
100103
const frame = page.frame({ name: 'target' });

0 commit comments

Comments
 (0)