jordanbyron / react-native-quick-actions

A react-native interface for Touch 3D home screen quick actions
MIT License
1.06k stars 93 forks source link

Unable to mock via jest #82

Closed Mookiies closed 5 years ago

Mookiies commented 5 years ago

testing my code using this package is turning out to be seemingly impossible. I tried mocking the react-native-quick-actions module in jest via:

jest.mock('react-native-quick-actions', () => {
  return {
    clearShortcutItems: jest.fn(),
    isSupported: jest.fn(),
    setShortcutItems: jest.fn(),
  }
});

That didn't work because it kept returning this error: TypeError: _reactNativeQuickActions2.default.popInitialAction is not a function which confuses me, because I can't find _reactNativeQuickActions2 anywhere in your code here.

I tried this again, trying this instead:

jest.mock('react-native-quick-actions', () => {
  return {
    QuickActions: {
      clearShortcutItems: jest.fn(),
      isSupported: jest.fn(),
      setShortcutItems: jest.fn(),
    },
  };
});

And same result.

So my next approach was to try and mock the QuickActions object itself as a native module, like so:

jest.mock('NativeModules', () => {
  return {
    DeviceEventEmitter: () => ({
      addListener: jest.fn(),
    }),
    RNQuickActionManager: () => ({
      initialAction: jest.fn(),
      isSupported: jest.fn(),
    }),
    QuickActions: {
      clearShortcutItems: jest.fn(),
      isSupported: jest.fn(),
      setShortcutItems: jest.fn(),
      popInitialAction: jest.fn(),
    },
  };
});

which also gave the same error: TypeError: _reactNativeQuickActions2.default.popInitialAction is not a function

Then I tried mocking higher up in its own mocked module file:

import { NativeModules } from 'react-native';

NativeModules.QuickActions = {
  /**
   * An initial action will be available if the app was cold-launched
   * from an action.
   *
   * The first caller of `popInitialAction` will get the initial
   * action object, or `null`. Subsequent invocations will return null.
   */
  popInitialAction: jest.fn(),

  /**
   * Adds shortcut items to application
   */
  setShortcutItems: jest.fn(),

  /**
   * Clears all previously set dynamic icons
   */
  clearShortcutItems: jest.fn(),

  /**
   * Check if quick actions are supported
   */
  isSupported: jest.fn(),
};

which again threw the same error.

I'm very stuck on where to go from here. If you have any recommendations, I would greatly appreciate it. Thanks.

jordanbyron commented 5 years ago

Hey @MalcolmScruggs,

Sorry to hear you are having problems stubbing out this library in your tests. It sounds like you are asking the more generic question: "How do I mock (or stub) out ES6 imports in jest". I took a look over at stack overflow for you and found this:

https://stackoverflow.com/questions/40465047/how-can-i-mock-an-es6-module-import-using-jest#40486695

This is a bug tracker, so if you find something about this library that is broken or could be improved to help with testing, feel free to open up another ticket.

Mookiies commented 5 years ago

Based on the way this package is setup, using jest to mock it is extremely difficult and unwieldy. To solve this issue I wrapped the API of this package in my own interface to easily mock it.

jordanbyron commented 5 years ago

Thanks for the update Malcom. Again if you have any suggestions or ideas for how this library could be easier to test with Jest, or in general, I’m all ears.

Mookiies commented 5 years ago

Jest gives very confusing error messages, so my error was mainly understanding what jest was giving back. Nothing wrong with the library, using this in a __mocks__ directory worked as expected:

module.exports = {
  /**
   * An initial action will be available if the app was cold-launched
   * from an action.
   *
   * The first caller of `popInitialAction` will get the initial
   * action object, or `null`. Subsequent invocations will return null.
   */
  popInitialAction: jest.fn(() => Promise.resolve()),

  /**
   * Adds shortcut items to application
   */
  setShortcutItems: jest.fn(),

  /**
   * Clears all previously set dynamic icons
   */
  clearShortcutItems: jest.fn(),

  /**
   * Check if quick actions are supported
   */
  isSupported: jest.fn(),
};