昼食前、UIの小さな変更をプッシュします。見た目は無害です。ボタンのラベルが変更され、条件付きレンダリングが簡略化され、ヘルパーホックが新しいbranchを取得します。プルリクエストはクリーンで、レビューは速く、デプロイは正常に進みます。
1時間後、サポートから1つのプラットフォームでログインが停止したとの報告があります。Webは正常です。デスクトップシェルには古いレンダリングパスがあります。モバイルビルドは非同期状態の変更後異なる動作を示します。誰も気づかなかったのは、codeがテストされていたからです。しかし、正しいテストは実行されていませんでした。確実に信頼できるシステムもありませんでした。
Reactの単位テストをプロダクションチームで行う主な問題は何ですか。少数のテストを書くのは簡単ではありません。リファクタ、リリーストレイン、ホットフィックス、クロスプラットフォームパッケージングを含む、まだ保護することができるテストスイートを構築するのは難しい部分です。 render()Reactアプリケーションは、チームが呼び出す方法を忘れたからではなく、失敗します。テストは実装詳細に近づき、非同期動作は紙に書き付けられ、CIはテストをチェックボックスとして扱うのではなく、リリースゲートとして扱うのではなく、テストは実装詳細に近づきます。
現代の単位テストReactは、安全システムのように振る舞うときに機能します。ローカルで迅速なフィードバック。CIで決定論的なチェック。単位テストと何も関係ないものの境界を明確にします。そうしたものは、同じReactコードベースをブラウザ、Capacitorコンテナ、またはElectronシェルで配信する場合にさらに重要です。
目次
- Reactの単位テストはあなたの最も安全な安全網です
- 現代のReactテスト環境を設定する
- 意味のあるコンポーネントテストを書く
- カスタムフックとアプリケーションロジックのテスト
- 高度なテクニックのマスター MockingとAsync
- テストの品質と戦略を向上させる
- クロスプラットフォーム CI/CD Pipelines にテストを統合する
ユニットテストは、ユーザーが依存している動作が変わった場合に、エラーを検出することで、最も安全なネットワークを提供する
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 のテストは、重要な点で変化したReact Testing Library は、内部構造ではなく、ユーザーが依存している動作をテストするための主流モデルになった これは、React __CAPGO_KEEP_0__ が常に再構築されるため、重要なこと. 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を正しく変更するか?
- 境界の扱い: コンポーネントは、期待される入力、欠落したデータ、またはエラーのパスを受け取ったときに正しく動作するか?
弱いテストは間違ったものを保護します:
- コンポーネントの内部: 状態の形状、プライベートメソッド、実装のみのプロパティ
- フレームワークのメカニズム: Whether React updated a hook in the exact way you expected internally
- 子コンポーネントの詳細: マークアップは、意図していないネストされたコンポーネントによって所有されているため、ここでは検証する必要はありません
実用的なルール: ユーザーが見たり行うことができるものの変更が必要ない場合、コンポーネントをリファクタリングすることができます。テストも変更する必要はありません。
ユニットテストは、より広いテストシステムの中で位置しています。彼らは、エンドツーエンドで全体のアプリが機能することを証明することを目指していません。彼らは、ブラウザレベルテストやデバイスレベル検証パスが必要になる前に、ローカルなレグレスションを迅速にキャッチするための高速な層です。 Reactチームが頻繁にリリースする場合、信頼性は、この労働の分割によって得られます。ユニットテストはローカルなレグレスションを迅速にキャッチします。統合テストはシームズを検証します。エンドツーエンドテストはクリティカルパスを確認します。ユニット層をスキップすると、すべての下流のスローライターは、過度に負担する必要があります。.
Reactのモダンなテスト環境を設定する
脆弱なテスト環境は、単一のアサーションを書く前にフレイクテストを生み出します。多くの開発者は、Jest、jsdom、またはReactを非難しますが、実際の問題は、ローカルマシンとCI間で一貫した構成が欠けていることです。解決策は、環境を面白くなくすることです。面白くないことは、ここでは良いことです。
クリーンなワークスペース。コンピュータモニターはReactユニットテストを表示し、__CAPGO_KEEP_0__エディターで表示されます。

