Short answer: define what must stay true when actions overlap, control their completion order in the test, and add a real browser scenario. A test in which two calls run one after another does not prove the code handles overlap.
Define the invariant before writing the test
A browser extension connects local code to state that changes outside it. A tab can close, a group can change, and a debugging connection can end. So ask what must be preserved between the start of an action and its completion.
In the public contribution to real-browser-mcp, a case appeared where two requests for a group's name on the same tab could create two groups. PR #71 describes a fix that orders actions per tab and re-reads the tab state inside the lock. That is a concrete example of the same gap: state read before the wait may be stale when the action begins.
Create overlap you can reproduce
A synthetic illustration: two requests see a tab with no group. Each prepares to create one. In the test, hold the first call's promise open, start the second, and only then let the first complete.
At the end, check how many times group creation ran and what the tab's final state is. If the requirement is one group, two "success" results are not enough. Ask the agent to show that under the same action order the old version fails and the new one meets the requirement.
The example is a proposed way to test. The completion order should represent the real interface, not a substitute that only permits the order convenient for the code.
Lock on the right resource
A per-tab lock can fit actions on the tab's group. A resource shared across the whole extension needs different thinking. PR #72 describes a single queue for acquiring a debugger connection and using it, to prevent two overlapping acquisitions with partial tracking.
The choice is not a blanket "add a mutex." Define which actions share state, what can run in parallel, and when the guard is released. Also test an error inside the action: a failure must leave a way for the next action to proceed per the contract, not jam the queue.
Separate external signals from connection ownership
Per Chrome's documentation, a failed debugger connection rejects the promise. An onDetach event arrives when the browser ends the session, for example when the tab closes or when DevTools opens on the attached tab.
A message about another debugger is not proof your extension holds the connection. PR #72 describes a probe that tries to distinguish a connection the extension still holds after a worker restart from a connection failure. Test both paths against the behavior the code actually implements.
Add a test at the Chrome boundary
A unit test with a mock can control overlap and count calls. It does not prove that permissions, browser messages, and close events behave the way you expected.
As proposed scenarios, test two overlapping requests, a tab closing mid-action, and DevTools opening during a session. An extension using the debugger needs the debugger permission in the manifest; using the tabGroups API requires the tabGroups permission. Match permissions to the actual implementation, and don't add a permission just to make a test pass.
Ask for a report that separates layers
When done, the agent should state what was tested with a mock, what was tested in a browser, what the event order was, and which version the test ran against. There is no need to promise coverage of every possible race. What is needed is evidence for the scenario that was found, and clear boundaries for what still needs testing.
From my experience
In my post about contributing to real-browser-mcp, I described a contributor who came back after review with two separate PRs and fixes for the cases found in testing. This guide proposes a working approach that can be applied to another contribution, without assuming every change has already been tested.
In short
Define what must stay true when actions overlap, control their completion order in the test, and add a real browser scenario. A test in which two calls run one after another does not prove the code handles overlap.
FAQ
Is Promise.all enough to test a race?
It can start overlapping calls, but it does not guarantee the problematic order actually happened. Control the await points and check the final state.
Should every action in the extension be locked?
Choose a guard based on the shared state and the requirement. A lock that is too wide can block permitted parallelism; one that is too narrow can leave a collision.
Does a mock test replace a browser test?
It helps control the event order. Permissions, detachments, and Chrome behavior also need testing at the real boundary.
About the author
Ofer Shapira - AI builder and lead in development teams, writing about agents, decisions, and workflows you can verify.
Top comments (0)