Jasmine 4.0 へのアップグレード

概要

要約:4.0 にアップグレードする前に、3.99 にアップデートし、すべての非推奨警告を修正してください。

Jasmine 4.0 はほとんどのユーザーにとって簡単なアップグレードになると考えています。しかし、いくつかの破壊的な変更が含まれており、アップグレードするためにコードを変更する必要がある人もいます。このガイドの手順に従うことで、スムーズなアップグレードを最大限に実現できます。

Jasmine 4.0 の破壊的な変更には、Jasmine の構成方法の変更、カスタムマッチャーと非対称等価性テスターの変更、一般的なエラーの検出の改善、およびシステム要件の変更が含まれます。破壊的な変更の完全なリストは、jasmine-corejasmine のリリースノートにあります。

目次

  1. システム要件
  2. Jasmine 3.99 を使用して互換性の問題を検出する
  3. Ruby および Python ユーザーの移行パス
  4. jasmine パッケージの公開インターフェース
  5. ESモジュールサポート
  6. 終了コードの変更
  7. beforeAll および beforeEach の失敗の処理方法の変更
  8. レポーターインターフェースの変更
  9. 特定の非推奨警告を解決するためのヒント

システム要件

以下の以前にサポートされていた環境は、現在はサポートされていません

Jasmine 4.0 は、これらの環境の一部でまだ動作する可能性がありますが、これらの環境に対するテストは行われなくなり、今後の 4.x リリースでの互換性を維持しようとすることはありません。奇数の Node バージョン(13.x、15.x、17.x)はサポートされておらず、動作する場合としない場合があります。特に、一部の 13.x バージョンは ES/CommonJS モジュールの相互運用に対するサポートが不完全で、Jasmine 4.0 を実行できません。

Jasmine 3.99 を使用して互換性の問題を検出する

Jasmine 3.99 では、4.0 で削除または互換性のない方法で変更された API を使用するほとんどのコードに対して非推奨警告が出力されます。4.0 にアップグレードする前に、3.99 にアップグレードし、すべての非推奨警告を修正することをお勧めします。通常どおり、直接依存している Jasmine パッケージをアップグレードする必要があります。jasmine NPM パッケージ、jasmine Rubygem、または jasmine Python パッケージを 3.99 にアップグレードすると、jasmine-core のバージョン 3.99 も取得できます。

jasmine-browser-runner を使用している場合は、依存関係に jasmine-core 3.99 を追加するだけです。

Ruby および Python ユーザーの移行パス

3.99 は、Ruby および Python 用の Jasmine の最終バージョンです。ほとんどのユーザーは、jasmine-browser-runner NPM パッケージに移行することをお勧めします。これは、jasmine Ruby gem および Python パッケージの直接の代替品です。headless Chrome や Saucelabs を含むブラウザーでスペックを実行します。また、jasmine gem ではサポートされていなかった Webpacker を使用する Rails アプリケーションでも動作します。

jasmine-browser-runner がニーズを満たさない場合は、次のいずれかが適合する可能性があります。

jasmine パッケージの公開インターフェース

jasmine-core パッケージとは異なり、jasmine パッケージには、バージョン 3.8 まで文書化されたパブリックインターフェースがありませんでした。4.0 以降、文書化されたパブリックインターフェースの一部ではないものはすべて、プライベート API とみなされ、いつでも変更される可能性があります。jasmine パッケージをプログラムで (つまり、require('jasmine') または import('jasmine') を実行するコードがある場合) 使用している場合は、コードをAPI ドキュメントと照らし合わせて確認してください。

ESモジュールサポート

バージョン 4 以降、jasmine パッケージは、動的な import() を使用してスペックやその他のファイルをロードすることをデフォルトとしています。これにより、.js 拡張子を持つ ES モジュールを構成なしで使用できます。バージョン 4.0.1 では、.jsx.coffee などの標準ではない拡張子のファイル読み込みが修正されているため、そのようなファイルがある場合は、少なくともそのバージョンをインストールしてください。

終了コードの変更

バージョン 4 より前は、jasmine コマンドは、完全に成功した場合以外は、ほぼすべてのシナリオでステータス 1 で終了しました。バージョン 4 では、さまざまな種類の失敗に対して異なる終了コードを使用します。ビルドまたは CI システムが特に終了コード 1 をチェックしない限り、何も変更する必要はありません (これは非常に珍しいことです)。0 を成功として扱い、それ以外をすべて失敗として扱うものは、引き続き動作します。

beforeAll および beforeEach の失敗の処理方法の変更