__CAPGO_KEEP_1__エディターで
現代のReactアプリケーション、特にViteで作成されたもののベースライン設定には、以下が含まれるべきです。
- テストランナー: Jestは、古いReactコードベースやエンタープライズCIスタックでよく使用されます。
- ブラウザのような環境:
jsdomコンポーネントテストでDOM出力をレンダリングするのに役立ちます。 - テストライブラリのユーティリティ:
@testing-library/reactそして@testing-library/jest-dom - 単一の設定エントリポイント: マッチャーとグローバルモックを登録するファイル
Reactのテストガイドラインが強調する主なワークフローは単純です: jsdom-backed環境でコンポーネントをレンダリングし、セレクターでUIをクエリし、 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 のユニットテストガイド は、チーム間の情報交換に役立ちます。
スイートが依存するセットアップファイルを追加します
適切な 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は厳格な設定で実行すると、merge後に驚く失敗が発生します。 スクリプトを明示的に:
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:ci": "jest --runInBand --coverage"
}
}
新しいチームメンバーが同じ基準を早く取得するのに役立つ短いウォークスルーを提供します:
最も影響力のあるセットアップの選択は、デフォルトの規則を守ることです。 アリースを設定ファイルに、環境モックを1つのセットアップファイルに、可能な限り軽い環境でUIテストを行い、純粋なユーティリティ用に軽い環境を使用します。 各個のテストが必要とするカスタム動作が少ないほど、システムの信頼性が高まります。 jsdom 意味のあるコンポーネントテストの書き方
組織はテストを書くことが問題ではありません。 6か月後でも意味のあるテストを書くことが問題です。
Reactコンポーネントのユニットテストの標準パターンはまだ正しいままです:
コンポーネントをレンダーし、ユーザー中心のセレクターでUIをクエリし、イベントをトリガーし、結果のDOMの変更をアサートする 実装詳細である状態やプロップスからテストを守ることを目的としたものです。Reactテストガイド Reactテストガイド. パターンを適切に制限する鍵はどこにある?
ユーザーがアコーディオンを使用するようにテストしてください
基本的なコンポーネントを取り入れてください。ボタンとタイトルを表示します。パネル コンテンツは非表示で始まります。ボタンをクリックするとコンテンツが表示され、可視性の状態が更新されます。 Accordion いくつかの便利なテストのための、十分な動作が得られます:
初期レンダリングではタイトルが表示されますがコンテンツは表示されません。
- トリガーをクリックするとコンテンツが表示されます。
- 再度クリックすると折り畳まれます。
- 可視性の属性は表示状態を反映しています。
- 最後の点はよく見落とされがちです。コンポーネントが使用する、または役割に基づく構造を確認してください。実装の詳細ではありません。ユーザー向けの契約の一部です。
最も優れたコンポーネントのテストは、受けたいことのないバグレポートのように読みます。 aria-expanded, aria-controls__CAPGO_KEEP_0__
__CAPGO_KEEP_0__
__CAPGO_KEEP_0__
React Testing Libraryにはいくつかのクエリスタイルが用意されていますが、互換性はありません。間違った選択肢を選択すると、テストが雑になり、誤解を招くことになります。
| クエリタイプ | 要素が見つかった場合 | 要素が見つからない場合 | 使用例 |
|---|---|---|---|
getBy |
要素がすぐに返されます | エラーがすぐに投げられます | ボタンやヘッダーがすでに画面上にあることを確認します |
queryBy |
要素がすぐに返されます | 結果 null |
非表示のコンテンツがインタラクション前に存在しないことを確認します |
findBy |
Resolves when the element appears | Rejects after waiting | Assert async-loaded content appears after a fetch or delayed update |
A simple mental model helps:
- Use
getByfor things that must already exist. - Use
queryByfor things that must not exist yet. - Use
findBywhen the UI changes later.
If a test starts with findBy for everything, it usually means the author isn’t sure when the component updates. That uncertainty becomes flakiness later.
__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 これらのテストは、メンテナンスを追加するのではなく、信頼性を高めるものです。
コンポーネントテストを強くする習慣があります。
- ロールベースのクエリを優先してください。 ボタン、ヘッダー、ダイアログ、警告、入力フィールドは、通常はロールで見つけるべきです。
- 各テストを狭くしてください。 ユーザーが見える動作ごとにテストを実行すると、エラーが読みやすくなります。
- テストの名前は結果に基づいてください。 “updates aria-expanded when opened” is much more useful than “works correctly.”
__CAPGO_KEEP_0__
カスタムホークとアプリケーションロジックのテスト
Reactアプリケーションでは、重要な動作がコンポーネント外に隠されています。Stateの移行はホーク内にあります。検証とフォーマットはヘルパー関数内にあります。データの形成はレンダリングされる前に発生します。コンポーネントのみをテストすると、生産環境の動作を破壊する可能性のある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 };
}
そのテストは、パブリック契約に焦点を当ててください:
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または機能原子を構築している場合、このパターンは非常に重要です。ホークはアプリケーション、デザインシステム、または内部ツール間で共有されるインターフェイスになります。商用意図で再利用可能な動作を設計している場合、 ホークのためのリソース 機能を製品化された構築ブロックとしてではなく、実装の詳細としてフレームすることができます。
純粋な論理は、テストで純粋に残すべきです。
すべてが、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 のツールはオーバーヘッドを追加します。ビジネスロジックのテストは、小さく、速く、関数を検証する近くに保ちましょう。
実用的で分割されたアプローチがうまくいきます。
- Hook: 必要な場合にのみ、&、& wrapper providers を使用してください。
renderHook,act()ユーティリティ: - Utilities: DOMを使用せずにJestを使用してください。
- 状態を保持する横断的ロジック: コンポーネントテストがロジックのアサーションを多く含むようになると、テストが複雑になります。ロジックをテスト可能なヘルパーに引き出して、コンポーネントテストが綺麗になり、ロジックテストが速くなります。
チームは、ロジックのアサーションが下のレベルに属しているのに、コンポーネントテストに多く含めることがよくあります。ロジックを外に出すと、2つの利点が得られます。コンポーネントテストが綺麗になり、ロジックテストが速くなります。
高度な技術のマスター MockingとAsync
ほとんどのReactのテストスイートは、依存関係の境界と時間に関連する2つの場所で破損します。タイミングの非同期性などの環境またはリソースに関連する問題が46.5%のテストの不安定性を引き起こしているという分析があります。
このReactの単体テスト分析では、 Reactアプリでは、状態の遷移、遅延したレンダリング、ネットワークドライブのUI、テストが決定的に待つのではなく、推測するテストに直接対応します。 Mocking Dependencies versus Asynchronous Testingの比較表を示します。 高度なReactテスト技術の比較表、Mocking DependenciesとAsynchronous Testingに特に焦点を当てています。高度なReactテスト技術の比較表、Mocking DependenciesとAsynchronous Testingに特に焦点を当てています。

