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');
});
위와 같이 번거로운 클래스 선언없이 사용할 수 있다