YD_Event.Web/scripts/workbench-business-contract-test.mjs

62 lines
4.2 KiB
JavaScript

import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
const read = (path) => readFileSync(resolve(process.cwd(), path), 'utf8').replace(/\r\n/g, '\n');
const controller = read('../YD_Event.Admin/YD_Event.Application/Workbench/WorkbenchController.cs');
const dtos = read('../YD_Event.Admin/YD_Event.Application/Workbench/Dtos/WorkbenchDtos.cs');
const orderBook = read('../YD_Event.Admin/YD_Event.Application/OrderBook/OrderBookService.cs');
const calculation = read('../YD_Event.Admin/YD_Event.Application/Event/Scoring/EventScoreCalculationService.cs');
const sql = read('../YD_Event.Admin/二期需求/dbo.sql');
const launcher = read('src/views/scoring/launcher/index.vue');
const workbench = read('src/views/scoring/workbench/index.vue');
const orderBookPage = read('src/views/scoring/orderbook/index.vue');
const scoreScreen = read('src/views/scoring/screen/index.vue');
const checkinScreen = read('src/views/scoring/checkin-screen/index.vue');
const menuSeed = read('../YD_Event.Admin/YD_Event.Core/InitData/sysmenu.txt');
const roleMenuSeed = read('../YD_Event.Admin/YD_Event.Core/InitData/sysrolemenu.txt');
const backEndRoutes = read('src/router/backEnd.ts');
const checks = [
['工作台接口不重复控制器前缀', controller, '[HttpGet("events")]'],
['秩序册接口使用文档约定路由', orderBook, 'Name = "order-book"'],
['投屏校验成绩与出场关联', controller, 'result.SessionEntryId != entry.Id'],
['投屏校验成绩版本', controller, 'input.ResultVersion.Value != result.ResultVersion'],
['投屏校验评分单收齐', controller, 'submittedJudgeCount < expectedJudgeCount'],
['投屏后进入状态30', controller, 'result.ResultStatus = 30'],
['成绩主表与版本表状态同步', controller, 'SyncResultVersionStatusAsync(result, 30'],
['更正成绩确认后进入40', controller, 'ScoreCorrectionId.HasValue == true ? 40 : 20'],
['聚合跳过成绩同步作废当前版本', calculation, 'version.ResultStatus = ResultStatusVoided'],
['排名排除DQ', controller, '!r.IsDisqualified'],
['排名不包含作废状态', controller, 'r.ResultStatus == 20 || r.ResultStatus == 30 || r.ResultStatus == 40'],
['投屏操作事务化', controller, '[UnitOfWork]\n public async Task<ResultScreenCastOutput> CastResult'],
['重赛按组别定位末位', controller, 'e.GroupName == originalEntry.GroupName'],
['重赛后续出场顺延', controller, 'laterEntry.PlayOrder++'],
['批量确认必须显式选择', controller, 'results.Count != requestedIds.Count'],
['原因服务端规范化', controller, 'NormalizeReason(input.VoidReason, "作废原因")'],
['动态评分项接口', dtos, 'List<WorkbenchScoreItemDto> ScoreItems'],
['秩序册支持xls和xlsx', orderBook, 'ext is not ".xlsx" and not ".xls"'],
['单一当前投屏唯一索引', sql, 'UX_EventResultScreenCast_Current'],
['SQL状态30为已投屏', sql, "WHEN 30 THEN N''已投屏''"],
['报名与秩序册数据源', launcher, "switchSource('orderbook')"],
['赛事列表分页', launcher, 'v-model:current-page="pageNo"'],
['工作台保存赛事上下文', launcher, "sessionStorage.setItem('scoring-context'"],
['秩序册具有独立页面', orderBookPage, 'orderBookImportPost'],
['成绩管理与投屏使用独立菜单路由', menuSeed, '"Path": "/scoring/cast"'],
['秩序册直达路由具有兼容兜底', backEndRoutes, 'ensureScoringOperationalRoutes'],
['超级管理员具有秩序册菜单授权', roleMenuSeed, '"MenuId": 1088'],
['工作台动态评分列', workbench, 'v-for="col in detailColumns"'],
['规定赛隐藏难度', scoreScreen, "includes('PRESCRIBED')"],
['评分卡列数随规则动态调整', scoreScreen, 'Math.max(scoreCards.length,1)'],
['成绩轮询防重入', scoreScreen, 'castRequesting'],
['检录轮询防重入', checkinScreen, 'requesting=false'],
['检录时间使用服务端基线', checkinScreen, 'serverBaseMs+(Date.now()-syncedAtMs)'],
];
for (const [name, source, expected] of checks) {
assert.ok(source.includes(expected), `${name}:缺少 ${expected}`);
process.stdout.write(`PASS ${name}\n`);
}
process.stdout.write(`工作台业务契约测试通过:${checks.length}/${checks.length}\n`);