境界を模倣せよ、すべての層ではない
最速で誤解を招くテストを書く方法は、半分のコンポーネントツリーをモックし、次に自分のモックが機能したことを確認することだ。
アカウントデータを取得するコンポーネントの場合、ネットワーククライアントまたはAPIモジュールをモックする。ホック、子要素コンポーネント、ローディングスピナー、3つのユーティリティ関数をモックしない。テストが実際に隔離が必要な場合は除く。
使用するルールセットを指定:
- 外部サービスをモックする: HTTPクライアント、アナリティクス、ブラウザのみAPI、ネイティブブリッジ
- 不安定なプラットフォームAPIをモックする:
matchMediaタイマー、Electronプレロードインターフェイス、Capacitorプラグイン(JavaScriptDOMで利用できない場合) - デフォルトでは自分の内部をモックしないようにする: カスタムホック、シンプルな子要素、ローカルユーティリティ
すべての難しい部分が偽物に置き換えられた場合にテストが通ったら、リリースの信頼性が高まることはない。
ランナーAPIの例とパターンを提供したいチーム向けのCapgo テストチュートリアル Capgoは、特にReactを学習した開発者がテストメカニズムをまだ知らない場合に、実用的なリファレンスライブラリです。
タイミングが曖昧な場合、非同期テストは失敗します。
非同期テストの失敗は、通常、次の3つの間違いから来ます。
- テストが早すぎます。
- テストが任意のタイマーで待機しています。
- コンポーネントが更新される回数が1つだけですが、テストは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 __CAPGO_KEEP_0__
__CAPGO_KEEP_0__のテストでは、タイマーの動作を明示的にテストし、偽のタイマーを使用していない限り、__CAPGO_KEEP_0__が実行されます。 act() Reactのテスト環境では、更新の意味合いを尊重することが期待されています。
Testing Libraryはこれらの問題の多くを処理しますが、状態を手動で操作したりタイマーを進めたりする場合は、更新がフラッシュするタイミングを考慮する必要があります。
どのモッキングツールを使用するかを知っておく
| 異なるモッキングツールは、異なる問題を解決します: | ツール | 最適な使用方法 |
|---|---|---|
jest.fn() |
一般的な誤用 | スタンドアロンで偽のコールバックまたはインジェクションされた関数を使用する |
jest.spyOn() |
単にコールバックが必要な場合に、モジュール全体を置き換える | 実際のオブジェクトまたはモジュールの1つのメソッドを観察またはオーバーライドする |
jest.mock() |
モジュール依存性をインポート境界で置き換える | デフォルトで大規模モジュールをモックし、意味のある動作を失う |
例のヘルプ:
- Reach for
jest.fn()コンポーネントがonSubmitプロパティを受け取る場合に使用します。 - Use
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.
エラー パス テストは、現代の React の多くのガイドで扱われていない高度な領域です。エラー バウンダリー、遅延した状態の変更、非同期のフォールバック UI に対して、最初のクラス テストが必要です。子要素が例外を投げた場合、フォールバック UI を確認します。要求が失敗した場合、表示される回復状態を確認します。ロード中のボタンが無効になっている場合、も同様に確認します。ユーザーが思い出すのはそのようなバグです。
targetLanguage":"Japanese",
protectedTokens":["Cloudflare","Capacitor","GitHub","Capgo","code","API","SDK","CLI","npm","bun"]
,

