Vitest HTML Reporter + Firebase Hosting + GitHub Actionsでテスト結果を出力したい!
こんにちは、Nofiです。
今回はテストカバレッジを視覚的にわかりやすく見られるようにしたお話です。
個人的に作っていたお買い物リストアプリについに単体テストを導入し、GitHub Actionsで自動テストを行なっているのですが、テスト項目をHTMLに出力して見やすくできるときいてやってみました。
単体テストにはVitest + jsdom + Testing Library(React Testing Library、jest-dom、user-event)を使っています。
テストの導入はこちらから↓
VitestのHTML Reporter
「テスト項目を外部に出力したい」と思って調べているとVitestのhtml reporterなるものが見つかりました。
JSON形式やHTML、GitHub Actionsでのレポート出力などができるようです。
今回はHTML出力でやってみました。
@vitest/uiパッケージが必要らしいのでインストールします。
インストールコマンド
pnpm i -D @vitest/ui
HTML出力する
1. アプリ直下に出力用のファイルを作成
例:docs/test-report/index.html
2. vitest.config.tsにレポートの設定を追加
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
reporters: ['default', 'html'],
outputFile: {
html: './docs/test-report/index.html'
}
}
});
・reporters: ['default', 'html']で、標準の出力+HTMLを生成
・outputFileをhtmlに設定して、レポートを出力するディレクトリ(例:docs/test-report)を指定
3. Vitest UIのコマンドを実行
vitest --ui
GitHub Pagesにdeployする予定が、privateリポジトリなのでできず
GitHubのリポジトリごとにGitHub Pagesにページをdeployできるのですが、privateリポジトリは課金が必要なので諦めました。
Firebaseで複数サイトHostingをやってみることに
今回のアプリはFirebaseでHostingしているため、同じプロジェクトから複数Hostingできればいいなあと思っていたら、できました!
公式の案内はこちらから↓
以下、Firebaseのプロジェクト内で複数のサイトをHostingする手順です。
1. 既存サイトのSITE_IDを確認
SITE_IDは、Firebase Hostingの一意の識別子です。複数のホスティングサイトを管理する際に使用します。デフォルトはFirebaseプロジェクトIDです。(例: todo-list-1234
)。
下記のコマンドで既存サイトのSITE_IDを確認できます。
firebase hosting:sites:list
このように、まずはデフォルトのFirebaseプロジェクトのIDが出ました。
2. 新しいSITE_IDを作成
下記のコマンドでテスト結果表示ページのSITE_IDを作成します。(例:test-result-1234
)
firebase hosting:sites:create SITE_ID
自分でわかりやすいSITE_IDを決めていいのですが、SITE_IDには次の要件があります。
・有効なホスト名ラベルであること(.
、_
などを含めることはできない)
・30 文字以下
・Firebase内でグローバルに一意
作成できているかは、最初に使ったこちらのコマンドで確認できます。
firebase hosting:sites:list
ここまでで2つ目のサイトのSITE_IDができています。
3. 作成したSITE_IDにTARGET_NAMEを適用
TARGET_NAMEとは、Firebase CLI内で使用する任意の識別名で、自由に命名可能(例: "app"
、"test-result"
)。
下記のコマンドでSITE_ID(例:test-result-1234
)にTARGET_NAME(test-result
)を適用します。
firebase target:apply hosting TARGET_NAME SITE_ID
※ここでデフォルトのFirebaseプロジェクト名に任意のTARGET_NAMEを設定しておくと、分けてHostingするときに便利です。
firebase.json
にテスト結果ページのターゲット設定がされているか確認
4. "hosting"
の中が配列になっていて、targrtがデフォルトのFirebaseプロジェクトとテスト結果用の2つ設定されているか確認します。
"public"
にはdeployするファイルがあるディレクトリを指定します。ディレクトリを間違うとdeployできなかったりエラーになるのでよく確認してください。
{
"hosting": [
{
"target": "todo-list-1234",
"public": "./app"]
},
{
"target": "test-results",
"public": "./docs/test-report",
"ignore": ["**/.*", "**/node_modules/**"]
}
]
}
実際のfirebase.json
.firebaserc
も2つのターゲットが指定されているか確認
5. {
"projects": {
"default": "todo-list-1234"
},
"targets": {
"todo-list-1234": {
"hosting": {
"todo-list": ["todo-list-1234"]**,
"test-result": ["test-result-1234"]**
}
}
}
}
実際の.firebaserc
6. デプロイ
どのtargetをデプロイするか指定してコマンドを実行すると、テストファイルの方だけをdeployできます。
firebase deploy --only hosting:TARGET_NAME
デプロイできてもfirebaseエラーが起きていたりします。
私もindex.htmlがないとFirebaseエラーが出てディレクトリ確認してもエラーで悩みましたが、なんとリロードしたら見れました。chromeはキャッシュが強いらしいので修正したらまずハードリロードをした方がいいかもしれません。(切実)
GitHub ActionsのWorkFlowにテストとデプロイを追加
テストを実行してできたテスト結果のファイル(test-result)をデプロイしたい!というところで悩みましたが、GitHubで提供されている2つのactionで解決できました。
actions/upload-artifact@v4とactions/download-artifact@v4でテスト実行の成果物をartifactとしてアップロードおよびダウンロードできます。
これでjob間でテスト結果のファイルを共有できます。
以下はworkflowの例です。
name: Deploy to Firebase Hosting on PR
on: pull_request
permissions:
checks: write
contents: read
jobs:
build_and_preview:
if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: v22.13.0
- uses: pnpm/action-setup@v3
with:
version: 9
run_install: true
- name: Build
run: pnpm build
# Vitest を使ってユニットテストを実行
- name: Run Vitest
id: run-vitest
run: pnpm vitest --ui
env:
CI: true
continue-on-error: true
# ファイルのアップロード
- name: Upload test results as an artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: docs/test-report
# ファイルのダウンロード
- name: Download a single artifact
uses: actions/download-artifact@v4
with:
name: test-results
path: docs/test-report
- name: Show downloaded files (debug)
run: ls -la docs/test-report
- uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: '${{ secrets.GITHUB_TOKEN }}'
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_TODO_LIST_1234 }}'
projectId: todo-list-1234
1. テストの実行
テストをrun: pnpm vitest --ui
で実行し、そのテストが通っても通らなくても出力できるようにcontinue-on-error: true
を設定する。
2. actions/upload-artifact@v4によるアップロード
with
にjob上で識別するための任意の名前と出力先のパスを設定し、ジョブが終了する前にデータをアップロードする。
3. actions/download-artifact@v4によるダウンロード
アップロードされたartifactをダウンロードできるのは、同じworkflowの実行中だけ。ファイルをダウンロードする際には名前で参照できる。
詳細はこちらを参照してください↓
デプロイ内容の確認
最後に、CommitをPushした後、GitHubのActionsタブのdeploy Previewからテスト結果ページ(例:test-result)のURLに飛んで、テストのfailedが表示されていたら(もしくは成功/意図した画面になっていれば)完成です。
これで自動でテストしてその結果をデプロイしてくれます!
補足:workflowが落ちたように見せたい
今回はテストが通らなくてもデプロイするため、テスト失敗を一旦無視してworkflowをcontinueしました。
この場合workflowは正常に終了しているため、deploy先でテスト結果を確認できることを知らない人が「テスト通った!」と思う可能性がありますよね。
workflowが落ちたように見せる方法があったのでそちらも追記しました。
workflowの最後に以下を記述します。
- name: If failed unit test, exit 1
if: steps.run-vitest.outcome == 'failure'
run: exit 1
テストした時に失敗していたら「exit 1」を実行するフローです。
テストが通らなかった場合GitHub Actionsのマークが赤くなります。
workflowにはこのようにエラーが出ています。
まとめ
これでかなり見やすくなりました。Pushのたびに目を凝らしてどこで落ちたのか探すことがなくなって万々歳です!
エンジニアでない人が見ても、なんのテストがあってどれが失敗しているのかわかりやすくていいですね。
「テスト結果見やすくしたい!」という方や「自動でテスト結果を更新してほしい!」という方の参考になれば幸いです!
Discussion