Pass parameter to jest.mock

I have a mock as follows

jest.mock('react-hook-inview', () => {
  const setRef = jest.fn();
  const observer = jest.fn();
  const intersecting = true;
  const entry = {
    y: 0,
  };
  return [setRef, intersecting, entry, observer];
});

Here I would like to change the intersecting value. How can I change that from one test to another? I was trying to use something like a factory:

const inView = (intersecting) => {
  jest.mock('react-hook-inview', () => {
    const setRef = jest.fn();
    const observer = jest.fn();
    const entry = {
      y: 0,
    };
    return [setRef, intersecting, entry, observer];
  });
}

and use it like

  it('is invisible by default', () => {
    const text = 'Test';
    const { container } = render(<Reveal>{text}</Reveal>);
    inView(false);
    expect(container.firstChild).not.toBeVisible();
  });

  it('is visible when in view', () => {
    const text = 'Test';
    const { container } = render(<Reveal>{text}</Reveal>);
    inView(true);
    expect(container.firstChild).toBeVisible();
  });

however this throws

The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
Invalid variable access: intersecting

does anybody have an idea?

cheers!

EDIT:

My solution for now is to mock it like this

import ReactHookInview from 'react-hook-inview';

jest.mock('react-hook-inview', () => ({
  useInView: jest.fn().mockImplementation(() => {
    const setRef = jest.fn();
    const observer = jest.fn();
    const intersecting = false;
    const entry = {
      boundingClientRect: {
        y: 0,
      },
    };
    return [setRef, intersecting, entry, observer];
  }),
}));

and in my test I overwrite like this:

ReactHookInview.useInView.mockImplementation(() => {
  const setRef = jest.fn();
  const observer = jest.fn();
  const intersecting = true;
  const entry = {
    boundingClientRect: {
      y: 1,
    },
  };
  return [setRef, intersecting, entry, observer];
});

but that's not really beautiful

Upvotes: 7

Views: 14363

Answers (1)

Teneff
Teneff

Reputation: 32158

You can mock your library as you have already done, import it and explicitly set it's value. And then before have two different sets of tests:

jest.mock('react-hook-inview', /* as above */ );

import rhi from 'react-hook-inview';

describe('my implementation', () => {

  describe('while intersecting', () => {
    let result;
    beforeAll(() => {
      rhi[1] = true;
      result = myImplementationUsingIntersecting();
    });

    it('should result X', () => {
      expect(result).toEqual(X);
    });
  });

  describe('while NOT intersecting', () => {
    let result;
    beforeAll(() => {
      rhi[1] = false;
      result = myImplementationUsingIntersecting();
    });

    it.todo('should result Y');
  });
})

working example

Edit 2: in order to properly mock a React hook

since the react hooks are functions that return stuff you'll can mock it like this

jest.mock('react-hook-inview', () => jest.fn());
// and you can take it's reference with import
import useInView from 'react-hook-inview';
// and then you can mock it's return value as array
beforeAll(() => {
  useInView.mockReturnValue(['a', true, 'b', 'c']);
  result = myImplementationUsingIntersecting();
})

Upvotes: 2

Related Questions