import { assert, assertEquals } from "@std/assert";
import { until } from "@berry/util";
import { viewContext, withDom } from "@berry/util/dom.ts";
import type { ViewContext } from "@berry/api/web.ts";
import { browserView } from "./view.ts";
import type { BrowserViewData, Snapshot } from "./types.ts";
const page = (tab: string, title: string): Snapshot => ({
tab,
title,
url: "https://example.com/",
text: ` ${title}`,
elements: [{ ref: "e1", role: "button", name: "Continue" }],
truncated: false,
frames: [],
diagnostics: ["HTTP 404: https://example.com/missing"],
});
const context = (request: ViewContext["request"], latest = 1) =>
viewContext({ tid: "conversation", latest, request });
Deno.test("the close button ends a live session and then shows it as ended", () =>
withDom(async () => {
const view = browserView();
const requests: string[] = [];
let active = true;
view.update(context((name) => {
requests.push(name);
if (name === "close") active = false;
return Promise.resolve(
name === "close"
? null
: { active, tabs: [page("t1", "First")], history: [], screenshots: [] },
);
}));
try {
const close = [...view.element.querySelectorAll("button")]
.find((button) => button.textContent === "Close browser") as HTMLButtonElement;
await until(() => !close.disabled);
close.click();
await until(() =>
view.element.querySelector('[role="status"]')?.textContent?.includes("historical") ?? false
);
assertEquals(requests, ["view", "close", "view"]);
assert(close.disabled);
} finally {
view.dispose?.();
}
}));
Deno.test("outdated view responses and disposed requests cannot replace the current conversation", () =>
withDom(async () => {
const view = browserView();
let resolveOld!: (value: BrowserViewData) => void;
let oldSignal!: AbortSignal;
const old = context((_, __, options) => {
oldSignal = options!.signal!;
return new Promise((resolve) => {
resolveOld = resolve;
});
});
view.update(old);
const fresh: BrowserViewData = {
active: true,
tabs: [page("t8", "Current")],
history: [],
screenshots: [],
};
view.update({ ...context(() => Promise.resolve(fresh)), tid: "another" });
await until(() => view.element.textContent?.includes("Current") ?? false);
assert(oldSignal.aborted);
resolveOld({ active: false, tabs: [page("t1", "Outdated")], history: [], screenshots: [] });
await Promise.resolve();
assert(!view.element.textContent?.includes("Outdated"));
let signal!: AbortSignal;
view.update(context((_, __, options) => {
signal = options!.signal!;
return new Promise(() => {});
}, 3));
view.dispose?.();
assert(signal.aborted);
}));