如何在 Jest 中模拟 IntersectionObserver API?

Ale*_*drH 1 javascript unit-testing jestjs

我已经阅读了有关该主题的所有相关问题,并且我意识到这可能会被标记为重复,但我根本无法弄清楚如何使其发挥作用。

我有这个简单的函数来延迟加载元素:

export default function lazyLoad(targets, onIntersection) {
  const observer = new IntersectionObserver((entries, self) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        onIntersection(entry.target);
        self.unobserve(entry.target);
      }
    });
  });

  document.querySelectorAll(targets).forEach((target) => observer.observe(target));
  return observer;
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

lazyLoad('.lazy-img', (img) => {
  const pictureElement = img.parentElement;
  const source = pictureElement.querySelector('.lazy-source');

  source.srcset = source.getAttribute('data-srcset');
  img.src = img.getAttribute('data-src');
});
Run Code Online (Sandbox Code Playgroud)

现在,我尝试lazyLoad使用 jest 测试该函数,但我显然需要模拟 IntersectionObserver,因为它是一个浏览器 API,而不是本机 JavaScript API。

测试该方法的工作如下observe

let observe;
let unobserve;

beforeEach(() => {
  observe = jest.fn();
  unobserve = jest.fn();

  window.IntersectionObserver = jest.fn(() => ({
    observe,
    unobserve,
  }));
});

describe('lazyLoad utility', () => {
  it('calls observe on each target', () => {
    for (let i = 0; i < 3; i++) {
      const target = document.createElement('img');
      target.className = 'lazy-img';
      document.body.appendChild(target);
    }

    lazyLoad(
      '.lazy-img',
      jest.fn(() => {})
    );

    expect(observe).toHaveBeenCalledTimes(3);
  });
});
Run Code Online (Sandbox Code Playgroud)

但我也想测试.isIntersecting回调触发的逻辑......但我不知道该怎么做。如何测试与 jest 的交集?

Ada*_*dam 5

当你将其作为参数传递时,嘲笑东西就变得非常容易:

export default function lazyLoad(targets, onIntersection, observerClass = IntersectionObserver) {
  const observer = new observerClass(...)
  ...
}


// test file
let entries = [];
const observeFn = jest.fn();
const unobserveFn = jest.fn()
class MockObserver {
  constructor(fn) {
    fn(entries,this);
  }

  observe() { observeFn() }
  unobserve() { unobserveFn() }
}

test('...',() => {
   // set `entries` to be something so you can mock it
   entries = ...something
   lazyLoad('something',jest.fn(),MockObserver);
});
Run Code Online (Sandbox Code Playgroud)