Install one Playwright tree, and notice when a container has two
Setup installed `playwright@latest` and `@playwright/cli@latest` together. Verified on a real container, that produces a tree that looks right and is broken: `@playwright/cli@0.1.18` pins `playwright-core@1.63.0-alpha`, npm hoists it, and `playwright@latest` (1.62.1) nests its own `playwright-core@1.62.1` beside it. The two cores want different browser revisions. The browser step runs the *resolved* — hoisted — CLI, so it downloads chromium-1237. Every script Claude writes says `require("playwright")`, gets the nested 1.62.1, and dies with: Executable doesn't exist at …/chromium_headless_shell-1234/… while the pane reports a browser installed, because one is. This is deterministic, not bad luck: every container set up through the pane lands in it. So the viewer package is installed first, and the `playwright` version installed after it is the one that package pins — read from the manifest npm just wrote, falling back to `@latest` only if it cannot be read. One core, one browser revision, both halves agreeing. Re-running "Set up Playwright" repairs an already-split tree. Detection now asks the question directly rather than listing a cache: it asks each resolved copy for `chromium.executablePath()` and whether that file exists — the viewer's copy *and* the one `require("playwright")` returns, since those are routinely different. `needs_browser()` covers "installed but not launchable", and the pane names both halves instead of saying "install a browser" over a cache that visibly has one. An absent field is "the probe didn't answer", never "skewed": containers predating these fields must not be told their browsers are wrong. The Rust side gets that from Option; the TypeScript mirror needed `!= null`, which an existing test caught. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,6 +69,11 @@ const NOTHING: PlaywrightDetection = {
|
||||
cli_entry: null,
|
||||
browsers: [],
|
||||
chrome_channel: null,
|
||||
chromium_executable: null,
|
||||
chromium_executable_exists: false,
|
||||
script_playwright_version: null,
|
||||
script_chromium_executable: null,
|
||||
script_chromium_executable_exists: false,
|
||||
searched: [
|
||||
"/workspace",
|
||||
"/usr/lib/node_modules",
|
||||
@@ -362,6 +367,41 @@ describe("BrowserTab", () => {
|
||||
expect(screen.queryByTitle(/browser view for/i)).toBeNull();
|
||||
});
|
||||
|
||||
it("names both halves when the installed browser isn\u2019t the one Playwright launches", async () => {
|
||||
// The cache is full and every script fails \u2014 "install a browser" alone
|
||||
// would read as nonsense, so the copy has to say which copy wants what.
|
||||
checkBrowserViewSupport.mockResolvedValue({
|
||||
...READY,
|
||||
browsers: ["chromium-1237"],
|
||||
chromium_executable: "/home/claude/.cache/ms-playwright/chromium-1237/chrome-linux64/chrome",
|
||||
chromium_executable_exists: true,
|
||||
script_playwright_version: "1.62.1",
|
||||
script_chromium_executable:
|
||||
"/home/claude/.cache/ms-playwright/chromium-1234/chrome-linux64/chrome",
|
||||
script_chromium_executable_exists: false,
|
||||
});
|
||||
|
||||
render(<BrowserTab project={project} active />);
|
||||
|
||||
expect(await screen.findByText(/isn\u2019t the one Playwright launches/i)).toBeInTheDocument();
|
||||
// Both revisions appear in the explanation: what is installed, and what
|
||||
// the failing copy actually wants.
|
||||
expect(screen.getAllByText(/chromium-1237/).length).toBeGreaterThan(0);
|
||||
expect(screen.getAllByText(/chromium-1234/).length).toBeGreaterThan(0);
|
||||
expect(screen.getAllByText(/Set up Playwright/).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("does not call an unanswered probe a skew", async () => {
|
||||
// A container older than these fields omits them; unknown is not broken.
|
||||
checkBrowserViewSupport.mockResolvedValue({ ...READY, browsers: ["chromium-1200"] });
|
||||
getBrowserViewStatus.mockResolvedValue(LIVE);
|
||||
|
||||
render(<BrowserTab project={project} active />);
|
||||
|
||||
expect(await screen.findByTitle("Playwright browser view for api-server")).toBeInTheDocument();
|
||||
expect(screen.queryByText(/isn\u2019t the one Playwright launches/i)).toBeNull();
|
||||
});
|
||||
|
||||
it("only offers a window of its own once there is something to watch", async () => {
|
||||
checkBrowserViewSupport.mockResolvedValue({ ...READY, browsers: ["chromium-1200"] });
|
||||
render(<BrowserTab project={project} active />);
|
||||
|
||||
Reference in New Issue
Block a user