Files
gacha-event-tracker/test/reader-codes-state.test.ts
T
Lucas WintherandClaude Opus 5.5 3b29010e7c feat(codes): redeemed and expired codes move below, and new codes are marked
A game's Codes tab lists the codes still to use first; a code redeemed on
every server played, or past its stated expiry, is greyed in a "Redeemed or
expired" section below. A date-only expiry passes once that date has ended
everywhere. Settings → Your games marks a followed game with its count of
unseen, still usable codes until its Codes tab is opened.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-18 05:15:36 +02:00

72 lines
2.1 KiB
TypeScript

import { expect, test } from "bun:test";
import type { CodesFeed, RedeemCode } from "../src/shared/codes.ts";
import {
codeExpired,
codeUsed,
unseenUsableCodes,
} from "../src/client/state/reader/codes.ts";
const code = (id: string, over: Partial<RedeemCode> = {}): RedeemCode => ({
id,
game: "genshin",
code: id.toUpperCase(),
reward: null,
expiresAt: null,
expiresOn: null,
firstObservedAt: "2026-10-01T00:00:00.000Z",
sourceUrl: "https://example.com/codes",
...over,
});
const now = Date.parse("2026-10-18T12:00:00.000Z");
test("a code expires at its stated instant", () => {
expect(
codeExpired(code("a", { expiresAt: "2026-10-18T11:59:59.000Z" }), now),
).toBe(true);
expect(
codeExpired(code("a", { expiresAt: "2026-10-18T12:00:01.000Z" }), now),
).toBe(false);
expect(codeExpired(code("a"), now)).toBe(false);
});
test("a date-only expiry passes only once the date has ended everywhere", () => {
// 17 Oct has ended everywhere by 18 Oct 12:00 UTC; 18 Oct has not.
expect(codeExpired(code("a", { expiresOn: "2026-10-17" }), now)).toBe(true);
expect(codeExpired(code("a", { expiresOn: "2026-10-18" }), now)).toBe(false);
expect(codeExpired(code("a", { expiresOn: "2026-10-17" }), now - 1)).toBe(
false,
);
});
test("a code is used once it is redeemed on every server played", () => {
const redeemed = { "account:eu": { a: "2026-10-18T00:00:00.000Z" } };
expect(codeUsed(code("a"), ["account:eu"], redeemed)).toBe(true);
expect(codeUsed(code("a"), ["account:eu", "account:na"], redeemed)).toBe(
false,
);
expect(codeUsed(code("a"), [], redeemed)).toBe(false);
});
test("the Settings marker counts unseen codes that can still be used", () => {
const feed: CodesFeed = {
schemaVersion: 1,
sources: [],
codes: [
code("seen"),
code("fresh"),
code("expired", { expiresAt: "2026-10-01T00:00:00.000Z" }),
code("used"),
code("other", { game: "hsr" }),
],
};
const ids = unseenUsableCodes(
feed,
["seen"],
"genshin",
["account:eu"],
{ "account:eu": { used: "2026-10-18T00:00:00.000Z" } },
now,
).map((c) => c.id);
expect(ids).toEqual(["fresh"]);
});