fix(browse): capture active-tab state before close() — last-tab auto-create raced the close event

closeTab checked `tabId === this.activeTabId` AFTER awaiting page.close(),
but the page 'close' event handler can fire during that await and reassign
activeTabId — losing the race meant the last-tab auto-create never ran,
leaving the manager with zero tabs. Capture wasActive before closing, and
only reassign activeTabId when it no longer points at a live tab.

Part of the test-integrity repairs unmasked by the suite-truncation fix.

Contributed by @time-attack (PR #2230, browser-manager hunk).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan 2026-08-14 18:46:46 -07:00
parent f77bbe7091
commit 3aab765417
No known key found for this signature in database
GPG Key ID: C1F69E85C74EFE1D
1 changed files with 16 additions and 4 deletions

View File

@ -798,19 +798,31 @@ export class BrowserManager {
const page = this.pages.get(tabId);
if (!page) throw new Error(`Tab ${tabId} not found`);
// Capture BEFORE close(): the page 'close' event handler wired in
// wirePageEvents() can fire while page.close() is awaited. It removes
// the tab from the maps and reassigns activeTabId (to 0 when no tabs
// remain), so a post-close `tabId === this.activeTabId` check is
// order-dependent — whether the event dispatches before or after
// close() resolves varies across Playwright/Chromium versions and
// machines, and losing the race means the last-tab auto-create below
// never runs, leaving the manager with zero tabs.
const wasActive = tabId === this.activeTabId;
await page.close();
this.pages.delete(tabId);
this.tabSessions.delete(tabId);
this.tabOwnership.delete(tabId);
// Switch to another tab if we closed the active one
if (tabId === this.activeTabId) {
if (wasActive) {
const remaining = [...this.pages.keys()];
if (remaining.length > 0) {
this.activeTabId = remaining[remaining.length - 1];
} else {
if (remaining.length === 0) {
// No tabs left — create a new blank one
await this.newTab();
} else if (!this.pages.has(this.activeTabId)) {
// The 'close' handler may have already switched to a valid tab;
// only reassign when activeTabId no longer points at a live tab.
this.activeTabId = remaining[remaining.length - 1];
}
}
}