プラグインのチェック、アプリへの登録、動作するユーザーの操作の流れは、それぞれ別の結果です。変更が影響する境界を確認します。まずプラグイン、次にアプリでの動作、公開する場合はパッケージの内容です。
エージェントを使う場合
このプラグインに動作のテストを追加し、成功、不正な入力、アクセスの境界を扱ってください。
本番の実装と実際のプラグインの宣言を使ってください。
コンポーネント、API、アプリのチェックを区別し、プラグインのチェックとアプリのビルドを実行して、
どのユーザーの操作の流れを確認し、どれを確認していないかを報告してください。テストの置き場所
ジェネレーターは、選んだ機能に合わせてテストと Vitest の設定を用意します。1 つのケースを直すためにすべてのテストをブラウザーの環境に移すのではなく、Node と jsdom の境界を保ってください。
| ディレクトリ | 環境とツール | 対象 |
|---|---|---|
tests/server/ | Node、@nocobase/app-testing/server | API、サービス、Server への組み込み |
tests/database/ | Node、同じ Server のテストの入口 | マイグレーション、メタデータ、実際のデータベースの操作 |
tests/client/ | jsdom、@nocobase/app-testing/client | コンポーネント、翻訳、操作、リクエストの取り決め |
tests/cli/ | Node、@nocobase/app-testing/cli | 引数、出力、エラー、コマンドの動作 |
| アプリのブラウザーのテスト | アプリの既存のブラウザーの設定 | サインイン、ナビゲーション、再読み込み、実際の API とのやり取り |
@nocobase/app-testing は devDependencies に宣言します。生成された依存関係とインストールされた公開のエクスポートを確認してください。/database や /playwright の入口はありません。
本番の実装を動かす
ルートと HTTP の API は、実際の提供内容の createRouter() を呼び出して、成功、不正な入力、API のドキュメントを確認します。データベースのリソースとマイグレーション は、実際の Migrator で適用、ロールバック、再適用を行います。コマンドラインの拡張 は、bindAppCommand() と runAppCommand() でコマンドの出力を確認します。
テストの中でルート、サービス、モデルを実装し直し、その複製をテストすることは避けてください。
コンテナだけを使う Provider は、完全な狭いインターフェース { container: ServiceContainer } を受け取れます。不完全なオブジェクトをアプリ全体にキャストせずに、実際のコンテナのフィクスチャーを使えます。認証、データベース、ライフサイクルには、アプリのフィクスチャーを使い、本番のプラグインを登録します。
Client のテストの境界
renderWithApp() は実際の Client のプラグインを登録し、サービス、API のクライアント、ルーティング、多言語化を提供します。MemoryRouter を追加しないでください。ルートのツリーを動かす場合も、実際の宣言からコンポーネントをレンダリングします。ページ、ルート、メニュー を参照してください。
ネットワークの境界でレスポンスを差し替えるには answerApi() を使います。メソッドと API の相対パスの両方を照合してください。すべてのリクエストに成功を返すと、パスの綴りの誤りや想定外の呼び出しが隠れます。
次は既存のページのテストのパターンです。Page とプラグインのファクトリーは実際のモジュールに置き換えてください。
const calls: { method: string; path: string }[] = [];
await renderWithApp(<Page />, {
plugins: [plugin()],
locale: 'zh-CN',
fetch: answerApi((call) => {
calls.push({ method: call.method, path: call.path });
if (call.method === 'GET' && call.path === 'announcements') {
return { data: [], meta: { total: 0 } };
}
return new Response(null, { status: 404 });
}),
});
expect(await screen.findByText('暂无公告。')).toBeInTheDocument();
expect(calls).toEqual([{ method: 'GET', path: 'announcements' }]);answerApi() は、ハンドラーの例外を HTTP 500 のレスポンスに変えます。ページのエラーの UI がアサーションの失敗を飲み込まないよう、アサーションはハンドラーの外に置きます。非同期の UI は findBy... や waitFor() で待ちますが、操作は再試行される waitFor() のコールバックの外に置きます。読み込み中の状態をテストするには、固定の待ち時間ではなく、レスポンスの完了を制御します。
アクセスとクリーンアップ
匿名の呼び出し元、サインインしているが拒否される呼び出し元、許可された呼び出し元を別々にテストします。テナントやレコードの範囲がある機能では、ユーザーをまたぐケースとレコードをまたぐケースも必要です。Client のボタンを隠しても、Server での書き込みは保護されません。
フィクスチャーは、自分が所有するデータベース、一時ディレクトリ、購読、アプリのインスタンスをクリーンアップします。直接作成したリソースには finally を使います。テストを通常の開発用のデータベースに向けたり、テストを通すためにエラーのチェックを無効にしたりしないでください。
関係する範囲を実行する
notice-api の場合、アプリのルートで次を実行します。
pnpm --filter @nocobase/app-plugin-notice-api exec vitest run tests/server/routes.test.ts
pnpm --filter @nocobase/app-plugin-notice-api check
pnpm buildまず対象を絞ったテストを、次にプラグインの check と、影響を受けるアプリのチェックを実行します。マイグレーションを変更した場合、データベースの統合テストは順番に実行します。文言だけの変更では、リポジトリ全体のテストは必要ありません。
作成時に --no-install を使った場合は、先にインストールします。--passWithNoTests で成功しても、テストできたことにはなりません。実際に実行されたファイルとケースを確認してください。
引き渡しの前に
| 変更 | 追加の確認 |
|---|---|
| Client のページ | サインインしたうえでのアクセス、URL の直接入力、再読み込み、ブラウザーの履歴 |
| Server の API | アプリのマウントの接頭辞、認証、認可、エラー、API のドキュメント |
| マイグレーション | 新規のインストール、古いデータからのアップグレード、コンパイル後のチェックサム |
| CLI | 登録されたアプリのコマンドとデプロイ環境のコマンド |
| 公開のエクスポートや公開 | 公開の入口からの利用。tarball に含まれる dist、リソース、スキル |
実行したコマンドと結果を正確に報告し、残っている境界も含めます。たとえば、「コンポーネントとルーターのテストは成功し、アプリもビルドできたが、サインインしたブラウザーでの操作の流れはまだ実行していない」のように書きます。plugin inspect は静的な登録だけを確認するもので、動作の検証の代わりにはなりません。