メインコンテンツにジャンプします。

Reactのユニットテスト:実践的なエンドツーエンドガイド

Reactのユニットテストの設定からCI/CDまでをマスターするガイドです。Jest、RTL、hooks、非同期code、モッキング、そして、強力なクロスプラットフォームアプリ用のベストプラクティスについて説明します。

Reactのユニットテスト:実践的なエンドツーエンドガイド

昼食前、UIの小さな変更をプッシュします。見た目は無害です。ボタンのラベルが変更され、条件付きレンダリングが簡略化され、ヘルパーホックが新しいbranchを取得します。プルリクエストはクリーンで、レビューは速く、デプロイは正常に進みます。

1時間後、サポートは1つのプラットフォームでログインが機能しないことを報告します。Webは正常です。デスクトップシェルには古いレンダーパスが残っています。モバイルビルドは非同期状態の変更後、異なる動作を示します。誰も気づかなかったのは、codeがテストされていたからです。しかし、正しいテストは実行されていませんでした。テストの信頼性のあるシステムも実行されていませんでした。

Unit Testing React の主な問題は、実稼働チームで行うことです。少数のテストを書くことは簡単ではありません。リファクタ、リリーストレイン、ホットフィックス、クロスプラットフォームパッケージングを含む、保護を維持するためのテストスイートを構築することは難しいことです。React アプリケーションは、チームが呼び出す方法を忘れたため失敗することはありません。 render()テストは実装詳細に傾き、非同期動作は覆い隠され、CI はテストをチェックボックスとして扱うのではなく、リリースゲートとして扱うのではなく、テストは実装詳細に傾きます。

現代の Unit Testing React は、安全システムのように動作する場合にのみ機能します。ローカルで迅速なフィードバック。CI で決定論的なチェック。単位テストとテストしないものの境界を明確にします。そうしたものは、ブラウザ、Capacitor コンテナ、または Electron シェルを通じて同じ React コードベースを配信することの重要性がさらに高まります。

目次

ユニットテストは、ユーザーが依存している動作が変更されたときに、コンポーネントがまだレンダリングされていることを意味します。 React の場合、通常は、ユーザーが依存している動作が変更されたときに、コンポーネントがまだレンダリングされていることを意味します。 例えば、非活性のボタンがクリック可能になる。ローディング状態がクリアされない。フォールバックメッセージがリファクタ後に消える。 そのような失敗は __CAPGO_KEEP_0__ で小さく、生産性では高価です。

Unit tests earn their keep when they catch the mistake you were confident couldn’t happen. In React, that usually means a component still renders, but the behavior a user depends on has changed. A disabled button becomes clickable. A loading state never clears. A fallback message disappears after a refactor. Those failures are small in code and expensive in production.

React Testing Library が、内部構造ではなく、ユーザーが依存している動作をテストするための主流モデルになった時期です。 、ユーザーが依存している動作をテストするための主流モデルになった時期です。、ユーザーが依存している動作をテストするための主流モデルになった時期です。 、ユーザーが依存している動作をテストするための主流モデルになった時期です。. That shift matters because React code gets rearranged constantly. Hooks move. components split. Context gets introduced. A test tied to internal structure breaks during healthy refactors. A test tied to visible behavior usually survives.

単位テストは何を守るべきか

良いReact単位テストは、1 つの小さな契約を守る:

  • レンダリングされた出力: ユーザーは正しいテキスト、ラベル、状態、またはフォールバックを見るか?
  • インタラクションの動作: クリック、入力、または切り替えによってUIが正しく変更されるか?
  • 境界の扱い: コンポーネントは、期待される入力、欠落したデータ、またはエラーのパスを受け取ったときに正しく動作するか?

弱いテストは間違ったものを守る:

  • コンポーネントの内部: 状態の形状、プライベートメソッド、実装専用のプロパティ
  • フレームワークのメカニズム: 内部では、Reactがハックをどのくらい正確に更新したかが、あなたが期待したとおりに
  • 詳細: ここでは、子コンポーネントが所有するマークアップを検証する必要がない

実用的なルール: ユーザーが見たり行うことができるものが変わらない限り、コンポーネントをリファクタリングすることができるなら、テストも変更する必要がない