カバレッジ目標を達成しても、重要なレグレッションを逃すことがある。浅いアサーション、広いスナップショット、内部モックで構成されたテストスイートは、安全性の印象を与えながら、メンテナンスコストを高める。",
品質テストの利点と高量テストスイートのメンテナンスオーバーヘッドを比較するインフォグラフィック。",
カバレッジは地図、目標ではない。",
カバレッジレポートは、次の質問に答える場合にのみ有用である。重要なパスが保護されていないものは何ですか?",
- 開発者を、重要なパスを保護する必要があるものにテストさせるのではなく、単にパーセンテージを上げるために、無関係なラッパー、静的マークアップ、または一行のパススルー ファイルをテストさせるのではないか?", カバレッジを発見ツールとして扱う。認証状態、請求アクション、機能フラグ、または更新の促進がテストされていない場合、それは信号である。プレゼンテーショナル アイコン コンポーネントがテストされていない場合、それは通常ではない。",
- 健康的なレビューの質問は単純である。テストはリリースリスクを減らすか?", はい:","テストはユーザーに視覚化される動作を検証する。",
- No: 実装の詳細を明らかにしたり、別のテストの値を重複したりすることはない。
何をユニットテストしない?
多くのReactガイドでは、欠陥について十分に時間を費やしていない。 そのギャップは重要である。 それほどモックを多くすることや、実装詳細のテストを多くすることは、ユーザー体験が壊れるのに対して、テストがパスするような、脆弱なテストスイートを作ることになる。 これは、BrowserStackのReactにおける何をテストしないかのガイドで指摘されている。 以下のパターンをスキップまたは厳しく制限する:.
内部状態のアサーション:
- 直接テストしない。 できるだけテストできる場合は、パネルが開いたかどうかをテストする。 フレームワークの動作:
isOpenReactが効果を呼び出したかどうかをテストしない。 効果が変更した結果をテストする。 - 第三者ライブラリの内部: __CAPGO_KEEP_0__
- __CAPGO_KEEP_0__ 日付ピッカーまたはルーターと統合テストを行ってください。ライブラリのレンダリングロジックではありません。
- 過度に分割された単位: __CAPGO_KEEP_0__のすべての子孫とヘルパーをモックした場合、意味のある動作をテストできなくなっているかもしれません。
テストが機能しないまま、リファクタリングをブロックし、実行時エラーを検出できなくなるテストは、欠陥のあるテストです。
境界所有という便利なヒューリスティックは、codeが所有するものをテストすることです。React、ブラウザ、または成熟したライブラリがすでに所有しているものは、統合層が契約を変更しない限りテストしないでください。
スナップショットの役割と欠点
スナップショットは無駄ではありません。ただし、誤用しやすいものです。
構造的な差分が意味をなす、安定したシンプルな出力を持つコンポーネントでは、スナップショットをsparingly使用してください。インタラクティブまたは高度に動的なコンポーネントでは、ノイズになります。開発者は読まず、自動的に更新するようになります。
代替案がよくあります:
- 条件付きレンダリングの場合、指定されたキーテキストの存在または非存在を確認してください。
- 視覚的な状態の変更の場合、重要な役割、ラベル、または属性を確認してください。
- エラーとフォールバックの場合、実際のメッセージまたは警告領域を確認してください。
あなたのチームがユニットテストのより広い品質プロセスを必要とする場合、堅固な相棒は、テスト、リリースチェック、ロールバック計画を一つのシステムとして扱うアプリケーション品質保証フローです。 アプリケーション品質保証フロー ユニットテストのより広い品質プロセスを必要とするチームの場合、テスト、リリースチェック、ロールバック計画を一つのシステムとして扱うアプリケーション品質保証フローが必要です。
CI/CD パイプラインにテストを統合する
開発者用ラップトップ上でしか実行しないテストスイートは、提案ではなく制御ではありません。
テストスイートが稼動するのは、プルリクエストごとに同じチェックをクリーンな環境で実行し、チェックが失敗するとマージをブロックする時です。

