コンテンツにスキップ

テストケース

テスト戦略

テスト種別 対象 ツール 実行場所
API テスト backend の route の振る舞い bun test heineken-survey-design-backend
単体テスト frontend のドメインロジック(分岐評価・バリデーション) Vitest heineken-survey-design-frontend
単体テスト 拡張の CS 変換ロジック Vitest Lab-web-extension
統合テスト dev 環境の画面操作・プレビュー走行 Playwright integration-tests
手動テスト Creative Survey への流し込みと実機回答 拡張の API ログ + 目視 CS 編集画面

テスト実行方法

# backend の API テスト
cd heineken-survey-design-backend
bun test
bun test src/app.test.ts        # 単一ファイル
bun test -t "テスト名"           # 名前フィルタ

# frontend の単体テスト
cd heineken-survey-design-frontend
bun run test
bun run test -- lib/surveys/preview-runner.test.ts

# 拡張の単体テスト
cd Lab-web-extension
pnpm test

# dev 環境に対する統合テスト
cd integration-tests
bun install
bun run auth                    # 初回のみ。dev に Google ログインしてセッションを保存
bun run test                    # 01 → 02 を通しで実行
bunx playwright test --grep "R13"   # 特定のルートだけ
bun run report                  # 直近の実行結果を HTML で確認
bun run cleanup                 # テストで作った案件を削除

backend の API テスト方針

createApp() に fake store と fake auth resolver を注入 し、DB を使わずに route の振る舞いを検証します。API テストで振る舞いを先に固定してから repository 実装に落とす進め方です。

const app = createApp({ store: fakeStore, resolveUser: async () => fakeUser });
const res = await app.request("/api/surveys");

テストヘルパーは src/test/helpers.ts にあります。PostgreSQL を伴う検証が必要な場合だけ、別途 integration test を追加します。

統合テスト(integration-tests)

dev 環境(survey-design-web.heineken.dev.4digit.ai)に対して、cs-import-test-cases.md のテストケースを Playwright で自動実行します。

スペック 内容
00-smoke.spec.ts dev への疎通確認(案件作成 → 設問追加 → 後片付け)。落ちたらログイン切れか環境側の問題
01-build-survey.spec.ts 「作成手順」を UI 操作で再現し、CP1〜CP13 を検証
02-preview-run.spec.ts 走行表 R1〜R28 をシステム側プレビューで走らせて期待遷移を検証

01 は describe.serial で S1 → S2 → S3 の順に流れます。作成した案件の id は .artifacts/survey-ref.json に残り、02 と 01 の再実行はこれを参照します(02 だけ流したいときは 01 を先に通しておく)。

テストシナリオの全体像

1 本の案件を決まった手順で作成し、CS へ流し込み、チェックリスト照合と回答走行を行う複合シナリオ方式です。

セクション 設問 タイプ 分岐 / 表示ロジック
S1 スクリーニング T1 説明文 —
Q1 性別 SA 回答しない → スクリーンアウト
Q2 居住地 PD その他 → スクリーンアウト
Q3 利用サービス MA ①排他設定(自動生成)②「だけである」→ SX
S2 演算子と表示 Q4 色(回答数 最小1・最大2) MA 3 ルール(AND / only / has_other)+ 評価順
Q5 施策 MA not_includes / not_only + 表示ロジック
Q6 満足度(行 × 列) TM セル条件 AND → SX / セル条件 → SC + 表示ロジック(行)
Q7 感想(良い点 / 悪い点) FA 欄指定の文字列一致 → SX / いずれかの回答 → SO / 回答あり → SO
S3 生活習慣 Q8 朝食 SA —
Q9 食事(サブ設問 朝/昼/夜) SA+サブ設問 サブ設問「昼」条件 → SX / 表示ロジック
Q10 総合満足 SA その他制御(Q11 が自動作成)
Q11 その他 FA FA Q10=その他 AND 未記入 → 留まる(自動生成)
Q12 年収(個人 / 世帯) PD 複数欄 個人年収 1000万以上 → SX / OR ルール → SX
Q13 利用チャネル(行 × 列) TM 複数選択 排他設定(行ごとに自動生成)

テストケース一覧

作成手順のチェックポイント(CP)

01-build-survey.spec.ts で検証します。

