昼食前、UIの小さな変更をプッシュします。見た目は無害です。ボタンのラベルが変更され、条件付きレンダリングが簡略化され、ヘルパーホックが1つの新しいbranchを取得します。プルリクエストはクリーンで、レビューは速く、デプロイは実行されます。
1時間後、サポートは1つのプラットフォームでログインが停止したことを報告します。Webは正常です。デスクトップシェルには古いレンダリングパスがあります。モバイルビルドは非同期状態の変更後異なる動作をします。誰もそれを捕まえませんでした。なぜなら、codeにはテストがありましたが、正しいテストではありませんでしたし、きちんとテストを管理するシステムもありませんでした。
Reactの単位テストは、実稼働チームで問題となるのは主な問題です。少数のテストを書くことは簡単ではありません。まだ保護されながらリファクタリング、リリーストレイン、ホットフィックス、クロスプラットフォームパッケージングをサポートするスイートを構築することは難しいことです。 render()Reactアプリケーションは、チームが呼び出す方法を忘れたためではなく、テストが実装詳細に近づき、非同期動作が隠蔽され、CIがテストをチェックボックスとして扱うため、失敗します。
現代の単位テストは、Reactが安全システムのように動作するときに機能します。ローカルで迅速なフィードバック。CIで決定論的なチェック。単位テストとテストしないものの境界が明確です。そのことは、同じReactコードベースがブラウザ、Capacitor コンテナ、またはElectronシェルを通じて配信される場合にさらに重要です。
目次
- 単位テストはReactの最も安全な安全網です
- 現代のReactテスト環境を設定する
- 意味のあるコンポーネントテストを書く
- カスタムフックとアプリケーションロジックのテスト
- 高度なテクニックのマスター、モッキングと非同期
- テストの質と戦略を向上させる
- クロスプラットフォーム CI/CD Pipelines にテストを統合する
ユニットテストは、起こりそうもない間違いをキャッチすることで、実際に値打ちがある
code では、通常、コンポーネントは表示されるが、ユーザーが依存している動作は変更される
ボタンが無効になっている場合にクリック可能になる。ローディング状態が解除されない。フォールバックメッセージがリファクタ後に消える。 __CAPGO_KEEP_0__ では、これらの失敗は小さく、生産性では高価__CAPGO_KEEP_0__ のテストは、重要な方法で変化した __CAPGO_KEEP_0__ のテストライブラリが、内部構造ではなく、ユーザーが見える動作をテストするための主流モデルになったこれは重要な問題である。code の構造は常に変更される。Hooks が移動する。コンポーネントが分割される。Context が導入される。内部構造に依存するテストは、正常なリファクタリングの際に破棄される。ユーザーが見える動作に依存するテストは、通常は破棄されない
単位テストが保護するべきものは何ですか
良いReact単位テストは、1 つの小さな契約を保護します:
- レンダリングされた出力: ユーザーが正しいテキスト、ラベル、状態、またはフォールバックを見るかどうか
- インタラクションの動作: クリック、入力、または切り替えがUIを正しく変更するかどうか
- 境界の扱い: コンポーネントが期待される入力、欠落したデータ、またはエラーのパスを受け取ったときに正しく動作するかどうか
弱いテストは間違ったものを保護します:
- コンポーネントの内部: 状態の形状、プライベートメソッド、実装専用のプロパティ
- フレームワークのメカニズム: 内部で正確に期待どおりにフックを更新したかどうか、Reactがどう更新したかは関係ありません。
- 子要素の詳細: ここでは確認したくないネストされたコンポーネントが所有するマークアップ
実用的なルール: ユーザーが見たりすることができるものの変更が必要ない場合、コンポーネントをリファクタリングするだけでテストも変更する必要がないはずです。
ユニットテストも、より広いテストシステムの中で位置しています。全体のアプリケーションがエンドツーエンドで動作することを証明することを目指しているわけではありません。ユニットテストは、ブラウザレベルテストやデバイスレベルバリデーションパスまで遅いテストを実行する前に、ローカルなレグレッションを迅速にキャッチするための高速な層です。そのため、製品アプリケーションの自動テストの合理的なスタックの最初の防衛線です。 頻繁にリリースするReactチームにとって、信頼はこの労働の分割によって得られます。ユニットテストはローカルなレグレッションを迅速にキャッチします。統合テストはシームズを検証します。エンドツーエンドテストはクリティカルパスを確認します。ユニット層をスキップすると、すべての下流のスローテストは、過度に負担することになります。.
モダンなReactテスト環境を設定する
フラッキーテストは、単一のアサーションを書く前に、不一致な構成がローカルマシンとCIにわたることによって生じる、脆弱なテスト環境によって生じます。多くの開発者は、Jest、jsdom、またはReactを非難しますが、実際の問題は、ローカルマシンとCIで一貫した構成が取れていないことです。対処法は、環境を面白くなくすることです。面白くないことはここでは良いことです。
コンピュータモニターが表示するReactユニットテストを特徴とする、きれいなワークスペース。

