{"record":{"id":"c7d822755cdac996","repo":"grafana/k6","slug":"getting-document-w","errorCode":null,"errorMessage":"getting document: %w","messagePattern":"getting document: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame.go","lineNumber":636,"sourceCode":"\tclick := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.click(p, opts.ToMouseClickOptions())\n\t}\n\tact := f.newPointerAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, click, &opts.ElementHandleBasePointerOptions,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\nfunc (f *Frame) count(selector string) (int, error) {\n\tf.log.Debugf(\"Frame:count\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tdocument, err := f.document()\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"getting document: %w\", err)\n\t}\n\n\tc, err := document.count(f.ctx, selector)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"counting elements: %w\", err)\n\t}\n\n\treturn c, nil\n}\n\n// Check clicks the first element found that matches selector.\nfunc (f *Frame) Check(selector string, popts *FrameCheckOptions) error {\n\tf.log.Debugf(\"Frame:Check\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.check(selector, popts); err != nil {\n\t\treturn fmt.Errorf(\"checking %q: %w\", selector, err)\n\t}\n","sourceCodeStart":618,"sourceCodeEnd":654,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame.go#L618-L654","documentation":"Frame.count() first resolves the frame's document element handle via f.document(). That helper waits for the main-world execution context and creates a document handle over CDP; if that fails (execution context destroyed, frame navigating/detached), count wraps the failure as 'getting document'.","triggerScenarios":"Calling frame.count(selector) while the frame is navigating (context destroyed and not yet recreated), on a detached iframe, or when the main-world execution context has not appeared — document() returns errors like 'getting new document handle: ...' or 'waiting for selector %q: execution context %q not found'.","commonSituations":"Counting elements immediately after page.goto() before load settles; counting inside an iframe during its load; test running against a page that redirects; slow CI machines where context creation exceeds waits.","solutions":["Wait for the page/frame to settle: await page.waitForLoadState('load') (or waitForNavigation) before count().","Retry count() once after a short delay — execution contexts are recreated after navigation.","If targeting an iframe, get the frame via page.frames() and ensure it is attached before counting."],"exampleFix":"// before\nconst n = page.frame('shop').count('.item');\n\n// after\nconst fr = page.frame('shop');\nawait fr.waitForSelector('.item', { state: 'attached', timeout: 30000 });\nconst n = fr.count('.item');","handlingStrategy":"retry","validationCode":"await page.waitForLoadState('load');\nconst fr = page.frames().find((f) => f.name() === 'shop');\nif (!fr) throw new Error('frame not attached yet');","typeGuard":null,"tryCatchPattern":"let n;\nfor (let i = 0; i < 3; i++) {\n  try { n = frame.count(sel); break; } catch (e) { await sleep(500); }\n}\nif (n === undefined) throw new Error('count failed after retries');","preventionTips":["Never call count() mid-navigation; wait for load state.","For iframes, resolve the frame object after it attaches.","Structure tests so goto+wait happen before any DOM query."],"tags":["browser","frame","execution-context","navigation","count"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}