fix(entities): 场景功能的真正根因 —— Scene 未注册进 ENTITIES(v0.7.4)
部署 v0.7.3 后,/health 的 scenes.error 给出决定性线索: No metadata for "Scene" was found. src/entities/index.ts 的 ENTITIES 一直漏了 Scene: export const ENTITIES = [Asset, Song, Motion, CharacterModel, ReviewRecord]; TypeORM 只按 ENTITIES 注册 metadata,漏注册的后果极其隐蔽: - 启动完全正常(DI 可解析、/health 正常、migrationsPending 0); - 迁移也正常(AddScenes 已执行,表其实是建好的); - 但第一次查 Scene 就抛 No metadata,于是 /api/scenes、/api/catalog/export、 /api/catalog/version、/api/reviews?status=pending 全部 500 → 客户端拉不到任何目录、管理端待审列表打不开。 即:此前"数据库缺 scenes 表"的判断也是错的(v0.7.3 的降级与诊断脚本因此仍然值得保留 —— 它们把"场景坏了"限制成"场景不可用",而不是整站不可用)。 修复:ENTITIES 加入 Scene 并导出。 新增静态防线 test/entities-registry.spec.ts(4 项):扫描 src/entities/*.entity.ts 里的 @Entity() 类并逐一与 ENTITIES 对账(漏一个即失败)、检查无重复/无多余、核对 AddScenes 迁移文件存在。已做反向验证:把 Scene 从 ENTITIES 移除后该测试立刻失败。 这类缺陷既过得了 tsc、也过得了启动冒烟(应用能启动),只能靠静态核对兜住。 文档:README.md/.txt 增加 v0.7.4 修订说明;tasks/015-scene-management.md 增 「缺陷修复记录四」;开发文档 §4.12 补「新增实体必须加入 ENTITIES」的硬性要求。 验证:npm run verify 通过(23 文件 / 285 项测试 + 契约/路由/版本一致 + 启动冒烟); 发布产物 opendance-web-v0.7.4.tar.gz sha256 e680c23fc382b6c39498608ea0154f8f80e9e6b5c13518f0f88095644ce88fe1。
This commit is contained in:
@@ -10,7 +10,30 @@ OpenDance Studio **阶段一**: Web 管理服务端(NestJS + TypeORM + 现有 My
|
|||||||
|
|
||||||
## 状态
|
## 状态
|
||||||
|
|
||||||
**阶段一已完成**: T-WEB-001 -> T-WEB-016 全部落地,当前版本 **v0.7.3**(契约 `rest-api 0.5.0`、`websocket-keypoints 0.2.0`、`data-models 0.7.0`、`model-formats 0.5.0`、`skeleton-topology 0.2.0`、`database 0.4.0`)。
|
**阶段一已完成**: T-WEB-001 -> T-WEB-016 全部落地,当前版本 **v0.7.4**(契约 `rest-api 0.5.0`、`websocket-keypoints 0.2.0`、`data-models 0.7.0`、`model-formats 0.5.0`、`skeleton-topology 0.2.0`、`database 0.4.0`)。
|
||||||
|
|
||||||
|
v0.7.4 修订(**场景功能的真正根因:`Scene` 没有注册进 `ENTITIES`**):
|
||||||
|
|
||||||
|
1. **根因(生产实测)**:`/health` 的 `scenes.error` 返回
|
||||||
|
`No metadata for "Scene" was found.` —— `src/entities/index.ts` 的
|
||||||
|
`ENTITIES = [Asset, Song, Motion, CharacterModel, ReviewRecord]` **漏了 `Scene`**。
|
||||||
|
TypeORM 只按 `ENTITIES` 注册 metadata,于是:
|
||||||
|
* **启动完全正常**(DI 图可解析、`/health` 正常、`migrationsPending 0`),
|
||||||
|
* 但**第一次查 Scene 就抛**`No metadata`,于是 `/api/scenes`、
|
||||||
|
`/api/catalog/export`、`/api/catalog/version`、`/api/reviews?status=pending`
|
||||||
|
全部 500 —— 客户端拉不到任何目录、管理端待审列表打不开;
|
||||||
|
* 我此前"数据库缺 scenes 表"的判断**也是错的**:表其实是由 AddScenes 迁移建好的,
|
||||||
|
缺的是**实体注册**;
|
||||||
|
2. **修复**:`ENTITIES` 加入 `Scene`(并导出)。这也解释了为什么 v0.7.3 的降级修复是必要的
|
||||||
|
—— 即使根因是漏注册,降级也保证了"场景坏了不拖垮整站";
|
||||||
|
3. **新增静态防线**`test/entities-registry.spec.ts`(4 项):扫描
|
||||||
|
`src/entities/*.entity.ts` 的 `@Entity()` 类,**逐一与 `ENTITIES` 对账**
|
||||||
|
(漏一个即失败)、检查无重复/无多余,并核对 `AddScenes` 迁移文件确实存在。
|
||||||
|
已做**反向验证**:把 `Scene` 从 `ENTITIES` 移除,该测试立刻失败。
|
||||||
|
这类"漏注册"既过得了 `tsc`,也过得了启动冒烟(应用能启动),
|
||||||
|
只能靠静态核对兜住;
|
||||||
|
4. `web-server/scripts/diagnose-scenes.mjs` 保持不变(默认只读),部署 v0.7.4 后运行它
|
||||||
|
可确认 `scenes` 表与列的实际情况。
|
||||||
|
|
||||||
v0.7.3 修订(**场景表不可用不再拖垮整站** —— 生产事故修复):
|
v0.7.3 修订(**场景表不可用不再拖垮整站** —— 生产事故修复):
|
||||||
**另有一个更直接的缺陷同时修掉**:`ScenesService.create()` 当初按**内存存储**写,
|
**另有一个更直接的缺陷同时修掉**:`ScenesService.create()` 当初按**内存存储**写,
|
||||||
@@ -171,15 +194,15 @@ v0.2.0 主要变更:
|
|||||||
3. 取得发布包并校验(**本仓库的真实发布地址**, 域名 `gitea.kasugano.cn`、属主 `zijunchiang` 属部署必需信息, 不是隐私项)
|
3. 取得发布包并校验(**本仓库的真实发布地址**, 域名 `gitea.kasugano.cn`、属主 `zijunchiang` 属部署必需信息, 不是隐私项)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -LO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.3/opendance-web-v0.7.3.tar.gz
|
curl -LO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.4/opendance-web-v0.7.4.tar.gz
|
||||||
curl -LO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.3/SHA256SUMS
|
curl -LO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.4/SHA256SUMS
|
||||||
sha256sum -c SHA256SUMS # 期望输出 "OK"
|
sha256sum -c SHA256SUMS # 期望输出 "OK"
|
||||||
```
|
```
|
||||||
|
|
||||||
4. 解压并生成配置(交互式引导,逐项问答,口令不回显)
|
4. 解压并生成配置(交互式引导,逐项问答,口令不回显)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tar -xzf opendance-web-v0.7.3.tar.gz && cd opendance-web-v0.7.3
|
tar -xzf opendance-web-v0.7.4.tar.gz && cd opendance-web-v0.7.4
|
||||||
bash deploy/init-env.sh
|
bash deploy/init-env.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -250,8 +273,8 @@ FLUSH PRIVILEGES;
|
|||||||
### 5. 部署步骤
|
### 5. 部署步骤
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tar -xzf opendance-web-v0.7.3.tar.gz
|
tar -xzf opendance-web-v0.7.4.tar.gz
|
||||||
cd opendance-web-v0.7.3
|
cd opendance-web-v0.7.4
|
||||||
bash deploy/init-env.sh # 首次启动引导: 逐项问答生成 deploy/.env(见下)
|
bash deploy/init-env.sh # 首次启动引导: 逐项问答生成 deploy/.env(见下)
|
||||||
bash deploy/install.sh # 已以 root 登录, 不需要 sudo
|
bash deploy/install.sh # 已以 root 登录, 不需要 sudo
|
||||||
```
|
```
|
||||||
|
|||||||
+16
-5
@@ -1,5 +1,5 @@
|
|||||||
================================================================
|
================================================================
|
||||||
OpenDance Studio -- Web 管理服务端 v0.7.3 使用说明
|
OpenDance Studio -- Web 管理服务端 v0.7.4 使用说明
|
||||||
================================================================
|
================================================================
|
||||||
|
|
||||||
本服务端是 OpenDance Studio 三端中的第一端, 负责管理歌曲、VRM 模型与
|
本服务端是 OpenDance Studio 三端中的第一端, 负责管理歌曲、VRM 模型与
|
||||||
@@ -8,6 +8,17 @@ OpenDance Studio -- Web 管理服务端 v0.7.3 使用说明
|
|||||||
重要: 本服务端 不部署、不管理 MySQL。数据库为部署方提供的现有实例,
|
重要: 本服务端 不部署、不管理 MySQL。数据库为部署方提供的现有实例,
|
||||||
连接信息通过 .env 注入。
|
连接信息通过 .env 注入。
|
||||||
|
|
||||||
|
v0.7.4 修订 - 场景功能的真正根因: Scene 没有注册进 ENTITIES
|
||||||
|
1. 生产实测 /health 的 scenes.error = 'No metadata for "Scene" was found.'
|
||||||
|
-- src/entities/index.ts 的 ENTITIES 漏了 Scene。TypeORM 只按 ENTITIES 注册
|
||||||
|
metadata, 于是启动完全正常、但第一次查 Scene 就抛错 => /api/scenes、
|
||||||
|
/api/catalog/export、/api/catalog/version、/api/reviews?status=pending 全 500。
|
||||||
|
此前"数据库缺 scenes 表"的判断也是错的: 表已由 AddScenes 迁移建好, 缺的是实体注册。
|
||||||
|
2. 修复: ENTITIES 加入 Scene 并导出。
|
||||||
|
3. 新增 test/entities-registry.spec.ts(4 项): 扫描 @Entity() 类与 ENTITIES 对账,
|
||||||
|
漏一个即失败; 已反向验证(移除 Scene 立刻失败)。
|
||||||
|
4. 部署后运行 node scripts/diagnose-scenes.mjs 可确认表与列的实际状态。
|
||||||
|
|
||||||
v0.7.3 修订 - 场景表不可用不再拖垮整站(生产事故修复)
|
v0.7.3 修订 - 场景表不可用不再拖垮整站(生产事故修复)
|
||||||
另修一个更直接的缺陷: ScenesService.create() 按内存存储写(判断 file.buffer),
|
另修一个更直接的缺陷: ScenesService.create() 按内存存储写(判断 file.buffer),
|
||||||
而上传中间件用的是 multer diskStorage(只有 path、没有 buffer) => 任何场景都传不上来,
|
而上传中间件用的是 multer diskStorage(只有 path、没有 buffer) => 任何场景都传不上来,
|
||||||
@@ -206,11 +217,11 @@ v0.2.1 修订
|
|||||||
本项目不会创建数据库本身
|
本项目不会创建数据库本身
|
||||||
3. 取得发布包并校验(以下是本仓库的真实发布地址; 域名 gitea.kasugano.cn
|
3. 取得发布包并校验(以下是本仓库的真实发布地址; 域名 gitea.kasugano.cn
|
||||||
与属主 zijunchiang 属部署必需信息, 不是隐私项)
|
与属主 zijunchiang 属部署必需信息, 不是隐私项)
|
||||||
curl -LO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.2/opendance-web-v0.7.3.tar.gz
|
curl -LO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.2/opendance-web-v0.7.4.tar.gz
|
||||||
curl -LO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.2/SHA256SUMS
|
curl -LO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.2/SHA256SUMS
|
||||||
sha256sum -c SHA256SUMS # 期望输出 "OK"
|
sha256sum -c SHA256SUMS # 期望输出 "OK"
|
||||||
4. 解压并生成配置(交互式引导, 逐项问答, 口令不回显)
|
4. 解压并生成配置(交互式引导, 逐项问答, 口令不回显)
|
||||||
tar -xzf opendance-web-v0.7.3.tar.gz && cd opendance-web-v0.7.3
|
tar -xzf opendance-web-v0.7.4.tar.gz && cd opendance-web-v0.7.4
|
||||||
bash deploy/init-env.sh
|
bash deploy/init-env.sh
|
||||||
5. 安装(建用户与目录 -> 装依赖 -> 迁移 -> 注册系统服务 -> 等健康检查)
|
5. 安装(建用户与目录 -> 装依赖 -> 迁移 -> 注册系统服务 -> 等健康检查)
|
||||||
bash deploy/install.sh
|
bash deploy/install.sh
|
||||||
@@ -269,8 +280,8 @@ v0.2.1 修订
|
|||||||
(本项目不会创建数据库本身, 也不需要 GRANT OPTION / FILE / SUPER 等管理权限)
|
(本项目不会创建数据库本身, 也不需要 GRANT OPTION / FILE / SUPER 等管理权限)
|
||||||
|
|
||||||
部署步骤
|
部署步骤
|
||||||
tar -xzf opendance-web-v0.7.3.tar.gz
|
tar -xzf opendance-web-v0.7.4.tar.gz
|
||||||
cd opendance-web-v0.7.3
|
cd opendance-web-v0.7.4
|
||||||
bash deploy/init-env.sh # 首次启动引导: 逐项问答生成 deploy/.env(见下)
|
bash deploy/init-env.sh # 首次启动引导: 逐项问答生成 deploy/.env(见下)
|
||||||
bash deploy/install.sh # 已以 root 登录, 不需要 sudo
|
bash deploy/install.sh # 已以 root 登录, 不需要 sudo
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
project: opendance-web-server
|
project: opendance-web-server
|
||||||
version: 0.7.3
|
version: 0.7.4
|
||||||
repository: opendance-web
|
repository: opendance-web
|
||||||
default_branch: main
|
default_branch: main
|
||||||
contracts_version:
|
contracts_version:
|
||||||
@@ -90,7 +90,7 @@ tasks:
|
|||||||
status: done
|
status: done
|
||||||
|
|
||||||
deliverable:
|
deliverable:
|
||||||
artifact: opendance-web-v0.7.3.tar.gz
|
artifact: opendance-web-v0.7.4.tar.gz
|
||||||
packaging: Linux 业务服务(系统服务托管,双端口:软件 API + 管理端,不含 MySQL、不含反向代理、不使用 Docker)
|
packaging: Linux 业务服务(系统服务托管,双端口:软件 API + 管理端,不含 MySQL、不含反向代理、不使用 Docker)
|
||||||
includes:
|
includes:
|
||||||
- web-server/ # NestJS 源码 + 构建产物(含 BVH / VMD 内置解析、ZIP 读取与模型压缩包转换)
|
- web-server/ # NestJS 源码 + 构建产物(含 BVH / VMD 内置解析、ZIP 读取与模型压缩包转换)
|
||||||
|
|||||||
@@ -140,3 +140,40 @@ if (!file || !file.buffer || file.buffer.length === 0) { …400… }
|
|||||||
**测试**:`test/scene-upload.spec.ts`(5 项)—— diskStorage 形状的文件不再被判成
|
**测试**:`test/scene-upload.spec.ts`(5 项)—— diskStorage 形状的文件不再被判成
|
||||||
"缺少 file 字段"、GLB 直传标注"未做重编码"且落 `pending`、中文文件名被还原、
|
"缺少 file 字段"、GLB 直传标注"未做重编码"且落 `pending`、中文文件名被还原、
|
||||||
缺文件仍 400、超限 400 且不落盘。该用例在修复前必然失败。
|
缺文件仍 400、超限 400 且不落盘。该用例在修复前必然失败。
|
||||||
|
|
||||||
|
## 缺陷修复记录四(v0.7.4):**真正的根因** —— `Scene` 没注册进 `ENTITIES`
|
||||||
|
|
||||||
|
部署 v0.7.3 后,`/health` 的 `scenes.error` 给出了决定性线索:
|
||||||
|
|
||||||
|
```
|
||||||
|
No metadata for "Scene" was found.
|
||||||
|
```
|
||||||
|
|
||||||
|
`src/entities/index.ts` 是:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export const ENTITIES = [Asset, Song, Motion, CharacterModel, ReviewRecord]; // ← 少了 Scene
|
||||||
|
```
|
||||||
|
|
||||||
|
TypeORM 的 DataSource **只按 `ENTITIES` 注册 metadata**,漏注册的后果非常隐蔽:
|
||||||
|
|
||||||
|
| 环节 | 表现 |
|
||||||
|
|--|--|
|
||||||
|
| 启动 | **完全正常** —— DI 图可解析、`/health` 正常、`migrationsPending 0` |
|
||||||
|
| 迁移 | 正常(`AddScenes` 已执行,**表其实是建好的**) |
|
||||||
|
| 第一次查该实体 | 抛 `No metadata for "Scene" was found.` |
|
||||||
|
| 连带影响 | `/api/scenes`、`/api/catalog/export`、`/api/catalog/version`、`/api/reviews?status=pending` 全部 500 → **客户端拉不到任何目录** |
|
||||||
|
|
||||||
|
也就是说:**此前"数据库缺 scenes 表"的判断是错的**(v0.7.3 的降级与诊断脚本因此仍然值得保留 ——
|
||||||
|
它们把"场景坏了"限制成"场景不可用",而不是整站不可用)。
|
||||||
|
|
||||||
|
**修复**:`ENTITIES` 加入 `Scene` 并导出。
|
||||||
|
|
||||||
|
**新增静态防线** `test/entities-registry.spec.ts`(4 项):
|
||||||
|
|
||||||
|
* 扫描 `src/entities/*.entity.ts` 里所有 `@Entity()` 类,**逐一与 `ENTITIES` 对账**
|
||||||
|
(漏一个即失败;已反向验证:移除 `Scene` 后测试立刻失败);
|
||||||
|
* 检查 `ENTITIES` 无重复、无多余项;
|
||||||
|
* 核对 `AddScenes` 迁移文件确实存在(迁移文件缺失时 `showMigrations()` 仍会显示 0 个待执行)。
|
||||||
|
|
||||||
|
这类"漏注册"既过得了 `tsc`,也过得了启动冒烟(应用能启动),因此**只能靠静态核对兜住**。
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "opendance-admin",
|
"name": "opendance-admin",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.7.3",
|
"version": "0.7.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "OpenDance Studio 管理端(React + TypeScript + Vite)",
|
"description": "OpenDance Studio 管理端(React + TypeScript + Vite)",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "opendance-web-server",
|
"name": "opendance-web-server",
|
||||||
"version": "0.7.3",
|
"version": "0.7.4",
|
||||||
"description": "OpenDance Studio Web 管理服务端(NestJS + TypeORM + 现有 MySQL 实例)",
|
"description": "OpenDance Studio Web 管理服务端(NestJS + TypeORM + 现有 MySQL 实例)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -2,9 +2,17 @@ import { Asset } from './asset.entity';
|
|||||||
import { CharacterModel } from './model.entity';
|
import { CharacterModel } from './model.entity';
|
||||||
import { Motion } from './motion.entity';
|
import { Motion } from './motion.entity';
|
||||||
import { ReviewRecord } from './review-record.entity';
|
import { ReviewRecord } from './review-record.entity';
|
||||||
|
import { Scene } from './scene.entity';
|
||||||
import { Song } from './song.entity';
|
import { Song } from './song.entity';
|
||||||
|
|
||||||
export { Asset, CharacterModel, Motion, ReviewRecord, Song };
|
export { Asset, CharacterModel, Motion, ReviewRecord, Scene, Song };
|
||||||
|
|
||||||
/** 显式列出实体:glob 在 ts-node 与编译产物下行为不一致,显式最稳 */
|
/**
|
||||||
export const ENTITIES = [Asset, Song, Motion, CharacterModel, ReviewRecord];
|
* 显式列出实体:glob 在 ts-node 与编译产物下行为不一致,显式最稳。
|
||||||
|
*
|
||||||
|
* ⚠️ **漏加一个实体不会在启动时报错,只会在第一次查它时报**
|
||||||
|
* `No metadata for "<Name>" was found.` —— 生产上就踩过:`Scene` 忘了加进来,
|
||||||
|
* 于是所有场景相关请求 500,连 `catalog/export` 都跟着挂(客户端拉不到目录)。
|
||||||
|
* 因此新增实体时**必须同时**加到这里,`test/entities-registry.spec.ts` 会强制核对。
|
||||||
|
*/
|
||||||
|
export const ENTITIES = [Asset, Song, Motion, CharacterModel, ReviewRecord, Scene];
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { readdirSync, readFileSync } from 'node:fs';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { ENTITIES } from '../src/entities';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* **每个 `@Entity()` 装饰的类都必须出现在 `ENTITIES` 里。**
|
||||||
|
*
|
||||||
|
* 生产事故:`scene.entity.ts` 定义了 `@Entity('scenes')` 的 `Scene`,
|
||||||
|
* 但 `src/entities/index.ts` 的 `ENTITIES` 漏了它。TypeORM 的 DataSource 只按
|
||||||
|
* `ENTITIES` 注册 metadata,于是:
|
||||||
|
*
|
||||||
|
* * **启动完全正常**(DI 图能解析、`/health` 也正常),
|
||||||
|
* * 但**第一次查该实体**就抛 `No metadata for "Scene" was found.` →
|
||||||
|
* `/api/scenes`、`/api/catalog/export`、`/api/catalog/version`、
|
||||||
|
* `/api/reviews?status=pending` 全部 500,客户端拉不到任何目录。
|
||||||
|
*
|
||||||
|
* 这类"漏注册"既不会被 `tsc` 发现,也不会被启动冒烟发现,只能靠**静态核对**
|
||||||
|
* 兜住,所以这里直接扫 `src/entities/*.entity.ts` 的 `@Entity` 装饰器,
|
||||||
|
* 与 `ENTITIES` 逐一对账。
|
||||||
|
*/
|
||||||
|
const entitiesDir = join(__dirname, '..', 'src', 'entities');
|
||||||
|
|
||||||
|
function decoratedEntityClasses(): string[] {
|
||||||
|
const files = readdirSync(entitiesDir).filter((f) => f.endsWith('.entity.ts'));
|
||||||
|
const classes: string[] = [];
|
||||||
|
for (const file of files) {
|
||||||
|
const source = readFileSync(join(entitiesDir, file), 'utf8');
|
||||||
|
// 只认真正带 @Entity() 装饰器的类;@Entity() 与 class 之间可能还有别的装饰器
|
||||||
|
// (例如 `@Index(...)`)或注释,所以先定位 @Entity(,再往后找第一个 export class。
|
||||||
|
const entityIndex = source.indexOf('@Entity(');
|
||||||
|
if (entityIndex < 0) continue;
|
||||||
|
const after = source.slice(entityIndex);
|
||||||
|
const match = after.match(/export class (\w+)/);
|
||||||
|
if (match) classes.push(match[1]);
|
||||||
|
}
|
||||||
|
return classes.sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('ENTITIES 注册表完整性', () => {
|
||||||
|
const decorated = decoratedEntityClasses();
|
||||||
|
const registered = ENTITIES.map((e) => e.name).sort();
|
||||||
|
|
||||||
|
it('扫到了实体文件(防止本测试因路径变化而空跑)', () => {
|
||||||
|
expect(decorated.length).toBeGreaterThanOrEqual(6);
|
||||||
|
expect(decorated).toContain('Scene');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('每个 @Entity() 类都在 ENTITIES 中(漏一个就会在运行期抛 No metadata 错误)', () => {
|
||||||
|
const missing = decorated.filter((name) => !registered.includes(name));
|
||||||
|
expect(missing, `以下实体有 @Entity() 但没有加入 ENTITIES:${missing.join(', ')}`).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ENTITIES 里没有多余/重复项', () => {
|
||||||
|
expect(new Set(registered).size).toBe(ENTITIES.length);
|
||||||
|
const extra = registered.filter((name) => !decorated.includes(name));
|
||||||
|
expect(extra, `ENTITIES 里有未定义 @Entity() 的类:${extra.join(', ')}`).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runMigrations 会加载到 AddScenes(场景表迁移必须在迁移列表里)', () => {
|
||||||
|
// 迁移文件与实体是两件事:漏了迁移文件时 showMigrations() 仍会显示 0 个待执行,
|
||||||
|
// 因为 TypeORM 只比较"代码里加载到的"迁移。这里直接核对文件存在。
|
||||||
|
const migrationsDir = join(__dirname, '..', 'src', 'migrations');
|
||||||
|
const files = readdirSync(migrationsDir);
|
||||||
|
expect(files.some((f) => f.includes('AddScenes'))).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user