140 lines
5.9 KiB
JavaScript
140 lines
5.9 KiB
JavaScript
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 = {}) {
|
|
// Each test represents a fresh app session; page navigation within a test
|
|
// still shares the environment module.
|
|
delete require.cache[require.resolve("../pets-fe/utils/environment")];
|
|
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" });
|
|
});
|
|
|
|
test("首页使用 GCJ-02 定位并展示真实城市天气", async () => {
|
|
const screen = page("home", async (route, method, body) => {
|
|
assert.equal(route, "/environment");
|
|
assert.equal(method, "GET");
|
|
assert.deepEqual(body, { latitude: 30.2, longitude: 120.1 });
|
|
return { location_name: "杭州市 · 西湖区", weather: { description: "小雨", temperature: "19" } };
|
|
}, {
|
|
getSetting: ({ success }) => success({ authSetting: { "scope.userLocation": true } }),
|
|
getLocation: ({ type, success }) => {
|
|
assert.equal(type, "gcj02");
|
|
success({ latitude: 30.2, longitude: 120.1 });
|
|
},
|
|
});
|
|
await screen.refreshEnvironment();
|
|
assert.equal(screen.data.locationName, "杭州市 · 西湖区");
|
|
assert.match(screen.data.headerSubtitle, /周. · 小雨 19°C$/);
|
|
});
|
|
|
|
test("拒绝定位不请求后端,点击后可以恢复授权", async () => {
|
|
let calls = 0;
|
|
const screen = page("home", async () => {
|
|
calls++;
|
|
return { location_name: "杭州市", weather: null };
|
|
}, {
|
|
getSetting: ({ success }) => success({ authSetting: { "scope.userLocation": false } }),
|
|
openSetting: ({ success }) => success({ authSetting: { "scope.userLocation": true } }),
|
|
getLocation: ({ success }) => success({ latitude: 30.2, longitude: 120.1 }),
|
|
});
|
|
await screen.refreshEnvironment();
|
|
assert.equal(calls, 0);
|
|
assert.equal(screen.data.locationName, "开启定位");
|
|
await screen.refreshEnvironment({ type: "locationtap" });
|
|
assert.equal(calls, 1);
|
|
assert.equal(screen.data.locationName, "杭州市");
|
|
assert.match(screen.data.headerSubtitle, /天气暂不可用$/);
|
|
});
|