プロジェクトをリモートリポジトリにpushした際にテストを自動で行うことを目的としています。
※すでにプロジェクトがあることが前提です。
※.envに格納した環境変数を用いてSupabaseに接続するアプリケーションです。
※本記事ではテストファイル作成時にモック関数を使用しません。
A : テスト環境導入
A-1: jestとreact-testing-libraryのインストール
npm install --save-dev jest @testing-library/react @testing-library/jest-dom @testing-library/user-event babel-jest @babel/preset-env @babel/preset-react
A-2: jest.config.mjs ファイルの作成
export default {
testEnvironment: "jsdom",
moduleNameMapper: {
"\\.(css|less)$": "identity-obj-proxy",
},
setupFilesAfterEnv: ["./jest.setup.js"],
};
A-3: dotenvのインストール(.env内の環境変数を使用するため)
npm i dotenv
A-4: jest.setup.js ファイルの作成
import "@testing-library/jest-dom";
// dotenvの設定
require("dotenv").config();
A-5 : babelのインストール
npm install --save-dev jest-environment-jsdom @babel/core @babel/preset-env
A-6: .babelrc ファイルの作成
{
"presets": [
"@babel/preset-env",
["@babel/preset-react", {
"runtime": "automatic"
}]
]
}
B : 既存のファイル調整
B-1: package.jsonの更新("test": "jest",を加える)
"scripts": {
"test": "jest",
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
}
B-2: .eslintrc.cjsを修正する(利用していない変数がエラーになるのを防ぐ)
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],
rules: {
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
"no-unused-vars": false
},
}
B-3 : 環境変数呼び出し修正
コード内でimport.meta~で環境変数を参照している場合は, process.env~に変更しておく
(import.meta は ES Modules(ESM)の機能であり、CommonJS 環境ではサポートされない為)
//例 src/supabase.js
import { createClient } from '@supabase/supabase-js';
- const supabaseUrl = import.meta.VITE_SUPABASE_URL;
- const supabaseAnonKey = import.meta.VITE_SUPABASE_ANON_KEY;
+ const supabaseUrl = process.env.VITE_SUPABASE_URL;
+ const supabaseAnonKey = process.env.VITE_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
B-4 : vite.config.jsの修正
prefix: 環境変数のプレフィックスを指定しています。VITE_で始まる環境変数が対象になります
mountedPath: 環境変数がマウントされるオブジェクトを指定します。ここではprocess.envとして設定しています
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import env from "vite-plugin-env-compatible";
export default defineConfig({
plugins: [
react(),
env({ prefix: "VITE", mountedPath: "process.env" }) // 環境変数プラグインを追加
],
build: {
outDir: "dist"
}
});
C : テストファイルの作成・実行
C-1 : src/tests/sample.spec.js ファイルを作成
ここでは例として3つのテストを作成します。
①should display the title - アプリケーションのタイトルが正しく表示されるか
②should add and delete a new record - Add機能とDelete機能が正しく動作するか
③should show an error if inputs are empty - 入力フィールドが空のままAddボタンを押したときにエラーメッセージが表示されるか
import { render, screen, fireEvent, waitFor } from '@testing-library/react'; // テストに必要なメソッドをインポート
import { App } from '../App'; // テスト対象のAppコンポーネントをインポート
import { supabase } from '../supabase'; // supabaseインスタンスをインポート
// テストを実行する前に、既存のデータをクリア
beforeAll(async () => {
// テーブルをクリア
await supabase.from('sample-app').delete().neq('id', 0);
});
test('should display the title', async () => {
render(<App />); // Appコンポーネントをレンダリング
// "Loading..."テキストが表示されなくなるまで待つ
await waitFor(() => {
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
});
// テストID 'title' を持つ要素を取得
const titleElement = await screen.findByTestId('title');
// タイトルのテキスト内容が「サンプルアプリ」であることを確認
expect(titleElement).toHaveTextContent('サンプルアプリ');
});
test('should add and delete a new record', async () => {
render(<App />); // Appコンポーネントをレンダリング
// "Loading..."テキストが表示されなくなるまで待つ
await waitFor(() => {
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
});
// "str_1"のプレースホルダーを持つ入力フィールドに' A'を入力
fireEvent.change(screen.getByPlaceholderText('str_1'), { target: { value: 'A' } });
// "val_1"のプレースホルダーを持つ入力フィールドに' 100'を入力
fireEvent.change(screen.getByPlaceholderText('val_1'), { target: { value: '100' } });
// "Add"ボタンをクリック
fireEvent.click(screen.getByText('Add'));
// "Delete"ボタンを全て取得
const deleteButtons = screen.getAllByText('Delete');
// 最後のDeleteボタンを取得
const lastDeleteButton = deleteButtons[deleteButtons.length - 1];
// 最後のDeleteボタンをクリック
fireEvent.click(lastDeleteButton);
});
test('should show an error if inputs are empty', async () => {
render(<App />); // Appコンポーネントをレンダリング
// "Loading..."テキストが表示されなくなるまで待つ
await waitFor(() => {
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
});
// "Add"ボタンをクリック(入力が空の状態)
fireEvent.click(screen.getByText('Add'));
// エラーメッセージが表示されるまで待つ
await waitFor(() => {
expect(screen.getByText('入力されていない項目があります')).toBeInTheDocument();
});
});
C-2 : sample.spec.jsの実行
npm run test
※上記を実行して下記のように表示されれば成功です
この記事の記述が足りずエラーが起きたらごめんなさい・・・
PASS src/tests/sample.spec.js
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 4.036 s
Ran all test suites.
D : GitHubActionsでテストを実行する
D-1 : githubのSecrets を作成する
・対象リポジトリのSettingを開く
・Secrets and ~ のActionsを選択
・New repository secrets から SUPABASE_ANON_KEY と SUPABASE_URL を登録します
↓↓↓↓↓↓
D-2 : github/workflows/test.yml を作成する
※Node.jsのバージョンは環境に合わせて選択してください
name: Push test
# ワークフローの名前。GitHub ActionsのUIに表示されます。
on:
push:
branches:
- main
# 'main'ブランチへのプッシュイベントでこのワークフローがトリガーされます。
workflow_dispatch:
# 手動でワークフローをトリガーできるようにします。GitHub UIから手動実行可能になります。
jobs:
test:
runs-on: ubuntu-latest
# このジョブは最新のUbuntu環境で実行されます。
steps:
- name: Checkout code
uses: actions/checkout@v3
# リポジトリのコードをチェックアウトするためのGitHub公式アクションです。
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
# Node.jsをセットアップするためのアクションです。ここではNode.jsバージョン18を指定しています。
- name: Install dependencies
run: npm install
# プロジェクトの依存関係をインストールするためのコマンドです。
- name: Run Jest tests
env:
VITE_SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
VITE_SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}
run: npm test
# Jestテストを実行します。環境変数はGitHub Secretsから取得します。
# `VITE_SUPABASE_URL`と`VITE_SUPABASE_ANON_KEY`は、セキュリティのためにリポジトリのSecretsから取得します。
D-3 : gitにpushする
git add .
git commit -m "AutoTest_v1"
git push origin main
push後にリポジトリのActionsからさらに入っていって詳細を見ることができます。
緑の✅は正常に完了したことを表しています。
以上で終了です!お疲れ様でした!