ID シナリオ 期待結果 優先度
CP1 Q3 を追加する コードが自動で Q3 になる(Q1 の重複にならない) 高
CP2 S2 を追加する 自動生成される設問のコードが T1-2 / Q1-2 など既存と重複しない形に振り直される 高
CP3 設問を削除してから追加する エラーにならず、コードが Q4 から振られる(サーベイ全体の連番) 高
CP4 セクションを複製する 複製先の設問コードが T1-2 / Q1-2 などに振り直される 高
CP5 複製したセクション内の排他設定を見る 分岐先が複製後の自分のコードを指している 高
CP6 Q3 に排他選択肢を追加して保存する 「排他選択肢を含む AND だけではない → この設問に留まる + メッセージ」が自動生成される 高
CP7 Q10 に「その他」を設定して保存する フォローアップ FA(Q11)が自動作成され、「Q10 でその他 AND Q11 が未記入 → 留まる」が自動生成される 高
CP8 回答数設定を操作する UI は MA 選択時のみ表示。保存後も保持される。最小 > 最大は保存時エラー 中
CP9 Q12 を PD 複数欄で設定する 編集 UI が「項目名称 + 改行区切り textarea」。分岐画面で欄ごとにグループ表示される 中
CP10 Q13 を TM 複数選択で設定する 行数分(2 件)の排他ルールが自動生成される。単一選択に戻すと自動ルールが消える 中
CP11 Q3 の排他選択肢のラベルを変更する 自動ルールの条件とメッセージが新ラベルに追従し、手動ルールは書き換わらない 中
CP12 Q10 の「その他」選択肢のラベルを変更する 自動生成されたフォローアップのルールが追従する 中
CP13 Q13 の行名をリネームする その行の自動ルールの条件 2 行が新しい行名に追従する 中

プレビュー走行(R)

02-preview-run.spec.ts で検証します。基本回答セット(Q1=男性, Q2=東京都, Q3=A, Q4=赤, Q5=施策1, Q6=A満足/B普通, Q7=空欄, Q8=はい, Q9=すべて自宅, Q10=満足, Q12=両欄とも400万未満, Q13=両行とも平日のみ)との差分だけを記載します。

ID 差分 期待結果 検証対象
R1 なし Q4=赤 で Q5 の施策2/3 が非表示 → Q6 ルール2で Q8 へジャンプ → 完走してコンプリート 表示ロジック, SC 変換, 終了ステップ
R2 Q1=回答しない 即スクリーンアウト。完全回答者にならない equals, SX
R3 Q2=その他 即スクリーンアウト プルダウン条件
R4 Q3=[A, どれも利用していない] メッセージが出て Q3 に留まる → 選び直すと進める 排他設定(AND + self + message)
R5 Q3=どれも利用していない のみ スクリーンアウト only
R6 Q4=[赤,青] スクリーンアウト(ルール3も該当しうるがルール1が先勝ち) AND, 評価順
R7 Q4=緑 Q7 へ(Q5, Q6 スキップ) only, 設問ジャンプ
R8 Q4=[赤,緑] Q6 へ。さらに Q6 の行「サービスB」が非表示になる has_other, 表示ロジック(行)
R9 Q4=青 Q5 で施策2/3 が表示される → Q5=施策2 で Q7 へ 表示ロジック不成立, not_includes
R10 Q4=青, Q5=未回答 Q7 へ(未回答でも「を含まない」成立 = CS 準拠仕様) not_includes × 未回答
R11 Q4=青, Q5=[施策1,施策2] スクリーンアウト not_only
R12 Q6=A不満/B不満 スクリーンアウト マトリクスセル × AND
R13 Q6=A普通/B普通, Q7 悪い点に「解約したい」 スクリーンアウト(部分一致で発火するか) FA 欄指定・部分一致
R14 同上, Q7 良い点に「解約」 ルール1は発火しない(欄の取り違えチェック)→ ルール3で調査完了 FA 欄解決, answered
R15 同上, Q7 良い点に「最高です」 調査完了(コンプリート扱い) FA「いずれかの回答」, SO
R16 Q9 昼=食べない スクリーンアウト サブ設問単位の条件
R17 Q9 朝=食べない(昼夜は自宅) 発火しない → 完走 分割先の取り違えチェック
R18 Q8=いいえ Q9 の朝だけ「自宅」が消える(昼・夜には残る) 分割先ターゲットの表示ロジック
R19 Q10=その他, Q11=未記入 メッセージが出て留まる → 記入すると完走 その他制御(未記入判定)
R20 Q10=満足, Q11=未記入 そのまま完走(その他未選択なら FA 空欄で通過) その他制御の AND 条件
R21 Q4=[赤,青,緑] エラーで Q4 に留まる(最大2超過。分岐より検証が先) 回答数制限(range)
R22 Q12 個人年収=1000万以上 スクリーンアウト PD 複数欄の条件
R23 Q12 世帯年収=1000万以上(個人は400万未満) 発火しない → 完走(欄の取り違えチェック) PD 複数欄の対象欄解決
R24 Q13 店舗=[平日, 利用していない] メッセージが出て Q13 に留まる → 選び直すと進める TM 排他(行内の同時選択)
R25 Q13 店舗=[利用していない] のみ, アプリ=[平日] 発火せず完走(別の行の選択では発火しない) TM 排他の行単位判定
R26 Q6=A普通/B普通, Q7=空欄 「回答あり」が発火せず Q8 へ自然遷移 → 完走 answered × 未入力
R27 Q12 個人年収=400万〜1000万未満 スクリーンアウト(OR の1つ目が成立) OR の分解
R28 Q12 世帯年収=400万〜1000万未満(個人は400万未満) スクリーンアウト(OR の2つ目が成立) OR の分解

CS 流し込み後の確認(I)

Chrome 拡張と Creative Survey 実機が必要なため Playwright では回しません。ただし拡張が出す API ログを読んで自動照合できます。

cd integration-tests
bun run check:cs <ログJSONのパス>   # I-1〜I-20 を判定してレポートする

