import test from "node:test"; import assert from "node:assert/strict"; import { registerHooks } from "node:module"; const configUrl = new URL("../functions/dailyTaskConfig.ts", import.meta.url); const serviceUrl = new URL("../functions/dailyTaskService.ts", import.meta.url); registerHooks({ resolve(specifier, context, nextResolve) { if (specifier === "@/dailyTaskConfig") return { url: configUrl.href, shortCircuit: true }; return nextResolve(specifier, context); }, }); const { getDayKey, getWeekKey, refreshTaskData, mergeClientProgress, claimDaily, claimWeekly } = await import(serviceUrl); test("uses Shanghai natural day and Monday week keys", () => { assert.equal(getDayKey(Date.parse("2026-09-06T15:59:59Z")), "2026-09-06"); assert.equal(getDayKey(Date.parse("2026-09-06T16:00:00Z")), "2026-09-07"); assert.equal(getWeekKey(Date.parse("2026-09-06T16:00:00Z")), "2026-09-07"); }); test("migrates legacy tasks into five v2 stages totaling twenty stars", () => { const legacy = JSON.stringify({ levelPass: { value: 3, state: 1 } }); const result = refreshTaskData(legacy, "user-1", 20, Date.parse("2026-09-04T04:00:00Z")); assert.equal(result.changed, true); assert.equal(result.data.version, 2); assert.equal(result.data.dailyTasks.length, 5); assert.equal(result.data.dailyTasks.reduce((sum, task) => sum + task.stars, 0), 20); assert.deepEqual(result.data.dailyTasks.map(task => task.locked), [false, true, true, true, true]); }); test("keeps the same selection during a day and avoids previous slot tasks next day", () => { const first = refreshTaskData(null, "user-2", 20, Date.parse("2026-09-04T04:00:00Z")).data; const same = refreshTaskData(JSON.stringify(first), "user-2", 20, Date.parse("2026-09-04T14:00:00Z")); assert.equal(same.changed, false); assert.deepEqual(same.data.dailyTasks.map(task => task.taskId), first.dailyTasks.map(task => task.taskId)); const next = refreshTaskData(JSON.stringify(first), "user-2", 20, Date.parse("2026-09-05T04:00:00Z")).data; next.dailyTasks.forEach((task, index) => assert.notEqual(task.taskId, first.dailyTasks[index].taskId)); }); test("locked stages accumulate but cannot be claimed before the previous reward", () => { const data = refreshTaskData(null, "user-3", 20, Date.parse("2026-09-04T04:00:00Z")).data; const submitted = structuredClone(data); submitted.dailyTasks[0].value = submitted.dailyTasks[0].target; submitted.dailyTasks[1].value = submitted.dailyTasks[1].target; mergeClientProgress(data, submitted); assert.equal(data.dailyTasks[1].state, 1); assert.equal(data.dailyTasks[1].locked, true); assert.equal(claimDaily(data, data.dailyTasks[1].taskId).ok, false); assert.equal(claimDaily(data, data.dailyTasks[0].taskId).ok, true); assert.equal(data.dailyTasks[1].locked, false); }); test("daily claims add stars once and weekly tiers claim independently", () => { const data = refreshTaskData(null, "user-4", 20, Date.parse("2026-09-04T04:00:00Z")).data; for (const task of data.dailyTasks) { task.value = task.target; task.state = 1; task.locked = false; assert.equal(claimDaily(data, task.taskId).ok, true); } assert.equal(data.weeklyStars, 20); assert.equal(claimDaily(data, data.dailyTasks[0].taskId).ok, false); data.weeklyStars = 140; const high = claimWeekly(data, "weekly_140"); assert.equal(high.ok, true); assert.equal(data.weeklyRewards.find(item => item.rewardId === "weekly_35").state, 0); }); test("daily reset preserves stars while weekly reset clears them", () => { const friday = refreshTaskData(null, "user-5", 20, Date.parse("2026-09-04T04:00:00Z")).data; friday.weeklyStars = 70; const saturday = refreshTaskData(JSON.stringify(friday), "user-5", 20, Date.parse("2026-09-05T04:00:00Z")).data; assert.equal(saturday.weeklyStars, 70); const monday = refreshTaskData(JSON.stringify(saturday), "user-5", 20, Date.parse("2026-09-07T04:00:00Z")).data; assert.equal(monday.weeklyStars, 0); assert.ok(monday.weeklyRewards.every(reward => reward.state === 0)); });