文件
shanghaipeiwan/server/tests/admin-features.spec.ts

139 行
7.2 KiB
TypeScript

// 已读取AGENTS.md
import * as fs from 'fs';
import * as path from 'path';
describe('PC总后台管理端核心业务与闭环能力自动化测试 (Post Manage, Finance CSV Export, WeChat Template Config)', () => {
const rootDir = path.resolve(__dirname, '../../');
const serverIndexPath = path.join(rootDir, 'server/src/index.ts');
const serverRepoPath = path.join(rootDir, 'server/src/db/repository.ts');
const serverMysqlPath = path.join(rootDir, 'server/src/db/mysql.ts');
const adminPostManageVuePath = path.join(rootDir, 'admin/arco-design-pro-vite/src/views/community/post-manage/index.vue');
const adminFinanceRecordsVuePath = path.join(rootDir, 'admin/arco-design-pro-vite/src/views/finance/records/index.vue');
const adminFinanceWithdrawVuePath = path.join(rootDir, 'admin/arco-design-pro-vite/src/views/finance/withdraw/index.vue');
const adminPlatformConfigVuePath = path.join(rootDir, 'admin/arco-design-pro-vite/src/views/safety/platform-config/index.vue');
const adminCommunityRouterPath = path.join(rootDir, 'admin/arco-design-pro-vite/src/router/routes/modules/community.ts');
describe('1. 友圈广场动态管理与置顶/状态流转/级联删除闭环验证', () => {
it('数据库层必须扩展 posts 表结构并包含 is_top 与 status 字段', () => {
const mysqlCode = fs.readFileSync(serverMysqlPath, 'utf-8');
expect(mysqlCode).toContain('ALTER TABLE posts ADD COLUMN is_top');
expect(mysqlCode).toContain('ALTER TABLE posts ADD COLUMN status');
});
it('仓储层 MysqlRepository 必须实现动态多维筛选、一键置顶、状态切换与评论管理', () => {
const repoCode = fs.readFileSync(serverRepoPath, 'utf-8');
expect(repoCode).toContain('async getPosts(');
expect(repoCode).toContain('ORDER BY is_top DESC, created_at DESC');
expect(repoCode).toContain('async togglePostTop(');
expect(repoCode).toContain('async updatePostStatus(');
expect(repoCode).toContain('async adminDeletePost(');
expect(repoCode).toContain('async adminDeletePostComment(');
});
it('后端服务 index.ts 必须注册动态管控的核心管理端 API 路由', () => {
const serverCode = fs.readFileSync(serverIndexPath, 'utf-8');
expect(serverCode).toContain("app.get('/api/admin/posts'");
expect(serverCode).toContain("app.post('/api/admin/posts/:id/top'");
expect(serverCode).toContain("app.post('/api/admin/posts/:id/status'");
expect(serverCode).toContain("app.delete('/api/admin/posts/:id'");
expect(serverCode).toContain("app.delete('/api/admin/posts/comments/:commentId'");
});
it('动态管理前端视图 post-manage/index.vue 必须具备完整交互与多图预览', () => {
const postManageCode = fs.readFileSync(adminPostManageVuePath, 'utf-8');
expect(postManageCode).toContain('handleToggleTop');
expect(postManageCode).toContain('handleToggleStatus');
expect(postManageCode).toContain('handleDeletePost');
expect(postManageCode).toContain('handleDeleteComment');
expect(postManageCode).toContain('a-image-preview-group');
expect(postManageCode).toContain('a-drawer');
expect(postManageCode).toContain('/api/admin/posts');
});
});
describe('2. 财务管理对账明细导出 CSV 规范校验', () => {
it('资金交易流水导出必须包含 UTF-8 BOM 与标准字段', () => {
const recordsFile = fs.readFileSync(adminFinanceRecordsVuePath, 'utf-8');
expect(recordsFile).toContain('exportCSV');
expect(recordsFile).toContain('\\uFEFF');
expect(recordsFile).toContain('流水号');
expect(recordsFile).toContain('交易类型');
expect(recordsFile).toContain('金额(元)');
expect(recordsFile).toContain('资金方向');
expect(recordsFile).toContain('交易对手方');
expect(recordsFile).toContain('关联业务ID');
expect(recordsFile).toContain('记账时间');
});
it('提现审核列表导出必须包含 UTF-8 BOM 与标准字段', () => {
const withdrawFile = fs.readFileSync(adminFinanceWithdrawVuePath, 'utf-8');
expect(withdrawFile).toContain('exportCSV');
expect(withdrawFile).toContain('\\uFEFF');
expect(withdrawFile).toContain('提现单号');
expect(withdrawFile).toContain('申请大神');
expect(withdrawFile).toContain('大神ID');
expect(withdrawFile).toContain('提现金额(元)');
expect(withdrawFile).toContain('账户余额(元)');
expect(withdrawFile).toContain('结算渠道');
expect(withdrawFile).toContain('申请时间');
expect(withdrawFile).toContain('审核状态');
});
});
describe('3. 微信小程序订阅消息与服务通知管理配置及模拟推送', () => {
it('平台配置种子与增量迁移中必须包含 message_template_rules', () => {
const mysqlCode = fs.readFileSync(serverMysqlPath, 'utf-8');
expect(mysqlCode).toContain('message_template_rules');
expect(mysqlCode).toContain('orderStatusTemplateId');
expect(mysqlCode).toContain('activityJoinTemplateId');
expect(mysqlCode).toContain('withdrawSuccessTemplateId');
expect(mysqlCode).toContain('verifyCodeTemplateId');
});
it('后台平台配置面板已集成微信服务通知与模板消息 Tab 及测试推送控制台', () => {
const configViewCode = fs.readFileSync(adminPlatformConfigVuePath, 'utf-8');
expect(configViewCode).toContain('message_template_rules');
expect(configViewCode).toContain('orderStatusTemplateId');
expect(configViewCode).toContain('activityJoinTemplateId');
expect(configViewCode).toContain('withdrawSuccessTemplateId');
expect(configViewCode).toContain('verifyCodeTemplateId');
expect(configViewCode).toContain('sendTestMessage');
expect(configViewCode).toContain('/api/admin/message/test-send');
});
it('后端必须提供模拟测试推送端点并正确返回结构化结果', () => {
const serverCode = fs.readFileSync(serverIndexPath, 'utf-8');
expect(serverCode).toContain("app.post('/api/admin/message/test-send'");
expect(serverCode).toContain('wechatMsgId');
expect(serverCode).toContain('status');
expect(serverCode).toContain('sendTime');
});
it('管理后台路由正确注册 community 模块并挂载 post-manage', () => {
expect(fs.existsSync(adminCommunityRouterPath)).toBe(true);
const routerCode = fs.readFileSync(adminCommunityRouterPath, 'utf-8');
expect(routerCode).toContain('/community');
expect(routerCode).toContain('post-manage');
expect(routerCode).toContain('icon-message');
});
});
describe('4. 全流程无 Emoji 门禁合规校验', () => {
it('新增的前后端代码中严禁包含任何系统 Emoji 图标字符', () => {
const filesToCheck = [
adminCommunityRouterPath,
adminPostManageVuePath,
adminFinanceRecordsVuePath,
adminFinanceWithdrawVuePath,
adminPlatformConfigVuePath
];
const emojiRegex = /[\uD83C-\uDBFF\uDC00-\uDFFF\u2600-\u26FF\u2700-\u27BF]/;
for (const file of filesToCheck) {
const content = fs.readFileSync(file, 'utf-8');
expect(emojiRegex.test(content)).toBe(false);
}
});
});
});