fix(soon): stop pointing at events you've finished or ignored
Two symptoms of one bug. The "next to expire" headline counted events the reader had marked done or ignored, and the dailies strip kept a tickable chip for a repeating event they had already finished. showCompleted and showIgnored decide what a reader can *look at*. The headline and the strip are *instructions*, so they answer a different question — what is still on your plate — and both now go through one `outstanding` lens. Also fixes a second bug in the same line: `next` took the head of the list, which under "doing first" sorting is whatever you're partway through, not the soonest deadline. It reads the minimum now. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c3e9b9064d
commit
edc6f3e4bb
@@ -0,0 +1,68 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { firstToExpire, outstanding } from "../src/client/state/lens.ts";
|
||||
import type { GameId } from "../src/shared/schema.ts";
|
||||
|
||||
const row = (id: string, game: GameId, msRemaining: number | null) => ({
|
||||
event: { id, game },
|
||||
clock: { msRemaining },
|
||||
});
|
||||
|
||||
const none = () => false;
|
||||
|
||||
describe("outstanding", () => {
|
||||
const rows = [
|
||||
row("a", "genshin", 1000),
|
||||
row("b", "hsr", 2000),
|
||||
row("c", "zzz", 3000),
|
||||
];
|
||||
|
||||
test("drops what the reader has finished", () => {
|
||||
// The headline and the dailies strip both tell the reader what to do, and
|
||||
// pointing at a job they already ticked off is the app arguing with them.
|
||||
expect(outstanding(rows, (id) => id === "b", none).map((r) => r.event.id)).toEqual(
|
||||
["a", "c"],
|
||||
);
|
||||
});
|
||||
|
||||
test("drops what they have ignored", () => {
|
||||
expect(outstanding(rows, none, (id) => id === "a").map((r) => r.event.id)).toEqual(
|
||||
["b", "c"],
|
||||
);
|
||||
});
|
||||
|
||||
test("done and ignored at once is still just gone", () => {
|
||||
expect(outstanding(rows, (id) => id === "a", (id) => id === "a")).toHaveLength(2);
|
||||
});
|
||||
|
||||
test("nothing outstanding is an empty list, not a null", () => {
|
||||
expect(outstanding(rows, () => true, none)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("firstToExpire", () => {
|
||||
test("takes the soonest, not the first row", () => {
|
||||
// The list arrives sorted by whatever mode the reader chose. Under "doing
|
||||
// first" its head is what they are partway through, which is not what a
|
||||
// panel headed "next to expire" claims to be showing.
|
||||
const rows = [
|
||||
row("mid-run", "genshin", 9 * 86_400_000),
|
||||
row("tonight", "hsr", 3 * 3_600_000),
|
||||
];
|
||||
expect(firstToExpire(rows)?.event.id).toBe("tonight");
|
||||
});
|
||||
|
||||
test("an unannounced end is never the deadline while a real one exists", () => {
|
||||
const rows = [row("unknown", "zzz", null), row("real", "wuwa", 5000)];
|
||||
expect(firstToExpire(rows)?.event.id).toBe("real");
|
||||
});
|
||||
|
||||
test("falls back to an unknown end when it is all there is", () => {
|
||||
// It is still a live event and still worth showing; it is just not a
|
||||
// countdown. Showing nothing would be worse.
|
||||
expect(firstToExpire([row("unknown", "zzz", null)])?.event.id).toBe("unknown");
|
||||
});
|
||||
|
||||
test("no rows is null rather than a crash", () => {
|
||||
expect(firstToExpire([])).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user