{"record":{"id":"ee6c12b4c1c1125e","repo":"grafana/k6","slug":"finding-iframe-with-selector-q-w","errorCode":null,"errorMessage":"finding iframe with selector %q: %w","messagePattern":"finding iframe with selector %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/element_handle.go","lineNumber":643,"sourceCode":"\treturn false, fmt.Errorf(\n\t\t\"waiting for states %v of element %q\", states, reflect.TypeOf(result))\n}\n\n// stepIntoFrame steps into an iframe/frame. Due to CORS, we need to perform this\n// step outside of the browser (chromium). It returns the frame that it has stepped\n// into and the selector to use within that frame.\nfunc (h *ElementHandle) stepIntoFrame(\n\tapiCtx context.Context, parsedSelector *Selector, frameNavIndex int, opts *FrameWaitForSelectorOptions,\n) (*Frame, string, error) {\n\t// Split selector at frame navigation boundary\n\tbeforeFrame, afterFrame := h.splitSelectorAtFrame(parsedSelector, frameNavIndex)\n\n\t// Find the iframe element using the \"before frame\" selector\n\tiframeSelector := h.reconstructSelector(beforeFrame)\n\n\tiframeHandle, err := h.waitForSelector(apiCtx, iframeSelector, opts)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"finding iframe with selector %q: %w\", iframeSelector, err)\n\t}\n\n\t// This is a valid response from waitForSelector. It means that the element\n\t// was either hidden or detached.\n\tif iframeHandle == nil {\n\t\treturn nil, \"\", ErrElementNotVisible\n\t}\n\n\tframe, err := iframeHandle.ContentFrame()\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"getting iframe frame: %w\", err)\n\t}\n\n\t// Wait for selector in the iframe using the \"after frame\" selector\n\tafterFrameSelector := h.reconstructSelector(afterFrame)\n\n\treturn frame, afterFrameSelector, nil\n}","sourceCodeStart":625,"sourceCodeEnd":661,"githubUrl":"https://github.com/grafana/k6/blob/3fcf5388d78cb382f0c0d42ec556a06bfd1b8dee/internal/js/modules/k6/browser/common/element_handle.go#L625-L661","documentation":"stepIntoFrame() resolves chained selectors that cross iframe boundaries (e.g. 'iframe#a >> button'). It waits for the iframe element itself using the selector prefix before the '>>' boundary, and that waitForSelector call failed — usually a timeout waiting for the iframe element to appear or become visible.","triggerScenarios":"Using a frame-crossing selector/locator where the <iframe> element does not exist yet or stays hidden within the timeout: page.locator('iframe[title=\"app\"] >> text=Submit').click() before the iframe is injected; iframe with display:none; wrong iframe selector (no match ever); default timeout too short for slow lazy-loading.","commonSituations":"SPAs that mount iframes late (after auth, after data fetch); ad or widget iframes hidden until interaction; misspelled iframe selectors; slow CI machines where the default timeout expires first.","solutions":["Wait for the iframe to exist/attach first: await page.locator('iframe#app').waitFor() before using the chained selector","Verify the iframe selector actually matches: (await page.locator('iframe#app').count()) should be 1","Increase the timeout on the action or globally (page.setDefaultTimeout / options.timeout)","If the iframe is cross-origin, ensure it has fully loaded — prefer page.waitForLoadState('load') or frame-level waits before stepping in"],"exampleFix":"// before\nawait page.locator('iframe#widget >> button.go').click();\n\n// after\nawait page.locator('iframe#widget').waitFor({ state: 'attached' });\nawait page.waitForLoadState('load');\nawait page.locator('iframe#widget >> button.go').click({ timeout: 30_000 });","handlingStrategy":"validation","validationCode":"const iframeSel = 'iframe#widget';\nawait page.locator(iframeSel).waitFor({ state: 'attached', timeout: 15_000 });\nif ((await page.locator(iframeSel).count()) !== 1) {\n  throw new Error(`expected exactly one iframe for ${iframeSel}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await page.locator('iframe#widget >> button').click({ timeout: 15_000 });\n} catch (e) {\n  if (/finding iframe with selector/.test(String(e))) {\n    await page.waitForLoadState('load');\n    await page.locator('iframe#widget >> button').click({ timeout: 30_000 });\n  } else throw e;\n}","preventionTips":["Wait for the iframe element to attach before using '>>' chained selectors","Assert selector uniqueness (count === 1) before chaining into frames","Size timeouts to when the app actually mounts iframes"],"tags":["browser","iframe","selector","wait-timeout","frame-navigation"],"backgroundTag":"iframe-not-found","analyzedSha":"3fcf5388d78cb382f0c0d42ec556a06bfd1b8dee","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}