import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import test from "node:test"; import { isCollectionScheduleDue } from "../lib/collection-service.ts"; import { sortWithNullsLast } from "../lib/sort-utils.ts"; test("runs the Beijing collection schedule from 09:00", () => { const scheduledDate = "2026-08-12"; assert.equal( isCollectionScheduleDue( scheduledDate, Date.parse("2026-08-12T00:59:59Z"), ), false, ); assert.equal( isCollectionScheduleDue( scheduledDate, Date.parse("2026-08-12T01:00:00Z"), ), true, ); assert.equal( isCollectionScheduleDue( scheduledDate, Date.parse("2026-08-13T00:00:00Z"), ), true, ); assert.equal( isCollectionScheduleDue( scheduledDate, Date.parse("2026-08-11T16:00:00Z"), ), false, ); }); test("sorts both directions while keeping missing values last", () => { const values = [ { id: "missing-a", value: null }, { id: "middle", value: 20 }, { id: "high", value: 50 }, { id: "missing-b", value: null }, { id: "low", value: 10 }, ]; assert.deepEqual( sortWithNullsLast(values, (item) => item.value, "asc").map( (item) => item.id, ), ["low", "middle", "high", "missing-a", "missing-b"], ); assert.deepEqual( sortWithNullsLast(values, (item) => item.value, "desc").map( (item) => item.id, ), ["high", "middle", "low", "missing-a", "missing-b"], ); }); test("a failed collection keeps historically successful rows on success", async () => { const source = await readFile( new URL("../lib/collection-service.ts", import.meta.url), "utf8", ); // 失败写入必须按 latest_likes 分流:无数据 → failed; // 已有历史数据 → 保持 success,仅描述里说明沿用上次数据。 assert.match( source, /collection_status = CASE\s+WHEN latest_likes IS NULL THEN 'failed'\s+ELSE 'success'\s+END/, ); assert.match( source, /ELSE \?\s+END,\s+collection_updated_at = CASE\s+WHEN latest_likes IS NULL THEN CURRENT_TIMESTAMP\s+ELSE collection_updated_at/, ); assert.match(source, /`\$\{message\},沿用上次采集数据`/); // run 行照实记录失败,保留可观测性 assert.match(source, /UPDATE collection_runs\s+SET status = 'failed'/); });