iT邦幫忙

2026 iThome 鐵人賽

DAY 27
0

目前《九重燼》的自動化測試,在劇情邏輯、存檔、分支與啟動 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:inkgenerate:manifestgenerate:sectionsvite build,但不會自動包含 validate:storyvalidate: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,確保執行期章節注入不會破壞既有載入流程。

劇情驗證:不是只看 Ink 能不能編譯

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/fullCompiler 做語法與邏輯編譯檢查。這一步能抓出未定義 knot、語法錯誤、或某些 Ink 結構問題。

換句話說,validate:story 比 build 更像「劇情上線前檢查」。它不保證每條路玩家都走得到,但至少能先擋掉 ID、tag、資產引用和 Ink 編譯層級的錯。

資產驗證:檔案在不在,比想像中重要

npm run validate:assets 主要是避免一種很煩的上線事故:程式和劇情都沒錯,但圖片或音訊路徑漏了。

它會掃 Ink 中用到的角色、背景、CG、BGM、SFX 和 ambience,再回頭對 characters-scenes.jsonasset-manifest.ts。角色立繪、場景圖、CG 檔案都會檢查是否真的存在;prop 還會讀 PNG / WebP 尺寸,確認檔案尺寸跟 manifest 裡寫的一樣。

這對《九重燼》很重要,因為這個專案的畫面資產不是裝飾,它會被 Ink tag 驅動。只要 # char:# bg: 對到不存在的 ID,玩家看到的就不是「一個小 bug」,而是某段演出直接破掉。

E2E:現在只有 Chromium 的主流程 smoke test

npm run test:e2e 背後是 Playwright,但目前 playwright.config.ts 只有一個 project:

projects: [
  { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
]

tests/e2e/main-flow.spec.ts 目前也只有一條主流程:

  1. /play.html
  2. .loading-screen 消失
  3. 確認主選單 title logo 出現
  4. #btn-new-game
  5. 如果有確認 modal,就按確認
  6. 確認 .dialogue-box 出現,而且台詞文字不是空的

Lighthouse 目前也還沒有

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 修正:

  • 手機直向 overlay 出現時,底層 .game-shell 會加上 inertaria-hidden="true"
  • overlay 本身使用 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。這層目前還不能省:

  • Chrome 桌面開 /play.html,新遊戲能進入第一段對話
  • 手機尺寸或裝置模擬器切橫向,確認選項不爆版
  • 手機直向時 overlay 會阻擋底層互動
  • 存檔、讀檔、快速存檔、快速讀檔至少各跑一次
  • 打開 DevTools 看有沒有嚴重 console error
  • 抽查幾個結局截圖是否仍能正常顯示

接下來最值得優化三件事

第一,Playwright 加上 Firefox 和 WebKit project。這是最直接的跨瀏覽器起點,而且不需要先改遊戲架構。

第二,補手機 viewport E2E。至少要有一條測試能確認手機直向 overlay 真的出現,橫向主流程真的能點到新遊戲與選項。

第三,導入 Lighthouse CI 或 @axe-core/playwright。前者偏效能與最佳實務,後者偏可及性。兩者不一定要同一天做,但至少要先選一個,把「人工看起來可以」推進到「每次改版都會重新檢查」。

Day27 結論:目前《九重燼》的測試比較像一組可靠的內部防線,不是一張完整的發行矩陣。它能守住劇情邏輯、存檔、分支、結局和基本啟動流程;真正的跨瀏覽器與 Lighthouse gate,還在下一階段。


上一篇
Day26 章節內容怎麼組織:Ink INCLUDE 與章節鎖
系列文
《九重燼》Vue3 + PixiJS + Ink.js 視覺小說遊戲開發全紀錄27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言