// Agents' tabs go in the user's window, inactive, in per-session tab groups that start collapsed. // An inactive tab takes trusted input and renders screenshots (measured 2026-11-14), so there is no // need for a window per session. A window is created only when Brave has none. import assert from "node:assert/strict"; import fs from "node:fs"; import vm from "node:vm"; import { test } from "node:test"; const workerSource = fs.readFileSync(new URL("../../extensions/chrome-profile-bridge/browser-extension/service_worker.js", import.meta.url), "utf8"); function worker({ groups = [], windows = { 5: { id: 5, type: "normal" } }, lastFocused = 5, tabs = {} } = {}) { const calls = []; const listener = { addListener() {}, removeListener() {} }; let nextTab = 100; const w = { console, setTimeout, clearTimeout, setInterval: () => 0, navigator: { userAgent: "unit-test" }, fetch: async () => { throw new Error("offline"); }, chrome: { runtime: { id: "test", getManifest: () => ({ version: "0.0.0" }), onInstalled: listener, onStartup: listener }, alarms: { create() {}, onAlarm: listener }, action: { onClicked: listener }, webNavigation: { onCommitted: listener }, debugger: { onDetach: listener, onEvent: listener, getTargets: (cb) => cb([]) }, storage: { session: { get: async () => ({}), set: async (v) => { calls.push({ method: 'storage.set', json: JSON.stringify(v) }); } } }, tabGroups: { query: async () => groups, update: async (id, props) => { calls.push({ method: "tabGroups.update", id, props }); return { id, ...props }; } }, windows: { get: async (id) => windows[id] ?? Promise.reject(new Error("No window")), getLastFocused: async () => (lastFocused === null ? Promise.reject(new Error("No window")) : windows[lastFocused]), getAll: async () => Object.values(windows), update: async (id, props) => { calls.push({ method: "windows.update", id, props }); return { id }; }, create: async (props) => { calls.push({ method: "windows.create", props }); return { id: 9, tabs: [{ id: 900, windowId: 9 }] }; }, }, tabs: { create: async (props) => { calls.push({ method: "tabs.create", props }); return { id: nextTab++, windowId: props.windowId }; }, query: async () => [], get: async (id) => tabs[id] ?? null, onUpdated: listener, group: async () => 77, update: async (id, props) => { calls.push({ method: "tabs.update", id, props }); return { id, ...props }; }, }, }, }; w.self = w; vm.runInNewContext(workerSource, w); return { w, calls }; } const piGroup = (windowId, name = "Pi Session: claude-code 1 other") => ({ id: 1, windowId, title: name }); const ops = (calls) => calls.filter((c) => c.method !== "storage.set").map((c) => c.method); const noWindows = { windows: {}, lastFocused: null }; test("a new session's tab goes in the user's window, inactive", async () => { const { w, calls } = worker({ groups: [piGroup(5)] }); await w.createAutomationTarget("claude-code 2 mine", "Pi Session: claude-code 2 mine"); assert.deepEqual(ops(calls), ["tabs.create"]); const props = calls.find((c) => c.method === "tabs.create").props; assert.equal(props.windowId, 5); assert.equal(props.active, false); }); test("a window is created only when Brave has none", async () => { const { w, calls } = worker(noWindows); await w.createAutomationTarget("claude-code 2 mine", "Pi Session: claude-code 2 mine"); assert.deepEqual(ops(calls), ["windows.create"]); assert.equal(calls[0].props.focused, false); }); test("a session that already has a group adds its tab to that group's window", async () => { const { w, calls } = worker({ groups: [piGroup(7, "Pi Session: claude-code 2 mine")], windows: { 5: { id: 5 }, 7: { id: 7 } } }); await w.createAutomationTarget("claude-code 2 mine", "Pi Session: claude-code 2 mine"); assert.deepEqual(ops(calls), ["tabs.create"]); assert.equal(calls.find((c) => c.method === "tabs.create").props.windowId, 7); }); test("chrome_tab new for a session with no group goes in the user's window, inactive", async () => { const { w, calls } = worker({ groups: [piGroup(5)] }); w.groupTab = async (tab) => tab; w.bringToFront = async () => {}; await w.dispatch("tab.new", { url: "https://x.test/", groupTitle: "Pi Session: claude-code 2 mine", sessionKey: "claude-code 2 mine" }); assert.deepEqual(ops(calls), ["tabs.create"]); assert.equal(calls[0].props.windowId, 5); assert.equal(calls[0].props.active, false); }); test("chrome_tab new with no window open creates an unfocused one", async () => { const { w, calls } = worker(noWindows); w.groupTab = async (tab) => tab; w.bringToFront = async () => {}; await w.dispatch("tab.new", { url: "https://x.test/", groupTitle: "Pi Session: claude-code 2 mine", sessionKey: "claude-code 2 mine" }); assert.deepEqual(ops(calls), ["windows.create"]); assert.equal(calls[0].props.focused, false); }); test("a new group starts collapsed; an existing group keeps the user's setting", async () => { const { w, calls } = worker({ tabs: { 300: { id: 300, windowId: 5, active: false, groupId: -1 }, 301: { id: 301, windowId: 5, active: false, groupId: 77 } } }); w.groupRecord = async (id) => ({ id }); w.formatTab = async (t) => t; await w.groupTab({ id: 300, windowId: 5, groupId: -1 }, "Pi Session: x", "blue"); await w.groupTab({ id: 301, windowId: 5, groupId: 77 }, "Pi Session: x", "blue"); const updates = calls.filter((c) => c.method === "tabGroups.update").map((c) => c.props.collapsed); assert.deepEqual(updates, [true, undefined]); }); test("a new group holding the tab that is showing is not collapsed", async () => { const { w, calls } = worker({ tabs: { 300: { id: 300, windowId: 5, active: true, groupId: -1 } } }); w.groupRecord = async (id) => ({ id }); w.formatTab = async (t) => t; await w.groupTab({ id: 300, windowId: 5, groupId: -1 }, "Pi Session: x", "blue"); assert.equal(calls.find((c) => c.method === "tabGroups.update").props.collapsed, false); }); test("bringing a tab forward expands its group", async () => { const { w, calls } = worker(); await w.bringToFront({ id: 300, windowId: 5, groupId: 77 }, { foreground: true, background: false }); assert.deepEqual(ops(calls), ["windows.update", "tabGroups.update", "tabs.update"]); assert.equal(calls[1].props.collapsed, false); }); test("input is sent to an inactive tab; only a minimized window refuses it", async () => { const { w } = worker({ windows: { 5: { id: 5, state: "normal" }, 6: { id: 6, state: "minimized" } }, tabs: { 300: { id: 300, windowId: 5, active: false }, 301: { id: 301, windowId: 6, active: true } } }); w.pageVisibilityState = async () => "hidden"; await w.assertTabVisibleForInput({ id: 300, windowId: 5 }, {}, "chrome.click"); await assert.rejects(w.assertTabVisibleForInput({ id: 301, windowId: 6 }, {}, "chrome.click"), /minimized/); });