ユニットテストも、より広いテストシステムの中で位置しています。全体のアプリケーションが正常に動作することを証明することを目的としたものではありません。ブラウザレベルのテストやデバイスレベルの検証パスまで遅延することなく、ローカルなレグレッションを迅速にキャッチするための高速な層です。そのため、製品アプリケーションの自動テストの合理的なスタックの最初の防衛線です Reactチームが頻繁にリリースする場合、信頼性はこの労働の分割によって得られます。ユニットテストはローカルなレグレッションを迅速にキャッチします。統合テストはシームズを検証します。エンドツーエンドテストはクライティカルパスを確認します。ユニット層をスキップすると、すべての下流のスローモードは、過度に負担することになります.

モダンなReactテスト環境の設定

フラッキーテストが生じる前に、単一のアサーションを書く前に、脆弱なテスト環境が生じます。多くの開発者は、Jest、jsdom、またはReactが原因であると非難しますが、実際の問題は、ローカルマシンとCI間で一貫した構成が欠けていることです。対処法は、環境を面白くなくすることです。面白くないことは、ここでは良いことです

環境が予測可能なランナーと環境で始める

A clean workspace featuring a computer monitor displaying React unit testing code in a code editor.

imageDescription: "コンピューターモニターが表示するReactユニットテストのクリーンなワークスペース

現代のReactアプリケーション、特にViteで作成されたものの基準設定には、以下が含まれるべきです。

  • テストランナー: Jestは、古いReactコードベースやエンタープライズCIスタックでよく使用されます。
  • ブラウザーのような環境: jsdom コンポーネントテストでDOM出力をレンダリングすることができます。
  • テストライブラリのユーティリティ: @testing-library/react そして @testing-library/jest-dom
  • 単一の設定エントリポイント: マッチャーとグローバルモックを登録するファイル

Reactのテストガイドラインが強調する重要なワークフローは、次のとおりです: jsdom-backed環境でコンポーネントをレンダリングし、セレクターでUIをクエリし、DOMの変更をトリガーし、DOMの変更をアサートする getByText または getByRoleトリガーする React のテストドキュメント . そのワークフローは、すべてのマシンが同じテスト環境を実行する場合にのみ信頼できる。

実践的な Jest のセットアップは、以下のようになります。

// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
  moduleNameMapper: {
    '\\.(css|less|scss)$': 'identity-obj-proxy',
    '^@/(.*)$': '<rootDir>/src/$1',
  },
  transform: {
    '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
  },
};

あなたのチームが SWC を使用している場合、Babel の代わりに、それでも問題ありません。Transformer の点ではなく、consistency の点が重要です。リポジトリで 1 つのパスを標準化し、必要に応じて、Capgo の JavaScript のユニットテストガイド は、より広範な JavaScript のテスト規範の参考資料として役立ちます。

セットアップファイルを追加します。スイートはそのファイルに依存します。

適切な setupTests.js は、繰り返しノイズを削減するのに役立ちます。

import '@testing-library/jest-dom';

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation(query => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: jest.fn(),
    removeListener: jest.fn(),
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    dispatchEvent: jest.fn(),
  })),
});

このファイルは、テストファイル 20 個にわたって環境のギャップを解決するのではなく、1 回だけ解決します。API のモックを追加します。UI が依存している、例えば matchMedia, ResizeObserver、または IntersectionObserver、もしコンポーネントライブラリがそれらを必要としている場合

開発者は、グローバルをアドホックに修正することなく、機能するようにします。 これにより、不一致のテストと追跡が困難なエラーが生じます。 一人の人のローカル実行は、ファイルに手動でモックを追加したため、パスします。 CIは、セットアップが共有されていないため、失敗します。

ローカルとCIの動作を同期させる

ローカルコマンドはCIコマンドとできる限り近くする必要があります。 開発者がwatchモードで許容的なデフォルトで実行する場合、CIは厳格な設定で実行すると、-surpriseエラーがマージ後に発生します。 スクリプトを明示的にします。

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:ci": "jest --runInBand --coverage"
  }
}

新しいチームメンバーが同じ基準を早く取得するのに役立つ短いウォークスルーがあります。

最も影響のある設定の選択は、デフォルトの規範の厳しさです。 アリセイを設定ファイルに追加します。 環境モックを1つのセットアップファイルに追加します。 UIテスト用にforを使用し、可能な限り軽い環境で純粋なユーティリティを使用します。 各テストが必要とするカスタム動作が少ないほど、システムの信頼性が高まります。 jsdom 意味のあるコンポーネントテストの書き方