プルリクエストは毎回同じゲートをトリガーするべきです。
React のユニットテストを安全な網掛けとして機能させるには、CI にいくつかの基本的なものが必要です。
- プルリクエストごとに実行する
- ロックファイルから依存関係をインストールする
- 毎回同じテストコマンドを使用する
- テストエラーで失敗することを速やかに検出する
- テストが成功した後のみアーティファクトを公開する
このプロダクトの中心です。 継続的デプロイの実践をアプリチームに導入リリース前に自信をつける、リリース後に。
Capgoのチームにとって、シンプルな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
この機能は素晴らしいものではありません。それが素晴らしいことです。最も強力なパイプラインは、通常、最も驚くことのないものです。
Why this matters more for Capacitor and Electron
Cross-platform React apps carry more release risk than browser-only apps because the same UI code often ships in different containers with different runtime assumptions.
パイプラインがどのように役立つかを示す例がいくつかあります。
- Capacitor アプリケーション: Web code はローカルでは動作するかもしれませんが、プラグインブリッジ、オフライン状態、またはアプリライフサイクルにおけるエッジケースの変更がパッケージング後に動作を変える場合に失敗する可能性があります。
- Electronアプリ: レンダラー コンポーネントは、プレロード API、ウィンドウ メッセージング、またはデスクトップ専用の状態に依存する可能性があります。これらは、意図的にモックされていない場合、平凡なブラウザ テストでは存在しません。
- 共有リリーストレイン: 1 つの不正なバンドルが、デプロイメント プロセスが厳密にパブリケーションをゲートしない場合、複数のターゲットに影響を与える可能性があります。
なぜなら、ユニット テストはパッケージング ジョブの前に実行されるべきであり、パッケージング ジョブはディストリビューション ジョブの前に実行されるべきだからです。各ステージはリスクを狭めます。ユニット テストはローカルなレグレッションを迅速に検出します。プラットフォーム パッケージングは環境の仮定を検証します。最終的なリリースの信頼性は、手動の承認またはステージド ロールアウトで管理されます。
実践的なGitHub Actions ワークフロー
より成熟したパイプラインは、責任を分割します。
- テスト ジョブ: 高速なユニット テストとハック テスト
- ビルド ジョブ: テストが成功した後のみプロダクション ビルド
- パッケージ ジョブ: Capacitor 同期、Electron パッケージング、またはアーティファクト バンドリング
- リリースジョブ: 承認されたブランチまたはタグのみから公開
Electron アプリや Capacitor へのライブ更新を配信するチームにとって、リリースツールは重要です。そのワークフローにおける 1 つのオプションは、CapacitorJS と Electron アプリ用に署名 Web バンドルを公開し、ロールバックサポートとチャネルベースのロールアウト制御を備えた Capacitor です。実際には、React テストジョブは、ステージングまたはプロダクション配信に進む前に、Web バンドルが最初のハードゲートとして機能するのです。 Capgoチームが React を __CAPGO_KEEP_0__ または Electron を通じて配信している場合、リリースの安全性は、グリーンなローカルテストだけに依存していません。
__CAPGO_KEEP_0__
チームに、署名 Web アップデートを公開する方法、ロールアウトチャネルをターゲットにする方法、悪いバンドルをロールバックする方法を提供します。ストアのレビューを待つ必要がなく、CI パイプラインがすでにデプロイ前にパスする必要があるユニットテストを必要とします。
Capacitor Capgo __CAPGO_KEEP_0__