test(checkups): pin that a linked visit older than the list's newest hundred is read and opened

This commit is contained in:
Marc-André Bombeck committed 2026-10-11 13:59:59 +02:00
1 parent 9a86a9427b
commit 3e2426187c
2 files changed
+143 -19

No files matched your search

@@ -0,0 +1,96 @@
/**
* `/checkups?visit=<id>` from a search hit. The visits list reads the newest
* hundred of each arm, and a search reaches back further than that, so a hit
* can name a visit the list does not hold. That visit is read on its own and
* opened like a listed one.
*/
import { describe, expect, it, vi } from "vitest";
import { openDeepLinked } from "../use-deep-linked-record";
type Visit = { id: string; occurredAt: string };
/** The newest hundred visits, the way the list holds them. */
const newestHundred: Visit[] = Array.from({ length: 100 }, (_, i) => ({
id: `v${i}`,
occurredAt: `2026-01-01T00:00:00Z`,
}));
const older: Visit = { id: "v-older", occurredAt: "2014-05-06T09:00:00Z" };
describe("a link to a visit older than the newest hundred", () => {
it("reads it on its own and opens it", async () => {
const resolve = vi.fn(async (id: string) =>
id === older.id ? older : null,
);
const open = vi.fn();
const scrollTo = vi.fn();
const outcome = await openDeepLinked({
wanted: older.id,
records: newestHundred,
open,
resolve,
stillWanted: () => true,
scrollTo,
});
expect(outcome).toBe("resolved");
expect(resolve).toHaveBeenCalledWith("v-older");
expect(open).toHaveBeenCalledWith(older);
// Not on the page, so there is nothing to scroll to.
expect(scrollTo).not.toHaveBeenCalled();
});
it("opens a listed visit without a second read", async () => {
const resolve = vi.fn();
const open = vi.fn();
const scrollTo = vi.fn();
const outcome = await openDeepLinked({
wanted: "v42",
records: newestHundred,
open,
resolve,
stillWanted: () => true,
scrollTo,
});
expect(outcome).toBe("listed");
expect(resolve).not.toHaveBeenCalled();
expect(scrollTo).toHaveBeenCalledWith("v42");
expect(open).toHaveBeenCalledWith(newestHundred[42]);
});
it("leaves the page alone when the visit is gone or refused", async () => {
const open = vi.fn();
for (const resolve of [
async () => null,
async () => {
throw new Error("403");
},
]) {
const outcome = await openDeepLinked({
wanted: "v-gone",
records: newestHundred,
open,
resolve,
stillWanted: () => true,
scrollTo: () => {},
});
expect(outcome).toBe("none");
}
expect(open).not.toHaveBeenCalled();
});
it("does not open a late answer for a link that is no longer wanted", async () => {
const open = vi.fn();
const outcome = await openDeepLinked({
wanted: older.id,
records: newestHundred,
open,
resolve: async () => older,
stillWanted: () => false,
scrollTo: () => {},
});
expect(outcome).toBe("none");
expect(open).not.toHaveBeenCalled();
});
});
+47 -19
View File
@@ -56,24 +56,52 @@ export function useDeepLinkedRecord<T extends { id: string }>({
useEffect(() => {
if (!wanted || !records || handled.current === wanted) return;
handled.current = wanted;
const record = records.find((entry) => entry.id === wanted);
if (!record) {
if (!resolve || !open) return;
void resolve(wanted)
.then((found) => {
// Still on the page, and still the link it was asked for.
if (found && mounted.current && handled.current === wanted) {
open(found);
}
})
.catch(() => {
// Gone or refused: the page stays as it would without the link.
});
return;
}
document
.querySelector(`[${anchorAttribute}="${CSS.escape(wanted)}"]`)
?.scrollIntoView({ block: "center" });
open?.(record);
void openDeepLinked({
wanted,
records,
open,
resolve,
// Still on the page, and still the link it was asked for.
stillWanted: () => mounted.current && handled.current === wanted,
scrollTo: (id) =>
document
.querySelector(`[${anchorAttribute}="${CSS.escape(id)}"]`)
?.scrollIntoView({ block: "center" }),
});
}, [wanted, records, anchorAttribute, open, resolve]);
}
/**
* What a link does once the list has loaded, apart from React: a record the
* list holds is scrolled to and opened; one it does not hold (older than the
* bounded read, say the newest hundred visits) is read on its own through
* `resolve` and opened when it comes back and the link is still wanted.
* Resolves to which of the three happened.
*/
export async function openDeepLinked<T extends { id: string }>(args: {
wanted: string;
records: readonly T[];
open?: (record: T) => void;
resolve?: (id: string) => Promise<T | null>;
stillWanted: () => boolean;
scrollTo: (id: string) => void;
}): Promise<"listed" | "resolved" | "none"> {
const { wanted, records, open, resolve } = args;
const record = records.find((entry) => entry.id === wanted);
if (record) {
args.scrollTo(wanted);
open?.(record);
return "listed";
}
if (!resolve || !open) return "none";
let found: T | null;
try {
found = await resolve(wanted);
} catch {
// Gone or refused: the page stays as it would without the link.
return "none";
}
if (!found || !args.stillWanted()) return "none";
open(found);
return "resolved";
}