組織はテストを書くことができるのですが、問題は6か月後でも意味のあるテストを書くことができないことです。

Reactコンポーネントのユニットテストの標準パターンはまだ正しいです:

コンポーネントをレンダーし、ユーザー中心のセレクターでUIをクエリし、インタラクションをトリガーし、結果のDOMの変更をアサートします。 これにより、実装詳細のような状態やプロップスからテストを遠ざけ、Reactのテストガイドで説明されているようにします。Reactコンポーネントのユニットテストの標準パターンはまだ正しいです: コンポーネントをレンダーし、ユーザー中心のセレクターでUIをクエリし、インタラクションをトリガーし、結果のDOMの変更をアサートします。 .

ユーザーがアコーディオンを使用するようにテストしてください。

基本的な Accordion コンポーネントを取ります。ボタンとタイトルをレンダリングします。パネルコンテンツは非表示で始まります。ボタンをクリックするとコンテンツが表示され、可視性の状態が更新されます。

それ以上の動作は、数多くの有用なテストのための十分な動作です:

  1. 初期レンダリングではタイトルが表示されますがコンテンツは表示されません。
  2. トリガーをクリックするとコンテンツが表示されます。
  3. 再度クリックすると折り畳まれます。
  4. 可視性の属性は、表示状態を反映しています。

最後の点はよく省略されます。コンポーネントが使用する場合、または役割に基づく構造を使用する場合、確認してください。実装の詳細ではありません。ユーザー向けの契約の一部です。 aria-expanded, aria-controls最良のコンポーネントテストは、受けたいことのないバグレポートのように読まれます。

__CAPGO_KEEP_0__

__CAPGO_KEEP_0__

__CAPGO_KEEP_0__

クエリタイプ 要素が見つかった場合 要素が見つからない場合 使用例
getBy 要素がすぐに返される すぐにエラーを投げる ボタンやヘッダーがすでに画面に表示されていることを確認する
queryBy 要素がすぐに返される 返却 null ユーザーがコンテンツにアクセスする前に、隠されたコンテンツが存在しないことを確認する
findBy 要素が表示される時点で解決される 待機後は拒否される fetchまたは遅延更新後に表示されるアシンクロナスロードされたコンテンツを確認する

単純なメンタルモデルが役に立つ:

  • すでに存在するものに使用する getBy まだ存在していないものに使用する
  • UIが後で変更される場合に使用する queryBy テストが
  • すべてのものに始まるとき、通常は作者がコンポーネントが更新される時点がわからなかったことを意味します。その不確実性は後にフラッキネスになります。 findBy __CAPGO_KEEP_0__

__CAPGO_KEEP_0__ findBy __CAPGO_KEEP_0__

実用的なアコーディオンの例

ここでは代表的なコンポーネントを示します。

function Accordion({ title, children }) {
  const [open, setOpen] = React.useState(false);

  return (
    <section>
      <button
        aria-expanded={open}
        aria-controls="accordion-panel"
        onClick={() => setOpen(prev => !prev)}
      >
        {title}
      </button>
      {open ? (
        <div id="accordion-panel">
          {children}
        </div>
      ) : null}
    </section>
  );
}

ここでは、維持すべきテストの形を示します。

import { render, screen, fireEvent } from '@testing-library/react';

test('renders the accordion title and hides content initially', () => {
  render(<Accordion title="Shipping details">Delivery takes 3 days</Accordion>);

  expect(screen.getByRole('button', { name: /shipping details/i })).toBeInTheDocument();
  expect(screen.queryByText(/delivery takes 3 days/i)).not.toBeInTheDocument();
});

test('reveals content when the trigger is clicked', () => {
  render(<Accordion title="Shipping details">Delivery takes 3 days</Accordion>);

  fireEvent.click(screen.getByRole('button', { name: /shipping details/i }));

  expect(screen.getByText(/delivery takes 3 days/i)).toBeInTheDocument();
});

test('updates aria-expanded when opened', () => {
  render(<Accordion title="Shipping details">Delivery takes 3 days</Accordion>);

  const button = screen.getByRole('button', { name: /shipping details/i });
  expect(button).toHaveAttribute('aria-expanded', 'false');

  fireEvent.click(button);

  expect(button).toHaveAttribute('aria-expanded', 'true');
});

