meteor-testing について
meteor-testingは、Meteor 3開発者向けのテストガイドスキルです。テストドライバーの選択から、サーバー、クライアント、DDP、ブラウザ操作のテストまで扱います。
主な機能
- 01meteortesting:mochaテストドライバーの利用
- 02メソッドとPublicationのテスト
- 03DDPを使ったエンドツーエンドテスト
- 04ユニット・統合・ブラウザテストの使い分け
活用シーン
- 01サーバーメソッドとPublicationロジックの検証
- 02実際のDDPクライアントとの連携テスト
- 03Meteorアプリのブラウザエンドツーエンドテスト設計
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ meteor/ agent-skills --skill meteor-testingインストール後、Claude Code で/meteor-testingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/ddp-test-helpers.mdeval-cases.mdfocused-runs.mdmeteor-3.5.2-testing.mdmocha-setup.md詳細
Meteor 3 アプリのテスト
meteortesting:mocha は、標準の Meteor テストドライバーです。アプリをテストモードで起動し(テストファイル以外のアプリコードは実行されません)、結果をサーバーコンソールに出力します。
既存のテストが失敗する、ハングする、または不安定で、失敗しているレイヤーが不明な場合は、原因を特定するために meteor-debugging を使用してください。証拠からテストのセットアップ、設計、ドライバーの動作、フィクスチャ、または回帰テストの範囲に原因があると分かったら、ここに戻ってください。
判断フロー
- 既存のテストで原因不明の失敗がありますか?
meteor-debuggingを使用して、アプリケーション、データ、ハーネス、ブラウザー、環境、または共有状態が原因かを分類します。 - Meteor API を使わない純粋なロジックですか?通常の Mocha または任意のテストランナーを使用します。Meteor 固有の設定は不要です。
- メソッドまたはパブリケーションですか?
Meteor.server.method_handlers[name].apply(ctx, args)またはpublish_handlersを使い、meteortesting:mochaで統合テストします。 - 実際の DDP クライアントを動かす必要がありますか(プロセス間またはエンドツーエンドの DDP セマンティクス)?
--full-appモードとDDP.connectを使用します。 - UI フローまたはブラウザー操作ですか?決定的なテスト設定で通常のアプリを起動し、Playwright または Cypress を使ってテストします。ブラウザーフローでアプリのテストモジュールを読み込む必要がある場合に限り、
meteor test --full-appを使用します。
セットアップ
meteor add meteortesting:mocha
meteor npm install --save-dev @types/mocha
// package.json
{
"scripts": {
"test": "TEST_WATCH=1 meteor test --driver-package meteortesting:mocha",
"test:ci": "meteor test --once --driver-package meteortesting:mocha",
"test:full": "meteor test --full-app --driver-package meteortesting:mocha"
}
}
テストモードの規則:
- 通常のテストモードでは
*.test[s].*ファイルと*.spec[s].*ファイルを先行して読み込みます。一方、通常のアプリケーションコードはテストからインポートされた場合にのみ読み込まれます。 - ファイルの検出では
tests/ディレクトリは無視されます。meteor.testModuleを設定すると、指定されたエントリーモジュールとインポート先が読み込まれます。 --full-appでは通常のアプリに加え、*.app-test[s].*ファイルと*.app-spec[s].*ファイルを先行して読み込み、Meteor.isAppTestを設定します。
Meteor 3.5.2 の Rspack における full-app/TLA の動作、親ディレクトリの private の検出失敗、および Meteor 3.6-beta.0 で修正された jQuery ハーネスの回帰については、リリース固有のテストセットアップをお読みください。バージョン固有の修正を適用する前に、解決済みのパッケージとスイート数を確認してください。
既存のテストに対象を絞る場合は、.meteor/versions でインストール済みのドライバーを確認したうえで、MOCHA_GREP などのサポートされているドライバーフィルターを優先してください。.only は一時的な場合に限り使用します。これらは登録済みのテストを選択しますが、ほかのテストモジュールの評価は防ぎません。読み込みそのものが干渉を引き起こす場合は、meteor.testModule を確認し、エントリーポイントのインポートを絞り込む前に references/focused-runs.md をお読みください。一時的に加えたフォーカスやインポートの変更はすべて元に戻し、その後、影響するスイートを通常どおり実行してください。設定済みのエントリーポイントのパスはプロジェクトから読み取ってください。パス、スクリプト、ポート、ヘルパーを作り上げないでください。
3.6-beta.3 の Rspack の ignore 例外や、別個のレガシーテストエントリーについては、アーキテクチャと ignore 境界を使用してください。選択した各プログラムで想定されるスイートを確認してください。モダン側で終了コードが 0 の実行結果は、レガシー側のカバレッジを示す証拠にはなりません。
メソッドのテスト(サーバーサイド)
import assert from "node:assert/strict";
import { Meteor } from "meteor/meteor";
import { Items } from "/imports/api/items";
if (Meteor.isServer) {
describe("items.add", function () {
beforeEach(async function () {
await Items.removeAsync({});
});
it("inserts when authed", async function () {
const _id = await Meteor.server.method_handlers["items.add"].apply(
{ userId: "u1" },
[{ title: "x", qty: 1 }],
);
const doc = await Items.findOneAsync(_id);
assert.equal(doc.title, "x");
});
it("rejects when unauthed", async function () {
await assert.rejects(() =>
Meteor.server.method_handlers["items.add"].apply({ userId: null }, [{}]),
);
});
});
}
.apply(context, argsArray) がドキュメントに記載された形式です。Meteor.server.method_handlers[name] は登録済みメソッドの実装です。userId(および必要に応じて unblock、connection など)を含むスタブの this を渡してください。
パブリケーションのテスト(サーバーサイド)
if (Meteor.isServer) {
describe("items.mine publication", function () {
it("only ships the subscribing user's items", async function () {
await Items.removeAsync({});
await Items.insertAsync({ _id: "a", ownerId: "u1" });
await Items.insertAsync({ _id: "b", ownerId: "u2" });
const cursor = await Meteor.server.publish_handlers["items.mine"]
.apply({ userId: "u1" }, []);
const docs = await cursor.fetchAsync();
assert.deepEqual(docs.map((d) => d._id), ["a"]);
});
});
}
低レベルの this.added/this.changed API を使用するパブリケーションは、--full-app モード(次のセクション)で実際の DDP クライアントを使ってテストしてください。
パブリッシュハンドラーを直接呼び出した場合は、必ずその結果を await してください。一般的なハンドラーはカーソルをすぐに返し、非同期ハンドラーはカーソルの Promise を返します。
エンドツーエンド DDP テスト(--full-app モード)
import { DDP } from "meteor/ddp-client";
import { Mongo } from "meteor/mongo";
import { Tracker } from "meteor/tracker";
const conn = DDP.connect(Meteor.absoluteUrl());
const RemoteItems = new Mongo.Collection("items", { connection: conn });
function ready(sub) {
return new Promise((resolve) => {
const computation = Tracker.autorun((c) => {
if (sub.ready()) {
c.stop();
resolve();
}
});
});
}
const sub = conn.subscribe("items.mine");
await ready(sub);
const docs = RemoteItems.find().fetch();
meteor test --full-app --driver-package meteortesting:mocha で実行します。
クライアントのユニットテスト(Minimongo)
if (Meteor.isClient) {
describe("Items minimongo", function () {
beforeEach(function () { Items.remove({}); });
it("filters by ownerId", function () {
Items.insert({ _id: "a", ownerId: "u1" });
Items.insert({ _id: "b", ownerId: "u2" });
assert.equal(Items.find({ ownerId: "u1" }).count(), 1);
});
});
}
クライアントテストは、ドライバーが起動するブラウザーで実行されます。TEST_BROWSER_DRIVER=puppeteer の場合、ブラウザーはヘッドレス Chromium で、結果はサーバーコンソールに返されます。
サーバーのみの実行が成功しても、クライアントのカバレッジが完了したとは見なさないでください。ブラウザーが接続されていない場合、ドライバーはメッセージを出力します。CI で TEST_BROWSER_DRIVER を設定し、クライアントテストの件数が表示されることを確認してください。
ブラウザー E2E
テストに Meteor の app-test モジュールが必要な場合を除き、通常のアプリケーションに対して Playwright または Cypress を実行してください。サーバーのコマンドは、追跡対象で機密情報を含まない設定フィクスチャ、または完全に文書化されたテスト用環境変数を使い、クローン直後の状態から実行できる必要があります。無視対象の開発者用設定ファイルを指定しないでください。
少なくとも、変更を伴う一連のフローを1つと、拒否されるサーバーアクションを1つテストしてください。基本的なページタイトルの確認では、非同期メソッドスタブ、認可、パブリケーションの準備状況を検証できません。
アンチパターン
- すぐに Jest を使わないでください。Jest は Meteor のビルドシステムを理解しません。
meteortesting:mochaを使ってください。 - Mongo をモックしないでください。クリーンな DB に対して実際のドライバーを実行してください。
if (Meteor.isServer) { ... }ガードを忘れないでください。サーバーテストがブラウザーハーネスで実行されると失敗します。beforeEachのクリーンアップを省略しないでください。テスト間で状態が残ります。beforeEachの失敗を再スローせずに捕捉してログに記録しないでください。そのままではテストが不明な状態で実行され、誤解を招くアサーションが報告される可能性があります。- 拒否されたメソッドの結果について、データベースの事後条件だけをアサートしないでください。Promise が期待される
Meteor.Errorで拒否されることも確認してください。 Meteor.userIdやその他のグローバルを置き換えた場合は、afterEachで元に戻してください。- 非同期テストコードで、コールバック付きの
Meteor.callを使わないでください。Meteor.callAsyncを使うか、method_handlersを直接アンラップしてください。
関連項目
references/mocha-setup.mdreferences/focused-runs.mdreferences/ddp-test-helpers.mdreferences/eval-cases.md