__CAPGO_KEEP_0__
モダンなReactアプリ、特にViteで作成されたものの基本的な設定には、以下が含まれるべきです。
- テストランナー: Jestは、古いReactコードベースやエンタープライズCIスタックでよく使用されます。
- ブラウザのような環境:
jsdomコンポーネントテストでDOM出力をレンダリングするのに役立ちます。 - テストライブラリのユーティリティ:
@testing-library/reactそして@testing-library/jest-dom - 単一の設定エントリポイント: マッチャーとグローバルモックを登録するファイル
Reactのテストガイドラインが強調する主なワークフローは単純です: jsdom-backed環境でコンポーネントをレンダリングし、 getByText または getByRole, インタラクションをトリガーし、DOMの変更を確認します。 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 の代わりに使用している場合、それでも問題ありません。トランスフォーマーではなく、consistency がポイントです。リポジトリで 1 つのパスを標準化し、望ましいより広範な JavaScript テスト規則のコメンテーション用の参考資料として、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, ResizeObserverAPI IntersectionObserverUI
開発者はグローバルを手動で修正するので、不一致のテストと追跡が困難なエラーが生じます。 一人の人のローカル実行はパッチが追加されたファイルで成功しますが、CIはセットアップが共有されていないため失敗します。
ローカルとCIの動作を同期させる
ローカルコマンドはCIコマンドとできる限り近くする必要があります。 開発者がwatchモードで緩いデフォルトで実行している場合、CIは厳しい設定で実行すると、merge後に驚く失敗が発生します。 スクリプトは明示的に記述すること:
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:ci": "jest --runInBand --coverage"
}
}
新しいチームメンバーが同じ基準を早く取得するのに役立つ短いウォークスルーを提供します:
最も影響力のある設定の選択は、デフォルトの規則を守ることです。 アリースは設定ファイルに置き、環境モックは1つの設定ファイルに置き、可能な限りUIテスト用に軽い環境で、純粋なユーティリティ用に軽い環境を使用します。 各個人のテストが必要とするカスタム動作が少ないほど、システムの信頼性が高まります。 jsdom 意味のあるコンポーネントテストの書き方
組織はテストを書くことができるのですが、問題はテストを書くことではなく、6か月後でも意味のあるテストを書くことです。
Reactコンポーネントのユニットテストの標準パターンはまだ正しいです:
コンポーネントをレンダーし、ユーザー中心のセレクターでUIをクエリし、イベントをトリガーし、結果のDOMの変更をアサートする 実装詳細である状態やプロップスからテストを守ることを保証するため、Reactテストガイド __CAPGO_KEEP_0__. パターンを適切に制限する鍵は何か。
ユーザーがアコーディオンを使用するようにテストしてください。
基本的なコンポーネントを取り入れてください。ボタンとタイトルを表示します。パネル内のコンテンツは非表示です。ボタンをクリックするとコンテンツが表示され、可視性の状態が更新されます。 Accordion そのような動作は、実用的なテストに十分です。
初期レンダリングではタイトルが表示されますがコンテンツは表示されません。
- トリガーをクリックするとコンテンツが表示されます。
- 再度クリックすると折り畳まれます。
- 可視性の属性は、表示状態を反映しています。
- 最後の点はよく見落とされます。コンポーネントが使用する場合、または役割に基づく構造を使用する場合、確認してください。実装の詳細ではありません。ユーザー向けの契約の一部です。
最も優れたコンポーネントのテストは、受けたいことのないバグレポートのように読まれます。 aria-expanded, aria-controls__CAPGO_KEEP_0__
__CAPGO_KEEP_0__
意図に基づいてクエリを選択する
React Testing Libraryでは、複数のクエリスタイルが用意されていますが、互換性はありません。間違ったスタイルを選択すると、テストが雑雑しく誤解を招くことになります。
| クエリタイプ | 要素が見つかった場合 | 要素が見つからない場合 | 使用例 |
|---|---|---|---|
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 コンポーネントのテストを強くする習慣は少しだけあります:
ロールベースのクエリを優先してください:
- ボタン、ヘッダー、ダイアログ、警告、入力フィールドは通常はロールで見つけるべきです。 各テストを狭くしてください:
- ユーザーが見える動作ごとにテストを一つずつ実行すると、エラーが読みやすくなります。 テストの名前は結果に基づいてください:
- Name tests after outcomes: “updates aria-expanded when opened” is much more useful than “works correctly.”
DOMを通じてテストが難しいコンポーネントが多い場合、それはデザイン上の問題を明らかにすることがよくあります。状態を間違った場所に隠しているかもしれません。意味のあるマークアップが不足しているかもしれません。良いテストは、チームをより良いコンポーネントに導くことがよくあります。
カスタムフックとアプリケーションロジックのテスト
Reactアプリは、コンポーネント外の重要な動作を隠しています。状態の移行はフック内にあります。検証とフォーマットはヘルパー関数内にあります。データの形成はレンダリングされる前に発生します。表示されるコンポーネントのみをテストすると、生産環境の動作を破壊する可能性のあるcodeを大幅にミスすることになります。
フックにはReactに認識されるハーネスが必要です
カスタムフックは、適切に実行するためにReactが必要なので、テストする必要があります。 renderHook と状態を変更する呼び出しをwrapする 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 };
}
そのテストは、フック自体がユニットであるため、役立ちます。Reactの内部動作をテストするのではなく、フックの外部動作を検証するのです。
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);
});
製品チームが再利用可能なUIまたは機能原子を構築している場合、このパターンは非常に重要です。フックはアプリ、デザインシステム、または内部ツール間で共有されるインターフェイスになります。商用目的で再利用可能な動作を設計している場合、
フックのためのリソースはmakersの製品向けです。 フックは、内部のReactの動作をテストするのではなく、フックの外部動作を検証する必要があります。 Capgoは、フレームワークの実装詳細としてではなく、製品化されたビルディングブロックとしてのハックをフレームワークがサポートできるようにすることができます。
純粋な論理は、テストで純粋なままにしておくべきです。
すべての機能は、React、またはテスト ライブラリが必要ではありません。 jsdom純粋な関数は、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()とラッパー プロバイダーを使用します。 - ユーティリティ: Jestを使用し、DOMを使用しない。
- 状態を持つ横断的ロジック: コンポーネントテストがロジックのアサーションを多く含むようになると、テストが複雑になることが多い。ロジックをテストヘルパーに引き出すことで、2つの利点が得られる。コンポーネントテストが綺麗になり、ロジックテストが速くなります。
チームは、ロジックのアサーションをコンポーネントテストに含めることが多いが、実際には下の階層に属するものである。ロジックをテストヘルパーに引き出すことで、2つの利点が得られる。コンポーネントテストが綺麗になり、ロジックテストが速くなります。
高度なテクニックのマスター MockingとAsync
ほとんどのReactのテストスイートは2つの場所で破損する。依存関係の境界と時間に関連する部分である。タイミングの問題や環境やリソースに関連する問題が46.5%のテストの不安定性を引き起こしているという分析がある。
このReactの単体テスト分析によると、 Reactアプリケーションでは、状態の遷移、遅延したレンダリング、ネットワークドライブのUI、テストが予測するのではなく、決定的に待つことによってテストが不安定になることが多い。 Mocking Dependencies versus Asynchronous Testingの比較表 __CAPGO_KEEP_0____CAPGO_KEEP_0__

