简体   繁体   中英

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

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();
})

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM