mirror of
https://github.com/Tencent/BrowserSkill.git
synced 2026-09-10 13:01:23 +08:00
- session_stop: exclude tabs still tracked in agentCreatedTabs from the release decision so a tab that failed to close is no longer mistaken for a user tab (which previously kept the window open and leaked the tab). - Distinguish user-created tabs from agent-created tabs in the Agent Window via a pending-tab counter consumed by chrome.tabs.onCreated, so tabs the user opens themselves (new-tab button / Cmd+T / open in new tab) are never taken over by the BrowserSkill control mask. - background overlay: decide per-tab state BEFORE showing controls (overlayStateForTab + pushOverlayStateForTab) so a user tab receives hidden on its first overlay.ready ping instead of flashing control then hiding. - AgentWindowApi.ensureActiveTab now resolves with the activated/created tab id instead of void, so SessionManager can record homeTabId. This fixes the tsc failure flagged in review (the interface previously returned Promise<void> while callers treated the result as number | null). - Wire the production tabManagement.tabs / tabsQuery deps into tool.session_stop, both in the dispatcher and in the disconnect cleanup. They were never injected, which left the agent-tab cleanup and the window-release path as dead code outside tests (behaviour identical to main). Added a dispatcher-level integration test that fails without the wiring: a surviving user tab must release the window, not close it.
59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import { createDisconnectCleanup } from "../disconnect-cleanup";
|
|
import { SessionManager } from "../manager";
|
|
|
|
describe("disconnect session cleanup", () => {
|
|
it("stops every local session through the safe session-stop path", async () => {
|
|
const remove = vi.fn(async () => {});
|
|
let nextWindowId = 100;
|
|
const manager = new SessionManager({
|
|
agentWindow: {
|
|
create: vi.fn(async () => nextWindowId++),
|
|
ensureActiveTab: vi.fn(async () => 1),
|
|
remove,
|
|
},
|
|
});
|
|
await manager.start("aa11");
|
|
await manager.start("bb22");
|
|
const detachSession = vi.fn(async () => {});
|
|
const onSessionsChanged = vi.fn();
|
|
const cleanup = createDisconnectCleanup({
|
|
manager,
|
|
sessionStopDeps: { cdp: { detachSession } },
|
|
onSessionsChanged,
|
|
});
|
|
|
|
const report = await cleanup();
|
|
|
|
expect(report).toEqual({ stoppedSessionIds: ["aa11", "bb22"], failures: [] });
|
|
expect(manager.list()).toEqual([]);
|
|
expect(remove).toHaveBeenCalledTimes(2);
|
|
expect(detachSession).toHaveBeenCalledWith("aa11");
|
|
expect(detachSession).toHaveBeenCalledWith("bb22");
|
|
expect(onSessionsChanged).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("coalesces overlapping disconnect notifications", async () => {
|
|
let releaseRemove: () => void = () => {};
|
|
const removeGate = new Promise<void>((resolve) => {
|
|
releaseRemove = resolve;
|
|
});
|
|
const manager = new SessionManager({
|
|
agentWindow: {
|
|
create: vi.fn(async () => 100),
|
|
ensureActiveTab: vi.fn(async () => 1),
|
|
remove: vi.fn(() => removeGate),
|
|
},
|
|
});
|
|
await manager.start("aa11");
|
|
const cleanup = createDisconnectCleanup({ manager });
|
|
|
|
const first = cleanup();
|
|
const second = cleanup();
|
|
expect(second).toBe(first);
|
|
releaseRemove();
|
|
|
|
await expect(first).resolves.toEqual({ stoppedSessionIds: ["aa11"], failures: [] });
|
|
});
|
|
});
|