欠けているのは、内部状態に対するアサーション、内部メソッドの呼び出しの確認、レンダリングされた木の全体的なスナップショットです。 setOpen コンポーネントテストを強くするには、以下の習慣があります。

ロールベースのクエリを優先してください。

  • ボタン、ヘッダー、ダイアログ、警告、入力フィールドは、通常、ロールで検索する必要があります。 各テストを狭くしてください。
  • 1つのユーザー視覚的な動作ごとにテストを実行すると、失敗が読みやすくなります。 テスト名を結果に基づいてください。
  • 「aria-expandedを更新する」は、「正しく動作する」よりも有用です。 __CAPGO_KEEP_0__

DOM経由でのコンポーネントのテストが難しい場合、それはデザイン上の問題を明らかにすることがよくあります。 たぶん、状態を間違った場所に隠していること、または意味のあるマークアップが不足していることです。 良いテストは、チームをより良いコンポーネントに導くことがよくあります。

カスタムフックとアプリケーションロジックのテスト

Reactアプリは、コンポーネントの外側に重要な動作を隠しています。 ステートの移行はフック内にあります。 検証とフォーマットはヘルパー関数内にあります。 データの形成は、レンダリングされる前にしばしば行われます。 しかしながら、表示されるコンポーネントのみをテストすると、生産環境の動作を破壊する可能性のあるcodeを大幅に漏れさせてしまいます。

フックには、Reactに対応したハーネスが必要です

カスタムフックは、適切に実行するためにReactが必要なので、テストするには renderHook とラップする必要があります。 act().

小さな useToggle フックは、良い例です。

import { useState, useCallback } from 'react';

export function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);
  const toggle = useCallback(() => setValue(current => !current), []);
  return { value, toggle };
}

そのテストは、パブリック契約に焦点を当てたままにする必要があります。

import { renderHook, act } from '@testing-library/react';
import { useToggle } from './useToggle';

test('returns the initial value', () => {
  const { result } = renderHook(() => useToggle(true));
  expect(result.current.value).toBe(true);
});

test('toggles the value', () => {
  const { result } = renderHook(() => useToggle(false));

  act(() => {
    result.current.toggle();
  });

  expect(result.current.value).toBe(true);
});

そのテストは、有用であるため、フック自体がユニットです。 Reactの内部動作をテストするのではなく、フックの外部動作を検証することです。

製品チームが再利用可能なUIまたは機能原子を構築している場合、このパターンは非常に重要です。 フックは、複数のアプリ、デザインシステム、または内部ツール間で共有されるインターフェイスになります。 商用目的で再利用可能な動作を設計している場合、makersの製品用のフックのリソース https://capgo.com/blog/ja/unit-testing-react/ Reactアプリケーションをテストする際に、フックを製品化されたビルディングブロックとしてではなく、実装の詳細として扱うことができます。

純粋なロジックはテストで純粋に残すべきです。

すべての機能は jsdomReact、またはTesting Libraryが必要ではありません。純粋な関数は、Node環境で単純なJestでテストする必要があります。

例:

export function formatDisplayName(firstName: string, lastName: string) {
  return `${firstName.trim()} ${lastName.trim()}`.trim();
}

そのテストは非常に簡単でなければなりません。

import { formatDisplayName } from './formatDisplayName';

test('joins and trims both names', () => {
  expect(formatDisplayName(' Ada ', ' Lovelace ')).toBe('Ada Lovelace');
});

test('handles a missing last name', () => {
  expect(formatDisplayName('Ada', '')).toBe('Ada');
});

ここでの勝ちはスピードと明確さです。関数がレンダリングされた木が必要なければ、レンダリングされた木を与えないでください。React固有のツールはオーバーヘッドを追加します。ビジネスロジックのテストは、小さく、速く、関数を検証するものに近くしてください。

実用的には、以下の分割が効果的です:

  • フック: 必要に応じて renderHook, act()ユーティリティ:
  • wrapper providers Jestを単純に使用し、DOMを使用しない。
  • 状態を持つ横断的ロジック: コンポーネントテストがロジックのアサーションを多く含むようになると、テスト可能なヘルパーにロジックを引き出すことができます。

チームは、ロジックのアサーションが下のレベルに属していることを認識せずに、コンポーネントテストにロジックを詰め込みすぎることがよくあります。ロジックを引き出すことで、コンポーネントテストがきれいになり、ロジックテストが速くなります。

