How to mock/test IntersectionObserver using JEST

In this blog post, we will explore the Intersection Observer API, which provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with the top-level document’s viewport. This API, supported by modern browsers like Mozilla Firefox, is especially useful for handling scenarios where you need to track when an element enters or exits the viewport or intersects with other elements on the page.

What is the Intersection Observer API?

The Intersection Observer API offers a powerful and efficient way to observe changes in the visibility of elements on a web page. Instead of continuously polling or listening for scroll events, the Intersection Observer API allows you to define a callback function that gets triggered when specific conditions are met, such as when an observed element enters or exits the viewport.

Writing a Simple Intersection Observer Function

Let’s start by writing a simple JavaScript function that utilizes the Intersection Observer API to log messages to the console based on the intersectionRatio value. The intersectionRatio is a property of the IntersectionObserverEntry object that represents the ratio of the target element’s visible area to its total area. Here’s an example implementation:

const TestModule = () => {
  const options = {
    root: null, // use null for viewport
    rootMargin: "0px",
    threshold: 1.0,
  };
  const _callback = (entries, observer) => {
    if (entries.intersectionRatio > 1) {
      console.log("do something");
    } else {
      console.info("do something else");
    }
  };
  const init = () => {
    const observer = new IntersectionObserver(_callback, options);
    const target = document.querySelector("#someSection");
    observer.observe(target);
  };
  const obj = {
    init,
  };
  return obj;
};
module.exports = TestModule;

In the code above, we define a TestModule function that returns an object containing an init method. The init method sets up an IntersectionObserver instance with the provided options and observes a target element with the ID “someSection”. The callback function _callback is triggered whenever the observed element intersects with the viewport.

Testing the Intersection Observer Function with Jest

To ensure the correctness of our Intersection Observer function, we can write tests using Jest, a popular JavaScript testing framework. Here’s an example test suite that covers the functionality of our TestModule:

const TestModule = require("../module")();
describe("IntersectionObserver", () => {
  it("should  call console.log", () => {
    const mockedEntries = [
      {
        isIntersecting: true,
        boundingClientRect: { x: 10, y: 20, width: 30, height: 40 },
      },
    ];
    const observe = jest.fn();
    const unobserve = jest.fn();
    window.IntersectionObserver = jest.fn(() => ({
      observe,
      unobserve
    }));
    jest.spyOn(document, "querySelector").mockReturnValueOnce(mockedEntries);
    const consoleLogSpy=jest.spyOn(console,"log");
    TestModule.init();
    let [callback] = window.IntersectionObserver.mock.calls[0];
    expect(observe).toBeCalledTimes(1);
    callback({
      isIntersecting: false,
      intersectionRatio: 10,
    });
    expect(consoleLogSpy).toBeCalledTimes(1);
  });
  it("should  call console.info", () => {
    const mockedEntries = [
      {
        isIntersecting: true,
        boundingClientRect: { x: 10, y: 20, width: 30, height: 40 },
      },
    ];
    const observe = jest.fn();
    const unobserve = jest.fn();
    window.IntersectionObserver = jest.fn(() => ({
      observe,
      unobserve
    }));
    jest.spyOn(document, "querySelector").mockReturnValueOnce(mockedEntries);
    const consoleInfoSpy=jest.spyOn(console,"info");
    TestModule.init();
    let [callback] = window.IntersectionObserver.mock.calls[0];
    expect(observe).toBeCalledTimes(1);
    callback({
      isIntersecting: false,
      intersectionRatio: 1,
    });
    expect(consoleInfoSpy).toBeCalledTimes(1);
  });
});

PASS  __tests__/module.test.js
  IntersectionObserver
    √ should  call console.log (30 ms)
    √ should  call console.info (3 ms)

-----------|---------|----------|---------|---------|------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s

-----------|---------|----------|---------|---------|------------------
All files  |     100 |      100 |     100 |     100 |

 module.js |     100 |      100 |     100 |     100 |
-----------|---------|----------|---------|---------|------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        4.266 s
Ran all test suites.

In the test suite, we mock the necessary functions and objects, such as IntersectionObserver and document.querySelector, to simulate the behavior of the Intersection Observer API. We then verify that the appropriate console logging methods, console.log and console.info, are called based on the provided test data.

Summary

In this blog post, we explored the Intersection Observer API, which provides a powerful way to observe changes in the visibility and intersection of elements on a web page. We implemented a simple JavaScript function that utilizes the Intersection Observer API and demonstrated how to test it using Jest. By leveraging the Intersection Observer API, you can efficiently handle scenarios where you need to track element visibility and intersection without relying on continuous scroll event listeners.

This code is taken from my book Test Driven Development Using JavaScript and Jest

Please do not post any spam link in the comment box😊

Post a Comment (0)
Previous Post Next Post