Skip to content

Commit 7107ca4

Browse files
committed
fix(desktop): walk cross-realm shadow roots when resolving upload targets
resolveFileInputTarget climbed out of shadow roots with `root instanceof ShadowRoot`. Elements in same-origin iframes belong to the frame's realm, so the check was false for their shadow roots and the ancestor walk stopped at the shadow boundary, failing browser_upload_file with "no nearby file input". Use the file's duck-typed `'host' in root` idiom like every other shadow-host hop.
1 parent d1af604 commit 7107ca4

2 files changed

Lines changed: 16 additions & 1 deletion

File tree

‎apps/desktop/src/main/browser-agent/page-functions.test.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,21 @@ describe('collectSnapshot', () => {
912912
expect(captured.input.ownerDocument).toBe(document)
913913
})
914914

915+
it('climbs out of a shadow root inside a same-origin frame to find the file input', () => {
916+
const frame = document.createElement('iframe')
917+
document.body.append(frame)
918+
const childDocument = frame.contentDocument as Document
919+
childDocument.body.innerHTML = '<div id="host"></div><input type="file">'
920+
const host = childDocument.getElementById('host') as HTMLElement
921+
const button = childDocument.createElement('button')
922+
host.attachShadow({ mode: 'open' }).append(button)
923+
const input = childDocument.querySelector('input') as HTMLInputElement
924+
register(button)
925+
926+
expect(button.getRootNode()).not.toBeInstanceOf(ShadowRoot)
927+
expect(resolveFileInputTarget(0)).toEqual({ input, document: childDocument })
928+
})
929+
915930
it('refuses a disconnected or stale upload reference', () => {
916931
const input = document.createElement('input')
917932
input.type = 'file'

‎apps/desktop/src/main/browser-agent/page-functions.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3348,7 +3348,7 @@ export function resolveFileInputTarget(id: number): {
33483348
)
33493349
if (candidates.length === 1) input = candidates[0]
33503350
const root = scope.getRootNode()
3351-
scope = scope.parentElement ?? (root instanceof ShadowRoot ? root.host : null)
3351+
scope = scope.parentElement ?? ('host' in root ? (root.host as Element) : null)
33523352
}
33533353
if (!input) throw new Error('The selected element has no nearby file input.')
33543354
if (input.matches(':disabled')) throw new Error('The file input is disabled.')

0 commit comments

Comments
 (0)