{"record":{"id":"bfe969e0c680cb8d","repo":"grafana/k6","slug":"parsing-wait-for-options-w","errorCode":null,"errorMessage":"parsing wait for options: %w","messagePattern":"parsing wait for options: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/browser/locator_mapping.go","lineNumber":427,"sourceCode":"\t\t\t\treturn nil, fmt.Errorf(\"parsing locator tap options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Tap(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"dispatchEvent\": func(typ string, eventInit, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameDispatchEventOptions(lo.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing locator dispatch event options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.DispatchEvent(typ, exportArg(eventInit), popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"waitFor\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameWaitForSelectorOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing wait for options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.WaitFor(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t}\n}\n\nfunc parseLocatorOptions(rt *sobek.Runtime, opts sobek.Value) *common.LocatorOptions {\n\tif k6common.IsNullish(opts) {\n\t\treturn nil\n\t}\n\n\tvar popts common.LocatorOptions\n\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {","sourceCodeStart":409,"sourceCodeEnd":445,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/browser/locator_mapping.go#L409-L445","documentation":"Thrown when locator.waitFor(opts) fails to parse options into FrameWaitForSelectorOptions. This is a live, strict error path for the state key: only 'attached', 'detached', 'visible', 'hidden' are accepted, and anything else returns '<state> is not a valid DOM state', wrapped as 'parsing wait for options: ...'. Also accepted: strict boolean and timeout number in ms (coerced leniently).","triggerScenarios":"waitFor({ state: 'shown' }) or { state: 'displayed' } — not valid state names; case errors like { state: 'Visible' }; passing a selector string into the opts slot: waitFor('#id').","commonSituations":"Translating wait conditions from other frameworks (Selenium's visibility wording, Cypress should('be.visible')); typos and case mismatches; expecting k6 to accept Playwright's full waitForSelector option set (e.g. polling keys are not read here).","solutions":["Use one of the four valid states: waitFor({ state: 'visible' }) — attached, detached, visible, hidden","Lowercase the state string exactly","Pass the selector to locator(), not to waitFor — the opts slot accepts only state/strict/timeout","Set timeout numerically in ms alongside the state"],"exampleFix":"// before\nawait page.locator('.toast').waitFor({ state: 'Shown' });\n\n// after\nawait page.locator('.toast').waitFor({ state: 'visible', timeout: 5000 });","handlingStrategy":"validation","validationCode":"const WAIT_FOR_STATES = new Set(['attached', 'detached', 'visible', 'hidden']);\nfunction assertWaitForOpts(opts) {\n  if (opts === null || opts === undefined) return;\n  if (typeof opts !== 'object' || Array.isArray(opts)) {\n    throw new TypeError('waitFor options must be a plain object');\n  }\n  if ('state' in opts && !WAIT_FOR_STATES.has(opts.state)) {\n    throw new TypeError(`waitFor state must be one of ${[...WAIT_FOR_STATES].join(', ')}, got ${JSON.stringify(opts.state)}`);\n  }\n  if ('timeout' in opts && typeof opts.timeout !== 'number') {\n    throw new TypeError('waitFor timeout must be a number (ms)');\n  }\n}","typeGuard":"function isWaitForOptions(v) {\n  if (v === null || v === undefined) return true;\n  if (typeof v !== 'object' || Array.isArray(v)) return false;\n  const stateOk = v.state === undefined ||\n    ['attached', 'detached', 'visible', 'hidden'].includes(v.state);\n  return stateOk && (v.timeout === undefined || typeof v.timeout === 'number');\n}","tryCatchPattern":"try {\n  await locator.waitFor(opts);\n} catch (e) {\n  if (/is not a valid DOM state/.test(String(e.message))) {\n    throw new Error(`waitFor state must be attached|detached|visible|hidden: ${e.message}`);\n  }\n  throw e;\n}","preventionTips":["Whitelist state strings against attached/detached/visible/hidden before the call","Lowercase state values exactly; 'Visible' is rejected","Pass the selector to locator(), never to waitFor()"],"tags":["k6","browser","locator","options","waitfor","state"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}