In Cypress's `before:browser:launch`, what must the handler do with `launchOptions`?
answer
- The Node side works on a copy
- Mutation alone does not travel back
- One argument describes what is launching
- Only four keys are accepted back
- Every branch ends the same way
basics
~20 sChange the launchOptions it was given - args, preferences, extensions or env - and then return it. Only the returned object is merged back into the real launch options, so a handler that forgets to return contributes nothing at all.
solid answer
~40 sThe handler is called with `(browser, launchOptions)` and must **return** the launch options it wants. `setupNodeEvents` runs in a child process, so the `launchOptions` it receives is a copy: mutating `launchOptions.args` and returning nothing changes the copy and leaves the browser untouched, with no warning. Return the object you were handed - Cypress fails the run if the returned object carries any key beyond `args`, `preferences`, `extensions` and `env`. Gate every change on the `browser` argument, because `args` has no effect on Electron and `preferences` has a different shape in each family; `browser.family === 'chromium' && browser.name !== 'electron'` is the usual guard, since Electron reports itself as chromium.
code
javascript · 25 linesconst { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
setupNodeEvents(on) {
on('before:browser:launch', (browser = {}, launchOptions) => {
const isChromium =
browser.family === 'chromium' && browser.name !== 'electron'
if (isChromium && browser.isHeadless) {
// wide enough that the tenant settings table fits in failure shots
launchOptions.args.push('--window-size=1600,1200')
launchOptions.args.push('--force-device-scale-factor=1')
}
if (browser.family === 'firefox') {
launchOptions.preferences['browser.download.folderList'] = 2
}
// without this return, none of the above reaches the browser
return launchOptions
})
},
},
})go deeper
Know that this hook exists and that it is where a browser flag or an extension is added. Being able to name its two arguments is enough at this level.
Explain why the return value matters when the object was already mutated, and what the four permitted keys mean in each browser family. This is the mechanics tier for this event.
Be ready to diagnose a launch flag that works locally and not in CI, and to say how you would keep browser-specific switches from silently accumulating in a shared configuration file.
Take a position on how much of a suite's browser behaviour may be tuned here at all, given that a launch switch is invisible in the run output and cannot be asserted on by any test.
## What the event is for `before:browser:launch` fires in Node immediately before Cypress launches a browser. It is the only seam that runs while the browser does not yet exist, which is why command-line switches, browser preferences, unpacked extensions and the browser process's own environment can be changed here and nowhere else. The handler receives two arguments: - **`browser`** - a description of what is about to launch: `name` (`chrome`, `edge`, `firefox`, `electron`), `family` (`chromium` or `firefox`), `channel`, `version`, `majorVersion`, `path`, `isHeadless` and `isHeaded`. - **`launchOptions`** - the four things you are allowed to change: `args`, `preferences`, `extensions` and `env`. ## Return it, do not merely mutate it `setupNodeEvents` runs in a child process. The `launchOptions` object your handler receives crossed that process boundary as a **copy**, so pushing onto `launchOptions.args` changes the copy and nothing else. Cypress merges back only what the handler **returns**: - Object-shaped properties (`preferences`, `env`) are merged key by key into the real launch options. - Array-shaped properties (`args`, `extensions`) are replaced wholesale by what you return, which is harmless as long as you return the object you were handed - it already carries Cypress's own entries alongside yours. - Returning nothing is not an error and produces no warning. The browser simply launches with the options Cypress started from, which is precisely why a forgotten `return launchOptions` is so easy to miss in review. Return the object you were given rather than assembling a fresh one. Cypress rejects a returned object carrying **any key outside `args`, `preferences`, `extensions` and `env`**, failing the run with a message that lists both the unexpected properties and the four permitted ones. ## Gate every change on the browser The same key means different things per browser, so a handler that changes something unconditionally will do the wrong thing on at least one of them. | launch option | chromium family | firefox | electron | |---|---|---|---| | `args` | Chromium command-line switches | Firefox command-line options | no effect | | `preferences` | `default`, `localState` and `secureDefault` maps | flat map of `about:config` preferences | a `BrowserWindow` options object | | `extensions` | absolute paths to unpacked extensions | absolute paths to unpacked extensions | DevTools extensions only | | `env` | environment for the browser process | environment for the browser process | not supported | Electron reports `family: 'chromium'`, so the correct guard for Chromium-only switches is `browser.family === 'chromium' && browser.name !== 'electron'`. Two further limits are worth knowing as of Cypress 16: - Headless Chrome cannot load extensions at all. - Chrome-branded builds from version 137 onward no longer load extensions through this event either, because Chrome removed the command-line flag Cypress relied on. Chrome for Testing and Chromium still work. ## The trap: window size is not viewport size Pushing `--window-size=1600,1200` for a headless run changes the **screen** the browser believes it has, and therefore the size of screenshots and videos. It does **not** change `viewportWidth` and `viewportHeight`, which govern the frame the application under test renders inside. A team chasing cropped failure screenshots of a wide admin console table wants this event; a team trying to exercise a narrow layout wants the viewport configuration instead, and confusing the two produces a change that looks like it worked and tested nothing new. ## Keeping the handler honest 1. **Branch on `browser`, never on the machine.** A handler that inspects an environment variable instead of `browser.name` behaves differently on a laptop and on CI, which is the hardest class of difference to reproduce. 2. **Every branch returns.** Each branch that changes something must end in `return launchOptions`, and so should the fall-through for browsers you did not special-case. 3. **Say why in a comment.** A pushed Chromium switch never appears in the run output. Six months later nobody can tell whether it is still load-bearing. 4. **Prefer configuration where it exists.** If Cypress already exposes the behaviour as a configuration value, change that instead: a launch switch is the least discoverable place in the project to hide a decision.
- What happens if a Cypress `before:browser:launch` handler returns `{ args, headless: true }`?The run fails immediately. Cypress checks the returned object against the four keys it knows - `args`, `preferences`, `extensions` and `env` - and reports any others as unexpected properties, listing both what you sent and what is allowed. Whether the browser is headless is decided by the CLI and the configuration, not by this handler.
- Why does pushing `--window-size` in a Cypress launch handler not change `viewportWidth`?They describe different things. `--window-size` tells the browser how large a screen it has, which sets the size of screenshots and video for a headless run. `viewportWidth` and `viewportHeight` size the frame the application under test renders in, and Cypress applies them inside that window regardless of how big the window is.
saying these in an interview costs you the question
- Assumes mutating launchOptions is enough without returning it
- Applies Chromium switches to every browser unconditionally
- Thinks Electron honours args pushed by the handler
- Believes --window-size changes the configured viewport