Game8 dropped "All" from "Wuthering Waves All Active Codes" around 2026-10-25, and the exact match rejected every refresh since, freezing the list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
90 lines
3.5 KiB
TypeScript
90 lines
3.5 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { CODE_SOURCES } from "../../src/ingest/codes/registry.ts";
|
|
import { parseGame8CodeTable } from "../../src/ingest/codes/game8.ts";
|
|
|
|
const now = "2026-10-18T12:00:00.000Z";
|
|
|
|
// Each page pinned 2026-10-18; expected files were spot-checked against the
|
|
// live pages (Star Rail's six codes, WUTHERINGGIFT, Endfield's ENDFIELDSTEAM /
|
|
// ENDFIELDGIFT / ENDFIELD4PC, CZN's NIGHTMARECARNIVAL, P5X's WEBSTORE1YEAR).
|
|
for (const source of CODE_SOURCES.filter((s) => s.game !== "genshin")) {
|
|
test(`${source.id} reads the page's active codes`, async () => {
|
|
const html = await Bun.file(`${source.fixture}.html`).text();
|
|
const expected = await Bun.file(`${source.fixture}.expected.json`).json();
|
|
expect(
|
|
source.parse(html, {
|
|
now,
|
|
sourceId: source.id,
|
|
sourceUrl: source.url,
|
|
game: source.game,
|
|
}),
|
|
).toEqual(expected);
|
|
});
|
|
}
|
|
|
|
test("an expired table inside the active section is not read as current", async () => {
|
|
const wuwa = CODE_SOURCES.find((s) => s.game === "wuwa")!;
|
|
const html = await Bun.file(`${wuwa.fixture}.html`).text();
|
|
const codes = wuwa.parse(html, {
|
|
now,
|
|
sourceId: wuwa.id,
|
|
sourceUrl: wuwa.url,
|
|
game: "wuwa",
|
|
});
|
|
expect(codes.map((c) => c.code)).toEqual(["WUTHERINGGIFT"]);
|
|
});
|
|
|
|
test("a page that says it has no codes is an empty read it may store; a changed page is not", async () => {
|
|
const uma = CODE_SOURCES.find((s) => s.game === "uma")!;
|
|
const html = await Bun.file(`${uma.fixture}.html`).text();
|
|
expect(
|
|
uma.parse(html, { now, sourceId: uma.id, sourceUrl: uma.url, game: "uma" }),
|
|
).toEqual([]);
|
|
expect("statesNoEvents" in uma && uma.statesNoEvents(html)).toBe(true);
|
|
expect(() =>
|
|
parseGame8CodeTable(
|
|
"<h2>Something else</h2>",
|
|
{
|
|
now,
|
|
sourceId: "x",
|
|
sourceUrl: "https://example.com",
|
|
game: "hsr",
|
|
},
|
|
/^Active Redeem Codes for/i,
|
|
),
|
|
).toThrow("could not be identified");
|
|
});
|
|
|
|
test("a reward shared with the code's cell, or listed with bullets, reads as text", () => {
|
|
const html =
|
|
"<h3>Codes</h3><table><tr><th>Date Added</th><th>Code & Reward</th></tr>" +
|
|
"<tr><td>09/24/2026</td><td><input class='a-clipboard__textInput' value='ONE'> Copied 100 Stamps</td></tr>" +
|
|
"<tr><td><input class='a-clipboard__textInput' value='TWO'> Copied</td><td>・ Fons x10 ・ Coin x5</td></tr></table>";
|
|
const codes = parseGame8CodeTable(
|
|
html,
|
|
{
|
|
now,
|
|
sourceId: "x",
|
|
sourceUrl: "https://example.com",
|
|
game: "nte",
|
|
},
|
|
/^Codes$/,
|
|
);
|
|
expect(codes.map((c) => [c.code, c.reward])).toEqual([
|
|
["ONE", "100 Stamps"],
|
|
["TWO", "Fons x10, Coin x5"],
|
|
]);
|
|
expect(codes.every((c) => c.expiresAt === null)).toBe(true);
|
|
});
|
|
|
|
test("Wuthering Waves' codes survive Game8 dropping 'All' from the heading", async () => {
|
|
// "Wuthering Waves All Active Codes" became "Wuthering Waves Active Codes" around
|
|
// 2026-10-25, and the exact match froze the list for two weeks.
|
|
const source = CODE_SOURCES.find((s) => s.id === "wuwa-game8-codes")!;
|
|
const ctx = { now: "2026-11-07T00:00:00.000Z", sourceUrl: source.url, sourceId: source.id, game: source.game };
|
|
const read = async (date: string) =>
|
|
(source.parse(await Bun.file(`fixtures/wuwa/game8-codes-${date}.html`).text(), ctx) as Array<{ code: string }>).map((c) => c.code);
|
|
expect(await read("2026-11-07")).toEqual(["TRAINOFSOULS", "BLOOMINGFLOWERS", "SCHOOLLIFE", "WUTHERINGGIFT"]);
|
|
expect(await read("2026-10-18")).toEqual(["WUTHERINGGIFT"]);
|
|
});
|