境界を模倣せず、すべての層を模倣しない
テストを書く最速の方法は、半分のコンポーネントツリーをモックし、自分のモックが機能したことを確認することです。
アカウントデータを取得するコンポーネントの場合、ネットワーククライアントまたはAPIモジュールをモックする。ホック、子要素コンポーネント、ローディングスピナー、3つのユーティリティ関数をモックしないでください。
このルールセットを使用します:
- 外部サービスをモックする: HTTPクライアント、アナリティクス、ブラウザのみAPI、ネイティブブリッジ
- 不安定プラットフォームAPIをモックする:
matchMedia, timers, Electron preload interfaces, Capacitor plugins when unavailable in jsdom - , ,
,
For teams that want examples and patterns around runner APIs, the Capgo Jest カテゴリ __CAPGO_KEEP_0__は、特にReactを学習した開発者がテストメカニズムをまだ知らない場合に、実用的なリファレンスライブラリです。
タイミングが曖昧な場合、非同期テストは失敗します。
非同期テストの失敗は、通常、次の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 使用しないでください。 setTimeout テストの場合、タイマーの動作を明示的にテストしていない限り、タイマーの偽物を使用しない。
React のテスト環境では、更新の意味を尊重することを期待されています。テスト ライブラリはこれらの問題の多くを処理しますが、状態を手動で操作している場合やタイマーを進めている場合、更新がフラッシュするタイミングを考慮する必要があります。 act() どのモック ツールを使用するかを知る
異なるモック ツールは異なる問題を解決します。
ツール
| 最も適切な使用方法 | 最もよくある間違い | スタンドアロンで偽のコールバックまたはインジェクションされた関数を使用する |
|---|---|---|
jest.fn() |
単純なコールバックが十分である場合に、モジュール全体を置き換える | 実際のオブジェクトまたはモジュールの 1 つのメソッドを観察またはオーバーライドする |
jest.spyOn() |
元の実装を復元することを忘れる | protectedTokens |
jest.mock() |
モジュール依存性をインポート境界で置き換える | デフォルトで大規模モジュールをモックし、意味のある動作を失う |
例の助け:
- Reach for
jest.fn()コンポーネントがonSubmitプロパティを受け取る場合に - 使用する
jest.spyOn()ストレージ方法を検証したい場合、またはエクスポートされた__CAPGO_KEEP_0__呼び出しを検証したい場合にconsole.error, a storage method, or one exported API call. - モジュールをインポートする場合、I/O、ネイティブ__CAPGO_KEEP_0__、またはユニット境界を超える動作にヒットしないようにする必要がある場合に
jest.mock()when importing a module would otherwise hit I/O, native code, or behavior outside the unit boundary.
使用する
テスト品質と戦略の向上
多くのチームは、信頼性とカバレッジを同じものと考えていますが、実際にはそうではありません。
カバレッジ目標を達成しても、重要なレグレッションを逃す可能性があります。浅いアサーション、広いスナップショット、内部モックのスーツは安全性の印象を与えながら、メンテナンスコストを高くします。