高度なテクニックのマスター MockingとAsync

ほとんどの不信頼のあるReactスイートは、2つの場所で破損します。依存関係の境界で破損し、時間に関連する場所で破損します。

これがなぜasyncテストとモッキングが、トイテストスイートと信頼できるリリース前のテストスイートの境界線であるかという理由です。1つの分析では、環境またはリソースに関連する問題であるasyncタイミングがテストの不一致の46.5%を占めているとされています。 Reactのユニットテスト分析 この .Reactアプリケーションでは、直接状態の移行、遅延したレンダリング、ネットワークドライブのUI、テストが決定的に待つのではなく、推測するテストに相当します。

Mocking Dependencies versus Asynchronous Testingの比較表です。

境界をモックする、ではなく各層をモックする

最速で誤解を招くテストを書く方法は、半分のコンポーネントツリーをモックし、次に自分のモックが機能したことを確認することです。

アカウントデータを取得するコンポーネントの場合、ネットワーククライアントまたはAPIモジュールをモックする。ホック、子要素コンポーネント、ローディングスピナー、3つのユーティリティ関数をモックしない。テストが実際に隔離が必要な場合は除きます。

このルールセットを使用します。

  • 外部サービスをモックする: HTTPクライアント、アナリティクス、ブラウザのみAPI、ネイティブブリッジ
  • 不安定なプラットフォームAPIをモックする: matchMediaタイマー、Electronプレロードインターフェイス、Capacitorプラグイン(JavaScriptDOMで利用できない場合)
  • デフォルトでは自分の内部をモックしないように避ける: カスタムホック、シンプルな子要素、ローカルユーティリティ

テストがすべての難しい部分を偽物に置き換えた場合、リリースの信頼性が高まることはありません。

ランナーAPIの例とパターンを提供したいチーム向けのCapgo テストチュートリアル 開発者がReactを知っているがテストメカニズムを知らない場合に、特別に役立つ実用的なリファレンスライブラリです。

タイミングが曖昧な場合、非同期テストは失敗します。

非同期テストの失敗は、通常、次の3つの間違いから生じます。

  1. テストが早すぎます。
  2. テストが任意のタイマーで待機しています。
  3. コンポーネントが更新されるが、テストは1つのトランジションのみをモデル化しています。

安定した非同期テストは、通常、この形をしています。

test('shows user details after data loads', async () => {
  render(<UserProfile userId="42" />);
  expect(screen.getByText(/loading/i)).toBeInTheDocument();

  expect(await screen.findByText(/account owner/i)).toBeInTheDocument();
});

または、特定の条件を待つ必要がある場合:

await waitFor(() => {
  expect(screen.getByRole('alert')).toBeInTheDocument();
});

要素の出現がイベントとして重要な場合に使用します。 findBy 条件が広い場合、または状態を単一のクエリで表すことができない場合に使用します。避けるべき waitFor Capgo setTimeout テストでは、タイマーの動作を明示的にテストし、偽のタイマーを使用していない限り、テストを実行しないでください。

Reactのテスト環境では、更新の意味を尊重することを期待されています。 act() 更新がフラッシュするときを考慮する必要があります。Testing Libraryはこれらの問題の多くを解決しますが、状態を手動で操作している場合やタイマーを進めている場合、まだ更新がフラッシュするときを考慮する必要があります。

どのモッキングツールを使用するかを知っておく

異なるモッキングツールは異なる問題を解決します:

ツール 最適な使用方法 一般的な誤用
jest.fn() スタンドアロンで偽のコールバックまたはインジェクションされた関数を使用 単にコールバックを置き換えるのに十分な場合、モジュール全体を置き換えるのに使う
jest.spyOn() 実際のオブジェクトまたはモジュールの1つのメソッドを観察または上書きする 元の実装を復元することを忘れる
jest.mock() モジュール依存性をインポート境界で置き換えます。 デフォルトで大規模モジュールをモックし、意味のある動作を失う。

