MatchMaster/server/laf-cloud/tests/daily-task-v2.test.mjs
2026-09-10 19:55:12 +08:00

122 lines
6.1 KiB
JavaScript

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, getDayEndsAt, getWeekKey, getWeekEndsAt, 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(getDayEndsAt(Date.parse("2026-09-06T16:00:00Z")), Date.parse("2026-09-08T00:00:00+08:00"));
assert.equal(getWeekKey(Date.parse("2026-09-06T16:00:00Z")), "2026-09-07");
assert.equal(getWeekEndsAt(Date.parse("2026-09-06T16:00:00Z")), Date.parse("2026-09-14T00:00:00+08:00"));
});
test("returns current server time and refreshes it on repeated reads", () => {
const firstNow = Date.parse("2026-09-07T04:00:00Z");
const secondNow = firstNow + 5000;
const first = refreshTaskData(null, "user-time", 20, firstNow).data;
const second = refreshTaskData(JSON.stringify(first), "user-time", 20, secondNow);
assert.equal(second.changed, false);
assert.equal(second.data.serverNow, secondNow);
assert.equal(second.data.dayEndsAt, Date.parse("2026-09-08T00:00:00+08:00"));
assert.equal(second.data.weekEndsAt, Date.parse("2026-09-14T00:00:00+08:00"));
});
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, false, false, false, false]);
});
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("all daily tasks accumulate and can be claimed in any order", () => {
const data = refreshTaskData(null, "user-3", 20, Date.parse("2026-09-04T04:00:00Z")).data;
const submitted = structuredClone(data);
submitted.dailyTasks.forEach(task => task.value = task.target);
mergeClientProgress(data, submitted);
assert.ok(data.dailyTasks.every(task => task.state === 1 && !task.locked));
for (const task of [...data.dailyTasks].reverse()) {
assert.equal(claimDaily(data, task.taskId).ok, true);
assert.equal(claimDaily(data, task.taskId).ok, false);
}
assert.equal(data.weeklyStars, 20);
});
test("opens stored locked tasks immediately without resetting progress or rewards", () => {
const now = Date.parse("2026-09-04T04:00:00Z");
const stored = refreshTaskData(null, "existing-user", 20, now).data;
stored.dailyTasks.forEach((task, index) => task.locked = index > 0);
stored.dailyTasks[4].value = stored.dailyTasks[4].target;
stored.dailyTasks[4].state = 1;
const original = structuredClone(stored);
const result = refreshTaskData(JSON.stringify(stored), "existing-user", 20, now);
assert.equal(result.changed, true);
assert.deepEqual(result.data.dailyTasks, original.dailyTasks.map(task => ({ ...task, locked: false })));
assert.deepEqual(result.data.weeklyRewards, original.weeklyRewards);
assert.equal(result.data.weeklyStars, original.weeklyStars);
assert.equal(refreshTaskData(JSON.stringify(result.data), "existing-user", 20, now).changed, false);
assert.equal(claimDaily(result.data, result.data.dailyTasks[4].taskId).ok, true);
});
test("ignores legacy lock flags but still requires completion", () => {
const data = refreshTaskData(null, "legacy-flags", 20, Date.parse("2026-09-04T04:00:00Z")).data;
const task = data.dailyTasks[4];
task.locked = true;
task.value = 0;
task.state = 0;
assert.equal(claimDaily(data, task.taskId).ok, false);
task.value = task.target;
task.state = 1;
assert.equal(claimDaily(data, task.taskId).ok, true);
assert.ok(data.dailyTasks.every(item => !item.locked));
});
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));
});