feat: 完成分类、worksheet 接口开发,资源迁移到七牛
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { test } from 'node:test';
|
||||
import { categoryTreeOrder } from '../src/categories/category-input';
|
||||
import { parseCategoryExport } from '../src/categories/category-import';
|
||||
|
||||
const root = {
|
||||
_id: 'math',
|
||||
name: '数感启蒙',
|
||||
icon: '📐',
|
||||
color: '#CDB4DB',
|
||||
sortOrder: 0,
|
||||
parentId: null,
|
||||
};
|
||||
|
||||
test('分类导入:兼容 JSON Lines/数组,保留原 ID、Emoji 和带时区时间', () => {
|
||||
const child = {
|
||||
...root,
|
||||
_id: 'Math',
|
||||
parentId: 'math',
|
||||
createdAt: '2025-01-01T08:00:00+08:00',
|
||||
};
|
||||
const lines = `\uFEFF${JSON.stringify(child)}\n\n${JSON.stringify(root)}\n`;
|
||||
const rows = parseCategoryExport(lines);
|
||||
assert.deepEqual(
|
||||
rows.map((row) => row.id),
|
||||
['Math', 'math'],
|
||||
);
|
||||
assert.equal(rows[0]?.createdAt?.toISOString(), '2025-01-01T00:00:00.000Z');
|
||||
assert.equal(rows[1]?.createdAt, undefined);
|
||||
assert.equal(rows[1]?.icon, '📐');
|
||||
assert.deepEqual(categoryTreeOrder(rows), ['math', 'Math']);
|
||||
assert.equal(
|
||||
parseCategoryExport(JSON.stringify([{ ...root, parentId: '' }]))[0]
|
||||
?.parentId,
|
||||
null,
|
||||
);
|
||||
});
|
||||
|
||||
test('分类导入:拒绝重复、未知字段、类型转换、越界及未迁移文件图标', () => {
|
||||
const bad = [
|
||||
[{ ...root, id: 'other' }],
|
||||
[root, root],
|
||||
[{ ...root, role: 'admin' }],
|
||||
[{ ...root, name: 42 }],
|
||||
[{ ...root, icon: 'https://private.example/icon.png' }],
|
||||
[{ ...root, icon: 'cloud://secret/icon' }],
|
||||
[{ ...root, _id: ' math' }],
|
||||
[{ ...root, sortOrder: '2' }],
|
||||
[{ ...root, sortOrder: 0.5 }],
|
||||
[{ ...root, sortOrder: 2147483648 }],
|
||||
[{ ...root, parentId: false }],
|
||||
[{ ...root, createdAt: '2025-01-01T00:00:00' }],
|
||||
[{ ...root, createdAt: { $date: '2025-01-01' } }],
|
||||
[
|
||||
{
|
||||
...root,
|
||||
createdAt: '2025-01-02T00:00:00Z',
|
||||
updatedAt: '2025-01-01T00:00:00Z',
|
||||
},
|
||||
],
|
||||
];
|
||||
for (const value of bad)
|
||||
assert.throws(() => parseCategoryExport(JSON.stringify(value)));
|
||||
for (const value of ['', '{}', '[]', '{broken'])
|
||||
assert.throws(() => parseCategoryExport(value));
|
||||
});
|
||||
|
||||
test('分类树:缺失父级、自引用和多层循环均拒绝,深层树不递归', () => {
|
||||
for (const rows of [
|
||||
[{ id: 'a', parentId: 'missing' }],
|
||||
[{ id: 'a', parentId: 'a' }],
|
||||
[
|
||||
{ id: 'a', parentId: 'b' },
|
||||
{ id: 'b', parentId: 'c' },
|
||||
{ id: 'c', parentId: 'a' },
|
||||
],
|
||||
])
|
||||
assert.throws(() => categoryTreeOrder(rows));
|
||||
const deep = Array.from({ length: 10_000 }, (_, i) => ({
|
||||
id: String(i),
|
||||
parentId: i ? String(i - 1) : null,
|
||||
})).reverse();
|
||||
assert.equal(categoryTreeOrder(deep).length, 10_000);
|
||||
});
|
||||
Reference in New Issue
Block a user