例を参照してください:

  • 必要な場合に jest.fn() コンポーネントがプロパティを受け取る場合。 onSubmit 使用してください。
  • 、ストレージメソッド、またはエクスポートされた__CAPGO_KEEP_0__コールを検証する必要がある場合。 jest.spyOn() 使用してください。 console.errorモジュールをインポートすると、I/O、ネイティブAPI、またはユニット境界を超える動作にヒットする場合。
  • エラーパスをテストする現代のReactの先進的な領域は、多くのガイドが欠陥しています。エラーバウンダリー、遅延した状態の変更、非同期のフォールバックUIには、最初のクラスをテストする必要があります。子要素が例外を投げた場合、フォールバックUIをアサートします。要求が失敗した場合、可視な回復状態をアサートします。ロード中のボタンが無効になっている場合、も同様にアサートします。ユーザーが思い出すのはそのようなバグです。 jest.mock() when importing a module would otherwise hit I/O, native code, or behavior outside the unit boundary.

Mocking large modules by default and losing meaningful behavior

テスト品質と戦略の向上

多くのチームは、信頼性とカバレッジを同じものとして追いかけている。そうではない。

カバレッジ目標を達成しても、重要なレグレッションを逃すことがある。浅いアサーション、広いスナップショット、モックされた内部部分で構成されるテストスイートは、安全性の印象を与えながら、メンテナンスコストを高くする。

品質テストの利点と高量テストスイートのメンテナンスオーバーヘッドを比較するグラフィック。

カバレッジは目標ではなく、地図である。

カバレッジレポートは、重要なパスに保護がまだないものが何であるかを答える質問に答える場合に役立つ。

カバレッジレポートは、開発者を重要なパス以外のトリビアルラッパー、静的マークアップ、または一行のパススルー ファイルにテストを強制するのではなく、信頼性を高めるツールとして扱うべきである。

信頼性を高めるテストは、リリースリスクを減らすかどうかを簡単に確認できる質問である。

  • はい: ユーザーが見える動作を検証する。
  • もしかしたら: ビジネスロジックを保護する。簡単に破壊される可能性があるものである。
  • No: 実装の詳細を確認したり、他のテストの値を重複することはありません。

何を単体テストしない?

多くのReactガイドでは、欠陥について十分な時間を費やしていません。その欠陥は重要です。過度のモックと実装詳細のテストは、ユーザー体験が壊れるまで、パスするのに脆弱なスイートを作成します。これは、BrowserStackのReactで何を単体テストしない?のガイドで指摘されています。 または、以下のパターンを大幅に制限するか、スキップします:.

内部状態の確認:

  • 直接確認しないでください。代わりに、パネルが開いたかどうかをテストします。 フレームワークの動作: isOpen Reactが効果を呼び出したかどうかをテストしないでください。効果が変更した結果をテストします。
  • 第三者ライブラリの内部: __CAPGO_KEEP_0__
  • __CAPGO_KEEP_1__ インテグレーションをテストするには、日付ピッカーまたはルーターを使用してください。ライブラリのレンダリングロジックではありません。
  • オーバーブロックされたユニット: すべての子供とヘルパーをモックした場合、意味のある動作をテストできなくなります。

悪いテストは、リファクタリングをブロックし、実行時エラーを検出できなくても、生産的なバグを検出できません。

有効なヒューリスティックは境界の所有権です。code が所有するものをテストしてください。React、ブラウザ、または成熟したライブラリが既に所有しているものは、インテグレーション層が契約を変更しない限りテストしないでください。

スナップショットの役割と害

スナップショットは無駄ではありません。ただし、誤用しやすいものです。

スナップショットを控えめに使用してください。構造的な差分が意味のあるものであるコンポーネントで使用します。インタラクティブまたは高度に動的なコンポーネントでは、ノイズになります。開発者は読まずに更新するようになります。

より良い代替案が存在します:

  • 条件付きレンダリングの場合、指定されたテキストの存在または非存在を確認してください。
  • 視覚的な状態の変更の場合、重要な役割、ラベル、または属性を確認してください。
  • エラーとフォールバックの場合、実際のメッセージまたはアラート領域を確認してください。

チームがユニットテストのより広い品質プロセスを必要としている場合、信頼できる相棒は アプリケーション品質保証フロー テスト、リリースチェック、ロールバック計画を一つのシステムとして扱う

テスト品質を最速で向上させる意識のシフト

テストの数を尋ねるのではなく、まだユーザーに到達する可能性のある失敗を尋ねる

クロスプラットフォームCI/CDパイプラインにテストを統合する

開発者用のラップトップ上でしか実行されないテストスイートは、提案ではなく制御ではありません。

