Jest는 node환경에서 dom을 테스트 하기위해 js-dom을 통해 복사된 dom을 이용하고 있습니다

그렇기 때문에 실제 브라우저에서 이용하는 Web api에 대해 테스트하기 힘든 경우가 간혹 있었습니다

이번에 이미지를 lazy-loading하는 컴포넌트를 storybook에서 시각화테스트를 이용할 경우엔 정상적으로 작동하지만

jest에서 테스트할 경우 intersectionObserver가 트리거 되지 않으며 lazy-loading이 정상적으로 작동하지 않습니다

jest테스트에서도 정상적으로 작동을 테스트 하기 위해서는 IntersectionObserver를 구현하여 Mocking해야합니다

const mockIntersectionObserver = class {
    constructor(callback, options) {
        this.viewPort = options.root
        this.entries = []
        this.viewPort.addEventListener('scroll', () => {
            this.entries.map((entry) => {
                entry.isIntersecting = this.isInViewPort(entry.target)
            })
            callback(this.entries, this)
        })
    }

    isInViewPort(target) {
        // const rect = target.getBoundingClientRect()
        // const viewPortRect = this.viewPort.getBoundingClientRect()
        // return (
        //     rect.left >= viewPortRect.x &&
        //     rect.top >= viewPortRect.y &&
        //     rect.right <= viewPortRect.right &&
        //     rect.bottom <= viewPortRect.bottom
        // )
        return true
    }

    observe(target) {
        this.entries.push({ isIntersecting: false, target })
    }

    unobserve(target) {
        this.entries = this.entries.filter((ob) => ob.target !== target)
    }

    disconnect() {
        this.entries = []
    }
}

// window 객체에 주입
window.IntersectionObserver = mockIntersectionObserver;

// 이후 테스트 코드에서 fireEvent.scroll 과 같은 이벤트를 해주면 intersectionObserver가 트리거 됩니다

위 처럼 작업을 해도 되지만 개인적으론 번거로운 작업이라고 생각했었습니다

하지만 아래 Lib를 이용하면 React에서 IntersectionObserver API를 구현하며 IntersectionObserver를 Mock하는 기능도 모함되어 있어 나에겐 적절했다

https://github.com/thebuilder/react-intersection-observer

test('should create a hook inView', () => {
  render(<HookComponent />);

  // This causes all (existing) IntersectionObservers to be set as intersecting
  mockAllIsIntersecting(true);
  screen.getByText('true');
});

위와 같이 번거로운 클래스 선언없이 사용할 수 있다