test(browser): stop gating chromium tests on a top-level-await export

`bun test` fails the coding-agent native/unit job with

  ReferenceError: Cannot access 'CHROMIUM_AVAILABLE' before initialization

in test/tools/browser-attach.test.ts and browser-tab-evaluate.test.ts,
taking the job red on every pull request.

chromium-probe.ts initializes its only export with top-level await. When
a test file importing it is the first file the runner loads, the await
settles before that file evaluates and the binding reads fine. When any
other test file was loaded first, the importer's body runs while the
binding is still in its temporal dead zone, and registration throws at
the `skipIf` call. `bun test <one file>` passes and `bun test --parallel=1
<any earlier file> <that file>` fails, which is why the job fails while a
single-file run does not.

Export the memoized probe as a function and let each test file await it
during its own evaluation, which the runner sequences. The probe still
runs once per process and resolves the executable exactly as before.

Signed-off-by: Christian Stewart <christian@aperture.us>
This commit is contained in:
Christian Stewart
2026-08-02 04:50:54 -07:00
parent 06343fef42
commit 78a4d2ea5a
4 changed files with 30 additions and 4 deletions
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- Fixed Chromium-backed tests failing during suite registration when the shared availability probe was still initializing ([#7384](https://github.com/can1357/oh-my-pi/pull/7384) by [@paralin](https://github.com/paralin)).
## [17.2.4] - 2026-08-01
### Added
@@ -11,7 +11,9 @@ import {
} from "@oh-my-pi/pi-coding-agent/tools/browser/registry";
import { acquireTab, releaseTab } from "@oh-my-pi/pi-coding-agent/tools/browser/tab-supervisor";
import type { Browser, Page, Target } from "puppeteer-core";
import { CHROMIUM_AVAILABLE } from "./chromium-probe";
import { chromiumAvailable } from "./chromium-probe";
const CHROMIUM_AVAILABLE = await chromiumAvailable();
interface FakePageOptions {
url: string;
@@ -3,7 +3,9 @@ import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/sdk";
import { BrowserTool } from "@oh-my-pi/pi-coding-agent/tools/browser";
import { getTabsMapForTest } from "@oh-my-pi/pi-coding-agent/tools/browser/tab-supervisor";
import { CHROMIUM_AVAILABLE } from "./chromium-probe";
import { chromiumAvailable } from "./chromium-probe";
const CHROMIUM_AVAILABLE = await chromiumAvailable();
function makeSession(): ToolSession {
return {
@@ -17,5 +17,23 @@ async function chromiumCanLaunch(): Promise<boolean> {
}
}
/** Gate for tests that launch a real Chromium: `describe.skipIf(!CHROMIUM_AVAILABLE)`. */
export const CHROMIUM_AVAILABLE = await chromiumCanLaunch();
let probe: Promise<boolean> | undefined;
/**
* Gate for tests that launch a real Chromium:
*
* const CHROMIUM_AVAILABLE = await chromiumAvailable();
* describe.skipIf(!CHROMIUM_AVAILABLE)(…);
*
* The result is a promise rather than an awaited `export const`. A module whose
* exports are initialized by top-level await hands the test runner a binding
* that is still in its temporal dead zone when a second test file in the same
* process imports it, and that file dies during registration with "Cannot
* access 'CHROMIUM_AVAILABLE' before initialization". Awaiting in the importer
* makes the wait part of that file's own evaluation, which the runner does
* sequence. The probe runs once per process.
*/
export function chromiumAvailable(): Promise<boolean> {
probe ??= chromiumCanLaunch();
return probe;
}