Add one-way task completion and exportable pet identity cards
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const fs = require("node:fs");
|
||||
const vm = require("node:vm");
|
||||
|
||||
function runtime() {
|
||||
const calls = [],
|
||||
notices = [];
|
||||
let confirm = true,
|
||||
failure = false,
|
||||
release;
|
||||
const module = { exports: {} };
|
||||
vm.runInNewContext(
|
||||
fs.readFileSync("pets-fe/utils/task-completion.js", "utf8"),
|
||||
{
|
||||
module,
|
||||
require: (name) =>
|
||||
name.includes("date")
|
||||
? { localDate: () => "2026-10-05" }
|
||||
: {
|
||||
secure: async (...args) => {
|
||||
calls.push(args);
|
||||
if (release) await release;
|
||||
if (failure) throw new Error("offline");
|
||||
},
|
||||
toast: (error) => notices.push(error.message),
|
||||
},
|
||||
wx: {
|
||||
showModal: async () => ({ confirm }),
|
||||
showToast: (opts) => notices.push(opts.title),
|
||||
vibrateShort() {},
|
||||
},
|
||||
},
|
||||
);
|
||||
const page = {
|
||||
data: {
|
||||
tasks: [
|
||||
{ id: "a", completed: false },
|
||||
{ id: "b", completed: true },
|
||||
],
|
||||
taskBusyIds: [],
|
||||
completingAll: false,
|
||||
},
|
||||
setData(value) {
|
||||
Object.assign(this.data, value);
|
||||
},
|
||||
};
|
||||
return {
|
||||
api: module.exports,
|
||||
page,
|
||||
calls,
|
||||
notices,
|
||||
cancel: () => {
|
||||
confirm = false;
|
||||
},
|
||||
fail: () => {
|
||||
failure = true;
|
||||
},
|
||||
hold: (p) => {
|
||||
release = p;
|
||||
},
|
||||
};
|
||||
}
|
||||
test("完成即时更新且不能撤销,快速重复点击只发送一次", async () => {
|
||||
const r = runtime();
|
||||
let release;
|
||||
r.hold(
|
||||
new Promise((resolve) => {
|
||||
release = resolve;
|
||||
}),
|
||||
);
|
||||
const action = r.api.complete(r.page, r.page.data.tasks[0]);
|
||||
await r.api.complete(r.page, r.page.data.tasks[0]);
|
||||
assert.equal(r.calls.length, 1);
|
||||
release();
|
||||
await action;
|
||||
assert.equal(r.page.data.tasks[0].completed, true);
|
||||
assert.equal(r.page.data.undoneCount, 0);
|
||||
await r.api.complete(r.page, r.page.data.tasks[0]);
|
||||
assert.equal(r.calls.length, 1);
|
||||
assert.equal(r.calls[0][2].completed, true);
|
||||
});
|
||||
test("一键完成只发送未完成项,确认取消不发送请求", async () => {
|
||||
const r = runtime();
|
||||
r.cancel();
|
||||
await r.api.completeAll(r.page);
|
||||
assert.equal(r.calls.length, 0);
|
||||
assert.equal(r.page.data.completingAll, false);
|
||||
const s = runtime();
|
||||
await s.api.completeAll(s.page);
|
||||
assert.equal(s.calls[0][0], "/tasks/completions");
|
||||
assert.equal(JSON.stringify(s.calls[0][2].task_ids), '["a"]');
|
||||
assert.equal(s.page.data.done, 2);
|
||||
});
|
||||
test("完成请求失败保留待办,释放按钮可重试", async () => {
|
||||
const r = runtime();
|
||||
r.fail();
|
||||
await r.api.completeAll(r.page);
|
||||
assert.equal(r.page.data.tasks[0].completed, false);
|
||||
assert.equal(r.page.data.completingAll, false);
|
||||
await r.api.complete(r.page, r.page.data.tasks[0]);
|
||||
assert.equal(r.page.data.taskBusyIds.length, 0);
|
||||
assert.equal(r.page.data.tasks[0].completed, false);
|
||||
});
|
||||
@@ -0,0 +1,104 @@
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const fs = require("node:fs");
|
||||
const vm = require("node:vm");
|
||||
function library(wx) {
|
||||
const module = { exports: {} };
|
||||
vm.runInNewContext(fs.readFileSync("pets-fe/utils/pet-card.js", "utf8"), {
|
||||
wx,
|
||||
module,
|
||||
});
|
||||
return module.exports;
|
||||
}
|
||||
|
||||
test("保存卡片被拒绝授权后,确认去设置并授权则重试同一图片", async () => {
|
||||
const saves = [];
|
||||
const api = library({
|
||||
saveImageToPhotosAlbum(options) {
|
||||
saves.push(options.filePath);
|
||||
if (saves.length === 1) options.fail({ errMsg: "auth deny" });
|
||||
else options.success();
|
||||
},
|
||||
getSetting: (options) =>
|
||||
options.success({ authSetting: { "scope.writePhotosAlbum": false } }),
|
||||
showModal: async () => ({ confirm: true }),
|
||||
openSetting: (options) =>
|
||||
options.success({ authSetting: { "scope.writePhotosAlbum": true } }),
|
||||
});
|
||||
assert.equal(await api.saveToAlbum("/tmp/card.png"), true);
|
||||
assert.deepEqual(saves, ["/tmp/card.png", "/tmp/card.png"]);
|
||||
});
|
||||
test("拒绝开启相册权限不报告保存成功,也不重复保存", async () => {
|
||||
let saves = 0;
|
||||
const api = library({
|
||||
saveImageToPhotosAlbum: (options) => {
|
||||
saves++;
|
||||
options.fail({ errMsg: "auth deny" });
|
||||
},
|
||||
getSetting: (options) =>
|
||||
options.success({ authSetting: { "scope.writePhotosAlbum": false } }),
|
||||
showModal: async () => ({ confirm: false }),
|
||||
});
|
||||
assert.equal(await api.saveToAlbum("/tmp/card.png"), false);
|
||||
assert.equal(saves, 1);
|
||||
});
|
||||
test("导出等待照片读取后生成 PNG,远程照片失败不会导出错误头像", async () => {
|
||||
let exported = 0,
|
||||
imageOptions;
|
||||
const ctx = new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target, key) {
|
||||
if (key === "measureText")
|
||||
return (text) => ({ width: text.length * 10 });
|
||||
if (key === "createLinearGradient")
|
||||
return () => ({ addColorStop() {} });
|
||||
return () => {};
|
||||
},
|
||||
set() {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
);
|
||||
const canvas = {
|
||||
getContext: () => ctx,
|
||||
createImage() {
|
||||
const img = { width: 200, height: 300 };
|
||||
Object.defineProperty(img, "src", {
|
||||
set() {
|
||||
queueMicrotask(() => img.onload());
|
||||
},
|
||||
});
|
||||
return img;
|
||||
},
|
||||
};
|
||||
const api = library({
|
||||
getImageInfo: (options) => {
|
||||
imageOptions = options;
|
||||
},
|
||||
canvasToTempFilePath: (options) => {
|
||||
exported++;
|
||||
assert.equal(options.fileType, "png");
|
||||
options.success({ tempFilePath: "/tmp/card.png" });
|
||||
},
|
||||
});
|
||||
const waiting = api.renderCard(canvas, {
|
||||
id: "1234",
|
||||
name: "毛孩",
|
||||
avatar_url: "https://s3.test/pet.png",
|
||||
});
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
assert.equal(exported, 0);
|
||||
imageOptions.success({ path: "/tmp/photo.png" });
|
||||
assert.equal(await waiting, "/tmp/card.png");
|
||||
assert.equal(canvas.width, 1200);
|
||||
assert.equal(canvas.height, 760);
|
||||
const failed = api.renderCard(canvas, {
|
||||
name: "毛孩",
|
||||
avatar_url: "https://s3.test/missing.png",
|
||||
});
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
imageOptions.fail();
|
||||
await assert.rejects(failed, /照片下载失败/);
|
||||
assert.equal(exported, 1);
|
||||
});
|
||||
Reference in New Issue
Block a user