Skip to content

Commit 35fbd84

Browse files
committed
chore(bidi): add support for context locators
1 parent e7bff52 commit 35fbd84

File tree

8 files changed

+43
-32
lines changed

8 files changed

+43
-32
lines changed

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,12 @@ export class BidiBrowser extends Browser {
135135
if (!parentFrame)
136136
continue;
137137
page._session.addFrameBrowsingContext(event.context);
138-
page._page.frameManager.frameAttached(event.context, parentFrameId);
139-
const frame = page._page.frameManager.frame(event.context);
140-
if (frame)
141-
frame._url = event.url;
138+
const frame = page._page.frameManager.frameAttached(event.context, parentFrameId);
139+
frame._url = event.url;
140+
page._getFrameNode(frame).then(node => {
141+
const attributes = node?.value?.attributes;
142+
frame._name = attributes?.name ?? attributes?.id ?? '';
143+
});
142144
return;
143145
}
144146
return;

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
@@ -195,7 +195,8 @@ export class BidiPage implements PageDelegate {
195195

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

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

605606
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)