Files

90 lines
3.5 KiB
TypeScript

import type { Flow, ModelPayload } from "@yaakapp-internal/proxy-lib";
import { describe, expect, test } from "vite-plus/test";
import { sortComparator } from "./columns";
import { appendPage, applySortedChanges, type SortedWindow } from "./sortedWindow";
function flow(n: number, status: number | null): Flow {
return {
id: `fl_${n}`,
number: n,
startedAt: `2026-11-09T12:00:0${n}`,
status,
error: null,
} as Flow;
}
const bySize = sortComparator([{ column: "status", descending: true }]);
const upsert = (model: Flow, search?: ModelPayload["search"]): ModelPayload => ({
model,
change: { type: "upsert", created: true },
...(search == null ? {} : { search }),
});
const remove = (model: Flow): ModelPayload => ({ model, change: { type: "delete" } });
const numbers = (flows: Flow[]) => flows.map((f) => f.number);
describe("applySortedChanges", () => {
const held = [flow(1, 500), flow(2, 404), flow(3, 200)];
test("places a new or changed flow by the sort, and drops a deleted one", () => {
let flows = applySortedChanges(held, null, [upsert(flow(4, 300))], bySize, null);
expect(numbers(flows)).toEqual([1, 2, 4, 3]);
flows = applySortedChanges(flows, null, [upsert(flow(3, 503))], bySize, null);
expect(numbers(flows)).toEqual([3, 1, 2, 4]);
flows = applySortedChanges(flows, null, [remove(flow(1, 500))], bySize, null);
expect(numbers(flows)).toEqual([3, 2, 4]);
});
test("leaves a flow past the last one read for paging to bring", () => {
const boundary = held[2] ?? null;
const flows = applySortedChanges(held, boundary, [upsert(flow(4, 100))], bySize, null);
expect(numbers(flows)).toEqual([1, 2, 3]);
// The last flow read, written again unchanged, stays.
const same = applySortedChanges(held, boundary, [upsert(flow(3, 200))], bySize, null);
expect(numbers(same)).toEqual([1, 2, 3]);
// A held flow that moves past the end leaves until paging reaches it.
const moved = applySortedChanges(held, boundary, [upsert(flow(1, 100))], bySize, null);
expect(numbers(moved)).toEqual([2, 3]);
});
test("searching, takes only flows the search matched, and keeps ones it can't tell", () => {
const changes = [
upsert(flow(4, 300), { key: "k", matches: true }),
upsert(flow(5, 300), { key: "k", matches: false }),
upsert(flow(2, 404), { key: "k", matches: false }),
upsert(flow(3, 999), { key: "other", matches: true }),
];
const flows = applySortedChanges(held, null, changes, bySize, "k");
expect(numbers(flows)).toEqual([1, 4, 3]);
});
});
test("a page adds what it does not already hold", () => {
const win: SortedWindow = {
key: "1",
sort: [],
query: null,
flows: [flow(1, 500), flow(2, 404)],
boundary: flow(2, 404),
cursor: [404, "fl_2"],
loading: false,
buffered: [],
};
const next = appendPage(win, [flow(2, 404), flow(3, 200)], [200, "fl_3"], 2);
expect(numbers(next.flows)).toEqual([1, 2, 3]);
expect(next.boundary?.id).toBe("fl_3");
expect(next.cursor).toEqual([200, "fl_3"]);
// A short page is the last: nothing is past it.
const last = appendPage(win, [flow(3, 200)], [200, "fl_3"], 2);
expect([last.boundary, last.cursor]).toEqual([null, null]);
// One the sweep deleted meanwhile is left out, but still marks where the page ended.
const swept = appendPage(
win,
[flow(3, 200), flow(4, 100)],
[100, "fl_4"],
2,
(f) => f.id !== "fl_4",
);
expect(numbers(swept.flows)).toEqual([1, 2, 3]);
expect(swept.boundary?.id).toBe("fl_4");
});