In k6, which scenario option enables a real browser, and where in the options object does it go?
answer
- not a root option
- it lives under a scenario
- the word options appears twice
- type, and only chromium
basics
~10 sSet type to 'chromium' in a scenario's own options.browser block, so the full path is options.scenarios.<name>.options.browser.type. It is per-scenario, there is no root-level browser option, and 'chromium' is the only value k6 v2 accepts.
solid answer
~40 sA browser scenario is declared inside the `scenarios` map, not at the root: `options.scenarios.<name>.options.browser.type = 'chromium'`. Each scenario entry may carry an `options` object, and `browser` is the block k6 v2 hands to the browser module. `type` is required and `'chromium'` is the only accepted value — omitting it gives `browser type option must be set`, and anything else gives `unsupported browser type: <value>`. Because it is per-scenario, one script can run a browser scenario and a plain protocol scenario side by side, each with its own `exec` function. Everything else about the browser — headless mode, extra Chrome arguments, executable path, global timeout — is configured through `K6_BROWSER_*` environment variables, not through script options.
code
javascript · 35 linesimport http from 'k6/http';
import { browser } from 'k6/browser';
export const options = {
scenarios: {
load: {
executor: 'constant-vus',
exec: 'callApi',
vus: 10,
duration: '30s',
},
ui: {
executor: 'constant-vus',
exec: 'checkFrontend',
vus: 1,
duration: '30s',
options: {
browser: { type: 'chromium' },
},
},
},
};
export function callApi() {
http.get('https://quickpizza.grafana.com/api/pizza');
}
export async function checkFrontend() {
const page = await browser.newPage();
try {
await page.goto('https://quickpizza.grafana.com/');
} finally {
await page.close();
}
}go deeper
Learn the literal path: options.scenarios.<name>.options.browser.type set to 'chromium'. Being able to type that block from memory is what a screening question is checking.
Explain why it nests under a scenario rather than the root, what each of the two error messages means, and that 'chromium' is the only accepted value in k6 v2.
Diagnose from symptoms: a run that starts and then fails on the first page call points at a block attached to the wrong place, while a run that never starts points at a misspelled key inside the scenario entry.
Decide what the team standardises: whether browser configuration is pinned in the script or injected as K6_BROWSER_* variables per environment, and how CI images guarantee a Chromium is actually present.
## Where the switch actually lives k6 v2 turns a scenario into a browser scenario with exactly one setting, and its full path is longer than people expect: ```javascript export const options = { scenarios: { ui: { executor: 'shared-iterations', options: { browser: { type: 'chromium', }, }, }, }, }; ``` Read the nesting carefully. The outer `options` is the exported options object. Inside it, `scenarios` maps a name you choose (`ui` here) to one scenario config. That scenario config has its own `options` key — a per-scenario bag that k6 core does not interpret itself — and `browser` is the block inside it that the browser module reads. So the path is `options.scenarios.<name>.options.browser.type`, and the word `options` legitimately appears twice. At run time k6 decides whether an iteration is a browser iteration by asking one question: **does this scenario's browser block contain a `type` key?** If it does, k6 launches a browser for the iteration; if it does not, it launches nothing. ## What `type` accepts `type` is the only script-level browser option there is, and in k6 v2 it takes exactly one value. | Value | Result | |---|---| | `'chromium'` | The scenario runs against a Chromium k6 launches for it | | any other string | `unsupported browser type: <value>` and the run is aborted | | key omitted entirely | `browser type option must be set` | There is no `'firefox'` and no `'webkit'` in k6 v2. The key name reads like a browser-family selector, which is exactly why a value such as `'firefox'` looks plausible right up to the moment the run rejects it. ## Why the root of the options object is the wrong place The most common misconfiguration is hoisting the block to the top level: ```javascript // wrong — browser is not a root option export const options = { browser: { type: 'chromium' }, vus: 5, duration: '30s', }; ``` This is nastier than a straightforward error, because k6 treats the two levels asymmetrically. An unknown key at the **root** of the exported options object only logs *"There were unknown fields in the options exported in the script"* — the run proceeds. So the script starts, appears healthy, and then the first `browser.newPage()` rejects with a message that spells the real problem out: *browser not found in registry. make sure to set browser type option in scenario definition in order to use the browser module.* An unknown key **inside a scenario entry** is treated far more strictly and fails configuration parsing instead. The practical reading order when a browser run misbehaves is therefore: 1. Did the run start at all? If configuration parsing failed, a key inside the scenario entry is misspelled. 2. Did it start and then fail on the first page call with *browser not found in registry*? The browser block is not attached to the scenario that is executing. 3. Did it start and abort with *unsupported browser type*? The block is in the right place but `type` is not `'chromium'`. ## Per-scenario, and why that is the point Because the switch belongs to a scenario rather than the whole test, a single script can mix a browser scenario with a protocol scenario. Each scenario names its own entry function through `exec`, and only the browser one carries the `options.browser` block: - the protocol scenario runs an `exec` function built on `k6/http` and needs no browser block at all; - the browser scenario carries `options.browser.type` and drives a page; - both run in the same execution, and the single end-of-test summary reports each family of metrics in its own section. The corollary is that you cannot enable the browser for *part* of a scenario. If some iterations need a browser and others do not, that is two scenarios. ## What is not a script option `type` is the whole script-facing surface. Everything else about how the browser is launched comes from environment variables read by the browser module: - **`K6_BROWSER_HEADLESS`** — headless mode, `true` by default. - **`K6_BROWSER_ARGS`** — extra Chrome command-line arguments. - **`K6_BROWSER_EXECUTABLE_PATH`** — which Chromium binary to launch. - **`K6_BROWSER_TIMEOUT`** — the module's global timeout. - **`K6_BROWSER_DEBUG`** and **`K6_BROWSER_LOG`** — the module's own diagnostics. Adding any of those as keys next to `type` in the script does not configure them; the browser block is not a general-purpose launch config.
- A script sets browser.type at the root of the options object. What does k6 do?It logs that there were unknown fields in the exported options and runs anyway. The scenario never becomes a browser scenario, so the first `browser.newPage()` rejects with `browser not found in registry. make sure to set browser type option in scenario definition`.
- How would you run half your iterations with a browser and half without?You would not — you would write two scenarios. The browser switch is a property of a scenario, so the split is a browser scenario with `options.browser.type` and a second scenario without it, each pointing at its own `exec` function.
- Can you set headless mode or extra Chrome flags next to `type`?No. `type` is the only script option in the browser block. Headless mode, Chrome arguments, the executable path and the module timeout are all `K6_BROWSER_*` environment variables, read by the browser module when it launches the process.
saying these in an interview costs you the question
- Puts browser.type at the root of the exported options object
- Thinks type accepts firefox or webkit in k6 v2
- Sets headless or Chrome args as keys beside type
- Assumes one browser block switches on the whole test
- Expects a missing browser block to fail config parsing loudly