char-slop/berry

multipurpose self-modifiable agentic harness

git clone https://git.t4t.associates/char-slop/berry

Charlotte Somadd flush() to views and use for diff edits481a657

main
2.9 KiB81 linesraw
1import { assertEquals } from "@std/assert";
2import type { View } from "@berry/api/web.ts";
3import { viewContext, withDom } from "@berry/util/dom.ts";
4import { extensionView, viewHref, viewRoute } from "./views.ts";
5
6Deno.test("a view opens with its route, follows it and new entries, and is disposed as it closes", () =>
7  withDom(() => {
8    const events: string[] = [];
9    const factory = (name: string) => (): View => {
10      events.push(`${name}:create`);
11      const element = document.createElement("section");
12      return {
13        element,
14        update: ({ route, latest }) =>
15          events.push(`${name}:${route}@${latest}:${element.isConnected ? "shown" : "unshown"}`),
16        dispose: () => events.push(`${name}:dispose`),
17      };
18    };
19    const diff = { name: "diff", create: factory("diff") };
20    const context = viewContext({ tid: "test", latest: 1 });
21    const pane = extensionView();
22    document.body.append(pane.element);
23    assertEquals(pane.element.hidden, true);
24
25    pane.update(diff, context);
26    assertEquals(pane.element.hidden, false);
27    // a conversation draws again as it streams, without anything the view shows changing
28    pane.update(diff, { ...context });
29    pane.update(diff, { ...context, route: "abc" });
30    pane.update(diff, { ...context, route: "abc", latest: 2 });
31    pane.update({ name: "diff", create: factory("reloaded") }, context);
32    pane.update(null, context);
33    assertEquals(pane.element.hidden, true);
34    assertEquals(pane.element.childNodes.length, 0);
35
36    pane.update({ name: "diff", create: null }, context);
37    pane.dispose();
38
39    assertEquals(events, [
40      "diff:create",
41      "diff:@1:unshown",
42      "diff:abc@1:shown",
43      "diff:abc@2:shown",
44      "diff:dispose",
45      "reloaded:create",
46      "reloaded:@1:unshown",
47      "reloaded:dispose",
48    ]);
49  }));
50
51Deno.test("a view's route survives its address, whatever it holds", () => {
52  for (const route of ["", "abc", "a b/c%d", "x/#y?z", "ünï/cødé"]) {
53    const href = viewHref("3mxd6epszps5d", "diff", route);
54    const escaped = href.match(/^#\/3mxd6epszps5d\/diff\/?(.*)$/)![1];
55    assertEquals(viewRoute(escaped), route);
56  }
57});
58
59Deno.test("flush reaches the open view, and is a no-op without one", () =>
60  withDom(async () => {
61    const pane = extensionView();
62    document.body.append(pane.element);
63    assertEquals(await pane.flush(), undefined);
64    let flushed = 0;
65    const element = document.createElement("section");
66    const view: View = {
67      element,
68      update: () => {},
69      flush: () => {
70        flushed++;
71        return Promise.resolve();
72      },
73    };
74    const context = viewContext({ tid: "test", latest: 1 });
75    pane.update({ name: "diff", create: () => view }, context);
76    await pane.flush();
77    assertEquals(flushed, 1);
78    pane.update(null, context);
79    assertEquals(await pane.flush(), undefined);
80    pane.dispose();
81  }));