web-dev-qa-db-ja.com

JS-IntersectionObserverを使用するテストコード

私のアプリケーションには、(かなり不十分に書かれた)javascriptコンポーネントがあり、無限スクロールのページ付けを処理します。記述されているように、IntersectionObserverを使用するように書き直そうとしています here ただし、私はテストに問題があります。

QUnitテストでオブザーバーの動作を制御する方法はありますか。つまり、テストに記述されているいくつかのエントリでオブザーバーコールバックをトリガーする方法はありますか?

私が思いついた考えられる解決策は、コンポーネントのプロトタイプでコールバック関数を公開し、次のように、テストで直接呼び出すことです。

InfiniteScroll.prototype.observerCallback = function(entries) {
    //handle the infinite scroll
}

InfiniteScroll.prototype.initObserver = function() {
    var io = new IntersectionObserver(this.observerCallback);
    io.observe(someElements);
}

//In my test
var component = new InfiniteScroll();
component.observerCallback(someEntries);
//Do some assertions about the state after the callback has been executed

コンポーネントがIntersectionObserverを内部で使用するという事実を公開しているため、このアプローチはあまり好きではありません。これは、実装の詳細であり、クライアントのコードからは見えないはずなので、より良い方法があります。これをテストしますか?

JQueryを使用しないソリューションへのボーナス愛:)

17
Raibaz

これは、以前の回答に基づく別の代替方法です。beforeEachメソッド内、または_.test.js_ファイルの先頭で実行できます。

パラメータをsetupIntersectionObserverMockに渡してobserveおよび/またはunobserveメソッドをモックしてjest.fn()モック関数でスパイすることもできます。

_/**
 * Utility function that mocks the `IntersectionObserver` API. Necessary for components that rely
 * on it, otherwise the tests will crash. Recommended to execute inside `beforeEach`.
 * @param {object} intersectionObserverMock - Parameter that is sent to the `Object.defineProperty`
 *      overwrite method. `jest.fn()` mock functions can be passed here if the goal is to not only
 *      mock the intersection observer, but its methods.
 */
export function setupIntersectionObserverMock({
  observe = () => null,
  unobserve = () => null,
} = {}) {
  class IntersectionObserver {
    observe = observe;
    unobserve = unobserve;
  }
  Object.defineProperty(
    window,
    'IntersectionObserver',
    { writable: true, configurable: true, value: IntersectionObserver }
  );
  Object.defineProperty(
    global,
    'IntersectionObserver',
    { writable: true, configurable: true, value: IntersectionObserver }
  );
}
_
1
Robert Molina

2019年の同じ問題はこれが私がそれを解決した方法です:

import ....

describe('IntersectionObserverMokTest', () => {
  ...
  const observeMock = {
    observe: () => null,
    disconnect: () => null // maybe not needed
  };

  beforeEach(async(() => {
    (<any> window).IntersectionObserver = () => observeMock;

    ....
  }));


  if(' should run the Test without throwing an error for the IntersectionObserver', () => {
    ...
  })
});

そこで、observe(およびdisconnect)メソッドを使用してモックオブジェクトを作成し、ウィンドウオブジェクトのIntersectionObserverを上書きします。使用方法によっては、他の関数を上書きする必要がある場合があります(以下を参照してください: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Browser_compatibility

コードは https://Gist.github.com/ianmcnally/4b68c56900a20840b6ca840e2403771c から着想を得ていますが、jestを使用していません

9
Stefan

jest.setup.jsファイルで、IntersectionObserverを次の実装でモックします。

global.IntersectionObserver = class IntersectionObserver {
  constructor() {}

  observe() {
    return null;
  }

  unobserve() {
    return null;
  }
};

Jest Setup File を使用する代わりに、テストまたはbeforeAll、beforeEachブロックで直接このモッキングを行うこともできます。

7
Robin Wieruch