Files
ny-exam-platform/docs/dev/testing.md
T
nxxy335 e87986fcc6 多考试块表:每场考试改为单列并修正第几次列合并
- ny_assemble_block_sheet() 中每场考试由 2 列改为 1 列,删除历史遗留的
  「是否最佳」空白列,消除每场右侧多余空白窄列
- 删除「第几次」列的纵向合并,改为逐行显示 1/2/3…,不再被吞成 1
- 合格次数行同步改为每场 1 列;未考合并加 $end > $start 跨行守卫,
  规避单行学生产生的非法 1x1 合并(Excel 修复提示)
- 列宽按考试名估算(CJK 记 2 半角宽),clamp 8~18
- 同步更新 test-multi-export.php(95 项含 4 条防回归断言)、
  make-samples.php(李四数学改为真正整场未考)、导出/接口/测试文档
  及样例预览文件;全量回归 404 项 0 失败
2026-10-06 12:22:16 +08:00

143 lines
6.5 KiB
Markdown
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.
# 测试
回归测试分两类:**PHP 自测**(纯逻辑断言)与 **Node e2e**(起 mock 服务 + PHP 内置服务器,走真实 HTTP)。
## 一键运行
```bash
bash tests/run-all.sh
```
脚本会依次执行:
| 文件 | 类型 | 覆盖 |
| --- | --- | --- |
| `tests/test-aggregate.php` | PHP | 聚合、去重、考试次数、排序 |
| `tests/test-new-features.php` | PHP | 再次提交置顶排序、XLSX 多表、名单导入列识别 |
| `tests/test-config-persist.php` | PHP | 配置双写兜底(DB / `config.json`) |
| `tools/test-xlsxwriter.php` | PHP | XLSX 写入与 ZIP 打包、合并单元格、单元格级红字 / 绿底 |
| `tests/test-multi-export.php` | PHP | 多考试块表与单场宽表的装配(合并区间、合格线、标红标绿、班级 / 组别列) |
| `tools/test-config-save.js` | Node e2e | 配置保存、连接变化检测、每卷配置隔离、CSRF |
| `tools/test-upload-guard.js` | Node e2e | 导入文件后缀白名单 |
| `tools/test-whitelist.js` | Node e2e | 白名单导入 / 名单识别 |
| `tools/test-login-loop.js` | Node e2e | 未配置账号 → 登录 → 已登录状态回流 |
| `tools/test-dashboard-nav.js` | Node e2e | 数据大屏两种形态:`dash-home` / `dash-class` 骨架、顶栏控件收敛、后退锁定、班级卡片渲染 |
| `tools/test-draw-alloc.js` | Node e2e | 随机抽取名额分配(加权 / 自定义 / 守恒 fuzz) |
| `tools/test-block-print.js` | Node(不需要服务) | 从 `assets/app.js` 抽取 `sheetToHtml` 校验合并区间换算与红 / 绿标记 |
> `tools/test-block-print.js`、`tools/make-samples.js`、`tools/test-dashboard-nav.js`、`tools/make-dash-sample.js`
> 都会**直接从生产源码里抽取函数在真数据上执行**,而不是另抄一份渲染逻辑——改了这些函数,这几处会立刻暴露漂移。
::: warning 端口占用会让 e2e「假通过 / 假失败」
每个 e2e 段用固定端口(`test-config-save.js` 18081、`test-whitelist.js` 18082、`test-upload-guard.js` 18083 等)。
若上一次跑测试时中断,PHP 子进程可能变成**孤儿服务**继续占着端口:新一次运行时它的 `waitPort` 会照常通过
(打到的是旧服务),于是登录直接失败、报错信息指向错误的连接地址。遇到"服务已就绪但登录失败",先查端口:
```bash
netstat -ano | grep LISTENING | grep -E ":180[0-9][0-9]|:199[0-9][0-9]"
taskkill //PID <pid> //F
```
:::
## 生成导出版式样例
想直观看新版式(以及验证打印与导出一致),可生成可打开的样例:
```bash
php tools/make-samples.php # 出两版 xlsx + sheet-data.json
node tools/make-samples.js # 用生产 sheetToHtml 渲染打印预览 HTML
node tools/make-dash-sample.js # 渲染数据大屏首页预览(含班级入口卡片)
```
产物在 `docs/samples/`:打印预览 `preview-multi-block.html` / `preview-single-wide.html`
(+ 对应 `.xlsx`),大屏首页预览 `dash-home-preview.html`。两者都自起 mock 服务与临时数据目录,
不会读写项目 `data/`。
可通过环境变量覆盖运行时路径:
```bash
PHP_BIN=/usr/bin/php NODE_BIN=$(which node) bash tests/run-all.sh
```
## 单独运行 PHP 自测
```bash
php -d extension_dir="C:/php/ext" -d extension=pdo_sqlite tests/test-aggregate.php
php tests/test-new-features.php
```
输出为逐条 `✓ / ✗` 断言,结尾给出通过数 / 总数,失败时非零退出。
## 单独运行 Node e2e
e2e 需要两个进程:
1. **mock 卷王服务**(必须在 `tools/` 目录下启动,内部用 `__dirname` 解析相对路径):
```bash
cd tools
node mock-server.js # 默认监听 19911
```
2. **PHP 内置服务器**(端口 18081):
```bash
php -S 127.0.0.1:18081
```
然后:
```bash
node tools/test-config-save.js
node tools/test-draw-alloc.js
```
::: warning 测试会污染 `data/`
e2e 会备份并修改 `data/ny.db`、`data/config.json`、`data/roster.json`,
并在结束后恢复。若中途异常中断,请手动检查并还原:
```bash
git status data/ # data/ 已被 gitignore,需手工核对
```
:::
## 写新测试时注意
| 陷阱 | 说明 |
| --- | --- |
| CSRF | 写接口必须带 `_csrf`,e2e 里先从 `config_get` 取全局 token |
| DB 优先 | 配置读的是 **DB 优先**,只备份 `config.json` 不够,必须一起备份 `data/ny.db` |
| `/tmp` 路径 | Node 在 Windows 下会把 `/tmp/x.js` 解析成 `C:\tmp\x.js`,脚本请写在项目目录内 |
| `json_decode` | 必须传 `true` 得到关联数组,否则 `is_array(stdClass)` 为 `false` 会静默跳过 |
| mock 账号 | mock-server 接受账号 `mock` |
## 手工冒烟清单
改完代码建议至少过一遍:
- [ ] 登录 → 主页面三张卡片有数字
- [ ] 切换班级 → 卡片与表格联动
- [ ] 点某一行 → 能看到该学生的每次提交
- [ ] 导入含 `.php` 后缀的文件 → 被拒绝
- [ ] 导入正常 `.xlsx` → 成功,且 `data/uploads/` 为空
- [ ] 工具栏「导出」只一个按钮 → 弹窗里四种内容都能出表,学号不是科学计数法
- [ ] 成绩明细「每人成绩」切 最高 / 最新 → 成绩列跟着变,文件名带 `_最高成绩` / `_最新成绩`
- [ ] 每次考试导出 → 最高分红字、合格次数达标绿底、未达标留白、整场未考合并成「未考」;每场考试只占 1 列,「第几次」逐行 1/2/3 不被合并
- [ ] 多考试打印 → 版式与导出的 Excel 一致,「合格次数」标签没被合并吞掉
- [ ] 打印预览 → 默认成绩降序,没有教师签字栏、没有站点域名页脚;**绿底 / 红字真的印出来了**
(打印样式带 `print-color-adjust: exact`,不需要在对话框里勾「背景图形」)
- [ ] 导出弹窗「附加内容 · 附缺考名单」→ 每次考试 / 多考试对比也出「缺考名单」工作表
- [ ] 在每卷配置里改满分成数 / 合格率 → 数据大屏成员榜的红绿跟着变
- [ ] 数据大屏首页 → 选试卷后列出班级卡片,点击进入单班大屏
- [ ] 单班大屏 → 顶栏只有试卷 / 自动刷新 / 全屏,没有班级选择与退出;按浏览器后退键**退不回去**
- [ ] 复制单班大屏链接在**无痕窗口**打开 → 直接看到该班数据(免登录),顶栏有「公开 · 无需登录」角标;
看不到其它班级的成绩;大屏首页仍要求登录
- [ ] 数据大屏全屏进入 / 退出都正常
- [ ] 随机抽取 → 名额守恒
## 相关
- [架构与目录](./architecture.md)
- [接口一览](./api.md)