P0 — 測試指南
Phase:P0 — Character Core + SRD / Rules Foundation
本文件定義 P0 各 Subphase 如何驗收。P0-F 必須最終證明 實作規格.md 的 AC-P0-01 ~ AC-P0-10,而不是只證明「頁面打得開」。
最後更新:2026-08-29
1. 測試原則
P0 的測試證據分為:
- SRD Content Validation
- Rules Unit Tests
- Character Schema / Persistence Tests
- API Tests
- Frontend Tests
- Playwright E2E
- P0-F Full Regression / Manual Smoke
每個 Subphase 必須先通過自己的測試再進下一個;不要把 P0-A~E 的驗證全部拖到 P0-F 才做。
測試 fixture 必須固定、可重現,不依賴人工先去 DB 改資料。
標準 fixture 保持無 Numeric Override;Override 測試由標準 fixture建立固定 variant,避免把正常規則與非標準數值混成同一基準。
三份 P0 文件的 Subphase 標題必須完全一致。
P0-A — Project Foundation
驗收目的
證明專案地基可重現啟動與測試,不在這一階段驗 Character rules。
必測
- Docker Compose 可啟動 P0 所需服務。
- PostgreSQL ready 後 backend 可連線。
- Alembic baseline migration 可 apply;fresh DB 不需要人工修改。
- FastAPI 啟動後 health/readiness 回成功。
- React/Vite app shell 可開啟。
- pytest baseline 能執行且 exit 0。
- Vitest baseline 能執行且 exit 0。
- Playwright baseline 能啟動真實 browser、開 app shell 並 exit 0。
負向/重現性
- DB 不可用時 backend readiness 不得假裝正常。
- fresh checkout + documented setup 必須能重建環境。
- P0-A 不應依賴 Character / Combat / Room / AI module 才能開機。
P0-A 關門
以上全綠後才進 P0-B。
P0-B — Character-Relevant SRD Foundation
對應主要契約:AC-P0-01、AC-P0-02。
Required Categories
測試 P0-B 定義的 character-relevant category 都存在、可 parse 成對應 Pydantic model 並可進 ContentRegistry:
- races
- classes
- subclasses
- backgrounds
- feats(SRD source 有者)
- features / traits(依實際資料拆法)
- skills / abilities / saves reference
- equipment / weapons / armor / adventuring gear / items
- spells
- conditions
- damage types
- languages
- P0 角色規則使用的其他 structured constants / references
不包含 monsters / beasts。
Monster / Beast Scope Guard
P0-B 測試必須明確證明:
monsters / beasts 不是 P0 mandatory category。
- P0 app 不需要 Monster stat block 才能啟動或通過 ContentRegistry validation。
- 不因 Monster / Beast 缺席而讓 AC-P0-01 失敗。
Monster / Beast stat blocks 已延後 P4-A。
Stable Key Uniqueness
每個 category:
- key 不可重複。
- key 不可空白。
- P0 fixture 使用的 key 必須存在。
Cross-reference Validation
至少驗證:
- Class / Subclass reference 可解析。
- Spell source / class reference 可解析。
- Equipment property / damage type 等必要 reference 可解析。
- Condition / item / spell 等 P0 使用的 required refs 不出現 dangling key。
不寫 Monster-specific dangling reference 測試,因 P0 不導入 Monster data。
Negative Cases
故意注入:
- duplicate key
- missing required field
- dangling content reference
- invalid enum / malformed value
預期:ContentRegistry validation fail,不能靜默略過。
Reference Query Baseline
至少能由 registry 查到 fixture 會使用的 Race / Class / Spell / Equipment / Condition entry。
P0-B 關門
- Character-Relevant SRD validation 全綠。
- negative fixtures 確實轉紅。
- Monster / Beast 仍不屬於 P0 dependency。
P0-C — Character Core & Persistence
對應主要契約:AC-P0-03、AC-P0-04、AC-P0-08 的資料承載部分。
標準驗證角色
固定 fixture:
Human Fighter 5 / Wizard 5,Character Level 10
Class order:Fighter 1→5,再 Wizard 1→5。
Ability Scores
| Ability |
Build Score |
Modifier expectation for P0-D |
| STR |
16 |
+3 |
| DEX |
14 |
+2 |
| CON |
14 |
+2 |
| INT |
16 |
+3 |
| WIS |
10 |
+0 |
| CHA |
8 |
-1 |
這些是永久 Build 效果已解析後、Numeric Override 前的值。Human racial ability increase 已包含。
至少包含:
- Saving Throw proficiency:STR、CON。
- Skill proficiency:Athletics、Arcana、Perception。
- Fighter / Wizard feature refs。
- Wizard Spellbook entries in Build。
- Wizard Prepared Spells in Current State,且指向可準備的 Build spell access entry。
- Spell Slot current state。
- Build starting equipment initialization data。
- Live Inventory:Chain Mail、Shield、Longsword、Healing Potion ×2。
- Temporary HP initial 0。
- initial no Condition。
Hit Dice
Build total:
Initial State:
d10 available = 5
d6 available = 5
HP Progression
fixture base HP gains:
Lv1 Fighter: 10
Lv2 Fighter: 6
Lv3 Fighter: 6
Lv4 Fighter: 6
Lv5 Fighter: 6
Lv6 Wizard: 4
Lv7 Wizard: 4
Lv8 Wizard: 4
Lv9 Wizard: 4
Lv10 Wizard: 4
這是 fixture choice,不是產品強制 fixed HP。
Class Order / Multiclass Representation
fixture 必須保存:
Fighter
Fighter
Fighter
Fighter
Fighter
Wizard
Wizard
Wizard
Wizard
Wizard
測試 derive-ready structure 能得到:
- starting class = Fighter
- Fighter level = 5
- Wizard level = 5
- total = 10
P0-C 主要驗資料結構保存,正式 derived rules 在 P0-D 驗。
Ability Score Round-trip
Save / Reload 後必須仍是:
16 / 14 / 14 / 16 / 10 / 8
不得因 Reload 或重新解析 race_ref 改值。
Spell Access vs Prepared State
Build entry 至少可辨識:
- logical
entry_id
- spell key
- source class / feature
- access type,例如
spellbook
State 另外保存 prepared_spell_entry_ids。
至少測:
- Wizard spellbook entry 在 Build。
- 可準備的 entry 能被 State 引用。
- prepared → unprepared / unprepared → prepared 只改 State。
- Build Version id 與 canonical Build payload 不變。
- State 指向不存在/不可準備的 Build entry 時 validation fail。
Hit Dice Structure / Persistence
修改:
預期:
- Build total 仍 d10×5 / d6×5。
- State d10=4 / d6=5。
- Save / Reload 後保留。
- Build Version 不變。
Optional Roleplay
- profile 全空:schema 合法。
- 有資料:可 round-trip。
Save / Reload
流程:
Seed fixture
↓
Read Character
↓
Serialize Build + State
↓
Close transaction/session
↓
Read again
↓
Compare
結果:Build 相同、State 相同。
Build / State Isolation
先記錄 current Build Version id 與 canonical Build payload,再依序修改:
- current HP
- temporary HP
- Prepared Spells
- Condition
- spell resource usage
- available Hit Dice
- Healing Potion quantity
- Shield equipped state
- 新增合法 live Inventory entry
- 移除 live Inventory entry
預期:
- Build Version id 不變。
- Build payload canonical equivalent 不變。
- State 正確改變。
Starting Equipment 不覆寫 Live Inventory
流程:
Seed from Build starting equipment
↓
Live Inventory 產生
↓
修改/新增/移除 live Inventory
↓
Save + Reload + new application session
Reload 後必須使用最後保存的 Inventory State,不能重新從 Build Starting Equipment 洗掉玩家後來的變化。
Fresh Application Session Persistence
至少建立新的 application / DB session;不能只測同一 ORM object 留在 memory。
P0-C 關門
- fixture seed / Save / Reload 全綠。
- Build / State isolation 全綠。
- Spell access / Prepared separation 全綠。
- Hit Dice persistence 全綠。
- Starting Equipment reload regression 全綠。
P0-D — Character Rules & Backend API
對應主要契約:AC-P0-02、AC-P0-05、AC-P0-08,以及 AC-P0-03/04/07 的 API 部分。
Fixed Derived Expectations
標準 fixture 預期:
Base HP = 10 + 6 + 6 + 6 + 6 + 4 + 4 + 4 + 4 + 4 = 54
CON contribution = +2 × 10 = 20
Max HP = 74
| 項目 |
預期 |
| Total Character Level |
10 |
| Fighter Level |
5 |
| Wizard Level |
5 |
| Proficiency Bonus |
+4 |
| STR Save |
+7 |
| CON Save |
+6 |
| Athletics |
+7 |
| Arcana |
+7 |
| Perception |
+4 |
| Passive Perception |
14 |
| AC(Chain Mail + Shield) |
18 |
| Wizard Spell Save DC |
15 |
| Wizard Spell Attack |
+7 |
| Max HP |
74 |
Ability Modifier
至少:
8 -> -1
10 -> 0
14 -> +2
16 -> +3
18 -> +4
另驗 fixture 的 Human racial bonus不會在 Rules Engine 再套一次。
Proficiency Bonus Boundaries
每區間 lower + upper 成對測:
Lv1 -> +2
Lv4 -> +2
Lv5 -> +3
Lv8 -> +3
Lv9 -> +4
Lv12 -> +4
Lv13 -> +5
Lv16 -> +5
Lv17 -> +6
Lv20 -> +6
Skill / Save
fixture:
- Athletics +7
- Arcana +7
- Perception +4
- STR Save +7
- CON Save +6
- unproficient DEX Save +2
Passive Perception
10 + Perception modifier 4 = 14
Armor Class
live Inventory:
Chain Mail equipped 16
+ Shield equipped 2
= AC 18
必測:
- Heavy Armor 不錯誤加入 DEX。
- AC 讀 Current State equipped Inventory,不讀 Build Starting Equipment。
- Shield equipped
true → false 後 calculated AC = 16,Build 不變。
Spellcasting
Wizard INT 16、PB +4:
Spell Save DC = 8 + 4 + 3 = 15
Spell Attack = 4 + 3 = +7
Prepared selection 不影響基礎公式。
Max HP
標準 = 74。
另做 rules-only variant:effective CON modifier +3、無 Max HP override:
用來證明 74 不是 hardcode。
Numeric Override Variant
從標準 fixture 建:
ability:strength = 18
ac = 19
max_hp = 80
固定 expectation:
| 項目 |
預期 |
| Effective STR |
18 |
| STR Modifier |
+4 |
| Athletics |
+8 |
| STR Save |
+8 |
| AC |
19 |
| Max HP |
80 |
另外驗:
- 標準 fixture 無 override 時仍用正常 derived value。
- AC override 在正常 Armor calculation 後成為 authoritative AC。
- Max HP override 後 Current HP validation 使用 80 作 Max HP。
- Override 不改 Race / Class / Feature / Spell access / Starting Equipment structure。
Multiclass Spellcasting Boundary
Fighter(非 Eldritch Knight)5 對 multiclass caster level 貢獻 0,因此 fixture 不測多個 caster class aggregation。
P0-D 只驗:representation、class order、spell source/access、Build Spellbook vs State Prepared separation。
Multiclass caster-level / combined spell-slot progression 留 P1。
Reference API
至少:
GET /api/rules/content/spells
GET /api/rules/content/spells/{fireball-key}
GET /api/rules/content/classes/{fighter-key}
- known key → 200 + valid DTO
- unknown key → 404 + machine-readable error code
Character Sheet API
GET /api/characters/{fixture-id}/sheet
至少驗:
- Header / three-page fields 完整。
- Hit Dice
d10 5/5、d6 5/5。
- Spellbook / Prepared 可區分。
- Inventory 來自 Current State。
State Patch
至少測:
PATCH HP
PATCH temporary HP
PATCH prepared spells
PATCH condition list
PATCH resource usage
PATCH available hit dice
PATCH inventory quantity
PATCH inventory equipped state
PATCH inventory add/remove entry
每次:
- request validation 正常。
- DB State 改變。
- Build Version / payload 不變。
- 後續 GET sheet 反映新 authoritative value。
Invalid State
至少:
- negative inventory quantity
- malformed condition key
- prepared spell 指向不存在/不合法 entry
- available Hit Dice 超出 Build total
- malformed inventory item ref
- wrong data type
預期 4xx,且 DB 不留下半套更新。
P0-D 關門
- rules unit tests 全綠。
- fixed expectations 全綠。
- Numeric Override variant 全綠。
- API success / error / atomicity 全綠。
P0-E — Character Sheet & State UI
對應主要契約:AC-P0-06、AC-P0-07、AC-P0-09、AC-P0-10 的 UI 部分。
- Name
- Level
- HP
- AC
- Conditions
Vitest — Page 1
- Ability / Skills / Saves
- Passive Perception
- Hit Dice
d10 5/5、d6 5/5
- Features / Traits
- Optional Roleplay collapsed / expanded
Vitest — Page 2
- spell source / Build access type
- Prepared / Unprepared Current State
- Always-prepared 與一般 Prepared selection 不混淆
- Spell Save DC / Spell Attack
- Spell Slot / resource state
Vitest — Page 3
- live inventory item
- quantity
- equipped state
Component tests 使用 mock CharacterSheetDTO,不要在 React test 重算 D&D 規則。
Playwright — Character Sheet 基本流程
啟動 app
↓
開啟 Fighter 5 / Wizard 5 fixture
↓
看到 Header
↓
切換 Attributes / Skills
↓
看到 d10 5/5、d6 5/5
↓
切換 Spells
↓
可區分 Spellbook / Prepared
↓
切換 Inventory
Playwright — Current HP Persistence
HP 74 → 50
↓
保存成功
↓
reload browser
↓
仍為 50
Playwright — Temp HP / Condition
Temp HP 0 → 8
加入 Poisoned
↓
reload
↓
Header / Page 1 仍正確顯示
Playwright — Spell Resource
改變 spell slot 使用狀態,reload 後保持。
Prepared Spells 的 Build/State isolation 主要由 P0-C / P0-D schema、persistence、API tests 驗;P0 不為了 E2E 額外要求完整準備法術 workflow。
Playwright — Inventory Quantity
Healing Potion ×2 → ×1,reload 後保持;Build Version / Starting Equipment 不變。
Playwright — Equipped State
Shield equipped → unequipped:
- reload 後仍 unequipped。
- Sheet authoritative AC 由 18 → 16。
- 前端不是自己硬算 16。
Playwright — Optional Roleplay
Roleplay profile 全空時 Page 1 不報錯、不要求必填。
Playwright — P0 Independence
沒有 Room / Campaign / Session / Combat / AI 連線時,P0 Character Sheet 仍可完整操作。
P0-E 關門
- Vitest 全綠。
- P0-E Playwright 全綠。
- reload persistence 路徑已真實走 backend,而不是 browser-only mock。
P0-F — Full P0 Integration & Closeout
P0-F 對 P0-A~E 做完整 regression / integration,並建立 AC-P0-01~10 的最終證據。
Acceptance Contract 對照
| Contract |
主要證據 |
| AC-P0-01 |
P0-B Content validation + P0-F startup regression;不含 Monster / Beast |
| AC-P0-02 |
P0-B ContentRegistry + P0-D Reference API |
| AC-P0-03 |
P0-C persistence round-trip + P0-F fresh-session regression |
| AC-P0-04 |
P0-C Build / State isolation + P0-D API mutation |
| AC-P0-05 |
P0-D rules unit tests + fixed override variant |
| AC-P0-06 |
P0-E Vitest + page navigation / Hit Dice E2E |
| AC-P0-07 |
P0-C persistence + P0-D state API + P0-E reload E2E + P0-F server restart |
| AC-P0-08 |
P0-C Fighter5/Wizard5 schema + P0-D derived tests;不含 multiclass caster aggregation |
| AC-P0-09 |
P0-D CharacterSheetDTO + P0-E frontend/E2E |
| AC-P0-10 |
P0-E standalone E2E + P0-F scope guard |
每一條 contract 至少有一個可定位自動測試;人工目視不能是唯一證據。
Full Regression
至少重跑:
- P0-A environment / health / baseline tests。
- P0-B full character-relevant SRD validation + negative fixtures。
- P0-C full schema / persistence / Build-State isolation suite。
- P0-D full rules + API suite。
- P0-E full Vitest + Playwright suite。
- standard fixture fixed expectations。
- Numeric Override variant。
- fresh app / server restart persistence。
- Starting Equipment reload regression。
- Shield equipped state → AC recalculation。
Monster / Beast Deferral Regression
P0-F 必須驗證:
- P0 mandatory SRD list 中沒有 monsters / beasts。
- 缺少 Monster stat blocks 不影響 P0 app startup / tests / E2E。
- 沒有測試偷偷把 Monster data 當 fixture dependency。
PROJECT_BRIEF.md 仍保留 P4-A 承接 SRD Monster / Beast stat blocks 的跨 Phase requirement。
人工驗收
自動測試全綠後,人工快速檢查:
- Character Sheet 三頁閱讀性。
- 繁體中文 UI 文案正常;Action / Spell Slot 等關鍵字可保留英文。
- Fighter / Wizard features 與 spells 沒明顯混在錯誤頁。
- HP / Conditions 在 Header 一眼可見。
- Hit Dice 清楚分辨 d10 available/total 與 d6 available/total。
- Spellbook / Prepared 不顯示成同一概念。
- Inventory 顯示 live state,不因 reload 回到 starting equipment。
- Roleplay 空白不造成大片必填阻擋。
- reload 後不出現明顯「先顯示 browser 舊 authoritative state 再跳正確值」的 UX 問題。
P0 不人工驗收 Room、AI、Combat、Map、Monster stat blocks。
建議測試命令
實際 scaffold 完成後統一提供簡單命令,例如:
# Backend
pytest
# Frontend unit
npm run test
# E2E
npm run test:e2e
最終命令以實際 package scripts / project config 為準;P0-F closeout 時更新。
P0-F 關門條件
P0 可以標記完成前:
- P0-A~P0-E 全部完成且各自已 commit。
- Character-Relevant SRD validation 全綠。
- pytest 全綠。
- Vitest 全綠。
- Playwright P0 suite 全綠。
- Fighter 5 / Wizard 5 標準 fixture fixed expectations 全通過。
- Numeric Override variant fixed expectations 全通過。
- Prepared Spells、Hit Dice available、live Inventory 的 Build / State isolation 全通過。
- Save / reload / server restart 後 Current State 正確。
- Starting Equipment reload regression 全通過。
- 三頁 Character Sheet 人工 smoke 通過。
- 沒有把 multiclass caster aggregation 誤做成 P0 完成條件。
- 沒有把 Monster / Beast stat blocks 拉回 P0;它們仍屬 P4-A。
- 沒有依賴 P2 以後 subsystem 才能跑 P0。
完成後才更新 PROJECT_BRIEF.md 為 P0 implementation complete,並開始規劃 P1 與 P1 Subphases。