目前《九重燼》的自動化測試,在劇情邏輯、存檔、分支與啟動 smoke test
package.json 目前幾個跟上線檢查有關的 script 是這些:
| 指令 | 目前用途 |
|---|---|
npm run typecheck |
跑 vue-tsc --noEmit,檢查 Vue / TypeScript 型別 |
npm run test |
串 22 支 Node / tsx 測試腳本 |
npm run validate:story |
編譯 Ink,檢查 tag、ID、Demo 結局與 knot |
npm run validate:assets |
檢查角色、場景、CG、音訊、prop 檔案與尺寸 |
npm run test:e2e |
用 Playwright 跑瀏覽器 E2E |
npm run build |
跑 Ink 檢查、產 manifest / sections,最後 Vite build |
npm run analyze |
用 ANALYZE=1 npm run build 產出 dist/bundle-stats.html |
這裡有個細節:npm run build 會跑 check:ink、generate:manifest、generate:sections 和 vite build,但不會自動包含 validate:story 或 validate:assets。也就是說,如果我改了劇情或資產,不能只跑 build 就安心。這兩個 validation 要另外跑。
npm run test:22 支腳本扛住核心邏輯目前 npm run test 串了 22 支測試。它不是 Jest 或 Vitest 那種集中 runner,而是用 shell 把一支支 tsx scripts/test-*.mjs 接起來跑。
大致可以分成幾組。
第一組是系統邏輯:
test-save-manager.mjs
test-save-migration.mjs
test-story-runtime.mjs
test-ink-tag-parser.mjs
test-story-command-router.mjs
test-ending-resolver.mjs
test-extra-unlock-resolver.mjs
test-endings-formal.mjs
這組測的不是畫面漂不漂亮,而是狀態會不會壞。像 test-story-runtime.mjs 會真的啟動 StoryRuntime,確認序章第一段能走到選項、初始調查有 6 個選項、選擇後 palace_intel 會變成預期值,匯出存檔再匯入後,旗標和選項仍然一致。
第二組是逐章分支:
test-ch00-vertical-slice.mjs
test-ch01-branch.mjs
test-ch02-branch.mjs
test-ch03-branch.mjs
test-ch04-branch.mjs
test-ch05-branch.mjs
test-ch06-branch.mjs
test-ch07-branch.mjs
test-ch08-branch.mjs
這些腳本很像劇情保險絲。只要某章的關鍵選項、旗標或數值被改壞,測試會先爆,不用等到玩家一路點到那裡才發現卡住。
第三組是系統整合:
test-evidence-system.mjs
test-character-events.mjs
test-pixi-stage.mjs
test-scene-texture-lifecycle.mjs
test-bundle-registry.mjs
其中 test-pixi-stage.mjs 很務實。它沒有在 Node 裡硬開真實 Canvas,而是 mock 掉 DOM 和 Pixi Application,只驗證舞台初始化、掛載、resize 算法和 destroy 行為。這種測試不能證明視覺百分之百正確,但可以抓到「Canvas 尺寸算法壞掉」或「destroy 沒有拆掉節點」這類很實際的問題。test-scene-texture-lifecycle.mjs 補了更進一步的壓力測試,反覆切換場景檢查材質與 display object 有沒有被正確釋放;test-bundle-registry.mjs 則驗證新加的 BundleRegistry seam,確保執行期章節注入不會破壞既有載入流程。
npm run validate:story 做的事情比「Ink 可以編譯」再多一點。
它會讀 src/narrative/main.ink,把 INCLUDE 的劇本一起組起來,先掃掉註解,再檢查幾類 tag:
# choice: 是否有重複 ID# event: 是否有重複 ID# char: 是否對得上 characters-scenes.json
# bg:、# cg: 是否對得上場景與 CG 定義# bgm:、# sfx:、# ambience: 是否對得上 assetManifest
# ending: 是否對得上結局定義它還會檢查四個 Demo 必備結局是否存在:
DEMO_END_A
DEMO_END_B
DEMO_END_C
DEMO_BAD_END
最後才交給 inkjs/full 的 Compiler 做語法與邏輯編譯檢查。這一步能抓出未定義 knot、語法錯誤、或某些 Ink 結構問題。
換句話說,validate:story 比 build 更像「劇情上線前檢查」。它不保證每條路玩家都走得到,但至少能先擋掉 ID、tag、資產引用和 Ink 編譯層級的錯。
npm run validate:assets 主要是避免一種很煩的上線事故:程式和劇情都沒錯,但圖片或音訊路徑漏了。
它會掃 Ink 中用到的角色、背景、CG、BGM、SFX 和 ambience,再回頭對 characters-scenes.json 與 asset-manifest.ts。角色立繪、場景圖、CG 檔案都會檢查是否真的存在;prop 還會讀 PNG / WebP 尺寸,確認檔案尺寸跟 manifest 裡寫的一樣。
這對《九重燼》很重要,因為這個專案的畫面資產不是裝飾,它會被 Ink tag 驅動。只要 # char: 或 # bg: 對到不存在的 ID,玩家看到的就不是「一個小 bug」,而是某段演出直接破掉。
npm run test:e2e 背後是 Playwright,但目前 playwright.config.ts 只有一個 project:
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
]
tests/e2e/main-flow.spec.ts 目前也只有一條主流程:
/play.html
.loading-screen 消失#btn-new-game
.dialogue-box 出現,而且台詞文字不是空的package.json 沒有 Lighthouse CI,也沒有 axe 之類的自動可及性測試套件。效能、SEO、可及性分數目前不是 CI gate。
這不代表完全沒做效能檢查。專案裡有 npm run analyze,會透過 rollup-plugin-visualizer 產出 dist/bundle-stats.html,用 treemap 看 bundle 組成。vite.config.ts 也把 Pixi、Vue / Pinia、inkjs 拆成不同 vendor chunk,避免遊戲程式更新時讓玩家重抓所有 vendor。
但 bundle treemap 和 Lighthouse 是兩件事。
npm run analyze 看的是打包體積與 chunk 結構;Lighthouse 會看載入、互動、可及性、最佳實務等瀏覽器端指標。Day27 這裡不能把它們混在一起講。
前面 Day13 和 Day18 提過幾個可及性與 RWD 修正:
.game-shell 會加上 inert 與 aria-hidden="true"
role="dialog"、aria-modal,並在啟用時移動焦點SystemPanel 開啟時會把焦點移進面板,關閉時還原DialogueBox 支援 Space / Enter 推進ChoiceMenu 支援鍵盤 1 到 6 選項GameView 支援 A 切自動模式、Escape 開設定但測試方式目前偏人工。docs/QA_TEST_PLAN.md 有列出裝置、UI、可及性、效能與發布阻擋條件。
所以比較準確的說法是:手機與可及性已經有部分修正與人工 QA,但還沒有完整的裝置矩陣或自動可及性檢查。
如果今天要把 Demo 推到正式環境,我會把檢查拆成兩層。
第一層是每次都該跑的指令:
npm run typecheck
npm run test
npm run validate:story
npm run validate:assets
npm run test:e2e
npm run build
如果這次改到 bundle、資產載入或 PWA 行為,我會再跑:
npm run analyze
第二層是人工 smoke test。這層目前還不能省:
/play.html,新遊戲能進入第一段對話第一,Playwright 加上 Firefox 和 WebKit project。這是最直接的跨瀏覽器起點,而且不需要先改遊戲架構。
第二,補手機 viewport E2E。至少要有一條測試能確認手機直向 overlay 真的出現,橫向主流程真的能點到新遊戲與選項。
第三,導入 Lighthouse CI 或 @axe-core/playwright。前者偏效能與最佳實務,後者偏可及性。兩者不一定要同一天做,但至少要先選一個,把「人工看起來可以」推進到「每次改版都會重新檢查」。
Day27 結論:目前《九重燼》的測試比較像一組可靠的內部防線,不是一張完整的發行矩陣。它能守住劇情邏輯、存檔、分支、結局和基本啟動流程;真正的跨瀏覽器與 Lighthouse gate,還在下一階段。