3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Viteで作成した環境変数のあるプロジェクトにCIを実装する

Posted at

プロジェクトをリモートリポジトリに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 ファイルの作成

.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を開く
image.png
・Secrets and ~ のActionsを選択
スクリーンショット 2024-07-29 151935.png
・New repository secrets から SUPABASE_ANON_KEY と SUPABASE_URL を登録します
image.png
↓↓↓↓↓↓
image.png

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からさらに入っていって詳細を見ることができます。
緑の✅は正常に完了したことを表しています。
image.png

エラーが起こった際には詳細を確認することもできます。
image.png

以上で終了です!お疲れ様でした!

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?