カバレッジは目標ではなく、目標を達成するための道具です。
カバレッジレポートは、重要なパスが保護されていないものを示す質問に答える場合にのみ有用です。
開発者を重要なパスをテストするのではなく、単にパーセンテージを上げるために、無駄なテストを強制するのではなく、カバレッジを発見のためのツールとして扱うべきです。
認証状態、請求アクション、機能フラグ、更新ポップアップなどのテストが不足している場合、それは信号です。
- プレゼンテーショナルアイコンコンポーネントなどのテストが不足している場合、それは通常ではありません。 健康的なレビューの質問は単純で、テストはリリースリスクを減らすかどうかを確認するべきです。
- はい: ユーザーに視覚化される動作を検証するためです。
- No: 実装詳細を明らかにしたり、他のテストの値を重複したりすることはありません。
何をユニットテストしない?
多くのReactガイドでは、欠陥を十分に扱っていないことが多い。 そのギャップは重要なものです。 それが、BrowserStackのガイドにあるように、オーバーモッキングと実装詳細テストは、ユーザー体験がまだ壊れているのに、パスする脆弱なスイートを作り出すからです。 スキップまたは厳格に制限するパターン:.
内部状態のアサーション:
- 直接テストしないでください。 できるだけテストするのは、パネルが開いたかどうかをテストすることです。 フレームワークの動作:
isOpenReactが効果を呼び出したかどうかをテストしないでください。 効果が変化した結果をテストすることです。 - 第三者ライブラリの内部: __CAPGO_KEEP_0__
- __CAPGO_KEEP_1__ 日付ピッカーまたはルーターと統合テストを行ってください。ライブラリのレンダリングロジックではありません。
- 過度に分割された単位: すべての子やヘルパーをモックした場合、意味のある動作をテストできなくなっているかもしれません。
テストが不正解の場合、改良が遅れ、実際のエラーを検出できなくなるため、欠けているテストよりも悪いです。
境界の所有権という便利なヒューリスティックを使用すると役立ちます。codeが所有するものをテストしてください。React、ブラウザ、または成熟したライブラリがすでに所有しているものは、統合層が契約を変更しない限りテストしないでください。
スナップショットの役割と欠点
スナップショットは無駄ではありません。簡単に誤用される傾向があります。
構造的な差分が意味をなす、安定したシンプルな出力を持つコンポーネントでは、スナップショットをsparingly使用してください。インタラクティブまたは高度に動的なコンポーネントでは、ノイズになります。開発者は読みにくくなり、自動的に更新するようになります。
代替案がよくあります:
- 条件付きレンダリングの場合、キーテキストの存在または非存在を確認してください。
- 視覚的な状態の変更の場合、重要な役割、ラベル、または属性を確認してください。
- エラーとフォールバックの場合、実際のメッセージまたは警告領域を確認してください。
チームがユニットテストのより広い品質プロセスを必要とする場合、補助的なものはアプリの品質保証フローです。 テスト、リリースチェック、ロールバック計画を一つのシステムとして扱う意識のシフトが、テスト品質を最速で改善します。 ユニットテストの範囲を超える品質プロセスを必要とするチームに
CI/CD Pipelinesにテストを統合する
開発者用のラップトップ上でしか実行されないテストスイートは、提案ではなく制御ではありません。
テストスイートは、プルリクエストごとに同じチェックをクリーンな環境で実行し、チェックが失敗した場合にマージをブロックするようになることが、稼働状態になります。

