How to Test Race Conditions in a Browser Extension an AI Agent Modifies A developer has published a testing approach for catching race conditions in browser extensions that AI agents modify, centered on the real-browser-mcp project. The method requires defining invariants that must hold when actions overlap, controlling completion order in tests, and validating behavior in a real browser rather than only with mocks. The writeup cites PR #71, which fixes duplicate tab-group creation by ordering actions per tab and re-reading tab state inside the lock, and PR #72, which uses a single queue for debugger connection acquisition. 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. 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. 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. 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. 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. 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. 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. 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. 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. It can start overlapping calls, but it does not guarantee the problematic order actually happened. Control the await points and check the final state. 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. It helps control the event order. Permissions, detachments, and Chrome behavior also need testing at the real boundary. Ofer Shapira - AI builder and lead in development teams, writing about agents, decisions, and workflows you can verify.