const test = require("node:test"); const assert = require("node:assert/strict"); const path = require("node:path"); const apiPath = require.resolve("../pets-fe/utils/api"); function page(name, secure, wx = {}) { global.wx = { getStorageSync: () => [], setStorageSync: () => {}, showToast: () => {}, showModal: async () => ({ confirm: true }), navigateBack: () => {}, getLocation: async () => ({ latitude: 31.2, longitude: 121.4 }), ...wx, }; require.cache[apiPath] = { id: apiPath, filename: apiPath, loaded: true, exports: { secure, toast: (error) => { throw error; } }, }; let definition; global.Page = (value) => { definition = value; }; const filename = path.resolve(__dirname, `../pets-fe/pages/${name}/${name}.js`); delete require.cache[filename]; require(filename); return { ...definition, data: { ...definition.data }, setData(changes) { Object.assign(this.data, changes); }, }; } test("编辑任务走 PUT,并保留选中的宠物", async () => { const calls = []; const pet = { id: "pet-1", name: "奶盖" }; const task = { id: "task-1", pet_id: pet.id, title: "换水", category: "water", time_of_day: "09:00", repeat_rule: "daily" }; const screen = page("tasks", async (route, method, body) => { calls.push({ route, method, body }); if (route === "/pets") return [pet]; if (route.startsWith("/tasks?")) return { items: [task] }; return task; }); await screen.load(); screen.edit({ currentTarget: { dataset: { index: 0 } } }); screen.setData({ title: "更换饮水" }); await screen.save(); assert.deepEqual(calls.find((call) => call.method === "PUT"), { route: "/tasks/task-1", method: "PUT", body: { pet_id: pet.id, title: "更换饮水", category: "water", time_of_day: "09:00", repeat_rule: "daily" }, }); }); test("多宠物遛狗发送全部 ID,结束后可再次开始", async () => { const calls = []; const active = { id: "walk-1", status: "active", started_at: new Date().toISOString(), pet_ids: ["a", "b"], distance_meters: 0, points: [] }; const screen = page("walk", async (route, method, body) => { calls.push({ route, method, body }); if (route === "/walks" && method === "POST") return active; if (route.endsWith("/points")) return { ...active, points: [{ latitude: 31.2, longitude: 121.4 }] }; if (route.endsWith("/finish")) return { ...active, status: "finished" }; }); screen.track = () => {}; screen.setData({ selected: ["a", "b"] }); await screen.start(); assert.deepEqual(calls[0].body.pet_ids, ["a", "b"]); assert.equal(calls[1].route, "/walks/walk-1/points"); await screen.action({ currentTarget: { dataset: { kind: "finish" } } }); assert.equal(screen.data.walk, null); assert.deepEqual(screen.data.selected, ["a", "b"]); }); test("足迹列表保留同行宠物和轨迹", async () => { const screen = page("walk-records", async (route) => route === "/pets" ? [{ id: "a", name: "奶盖" }, { id: "b", name: "布丁" }] : [{ id: "walk-1", status: "finished", started_at: "2026-10-01T08:00:00+08:00", duration_seconds: 120, distance_meters: 500, pet_ids: ["a", "b"], points: [{ latitude: 31.2, longitude: 121.4 }, { latitude: 31.3, longitude: 121.5 }] }]); await screen.load(); assert.equal(screen.data.records[0].petNames, "奶盖、布丁"); assert.equal(screen.data.records[0].distance, "0.50"); assert.equal(screen.data.records[0].polyline[0].points.length, 2); }); test("约遛详情识别已报名并能退出", async () => { const calls = []; const screen = page("meetups", async (route, method) => { calls.push({ route, method }); if (route === "/meetups/event-1") return { id: "event-1", starts_at: "2026-10-05T08:00:00+08:00", people: [{ user_id: "user-1", pet_ids: ["pet-1"] }] }; return {}; }); screen.setData({ userId: "user-1", meetups: [{ id: "event-1" }] }); screen.load = async () => {}; await screen.open({ currentTarget: { dataset: { index: 0 } } }); assert.equal(screen.data.joined, true); assert.deepEqual(screen.data.selected, ["pet-1"]); await screen.leave(); assert.deepEqual(calls[1], { route: "/meetups/event-1/join", method: "DELETE" }); });