Jasmine 4 では、beforeAll および beforeEach の失敗の処理方法が異なります。この変更により、特定の異常なセットアップおよびティアダウンパターンで問題が発生する可能性があります。リソースをセットアップしたのと同じスイートでリソースをティアダウンする限り、変更を加える必要はありません。

beforeAll 関数が期待値の失敗以外の理由で失敗した場合、Jasmine 4 は、失敗した beforeAll と同じスイートで定義された afterAll 関数を除いて、スイート全体をスキップします。同様に、期待値の失敗以外の beforeEach の失敗は、後続の beforeEach 関数、問題のスペック、およびネストされたスイートで定義された afterEach 関数をスキップさせます。

// Unsafe. Test pollution can result because the afterEach won't always run.
describe('Outer suite', function() {
  beforeEach(function() {
    setSomeGlobalState();
    possiblyFail();
  });

  describe('inner suite', function() {
    it('does something', function() { /*...*/ });

    // This afterEach function should be moved up to the outer suite.
    afterEach(function() {
      cleanUpTheGlobalState();
    });
  });
});

レポーターインターフェースの変更

Jasmine 4.0 では、レポーターの specDone メソッドに渡されるオブジェクトdebugLogs フィールドが追加されます。スペックが jasmine.debugLog を呼び出し、さらに失敗した場合に定義されます。ほとんどのレポーターは、存在する場合は表示する必要があります。

Jasmine 4.0 は、以前のバージョンよりも jasmineDone イベントでエラーを報告する可能性が高くなります。これらのエラーを表示できないことは、カスタムレポーターによくあるバグです。トップレベル (つまり、describe 内ではない) で例外をスローする afterAll 関数を作成し、レポーターが表示されることを確認することで、レポーターをチェックできます。

特定の非推奨警告を解決するためのヒント

マッチャーのカスタム等価性テスターに関連する非推奨

3.6 より前は、カスタムマッチャーカスタム等価性テスターをサポートする場合は、カスタム等価性テスターの配列をマッチャーファクトリーの 2 番目の引数として受け入れ、MatchersUtil#equalsMatchersUtil#contains などのメソッドに渡す必要がありました。3.6 以降、マッチャーファクトリーに渡される MatchersUtil インスタンスには、現在のカスタム等価性テスターのセットが事前に構成されており、マッチャーがそれらを提供する必要はありません。Jasmine 4.0 以降、カスタム等価性テスターはマッチャーファクトリーに渡されず、MatchersUtil メソッドのパラメーターとしても受け入れられません。カスタムマッチャーを新しいスタイルに更新するには、マッチャーファクトリーから余分なパラメーターを削除し、MatchersUtil メソッドに渡すのをやめるだけです。

変更前

jasmine.addMatchers({
  toContain42: function(matchersUtil, customEqualityTesters) {
    return {
      compare: function(actual, expected) {
        return {
          pass: matchersUtil.contains(actual, 42, customEqualityTesters)
        };
      }
    };
  }
});

変更後

jasmine.addMatchers({
  toContain42: function(matchersUtil) {
    return {
      compare: function(actual, expected) {
        return {
          pass: matchersUtil.contains(actual, 42)
        };
      }
    };
  }
});

ライブラリ作成者への注意

上記の更新された形式は、Jasmine 3.6 以降とのみ互換性があります。古いバージョンの Jasmine との互換性を維持する場合は、単一の引数を取るマッチャーファクトリーを宣言し、arguments オブジェクトまたはレストパラメーター構文を使用して、カスタム等価性テスターの配列にアクセスすることで、非推奨警告を回避できます。次に、Jasmine 3.6 以降に存在する場合は、配列の deprecated プロパティをチェックしてから、渡します。

jasmine.addMatchers({
  toContain42: function(matchersUtil, ...extraArgs) {
    const customEqualityTesters = 
      extraArgs[0] && !extraArgs[0].deprecated ? extraArgs[0] : undefined;
    
    return {
      compare: function(actual, expected) {
        return {
          pass: matchersUtil.contains(actual, 42, customEqualityTesters)
        };
      }
    };
  }
});

「非対称一致の 2 番目の引数は MatchersUtil になりました。カスタム等価性テスターの配列として使用することは非推奨であり、将来のリリースでは機能しなくなります。」

3.6 より前は、カスタム非対称等価性テスターカスタム等価性テスターをサポートする場合は、asymmetricMatch の 2 番目の引数としてカスタム等価性テスターの配列を受け入れ、MatchersUtil#equalsMatchersUtil#contains などのメソッドに渡す必要がありました。3.6 から 3.99 までは、2 番目の引数はカスタム等価性テスターの配列と、それらが事前に構成されている MatchersUtil インスタンスの両方でした。4.0 以降では、適切に構成された MatchersUtil のみになります。非推奨警告を解決するには、提供された MatchersUtil を直接使用してください。

