人物卡、菜单、编辑和删除换成组件库。chart_profiles 增加可空的 archive_order,本人始终排在第一。合盘选人页两个名字并排,开始按钮居中,点了先说出点数和余额。 自测:tsc 0;lint 0 error(122 警告,与上一张相同);定向测试通过;next build 后 / 仍是 Static;首页 JS gzip-9 639609,相对 640131 少 0.08%。test:db 79 通过、13 失败,失败名单与 windows-known-failures.txt 一致,排序列断言在通过的那一组。没有浏览器登录态。 Co-Authored-By: Grok (agent loop)
51 lines
2.7 KiB
TypeScript
51 lines
2.7 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
import { archiveOrdersForIds, moveArchiveIds, sortByArchiveOrder } from "../src/lib/people-archive-order.ts";
|
|
import { synastryChargeCopy } from "../src/components/synastry/synastry-picker.tsx";
|
|
|
|
test("archive order keeps an untouched list, then puts numbered rows first", () => {
|
|
const rows = [
|
|
{ id: "b", archiveOrder: null },
|
|
{ id: "a", archiveOrder: null },
|
|
{ id: "c", archiveOrder: 10 },
|
|
];
|
|
assert.deepEqual(sortByArchiveOrder(rows.slice(0, 2)).map((row) => row.id), ["b", "a"]);
|
|
assert.deepEqual(sortByArchiveOrder(rows).map((row) => row.id), ["c", "b", "a"]);
|
|
});
|
|
|
|
test("moving archive ids never moves self and writes gaps of 10", () => {
|
|
assert.deepEqual(moveArchiveIds(["self", "a", "b"], "self", "b"), ["self", "a", "b"]);
|
|
assert.deepEqual(moveArchiveIds(["a", "b", "c"], "c", "a"), ["c", "a", "b"]);
|
|
assert.deepEqual(moveArchiveIds(["a", "b"], "a", "missing"), ["a", "b"]);
|
|
const orders = archiveOrdersForIds(["a", "b", "self"]);
|
|
assert.equal(orders.get("a"), 10);
|
|
assert.equal(orders.get("b"), 20);
|
|
assert.equal(orders.has("self"), false);
|
|
});
|
|
|
|
test("order writes do not touch updated_at, and the start button stays centered", () => {
|
|
const route = readFileSync(new URL("../src/app/api/chart-profiles/[id]/route.ts", import.meta.url), "utf8");
|
|
const patch = route.slice(route.indexOf("export async function PATCH"));
|
|
assert.match(patch, /archive_order: order/);
|
|
assert.doesNotMatch(patch, /updated_at/);
|
|
assert.match(patch, /id === "self"/);
|
|
const list = readFileSync(new URL("../src/app/api/chart-profiles/route.ts", import.meta.url), "utf8");
|
|
assert.match(list, /sortByArchiveOrder/);
|
|
assert.match(list, /\.order\("updated_at", \{ ascending: false \}\)/);
|
|
const css = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8");
|
|
assert.match(css, /\.synastry-go \{[^}]*align-items:\s*center/);
|
|
assert.match(css, /\.synastry-start \{[^}]*margin-inline:\s*auto/);
|
|
assert.equal(css.includes(".synastry-times { display: none; }"), false);
|
|
assert.match(css, /\.synastry-pick \{ grid-template-columns: minmax\(0, 1fr\); \}/);
|
|
assert.match(css, /\.synastry-times \{ justify-self: center; padding-bottom: 0; \}/);
|
|
assert.match(css, /\.synastry-go \{ align-items: center; \}/);
|
|
});
|
|
|
|
test("the confirm copy reads the price and the balance", () => {
|
|
assert.deepEqual(synastryChargeCopy(19, 40), { short: false, text: "会用掉 19 点,余额 40 点。" });
|
|
assert.deepEqual(synastryChargeCopy(19, 3), { short: true, text: "需要 19 点,余额只有 3 点。" });
|
|
assert.equal(synastryChargeCopy(19, 19).short, false);
|
|
});
|