ログの取り方:

  1. 拡張の「CS API ログ」パネルで クリア
  2. 流し込みを実行
  3. 編集画面をリロードし、設問一覧を最後までスクロール(is_connect は並び替え後の再取得で初めて入る。ページングされるため全ページ読み込む必要がある)
  4. ダウンロード して bun run check:cs <パス>
ID 確認内容 優先度
I-1 warnings が空 高
I-2 並び順が 開始ステップ → T1〜Q13 → コンプリート → スクリーンアウト。終了ステップ 2 枚にラベルが自動設定されている 高
I-3 ページ結合: Q9 の3分割 + Q10 + Q11 が同一ページ、Q8 は別ページ(is_connect は前方向) 高
I-4 Q2 プルダウンの選択肢が 3 件に分かれている 高
I-5 Q3 の分岐: ルール1が条件2行(AND)で宛先が自設問 + メッセージ、ルール2が「だけである」 高
I-6 Q4 の分岐が 3 件、この順で並んでいる(order_index) 高
I-7 Q5 の表示制御: ターゲットに施策2・施策3 の 2 件とも入っている 高
I-8 Q6 の条件が 行 × 列 のセル指定 高
I-9 Q7 の条件: ルール1の対象が「悪い点」欄、ルール2が「いずれかの回答」 高
I-10 Q6 ルール2の宛先が Q8(セクション完了 → 次セクション先頭への変換) 高
I-11 Q9 の分岐が分割後の最後(夜)に付き、条件が 2 番目(昼)を参照している 高
I-12 Q9 の表示制御が分割後の 1 番目(朝)に付き、ターゲットが「自宅」 高
I-13 Q11 が Q9〜Q10 と同一ページに結合され、Q11 宛ての分岐に条件 2 行が入っている 中
I-14 Q4 の回答数制限が反映されている(is_range: true, range_min: 1, range_max: 2) 中
I-15 Q12 が 1 設問のまま answer_items 2 件。条件対象が 1 つ目(個人年収)を指している 中
I-16 Q13 の分岐が 2 件(行ごと)、各ルールがセル条件 2 行(AND) で宛先が自設問 + メッセージ 中
I-17 必須設定が FA / PD / TM で CS 側にも反映されている 中
I-18 Q6 の表示制御: 条件が Q4=緑、非表示対象が行「サービスB」 中
I-19 Q7 の分岐が 3 件。3 件目が verb 3 + 検索文字列 空 + 対象「いずれかの回答」 中
I-20 Q12 の分岐が logic 3 件(ルール2 の OR が 2 件に分解されている) 中

統合テストの注意点

  • dev は他メンバーと共有している環境。テストは新しい案件を毎回作って残す運用なので、溜まってきたら bun run cleanup で消す
  • API 認証は x-user-email ヘッダ方式。既定は config.ts のアカウント
  • 画面操作は headless: false(playwright.config.ts)。CI で回すならここを変える
  • 分岐の保存は画面が持っている設問データを丸ごと送り直す実装のため、自動生成ルール(排他設定など)の反映を待たずに分岐パネルを開くと、そのルールを消してしまう。BranchPanel.openFor() が毎回リロードしているのはこのため
  • 保存の完了はボタンの表示で判断しない。「保存中...」が出る前に消えたと判定してしまい、直後の reload で保存リクエストがキャンセルされる。lib/wait.ts の waitForQuestionWrite() で POST / PATCH のレスポンスを待ってから次の操作に進むこと

落ちたときの調査先

cs-import-test-cases.md の「診断表」に、症状から修正先を引くための対応表があります。主なものは次のとおりです。

症状 想定原因 調査先
CP1〜CP5 が NG コード振り直しの不備 backend survey-store.ts(buildUniqueQuestionCode / remapCopiedSectionCodes)
CP10 / CP11〜CP13 が NG 自動ルールの生成・同期 frontend auto-branch-rules.ts
I-6 / R6 で先勝ちしない logic の order_index 制御 拡張 execute-import-plan.ts の import ボディ
R10 が NG(未回答で発火しない) not_includes の未回答挙動 frontend preview-runner.ts
R13 が NG(部分一致で発火しない) CS の FA マッチ仕様 frontend preview-runner.ts の evaluateFreeTextCondition
I-11 / R16〜R17 が NG サブ設問 index の解決 拡張 execute-import-plan.ts の resolveConditionTarget
R2 で完全回答者になる コンプリート/スクリーンアウトの並び順 拡張 execute-import-plan.ts の setQuestionOrder
R4 が NG(差し戻されない) 自設問宛て / message の送出 拡張 execute-import-plan.ts の resolveDestinationId
I-20 / R27・R28 が NG OR の logic 分解 拡張 build-import-plan.ts の conditionGroups

未検証の項目

CS 実機での確認が済んでいない項目です。

  • 拡張の visibility 追加 POST(2 件目以降)
  • プルダウンの placeholder 区切り文字
  • FA の部分一致挙動
  • セル条件での verb 4(だけではない)の CS 解釈
  • サバイバル形式の answer_type と条件表現(対象外だが未収集)