変更前

function somethingContaining42() {
  return {
    asymmetricMatch: function(other, customEqualityTesters) {
      return jasmine.matchersUtil.contains(other, 42, customEqualityTesters);
    }
  };
}

変更後

function somethingContaining42() {
  return {
    asymmetricMatch: function(other, matchersUtil) {
      return matchersUtil.contains(other, 42);
    }
  };
}

ライブラリ作成者への注意

上記の更新された形式は、Jasmine 3.6 以降とのみ互換性があります。古いバージョンの Jasmine との互換性を維持する場合は、2 番目の引数が MatchersUtil であるかどうか (たとえば、equals メソッドをチェックすることによって) を確認し、MatchersUtil でない場合は上記の古い形式に戻すことで、非推奨警告を回避できます。

グローバルで利用できなくなったマッチャーユーティリティに関連する非推奨

Jasmine 4.0 まで、静的な MatchersUtil インスタンスが jasmine.matchersUtil として、静的なプリティプリンターが jasmine.pp として利用可能でした。現在、これらは両方とも現在のスペックに固有の設定を持つため、静的なインスタンスを持つことはもはや意味がありません。jasmine.matchersUtil を使用する代わりに、次のいずれかの方法で現在の MatchersUtil にアクセスしてください。

jasmine.pp を使用する代わりに、上記のいずれかの方法で matchersUtil にアクセスし、その pp メソッド を使用してください。

また、オブジェクトに jasmineToString メソッドがある場合、pp が最初のパラメータとして渡されます。

ライブラリ作成者への注意

matchersUtil は、バージョン 2.0 以降のすべてのバージョンでマッチャーファクトリーに、バージョン 2.6 以降のすべてのバージョンで非対称等価性テスターに提供されています。matchersUtil#pp は 3.6 で導入され、これはプリティプリンターが jasmineToString に渡された最初のバージョンでもあります。3.6 より古い Jasmine バージョンと互換性のある方法でプリティプリントする必要がある場合は、matchersUtil インスタンスまたは jasmineToString に渡されたパラメータで pp メソッドを確認し、存在しない場合は jasmine.pp にフォールバックできます。

2つの形式の非同期処理の混在に関する非推奨

Jasmine は複数の形式の非同期処理を組み合わせた関数をサポートしたことはなく、それらは一貫したまたは明確に定義された動作をしませんでした。Jasmine 4.0 は、そのような関数を検出するたびにスペックの失敗を発行します。FAQ では、この変更の理由とスペックを更新する方法について説明しています

done を複数回呼び出すことによる非推奨

Jasmine は歴史的に複数の done 呼び出しを許容していましたが、これにより隠蔽されたバグは混乱の一般的な原因であることが判明しました。Jasmine 4 は、非同期関数が done を複数回呼び出すたびにエラーを報告します。FAQ では、この変更の理由とスペックを更新する方法について説明しています

jasmine.clock().tick() へのリエントラント呼び出しによる非推奨

4.0 より前は、setTimeout または setInterval ハンドラー内から jasmine.clock().tick() を呼び出すと、Date によって公開される現在時刻が過去に戻ることがありました。4.0 以降、現在時刻は tick() へのリエントラント呼び出しの場合でも減少しなくなります。これは、タイマーハンドラー内から tick() を呼び出し、現在の時刻も気にしているスペックの動作に影響を与える可能性があります。

影響を受けるスペックが現在の時刻を気にしていない場合、または 4.0 にアップグレードした後にそれらを確認する予定の場合は、この警告を無視できます。ただし、影響を受けるスペックをタイマーハンドラー内から tick() を呼び出さないように変更することをお勧めします。

変更前

it('makes a reentrant call to tick()', function() {
  const foo = jasmine.createSpy('foo');
  const bar = jasmine.createSpy('bar');

  setTimeout(function() {
    foo();
    jasmine.clock().tick(9);
  }, 1);

  setTimeout(function() {
    bar();
  }, 10);

  jasmine.clock().tick(1);
  expect(foo).toHaveBeenCalled();
  expect(bar).toHaveBeenCalled();
});

変更後

it('does not make a reentrant call to tick()', function() {
  const foo = jasmine.createSpy('foo');
  const bar = jasmine.createSpy('bar');

  setTimeout(function() {
    foo();
  }, 1);

  setTimeout(function() {
    bar();
  }, 10);

  jasmine.clock().tick(1);
  expect(foo).toHaveBeenCalled();
  jasmine.clock().tick(9);
  expect(bar).toHaveBeenCalled();
});