2

I have this code:

const browserNotification = new Notification(title, options);

browserNotification.onshow = () => this.props.sendTracking('in-app-chat-notification-start');

browserNotification.onclick = event => {
  const notification = event.target;

  this.props.router.push(notification.data.url.split('.com')[1]);
  this.props.sendTracking('in-app-chat-notification-complete');

  notification.close();
};

I'm trying to mock window Notification because I need to call these two methods (onshow and onclick):

it('should call onshow method', () => {
  window.Notification = () => ({
    onshow: jest.fn(),
    onclick: jest.fn()
  });
  const instance = shallow(<MyComponent />).instance();

  instance.myMethod();

  //window.Notification.onShow();

  expect(sendTracking).toHaveBeenCalledTimes(1);
});

I know that if I do that, I'm losing the original method but, since tests does not have window and Notification, I have to mock it.

How can do it properly with Jest in order to pass this code?

I have tried also mocking with global, but at the end, is the same as window.

The coverage:

enter image description here

Thanks

Albert Olivé Corbella
  • 4,061
  • 7
  • 48
  • 66
  • Possible duplicate of [Mocking globals in Jest](https://stackoverflow.com/questions/40449434/mocking-globals-in-jest) – Axnyff Nov 10 '17 at 16:13
  • Hi, I have checked that and does not help me. As you can see, I'm doing exactly the same but without global (I'm using window). Thanks anyway :) – Albert Olivé Corbella Nov 10 '17 at 16:18
  • I think it will be the same, just replace window by global in your case and it should work – Axnyff Nov 10 '17 at 16:20
  • Let me check again then. – Albert Olivé Corbella Nov 10 '17 at 16:20
  • The same, my problem is that I want to fire those methods (onclick and onshow) in my tests. – Albert Olivé Corbella Nov 10 '17 at 16:23
  • Ok I think I get it, it's not onshow and onclick that should be mocked, it's sent tracking. You need to either have a reference to browserNotification and then call it's onshow method to see if it's working. Do you have access to that object from your component? Otherwise, modify the mock Notification class so that it will expose the object its creation – Axnyff Nov 10 '17 at 16:32
  • browserNotification is created few lines before as this: `const browserNotification = new Notification(title, options);` so at the end is created from global.Notification. What I mean is that I can't call it from anywhere until I don't mock Notification. Do you know what I mean? – Albert Olivé Corbella Nov 10 '17 at 16:34
  • Could you try it using `Object.defineProperty(globalObject, key, { value, writable: true });` – Andreas Köberle Nov 11 '17 at 11:21
  • I tried this code in my test but it doesn't work. Have in mind that inside tests, we don't have window or global so, it will never works. – Albert Olivé Corbella Nov 13 '17 at 07:56

1 Answers1

-2

Finally I suceded to test those two methods by splitting the code that I showed in my question.

This is it:

handleNewFirebaseNotification = notification => {
  const title = notification.data.title || 'letgo';
  const options = {
    body: notification.data.body,
    icon: notification.data.icon || 'https://static.letgo.com/site-images/logo_letgo_share_fb.jpg',
    data: {
      url: notification.data.url
    }
  };

  this.handleNotifications(title, options);
};

handleNotifications = (title, options) => {
  const browserNotification = new Notification(title, options);

  browserNotification.onshow = this.onShowNotification;
  browserNotification.onClick = this.onClickNotification;
}

onShowNotification = () => {
  this.props.sendTracking('in-app-chat-notification-start')
}

onClickNotification = event => {
  const notification = event.target;

  this.props.router.push(notification.data.url.split('.com')[1]);
  this.props.sendTracking('in-app-chat-notification-complete');

  notification.close();
}

And then I can test with enzyme all this new methods. For example:

it('should call handleNewFirebaseNotification and then call handleNotifications with title and icon', () => {
  window.Notification = () => ({
    onshow: jest.fn(),
    onclick: jest.fn()
  });
  const instance = shallow(mockComponent()).instance();
  const notificationMock = {
    data: {
      title: 'test',
      body: 'test',
      icon: 'test',
      url: 'test'
    }
  };

  instance.handleNewFirebaseNotification(notificationMock);

  expect(window.Notification()).toEqual(expect.objectContaining({
    onshow: expect.any(Function),
    onclick: expect.any(Function)
  }));
});

And one of the new methods:

it('should call onShowNotification', () => {
  const instance = shallow(mockComponent()).instance();

  instance.onShowNotification();

  expect(sendTrackingSpy).toHaveBeenCalledTimes(1);
});
Albert Olivé Corbella
  • 4,061
  • 7
  • 48
  • 66
  • This is not true because I'm using the arrow function and therefore ```this.props```is not undefined. Please, don't downvote or at least, try this before commenting – Albert Olivé Corbella Jul 20 '18 at 14:07