fix: align browser history tab metadata

This commit is contained in:
Shakker
2026-08-11 15:23:23 +02:00
parent aca083ae0c
commit 6aab02e6a5
2 changed files with 65 additions and 0 deletions
@@ -656,6 +656,58 @@ describe("BrowserPanelController capture and input ownership", () => {
expect(inspections[0]?.[1]).toMatchObject({ body: { targetId: "tab-a" } });
});
it("reconciles selected tab metadata from the captured history document", async () => {
vi.useFakeTimers();
stubScreenshotMedia();
const currentUrl = "https://example.test/current";
const previousUrl = "https://example.test/previous";
const { client, request } = createBrowserClient(async (envelope) => {
if (envelope.path === "/act") {
const fn = String(envelope.body?.fn ?? "");
return fn.includes("history.go")
? { result: true }
: createBrowserPanelTestMetrics(previousUrl, "Previous");
}
if (envelope.path === "/screenshot") {
return { path: "/fresh.png", targetId: "raw-a", url: previousUrl };
}
throw new Error(`Unexpected browser route: ${envelope.path}`);
});
const controller = createBrowserPanelTestController(client, "tab-a", currentUrl);
controller.tabs = [
{ id: "tab-a", targetId: "raw-a", title: "Current", url: currentUrl },
{
id: "tab-b",
targetId: "raw-b",
title: "Background",
url: "https://example.test/background",
},
];
controller.goHistory(-1);
await flushBrowserResponses();
await vi.advanceTimersByTimeAsync(350);
await flushBrowserResponses();
await vi.runAllTimersAsync();
await flushBrowserResponses();
expect(controller.tabs).toEqual([
{ id: "tab-a", targetId: "raw-a", title: "Previous", url: previousUrl },
{
id: "tab-b",
targetId: "raw-b",
title: "Background",
url: "https://example.test/background",
},
]);
expect(controller.urlDraft).toBe(previousUrl);
expect(
request.mock.calls.filter(([, envelope]) => {
return (envelope as BrowserRequestEnvelope).path === "/tabs";
}),
).toEqual([]);
});
it("never forwards a queued wheel action to a newly selected tab", async () => {
vi.useFakeTimers();
const { client, request } = createBrowserClient(async (envelope) => {
@@ -223,6 +223,19 @@ export class BrowserPanelController implements ReactiveController {
shot.url && observedMetrics?.url && shot.url !== observedMetrics.url
? null
: observedMetrics;
const tabIndex = this.tabs.findIndex((tab) => tab.id === targetId);
const tab = this.tabs[tabIndex];
if (tab) {
// Tab snapshots can lag history and in-page navigation. Keep the active
// tab's stable identity aligned with the document this capture owns.
const url = metrics?.url || shot.url || tab.url;
const title = metrics ? metrics.title : tab.title;
if (url !== tab.url || title !== tab.title) {
const tabs = [...this.tabs];
tabs[tabIndex] = { ...tab, title, url };
this.setState("tabs", tabs);
}
}
this.setState("view", { targetId, dataUrl, image, url: shot.url, metrics });
if (!this.urlDraftEditing && shot.url) {
this.setState("urlDraft", shot.url);