Files
blog/editor-api/test/date-time.mjs
T
zqlit 5e9d328841 fix(排序): 同日文章 date 补全时分秒 + EdgeOne 部署重试增强
现象:小乖同一天发的第二篇排到了第一篇后面。

根因:front matter 的 date 只写到年月日(写入侧只收得到日期),
同一天多篇的时间戳完全并列 → 排序退化成比标题,前台/后台都错。

改动:
- 数据(6 篇):用目录名/slug 里的时间戳把 date 补全为
  'YYYY-MM-DDTHH:MM:SS+08:00',slug 即写作时刻。每篇仅 1 行 diff。
  2026-10-05 两篇(必须)、2026-06-02 / 06-03 四篇(同一 bug 的历史遗留)。
- 写入侧根治
  - editor-api/src/posts.mjs:新建时「只到天」补北京时间此刻;
    保存时「同日保真」——没换日子则原有时分秒一字符不动。
  - write-server/src/lib/posts.ts:parseDate 按 Asia/Shanghai 归日,
    列表同天排序不再受 UTC 时区漂移影响。
- 回归测试:新增 editor-api/test/date-time.mjs(8 项,自带一次性临时仓库)。
- .cnb.yml:EdgeOne stage 重试 3 次/20s → 5 次/30s。
  构建节点到 api.edgeone.ai 偶发 15s 超时会被 CLI 误报
  「Invalid EDGEONE_PAGES_API_TOKEN」,纯网络抖动,令牌没坏。
- .gitignore:忽略 *.zip 与 .edgeone/(误留的 blog.zip 达 361MB)。
2026-10-05 21:54:03 +08:00

114 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* date 时分秒回归测试(2026-10-05 加)。
*
* node test/date-time.mjs
*
* 背景:编辑器的日期框只有年月日,写出来的 front matter 是 `date: 2026-10-05`。
* 同一天发两篇 → 两篇 date 一模一样 → 前台(Hugo 按 Date 排)和后台列表
* (posts.mjs 的 listPosts 按 date 排)都只能拿标题当兜底比较,于是 21:30 发的
* 新文章排在了 11:34 发的旧文章**后面**(真实事故:首页第 2 位)。
*
* 这里在一个一次性临时仓库里跑,不碰真仓库。断言 5 件事:
* ① 新建时 date 只给「天」→ 落盘必须带时分秒 + 北京时区偏移
* ② 同一天连发两篇 → 时间戳必须不同,列表里新的在前
* ③「时间正好 00:00:00」的写法也按「只到天」处理,同样补时刻
* ④ 保存时不改日子 → 原有的时分秒一个字符都不能动
* ⑤ 保存时真的换了日子 → date 换成新日子 + 新时刻
*/
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { makePosts } from '../src/posts.mjs';
const TMP = fs.mkdtempSync(path.join(os.tmpdir(), 'editor-date-'));
const contentDir = path.join(TMP, 'content', 'posts');
fs.mkdirSync(contentDir, { recursive: true });
const api = makePosts({
contentDir,
trashDir: path.join(TMP, 'trash'),
defaultAuthor: '测试',
repoRoot: TMP,
blogBase: '',
});
const admin = { uid: 1, name: '测试', role: 'admin' };
let pass = 0;
let fail = 0;
function check(name, ok, extra = '') {
if (ok) {
pass++;
console.log(' ✓ ' + name + (extra ? ' ' + extra : ''));
} else {
fail++;
console.log(' ✗ ' + name + (extra ? ' ' + extra : ''));
}
}
/** 读回落盘的 date 值(序列化会把带 ':' 的值加单引号,剥掉) */
function dateOf(dirName) {
const raw = fs.readFileSync(path.join(contentDir, '2026', dirName, 'index.md'), 'utf8');
const v = ((/^date:\s*(.+)$/m.exec(raw) || [])[1] || '').trim();
return /^'.*'$/.test(v) ? v.slice(1, -1) : v;
}
const CN = /^2026-10-0[57]T\d{2}:\d{2}:\d{2}\+08:00$/;
try {
// ---- ① 只给「天」----
const a = api.createPost(
{ frontMatter: { title: '同日甲', date: '2026-10-05', slug: '20261005090000' }, content: '甲' },
admin
);
const da = dateOf(a.dirName);
check('① 新建:date 补上了时分秒', CN.test(da), da);
// ---- ② 同一天再发一篇(隔 1 秒,保证时刻严格更大)----
await new Promise((r) => setTimeout(r, 1100));
const b = api.createPost(
{ frontMatter: { title: '同日乙', date: '2026-10-05', slug: '20261005103000' }, content: '乙' },
admin
);
const db = dateOf(b.dirName);
check('② 第二篇也有时分秒', CN.test(db), db);
check('② 两篇时间戳不再相同', da !== db, da + ' vs ' + db);
const order = api.listPosts({ perPage: 50 }, admin).posts.map((p) => p.title);
check('② 列表里新的排在前面', order[0] === '同日乙' && order[1] === '同日甲', JSON.stringify(order));
// ---- ③ 时刻正好 00:00:00 的老写法 ----
const c = api.createPost(
{
frontMatter: { title: '零点写法', date: '2026-10-06T00:00:00.000Z', slug: '20261006000000' },
content: '丙',
},
admin
);
check('③ 00:00:00 也按「只到天」补时刻', /^2026-10-06T\d{2}:\d{2}:\d{2}\+08:00$/.test(dateOf(c.dirName)), dateOf(c.dirName));
// ---- ④ 保存时不改日子(编辑器只会回传 2026-10-05)----
api.savePost(b.dirName, { content: '乙(改了正文)', frontMatter: { date: '2026-10-05' } }, admin);
check('④ 不改日子 → 时分秒保留', dateOf(b.dirName) === db, dateOf(b.dirName));
// ---- ⑤ 真的换了日子 ----
api.savePost(b.dirName, { frontMatter: { date: '2026-10-07' } }, admin);
check('⑤ 改日子 → 新日子 + 时刻', /^2026-10-07T\d{2}:\d{2}:\d{2}\+08:00$/.test(dateOf(b.dirName)), dateOf(b.dirName));
// ---- ⑥ 明确给了时刻的(含手工指定的历史时间)不能被覆盖 ----
const d = api.createPost(
{
frontMatter: { title: '指定时刻', date: '2026-10-05T08:15:30+08:00', slug: '20261005081530' },
content: '丁',
},
admin
);
check('⑥ 明确给了时刻则原样保留', dateOf(d.dirName) === '2026-10-05T08:15:30+08:00', dateOf(d.dirName));
} finally {
fs.rmSync(TMP, { recursive: true, force: true, maxRetries: 3 });
}
console.log('\n================================');
console.log('通过 ' + pass + ' / 失败 ' + fail);
process.exit(fail ? 1 : 0);