Amplitude-JavaScript icon indicating copy to clipboard operation
Amplitude-JavaScript copied to clipboard

Reference to window specific properties when using Jest in React Native

Open divyanshu013 opened this issue 5 years ago • 2 comments

I followed the docs and moved to the JS SDK for our react native app. We use jest for testing and it's throwing errors despite using the react-native preset.

  ● Test suite failed to run

    ReferenceError: window is not defined

      at node_modules/amplitude-js/amplitude.js:778:12
      at node_modules/amplitude-js/amplitude.js:2:83
      at Object.<anonymous> (node_modules/amplitude-js/amplitude.js:1:2)
      at Object.<anonymous> (node_modules/core-mobile/src/services/tracking/index.js:6:1)

To solve this I added a window: {} global to my test environment but then it throws error for more window specific properties such as navigator

  ● Test suite failed to run

    ReferenceError: navigator is not defined

      at getLanguage (node_modules/amplitude-js/amplitude.js:3219:5)
      at node_modules/amplitude-js/amplitude.js:3223:15
      at node_modules/amplitude-js/amplitude.js:2:83
      at Object.<anonymous> (node_modules/amplitude-js/amplitude.js:1:2)
      at Object.<anonymous> (node_modules/core-mobile/src/services/tracking/index.js:6:1)

I'd to add the following to my jest config. Not sure if its the best way to resolve this issue:

"globals": {
      "window": {},
      "navigator": {}
    }

divyanshu013 avatar Apr 07 '20 09:04 divyanshu013

Yeah. That's not ideal. Given that jest is the way to write tests for the platform, we'll look into make the experience a bit better here.

blazzy avatar Apr 23 '20 18:04 blazzy

For anyone else struggling with this, I think the easiest way around it is to bypass jest's automocking and explicitly provide a module factory for amplitude. E.g. mocking the module like this:

import {getInstance} from 'amplitude-js';

jest.mock('amplitude-js', () => {
  const instance = {
    init: jest.fn(),
    logEvent: jest.fn(),
    setUserId: jest.fn(),
    setUserProperties: jest.fn(),
    // ...
  };
  return {
    getInstance: () => instance,
  };
});

Will provide the ability to make assertions like this:

const mockAmplitude = getInstance();
// ... do something ...
expect(mockAmplitude.logEvent).toHaveBeenCalled();

If it's affecting a lot of tests a manual mock might be better.

domharries avatar Aug 21 '20 10:08 domharries