Search code examples
reactjssettimeoutenzymereact-testing-libraryistanbul

Can't seem to get test coverage for a setTimeout action dispatched inside of an useEffect


I'm having an issue getting test coverage for a react action dispatch with window.setTimeout() the test passes with done() but it doesn't actually provide any coverage for the istanbul coverage. I tried a few things but nothing has worked so far. Anyone familiar with testing this? I've also tried using lolex instead to mock the time instead of using window.setTimeout() but it fails saying getBrSeoData was never called.

This is my code

  useEffect(() => {
    if (!Config.ui.isBot) {
      window.setTimeout(() => {
        getBrSeoData(productType, productId, productName, productStatus);
      }, BR_DELAY);
    }
  }, [getBrSeoData, productType, productId, productName, productStatus]);

This is the test

  it("should make the blooomreach api call if !Config.ui.isBot", done => {
    const BR_DELAY = 6000;
    const response = {
      status: "SUCCESS",
      payload: {
        "related-item": bloomreachState["related-item"],
        "related-category": [],
        "more-results": []
      }
    };
    props = {
      relatedSearches: bloomreachState["related-item"],
      relatedCategories: bloomreachState["related-category"],
      relatedProducts: bloomreachState["more-results"],
      getBrSeoData: sinon.spy(() => new Promise(resolve => resolve({ response })))
    };
    Config.ui.isBot = false;
    component = render(<BloomreachSeo {...props} />);
    window.setTimeout(() => {
      expect(props.getBrSeoData).to.have.been.calledOnce;
    }, BR_DELAY);
    done();
  });

Istanbul showing no coverage for the line

enter image description here


Solution

  • I was able to get it working by using the npm package lolex. If anyone has issues with it using react testing library along with testing a window.setTimeout()

      let clock;
    
      beforeEach(() => {
        clock = lolex.install({ now: 4476701471000, toFake: ["setTimeout"] });
      });
    
      afterEach(() => {
        clock.uninstall();
      });
    
      it("should make the bloomreach api call if !Config.ui.isBot", () => {
        const BR_DELAY = 5000;
        const response = {
          status: "SUCCESS",
          payload: {
            "related-item": bloomreachState["related-item"],
            "related-category": [],
            "more-results": []
          }
        };
        props = {
          relatedSearches: bloomreachState["related-item"],
          relatedCategories: bloomreachState["related-category"],
          relatedProducts: bloomreachState["more-results"],
          getBrSeoData: sinon.spy(() => new Promise(resolve => resolve({ response })))
        };
        Config.ui.isBot = false;
        component = render(<BloomreachSeo {...props} />);
        clock.tick(BR_DELAY);
        clock.setTimeout(() => {
          expect(props.getBrSeoData).to.have.been.called;
        }, BR_DELAY);
      });