17 KiB
测试规范
项目只维护两层测试,不增加第三套 scripts/*smoke*、*e2e* 或一次性测试框架。
1. 纯单元测试
- 仅放在
src/shared,验证确定性、可复用的引擎和领域逻辑。 - 使用 Vitest;先运行受影响的测试,再根据影响范围运行
bun run test。 - 不引入数据库、Redis、HTTP、认证或第三方服务模拟;不在
src/server、src/react-app或scripts添加单元测试。
2. Codex 浏览器/Playwright 模拟
由 Codex 在当次开发任务中操作真实本地页面,不将操作固化为一次性仓库脚本。
- 准备
env/local.env,执行bun run services up -d --wait和bun run db:migrate。普通验证使用bun run dev;长流程需关闭 watch 时,在两个终端执行APP_ENV=local NODE_ENV=development bun --env-file=env/local.env src/index.ts和bun run dev:web。确认页面为127.0.0.1:5174、服务指向专用本地数据;不得使用prd进行测试写入。 - 列出本次改动需要验证的用户行为、预期结果和准备条件。通过页面注册/登录,邮件验证使用 Mailpit;优先复用已有测试角色。缺少 LLM 或角色构筑等条件时如实说明,不通过假成功继续。
- 使用可用的 Codex 浏览器能力或 Playwright,按可访问名称和实际页面定位控件。操作后等待具体界面/网络状态,不依赖固定长时间 sleep。多人测试使用独立浏览器上下文或配置文件,每个角色有独立会话。
- 同时观察界面、控制台和网络:检查请求次数、错误、权限边界、提交结果及恢复过程。涉及布局时检查桌面和 360px;涉及性能时使用网络面板/Profiler,不维护一次性基准脚本。
- 多人战按本次改动选择场景:收令、重复点击、超时、断线重连、逐行动播放、终局和回放权限。故障恢复可在本地暂停/重启实际服务后观察,不添加模拟故障 Worker 或另一套接口测试程序。
- 测试完成后退出或结束当次创建的活动状态,恢复暂停的服务;只清理本次测试数据,不重置整个环境。
- 记录环境、验证步骤、实际结果和未验证项。截图、网络记录等留在当次任务产物中;不得把旧验证记录当成本轮通过证据。
Lint、TypeScript/构建、Prettier 是静态质量检查,不是额外一层集成测试。根据改动运行必要检查;不以新增脚本替代真实用户流程验证。
3. 本地测试账号与密码
- 本地测试账号统一密码:
LocalCombat123!。仅用于env/local.env对应的纯本地环境,不适用于预发布或生产账号。 - 优先复用已有账号与角色。已知账号包括
local1@daoyou.local至local8@daoyou.local,实际是否存在、邮箱是否验证及角色状态以当前本地数据库为准,不假定环境重建后仍然保留。 - 需要选择账号时,可直接只读查询本地 PostgreSQL(
127.0.0.1:15432,数据库daoyou_local)的better_auth.user与角色表,读取邮箱、验证状态和所需角色信息;无需再次向用户索要已有测试账号或统一密码。不读取或输出密码哈希、会话令牌等无关认证数据。 - 使用真实页面和上述密码登录。邮箱未验证时,通过 Mailpit(
http://127.0.0.1:18025)完成正常验证流程,不直接修改数据库中的验证标记或认证状态。 - 缺少账号时通过页面注册本地测试账号,并沿用统一密码;已有账号登录失败时先确认环境、账号存在性及邮箱验证状态,不擅自重置密码或修改认证配置。
- 多人测试使用独立浏览器上下文或配置文件,确认每个会话实际登录的角色,避免共享 Cookie 将多人测试变成同账号多标签页。
4. 本地物资发放与角色调整
POST http://127.0.0.1:3001/api/dev/resources 不要求登录,仅在显式 APP_ENV=local 且 NODE_ENV 非 production 时注册;缺省、预发布及生产不开启。不要将 local 配置用于外部可访问的部署。
先只读查询已有测试角色 ID,然后提交 JSON,例如:
{
"cultivatorId": "替换为已有本地角色的UUID",
"grants": [
{
"type": "item",
"item": { "definitionId": "blueprint.weapon.10", "quantity": 1 }
},
{
"type": "vault-material",
"facts": { "name": "验收玄铁", "type": "ore", "rank": "凡品" },
"quantity": 1
},
{ "type": "spirit-stones", "amount": 1000 },
{ "type": "qi", "amount": 20 }
]
}
新库存材料使用 type: item、definitionId: material.v1、instanceData: { name, type, rank, element?, description? }。传承灵印使用注册的定义 ID;随机道装使用 { "type": "equipment", "slot": "weapon", "level": 10 },法兵默认生成剑,可加 weaponType 指定 axe/blade/spear/staff/sword/fan/bell/brush/banner,非武器不得指定。全部定义在 src/shared/items/definitions,参数边界见 src/shared/contracts/forging.ts。
旧丹药/消耗品验收可提交 { "type": "vault-consumable", "facts": { name, type, quality, description, prompt, score, spec }, "quantity": 2 },facts 须符合 ConsumableFactsSchema,quantity 为 1–3960;沿用历史消耗品发放入口写入洞府宝库,再通过正式取出操作转换。新版消耗品直接发放使用 type: item、definitionId: consumable.v1 及同一完整 facts 作为 instanceData。该能力仍只在纯本地开放。
邮件附件验收可提交 { "type": "mail", "format": "historical" | "new_reward", "attachments": [...] }。附件遵循共享 MailAttachmentsSchema,每次1–20个。format默认为new_reward,经过正式新奖励生产入口;historical原样保存合法附件协议,可构造新旧混合邮件。邮件固定使用本地验收标题与正文,返回邮件ID。该能力只创建样本,领取仍需真实角色通过正式邮件接口完成,不直接标记领取或绕过好友赠送成本。
发放遵循正式背包容量、材料校验、资源上限和战斗占用规则,整批事务成功或整体回滚。不支持修改任意字段、账号创建或整库清空。测试前记录物资与资源基准,完成后只清理本次发放和生成的测试物品;保留其他测试已产生的角色进度及历史记录。
灵兽可通过同一发放接口提交 { "type": "beast", "speciesId": "combat.wild.species.rock-boar" }(speciesId 必须来自灵兽定义)。生成标准 10 级个体,遵循兽栏容量;不会自动携带或设为首发,随后使用正式阵容接口配置。
融合验收可增加 level: 30,范围10—180且不得超过主人等级。通过正式经验成长函数生成相应等级宝宝,保留初始50自由点;省略仍为10级。此参数仅存在于纯本地物资发放接口。
验收多技能展示时,可额外传入 skills,例如 ["beast.strength", "beast.advanced-defense"]。允许 1–8 个不重复的当前有效技能 ID,技能格容量同步为技能数量,并通过完整灵兽数据校验;省略时沿用初始技能生成规则。
PATCH http://127.0.0.1:3001/api/dev/cultivators/:id 使用相同的纯本地环境限制,无需登录。只读查询已有角色 UUID 后,可按需提交以下白名单字段:
{
"realm": "金丹",
"realmStage": "初期",
"attributes": { "vitality": 1000, "strength": 1000 },
"unallocatedAttributePoints": 0,
"spiritStones": 10000,
"reputation": 0,
"resources": { "hp": 10000, "mp": 10000 }
}
所有数值为新绝对值,省略字段保持原值。基础属性支持 vitality、strength、spirit、endurance、speed、willpower(1–10000);待分配属性点 0–100000、灵石 0–100000000、声望 0–1000000。resources 必须同时给出 hp、mp(0–10000000),按调整后 v6 构筑的资源上限裁剪。不自动分配属性、补满资源或迁移宗门深度。
空对象、未知字段、非法境界或越界值返回 400;不存在或非活跃角色、战斗占用返回 409。角色调整采用角色锁和数据库事务,提交后更新资源版本;脚本发起的变更后应刷新页面获取新数据。禁止修改用户归属、认证、角色状态等任意数据库字段。测试结束恢复事先记录的境界、属性和准备性资源改动,保留实际玩法奖励与战绩。
本地灵根与先天命格
同一 PATCH /api/dev/cultivators/:id 支持以下两个数组。字段省略时保留原值,传 [] 清空该类记录,非空数组整体替换;修改沿用角色锁、战斗占用检查、事务与资源版本提交。仅用于纯本地环境,无需数据库迁移。
{
"spiritualRoots": [
{ "element": "木", "baseStrength": 76, "marrowWashBonus": 6 },
{ "element": "水", "baseStrength": 64 }
],
"preHeavenFates": [
{
"name": "青木长生",
"quality": "玄品",
"description": "生来气脉绵长,调息时如草木逢春。",
"effectIds": ["natural-recovery"]
},
{
"name": "悟道忘尘",
"quality": "地品",
"effectIds": ["retreat-insight-gain", "system-spirit-stone-surcharge"]
}
]
}
- 灵根最多 8 条,元素须有效且不重复;
baseStrength为 0–100 的整数,marrowWashBonus默认 0,两者之和不超过 120。品级由现有仓储规则根据元素及灵根数量推导;不接受客户端传入品级或当前强度。 - 命格最多 3 条;名称 1–100 字、品质须为现有品质,说明可省略(最多 2000 字)。每条指定 1–2 个不重复的效果 ID。
- 效果 ID 来自
src/server/lib/services/FateFragmentRegistry.ts,例如retreat-exp-gain、retreat-insight-gain、natural-recovery、toxicity-mitigation、system-spirit-stone-surcharge。数值、标签、说明及 rollMeta 由既有构造器按品质和固定 0.5 分位生成;测试接口允许自由组合现有效果,不模拟创角抽签概率,也不接受自定义效果数值。 - 非法结构、越界、重复元素或重复效果返回 400;未知效果 ID 返回 409,整笔事务回滚。响应在
data.spiritualRoots/data.preHeavenFates返回本次调整后的运行时结构,便于核对先天与后天展示。 - 后天增益仅作为本地测试数据注入,不推进洗髓等级或执行破限;先天设定页显示
baseStrength,肉身修炼页显示后天增益与当前总强度。命格使用真实效果,会影响相应玩法。 - 临时验收前记录原值并恢复;用户明确要求补齐并保留的本地测试角色配置可以保留。外部调用后刷新页面读取新版本。
同一接口支持调整角色当前已加入宗门的数据。
高阶宗门技能验收也可通过sectCombat临时准备并恢复当前已正式启用的宗门构筑:
{
"realm": "化神",
"realmStage": "中期",
"sectCombat": {
"methods": { "jiujie.method.canon": 60, "jiujie.method.thunder": 60 },
"meridianDepth": 3
}
}
methods接受当前宗门已有的1~6个心法ID及1~180的整数等级;省略的心法保持原值。meridianDepth为0~7的整数。调整采用同一角色锁、宗门成员锁和事务,校验调整后境界的心法上限、主支心法关系、经脉等级门槛及两套流派方案;未知心法或不合法构筑返回409,整笔联合调整回滚。它不初始化流派、不自动选择或清除节点、不执行研习扣费;不能将准备数据记作正式养成验收。正式选择节点、保存与技能施放仍使用页面。
准备前记录境界、心法、经脉深度、节点和资源。结束训练后,通过正式页面恢复本次节点修改,再在一次PATCH中恢复原境界、心法等级和经脉深度,必要时同时恢复准备性资源;深度降低后仍有越层节点时会拒绝恢复,不静默删除。修订号正常递增,保留实际战斗记录,不回滚其他角色数据。组织身份与贡献使用下面的sect字段。
{
"sect": {
"discipleRank": "inner",
"contribution": 3000,
"lifetimeContribution": 3000
}
}
sect 至少填写一个字段;弟子身份为 registered、outer、inner、true,两类贡献为 0–100000000 的整数绝对值,省略保持原值。调整后的累计贡献不得小于可用贡献,否则返回 409;角色没有 active 宗门成员记录也返回 409。可与境界/属性调整放在一次请求中,整笔事务成功或回滚,并更新宗门成员、任务和角色资源版本。此能力只准备身份与贡献,不执行正式晋升、不生成晋升资格、不修改任务完成记录、职务或宗门归属。准备前记录基准,验收后恢复身份、贡献等准备字段,保留真实试炼战绩与资格记录。
突破试炼验收可使用同一 PATCH 接口补齐准备条件:
{
"realm": "元婴",
"realmStage": "圆满",
"cultivation": { "experience": 100000, "insight": 90 },
"breakthroughPreparation": {
"clearMind": true,
"protectMeridians": true,
"completedDungeonObjectiveIds": ["clear-archive"]
}
}
cultivation 的 experience 为 0–1000000000000 整数修为绝对值,insight 为 0–200 整数感悟;修为上限仍按调整后的境界实时计算,不写入 exp_cap。两个准备对象均不能为空,省略字段不变。清心/护脉 true 添加带 devTools 标记的系统状态,false 只移除本接口添加的对应状态,保留正常玩法已有状态。
调整 realm、realmStage 或 breakthroughPreparation 时会同步当前破境任务,确保准备目标有对应任务。通过外部 dev 请求准备后应刷新浏览器再开始验收,避免页面沿用先前角色缓存。10F 实际运行记录及准备数据去向见 阶段验收记录。
completedDungeonObjectiveIds 只接受当前大境界破境任务中 kind 为 complete_dungeon 的目标 ID,用于跳过验收准备所需的长秘境流程,不创建秘境通关记录或奖励。未知目标及 win_task_challenge 战斗目标返回 409,整笔联合调整回滚;不能用本接口直接制造试炼胜利。真实试炼胜负、灵兽消耗、任务推进和最终突破必须通过正式页面完成。准备前记录境界、六属性、资源、修为、感悟及任务目标基准;验收记录须区分 dev 准备目标和真实战斗完成目标,结束后恢复临时角色字段并移除 dev 状态,不把准备数据记作真实验收证据。
归元灵露洗炼验收:通过上述type: item发放beast.refinement.origin-dew或beast.refinement.superior-origin-dew,在灵兽详情「学习兽诀」旁选择「洗炼」。规则及示例见洗炼文档。首版不配置掉落或商店。
本地清空随身物品
DELETE http://127.0.0.1:3001/api/dev/cultivators/:id/inventory/bag 仅在显式 APP_ENV=local 且 NODE_ENV 非 production 时可用,不要求登录。只清空指定活跃角色 bag 位置的随身物品,并解除这些物品的残留穿戴引用;保留独立 equipped 位置的已穿戴道装、储藏室、旧宝库、灵石、灵兽及已参悟功法。需要清空已穿戴道装时,先通过正式卸下操作移回背包。
接口复用角色 Redis 锁、SQL 事务、战斗占用检查和资源事件提交/发布。返回 data: { removed, unequipped };空背包重复调用返回两个 0。非法 UUID 返回 400,角色不存在或不活跃、战斗占用等业务冲突返回 409。
需要重新准备物资时,清空后使用已有 POST /api/dev/resources 发放,不直接写数据库。清空与发放是两个独立事务;发放失败时背包保持空态,应修正参数后重新发放。验收前保存要保留的样本事实,结束后检查物品数量和储藏室没有变化。
本地重置每日占卜
DELETE http://127.0.0.1:3001/api/dev/cultivators/:id/divination 仅在显式 APP_ENV=local 且 NODE_ENV 非 production 时可用,不要求登录。:id 为已有活跃角色 UUID。
curl -X DELETE http://127.0.0.1:3001/api/dev/cultivators/角色UUID/divination
成功返回 { "success": true, "data": { "removed": 1 } }。清除该角色唯一的占卜记录(含骰子、卦象、解读和发奖标记),包括尚未完成的旧签;没有记录时幂等返回 removed: 0。已领取的符箓保留,天地灵气与其他角色记录不变;再次完成占卜会再次正常发奖。刷新占卜页面或切回窗口后即可重新选择方向、掷骰。
重置与正式掷骰、解签共用角色占卜 Redis 锁,并在事务内锁定角色行;正在解签或领取时返回锁冲突,应等待完成后重试,不强制中断 SSE。非法 UUID 返回 400,不存在或非活跃角色返回 404。不要对预发布或生产执行此接口。