スイートは、すべてのプルリクエストが同じチェックをクリーンな環境で実行し、チェックが失敗するとマージをブロックするようにすることで、実行可能になります。

それは明らかですが、多くのチームは重要な欠陥を残しています。

  • テストは手動で実行されます。
  • カバレージレポートはオプションです。
  • パッケージングとリリースジョブは、テストジョブが完了する前に開始されます。
  • テスト失敗で速く失敗する
  • テストがパスするまでアーティファクトを公開しない

これは アプリチームのための継続的デプロイの実践の核となる部分リリース前に信頼を築くこと、リリース後にしないこと

多くのチームにとって、シンプルなGitHubアクションワークフローが十分です:

name: test

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  react-tests:
    runs-on: ubuntu-latest

    steps:
      - name: Check out code
        uses: actions/checkout@v4

      - name: Set up Node
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Run unit tests
        run: npm run test:ci

これは、華やかなものではありません。それがポイントです。最も強力なパイプラインは、通常、最も驚くことのないものです。

なぜCapacitorとElectronの場合にこれがもっと重要になるのか

クロスプラットフォームのReactアプリは、ブラウザのみのアプリよりもリリースリスクが高い。同じUIcodeは、異なるコンテナに異なる実行環境の仮定で配信されることが多い。

いくつかの例は、パイプラインがどのように役立つかを示しています:

  • Capacitorアプリ: Webcodeはローカルでパスするかもしれませんが、プラグインブリッジ、オフライン状態、またはアプリライフサイクルエッジケースがパッケージング後に動作を変える場合に失敗する可能性があります。
  • Electronアプリ: A rendererコンポーネントは、プレロードAPI、ウィンドウメッセージング、またはデスクトップ専用の状態に依存する可能性があります。これらは、通常のブラウザテストでは存在せず、意図的にモック化する必要があります。
  • 共通リリーストレイン: 1 つの不良バンドルが複数のターゲットに影響を与える可能性があります。デプロイメントプロセスが厳密にパブリケーションをゲートしていない場合。

したがって、パッケージングジョブが実行される前にユニットテストを実行し、パッケージングジョブが実行される前に配布ジョブを実行する必要があります。各ステージはリスクを縮小します。ユニットテストはローカルなバグを迅速に検出します。プラットフォームパッケージングは環境の仮定を検証します。最終リリースの信頼性は、手動の承認またはステージドロールアウトで取り扱います。

実践的なGitHubアクションワークフロー

より成熟したパイプラインでは、責任を分割します:

  1. テストジョブ: 高速なユニットテストとフックテスト
  2. ビルドジョブ: テストが成功した後のみ、プロダクションビルド
  3. パッケージングジョブ: Capacitor 同期、Electron パッケージング、またはアーティファクト バンディング
  4. リリースジョブ: 承認済みブランチまたはタグからのみ公開

For teams shipping live updates to Capacitor or Electron apps, this is where release tooling matters. One option in that workflow is CapgoCapacitorJS と Electron アプリ用に署名された Web バンドルを公開し、ロールバックサポートとチャネルベースのロールアウト制御を提供するオプションがあります。実際には、React テストジョブは、ステージングまたはプロダクション配信に進む前に、Web バンドルが最初のハードゲートとして機能します。

動作ルールは簡単です。リリースインフラが弱いテストを補うのを許すな。信頼できるテストがすでに悪い変更をフィルタリングした後、リリースインフラを使用する。

信頼できるテストシステムはチームの行動を変える。エンジニアはマージに少しあまり躊躇しない。レビュアーはエッジケースに焦点を当てるのではなく、基本的なものを手動で再実行するのではなく。リリースマネージャは、毎回のデプロイを賭けにしているのではなく、リリースを安全に実行できるようになる。


If your team ships React through Capacitor or Electron, release safety depends on more than green local tests. Capgo Capgo は、CI パイプラインがすでにデプロイ前にユニットテストを通過することを要求している場合に、チームに制御された方法で署名された Web アップデートを公開し、ターゲットロールアウトチャネルを指定し、悪いバンドルをロールバックすることができる。

Live updates for Capacitor apps

When a web-layer bug is live, ship the fix through Capgo instead of waiting days for app store approval. Users get the update in the background while native changes stay in the normal review path.

マーティンから人間のサポート

今すぐ始めよう

最新のブログ記事

Capgo gives you the best insights you need to create a truly professional mobile app.