113 行
5.0 KiB
TypeScript
113 行
5.0 KiB
TypeScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import defaultI18n from '../src/locale/index.ts';
|
|
import { routes } from '../src/routes.ts';
|
|
|
|
const adminRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
const articlesPagePath = path.join(adminRoot, 'src/pages/card/articles/index.tsx');
|
|
const articlesLocalePath = path.join(adminRoot, 'src/pages/card/articles/locale/index.ts');
|
|
|
|
test('1. card/articles 路由必须在 routes.ts 注册,且多语言包含 menu.card.articles', () => {
|
|
const cardGroup = routes.find((r) => r.key === 'card');
|
|
assert.ok(cardGroup, 'routes.ts 必须存在 card 顶级路由');
|
|
const articlesRoute = cardGroup.children?.find((c) => c.key === 'card/articles');
|
|
assert.ok(articlesRoute, 'routes.ts 中 card 分组下必须存在 card/articles 路由');
|
|
assert.equal(articlesRoute?.name, 'menu.card.articles');
|
|
|
|
assert.ok(
|
|
(defaultI18n['zh-CN'] as Record<string, string>)['menu.card.articles'],
|
|
'zh-CN 必须包含 menu.card.articles'
|
|
);
|
|
assert.ok(
|
|
(defaultI18n['en-US'] as Record<string, string>)['menu.card.articles'],
|
|
'en-US 必须包含 menu.card.articles'
|
|
);
|
|
});
|
|
|
|
test('2. card/articles 页面必须请求 article API,并严格使用 Arco Table/Drawer/Form/Input/Switch', () => {
|
|
assert.ok(fs.existsSync(articlesPagePath), '文章管理页面文件必须存在');
|
|
const content = fs.readFileSync(articlesPagePath, 'utf-8');
|
|
|
|
// API 路径断言
|
|
assert.ok(
|
|
content.includes('admin/card/article/page'),
|
|
'必须请求 POST /api/admin/card/article/page'
|
|
);
|
|
assert.ok(
|
|
content.includes('admin/card/article/add'),
|
|
'必须请求 POST /api/admin/card/article/add'
|
|
);
|
|
assert.ok(
|
|
content.includes('admin/card/article/update'),
|
|
'必须请求 POST /api/admin/card/article/update'
|
|
);
|
|
assert.ok(
|
|
content.includes('admin/card/article/delete'),
|
|
'必须请求 POST /api/admin/card/article/delete'
|
|
);
|
|
|
|
// Arco 组件断言
|
|
assert.ok(content.includes('Table'), '必须使用 Arco Table');
|
|
assert.ok(content.includes('Drawer'), '必须使用 Arco Drawer');
|
|
assert.ok(content.includes('Form'), '必须使用 Arco Form');
|
|
assert.ok(content.includes('Input'), '必须使用 Arco Input');
|
|
assert.ok(content.includes('Switch'), '必须使用 Arco Switch');
|
|
assert.ok(content.includes('Popconfirm'), '删除确认必须使用 Arco Popconfirm');
|
|
assert.ok(
|
|
content.includes("from '@arco-design/web-react'"),
|
|
'必须从 @arco-design/web-react 引入组件'
|
|
);
|
|
|
|
// 代码规范断言
|
|
assert.ok(content.includes('CardArticle'), '必须使用 CardArticle 类型');
|
|
assert.ok(
|
|
content.includes('code === 1000') || content.includes('code ===1000'),
|
|
'必须按 Cool-Admin code === 1000 判断成功'
|
|
);
|
|
assert.ok(content.includes('Message.error'), '失败必须使用 Arco Message.error');
|
|
assert.ok(!content.includes('Mock.js') && !content.includes("from 'mockjs'"), '禁止使用 Mock.js 假数据');
|
|
assert.ok(!/\bany\b/.test(content), '禁止使用 any');
|
|
assert.ok(!content.includes('<Pagination'), '禁止手写分页器,必须使用 Table 自带分页');
|
|
});
|
|
|
|
test('3. card/articles 必须遵循瑞士国际主义风格、严格 Token、单一主 CTA 与无 emoji', () => {
|
|
const content = fs.readFileSync(articlesPagePath, 'utf-8');
|
|
|
|
assert.ok(content.includes('lightColors'), '颜色必须引用 lightColors token');
|
|
assert.ok(!/#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})\b/.test(content), '禁止硬编码颜色 (#hex)');
|
|
|
|
// 单一主 CTA
|
|
const primaryButtonMatches = content.match(/type=["']primary["']/g) || [];
|
|
assert.equal(
|
|
primaryButtonMatches.length,
|
|
1,
|
|
'遵循瑞士国际主义风格:全屏仅允许 1 个 type="primary" 主 CTA'
|
|
);
|
|
|
|
// 禁止 emoji 正则测试
|
|
const emojiRegex = /[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u;
|
|
assert.ok(!emojiRegex.test(content), '禁止使用 emoji');
|
|
|
|
// 支持富文本/Markdown 草稿/发布编辑与 OpenGraph 社交预览卡
|
|
assert.ok(
|
|
content.includes('ogPreview') || content.includes('OpenGraph') || content.includes('ogMeta'),
|
|
'必须支持 OpenGraph 社交卡片预览联动'
|
|
);
|
|
assert.ok(content.includes('isPublished'), '必须支持发布状态草稿/上架控制');
|
|
});
|
|
|
|
test('4. card/articles 语言包必须包含中英文案与 OpenGraph 预览词条', () => {
|
|
assert.ok(fs.existsSync(articlesLocalePath), '语言包文件必须存在');
|
|
const content = fs.readFileSync(articlesLocalePath, 'utf-8');
|
|
|
|
assert.ok(content.includes("'en-US'"), '必须包含 en-US');
|
|
assert.ok(content.includes("'zh-CN'"), '必须包含 zh-CN');
|
|
assert.ok(content.includes('cardArticles.title'), '必须包含页面标题文案');
|
|
assert.ok(content.includes('cardArticles.action.add'), '必须包含新增文章主 CTA 文案');
|
|
assert.ok(content.includes('cardArticles.ogPreview.title'), '必须包含 OG 社交预览卡文案');
|
|
assert.ok(!/\bany\b/.test(content), '语言包禁止使用 any');
|
|
});
|