Blog · November 3, 2026 · 7 min read
Running Headed Browser Tests on Your Mac While You Step Away
There is a kind of test run that cannot be left alone on a Mac. Not the headless one that CI runs; that is fine, it does not need a screen. The one you start with --headed because a test only fails when you can see it, or the visual regression suite whose screenshots have to match pixel for pixel, or the Selenium job that drives a real Chrome window through a flow with drag-and-drop and hover menus. Those runs need the display awake and they need nobody, including you, to touch the machine for twenty minutes. Reach for the mouse to check Slack, and the hover menu the test was about to click closes. Let the screen sleep, and the browser stops repainting. This post is about making that twenty minutes safe: what actually breaks a headed run, the free tool that fixes half of it, and what VibeLock adds for the other half.
What breaks a headed run when you walk away
Four things, in rough order of how often they bite.
- Display sleep and the screen saver. A headed browser is drawing to a real window. When macOS turns the display off, rendering, animation timing and anything that depends on the page being visible (intersection observers,
requestAnimationFrame, video playback) behave differently from a lit screen. Screenshot comparisons taken across a sleep boundary are the classic unexplained diff. - Stray keystrokes. The test browser is the frontmost window. Anything you type, including the reflexive Cmd-Tab to look at something else, lands in it. A single space can scroll the page the test is measuring; a Cmd-W closes the tab it is driving.
- Pointer movement and clicks. Browser automation synthesises mouse events for the page, but the real cursor is still on screen. Bump the trackpad over a hover menu and the page gets a genuine
mouseleave; click anywhere and focus moves. Tests that wait for a tooltip or a dropdown are the ones that fail with a timeout and no obvious cause. - Focus stealing. A notification, a calendar reminder, another app updating itself and asking for attention, all of these can take focus from the browser window. Some test runners cope; keyboard-driven tests mostly do not.
You cannot fix all four with one setting. The first is a power management problem; the other three are an input problem, and macOS has no built-in way to ignore input while keeping the screen on. The Lock Screen shortcut blanks the display, which is the opposite of what a headed run needs.
The free half: caffeinate
macOS ships a command-line tool for the display problem. The man page for caffeinate says it “creates assertions to alter system sleep behavior,” and the flag you want is -d, which creates “an assertion to prevent the display from sleeping.” Pass the test command as the argument and the assertion lasts exactly as long as the run:
# Playwright, headed, display held awake for the duration of the run
caffeinate -d npx playwright test --headed
# Cypress run with a real browser window
caffeinate -d npx cypress run --headed --browser chrome
# belt and braces: display (-d), idle sleep (-i), and disk (-m)
caffeinate -dim npm run test:e2e:headedThe other flags, from the same man page: -i prevents the system from idle sleeping, -m prevents the disk from idle sleeping, -s prevents system sleep but is “valid only when system is running on AC power,” -u declares the user active and turns the display on if it was off, and -t sets a timeout in seconds. With no flags at all, caffeinate only prevents idle sleep, which does not keep the display lit, so the -d is not optional for a headed run. A lid gotcha: a sleep assertion is not clamshell mode, so a MacBook with the lid closed and no external display and power attached still goes to sleep; keep it open.
What caffeinate does not do is touch input. The keyboard, the trackpad and the mouse all work exactly as before, which means the run is only safe for as long as nobody touches the Mac. On your own desk, that includes you.
The other half: ignore every key and click, keep the window on screen
VibeLock is a $10 one-time macOS menu bar app, macOS 13 Ventura or later, built for exactly the walk-away case. Locking does three things at once. It blocks every keystroke, click, scroll and gesture system-wide through an event tap, including Spotlight, Force Quit and Cmd-Q, so nothing you or anyone else does at the keyboard reaches the test browser. It hides every app that is not on your “Visible While Locked” list behind an opaque backdrop and keeps them hidden, which removes the focus-stealing apps from the screen. And it holds a macOS “no display sleep” power assertion while locked, released on unlock, so you do not need caffeinate for the display at all (though running both does no harm). You unlock with Touch ID, or by typing your Mac login password into VibeLock's own shield; nothing new to remember.
The one setup step that matters for test runs is the allowlist. VibeLock pre-allows terminals (Terminal, iTerm2, Warp, Ghostty, kitty, Alacritty, WezTerm), Claude desktop, ChatGPT/Codex and VS Code. That pre-allowed list does not include Chrome, Firefox, Safari or WebKit. If the browser the test drives is not ticked under Visible While Locked when you lock, VibeLock hides it, and a hidden window is not a window that can be screenshotted or clicked. So before the first headed run: menu bar, Visible While Locked, tick the browser (and the Playwright or Cypress runner UI if you use one). Visible means watch-only: the window stays on screen and keeps rendering, while real input aimed at it is swallowed. That is the correct state for a test browser, because the only “input” it should receive is the synthetic kind the automation library sends, and an event tap does not intercept those.
Two honest caveats from the security model page. The cursor still moves while locked (clicks do nothing), so if your suite is sensitive to the physical pointer position, park the mouse in a corner before you lock. And trackpad gestures that switch Spaces cannot be blocked by an event tap; VibeLock covers a Space that shows a blocked app with its shield, but a four-finger swipe can still move the visible Space away from the browser. Keep the test browser on the Space you lock from, and keep your hands off the trackpad, which was the plan anyway.
A checklist for the headed run
- Decide whether the run truly needs a head. If it passes headless and you only want to watch it, use Playwright's trace viewer or Cypress's recorded video afterwards instead and skip the rest of this list.
- Plug in. caffeinate's
-sonly works on AC, and a thirty-minute suite on battery with the display forced on is a thirty-minute suite that may not finish. - Close or mute notification sources: a Focus mode stops banners, which VibeLock cannot hide because macOS draws them.
- In VibeLock, tick the browser under Visible While Locked. Leave Accessible While Locked empty; the browser should not accept real input.
- Start the run from a visible terminal with
caffeinate -din front of it, confirm the first test is actually running in a window you can see, then lock from the menu bar. - Park the cursor in a corner, take your hands off, go. A glance from across the room shows the terminal scrolling and the browser working; an unlock with Touch ID brings everything back exactly as it was.
When not to do this
If the run is part of CI, run it headless on CI and stop reading; a locked laptop is not a build agent, and VibeLock is not a substitute for a proper runner. If the test needs you, say to click through a one-time-password prompt halfway, locking the keyboard just turns that into a timeout; either mark the browser Accessible While Locked for that one step (it then accepts your typing while everything else stays locked) or do not lock until the prompt is past. If the suite prints anything secret to the terminal or the browser, remember that a visible app is readable by anyone who walks past; VibeLock protects against touching, not looking. And if the machine is shared or in a public place, the honest option is the one we give in the cafe and coworking post: take it with you.
This is the same pattern as leaving an export or render running, which we covered in the long export post, and the same reason people first picked up VibeLock to leave Claude Code running while away: a process that needs the screen on and the keyboard dead for a while, on a machine you are about to walk away from. A headed test suite is just the case where the thing on screen is a browser doing your clicking for you, and where one real click of yours is enough to make it lie.