テストは手動で実行されます。
カバレッジレポートはオプションです。
- パッケージングとリリースジョブは、テストジョブが完了する前に開始されます。
- これは、小さなUIの不具合が大きなリリースの失敗に繋がる原因となります。
- CI/CD PipelinesにReactの自動化テストを統合する5つのステップのフローチャートです。
- テスト失敗時速い速い失敗
- テストが通った後のみアーティファクトを公開
これは アプリチーム向けのリリース前に信頼を築く、ではなく。
多くのチームにとって、シンプルなGitHub Actions ワークフローが十分です。
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 アプリ: レンダラー コンポーネントは、プレロード API、ウィンドウ メッセージング、またはデスクトップ専用の状態に依存する可能性があります。これらは、意図的にモックされていない場合、平凡なブラウザ テストでは存在しません。
- 共有リリース トレイン: 1 つの悪いバンドルが、デプロイメント プロセスが厳密にパブリケーションをゲートしていない場合、複数のターゲットに影響を与える可能性があります。
したがって、パッケージング ジョブが実行される前に、ユニット テストが実行されるべきであり、パッケージング ジョブが実行される前に、ディストリビューション ジョブが実行されるべきです。各ステージはリスクを縮小します。ユニット テストはローカルなリグレッションを迅速に検出します。プラットフォーム パッケージングは環境の仮定を検証します。最終リリースの信頼性は、手動の承認またはステージド ロールアウトで管理されます。
A practical GitHub Actions workflow
より成熟したパイプラインは、責任を分割します。
- テスト ジョブ: 高速なユニット テストとハック テスト
- ビルド ジョブ: テストが成功した後のみ、プロダクション ビルド
- パッケージング ジョブ: Capacitor 同期、Electron パッケージング、またはアーティファクト バンドリング
- リリースジョブ: 承認されたブランチまたはタグのみから公開する
Capacitor または Electron アプリにライブアップデートを配信するチーム向けに、このリリースツールは重要です。ワークフローにおける 1 つのオプションは、 Capgo、です。このツールは、CapacitorJS と Electron アプリ用に署名された Web バンドルを公開し、ロールバック機能とチャネルベースのロールアウト制御を提供します。実際には、React テストジョブは、Web バンドルがステージングまたはプロダクション デリバリーに進む前に、最初のハードゲートとして機能します。
運用ルールは簡単です。リリースインフラが弱いテストを補償しないようにしてください。信頼できるテストがすでに悪い変更をフィルタリングした後、リリースインフラを使用してください。
信頼できるテストシステムはチームの行動を変える。エンジニアはマージに少しあまり躊躇しなくなります。レビュアーはエッジケースに焦点を当てるのではなく、基本的なものを手動で再実行するのではなく、エンジニアはリリースマネージャが毎回のデプロイを賭けのように扱わなくなるのです。そうした結果は、React のユニットテストをうまく行うことによって得られるのです。
Capacitor を使用して、チームは署名された Web アップデートを公開し、ロールアウトチャネルをターゲットし、悪いバンドルをロールバックすることができます。ストアのレビューを待つ必要はありません。これは、すでにデプロイメントに必要なユニットテストを通過する CI パイプラインの背後で自然に機能します。 Capgo は、チームに署名された Web アップデートを公開するための制御された方法を提供し、ロールアウトチャネルをターゲットし、悪いバンドルをロールバックすることができます。ストアのレビューを待つ必要はありません。