6

I test redux-actions with jest. Particular redux-action uses Notifications API as a side-effect. How can i mock Notifications API?

Now, i simply mock it this way:

global.Notification = {...};

It works, but i think there is more elegant solution to solve this problem. Any ideas?

I have this module to handle Notifications API:

export const requestNotifyPermission = () => {
    try {
        return Notification.requestPermission().then(function(result) {
            return result;
        });
    } catch(err) {
        console.warn('NotificationsAPI error: ' + err);
    }
};

export const getCurrentNotifyPermission = () => {
    // Possible values = default, granted, denied
    try {
      return Notification.permission;
    } catch {
      return 'denied';
    }
};

export const createNotify = (title, body)  => {
  try {
    if (getCurrentNotifyPermission() === 'granted') {
      var options = {
          body: body
      };
      return new Notification(title, options);  
    }
  } catch(err) {
    console.warn('NotificationsAPI error: ' + err);
  }
}
skyboyer
  • 22,209
  • 7
  • 57
  • 64
Constantine
  • 544
  • 5
  • 15
  • 1
    I'm afraid there is no way. the best you can do is encapsulating mocked code in separate file to avoid repeating that from test to test. – skyboyer May 10 '19 at 07:23
  • What do you expected? Is there any error in your unit test? – Lin Du Nov 12 '19 at 08:52

1 Answers1

6

One way to prevent mocking Notification API at every test file, is by configuring Jest setupFiles.

jest.config.js

module.exports = {
  setupFiles: ["<rootDir>config.ts"],
};

config.ts

globalThis.Notification = ({
  requestPermission: jest.fn(),
  permission: "granted",
} as unknown) as jest.Mocked<typeof Notification>;

Note: globalThis is the most modern way to access the Global scope. If you don't have the required Node version (v12+), just stick with using global object.

This example is also showcasing the use with Typescript, which is a little more tricky.

If you want to mock different permission states, you can do that in the test case:

// Notification.permission
jest
  .spyOn(window.Notification, "permission", "get")
  .mockReturnValue("denied");


// Notification.requestPermission (which is a Promise)
jest
  .spyOn(window.Notification, "requestPermission")
  .mockResolvedValueOnce("granted");

Guilherme Maia
  • 161
  • 1
  • 7
  • 1
    The spyOn logic gives `Cannot spyOn on a primitive value; undefined given` error – IamMowgoud Mar 15 '21 at 01:42
  • @IamMowgoud Are you using any JS framework? In your case, the Notification API seems to be missing in the Jest environment. You can expect slight API differences for each **browser** depending on your setup (like [here](https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API#browser_compatibility) and [here](https://stackoverflow.com/a/45140032/4734523)), but AFAIK that's not the case for the Jest environment. – Guilherme Maia Apr 13 '21 at 20:52