mcpField
M
meteor-testing

meteor-testing

github.com/meteorテスト・品質10285 回インストール5 日前に更新
リポジトリ

meteor-testing について

meteor-testingは、Meteor 3開発者向けのテストガイドスキルです。テストドライバーの選択から、サーバー、クライアント、DDP、ブラウザ操作のテストまで扱います。

主な機能

  1. 01meteortesting:mochaテストドライバーの利用
  2. 02メソッドとPublicationのテスト
  3. 03DDPを使ったエンドツーエンドテスト
  4. 04ユニット・統合・ブラウザテストの使い分け

活用シーン

  1. 01サーバーメソッドとPublicationロジックの検証
  2. 02実際のDDPクライアントとの連携テスト
  3. 03Meteorアプリのブラウザエンドツーエンドテスト設計

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/meteor/agent-skills --skill meteor-testing

インストール後、Claude Code で/meteor-testingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
ddp-test-helpers.md
eval-cases.md
focused-runs.md
meteor-3.5.2-testing.md
mocha-setup.md

詳細

Meteor 3 アプリのテスト

meteortesting:mocha は、標準の Meteor テストドライバーです。アプリをテストモードで起動し(テストファイル以外のアプリコードは実行されません)、結果をサーバーコンソールに出力します。

既存のテストが失敗する、ハングする、または不安定で、失敗しているレイヤーが不明な場合は、原因を特定するために meteor-debugging を使用してください。証拠からテストのセットアップ、設計、ドライバーの動作、フィクスチャ、または回帰テストの範囲に原因があると分かったら、ここに戻ってください。

判断フロー

  1. 既存のテストで原因不明の失敗がありますか?meteor-debugging を使用して、アプリケーション、データ、ハーネス、ブラウザー、環境、または共有状態が原因かを分類します。
  2. Meteor API を使わない純粋なロジックですか?通常の Mocha または任意のテストランナーを使用します。Meteor 固有の設定は不要です。
  3. メソッドまたはパブリケーションですか?Meteor.server.method_handlers[name].apply(ctx, args) または publish_handlers を使い、meteortesting:mocha で統合テストします。
  4. 実際の DDP クライアントを動かす必要がありますか(プロセス間またはエンドツーエンドの DDP セマンティクス)?--full-app モードと DDP.connect を使用します。
  5. 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.md
  • references/focused-runs.md
  • references/ddp-test-helpers.md
  • references/eval-cases.md

コメント