Jamadan
Jamadan

Reputation: 2313

Jest coverage testing global objects and inverse condition

I've got a global object on window that has a function. In my code I'm writing this:

if (window.foo) {
      window.foo.bar();
}

In the tests, when window.foo has a value I assert that window.foo.bar has been called. Easy enough.

Jest coverage is complaining that I'm not testing the negative value, i.e. when window.foo is undefined. But I've been struggling to work out what to assert on.

What I'd like to do - is mock window.foo and assert that it is only called once, when we check whether it has a value or is undefined (i.e. the call to window.foo.bar is never made.

I'm trying to mock the global window object and return an object but I'm getting confused as to how to mock and spyOn a value when it isn't a function, and then check it has been accessed.

Any help appreciated!

Upvotes: 1

Views: 506

Answers (1)

Fabio Antunes
Fabio Antunes

Reputation: 22862

You could use a getter so whenever a property in the object is being accessed inside the getter we could run multiple actions, in our case we just trigger our spy manually.

describe('window.foo', () => {
  afterEach(() => {
    delete global.foo // make sure you clean your global object after each test
  })

  it('should be called twice', () => {
    const fooSpy = jest.fn();
    const barSpy = jest.fn();
    Object.defineProperty(global, 'foo', {
      configurable: true, // very important or else you can't delete
      get() {
        fooSpy(); //we manually call our spy so we can assert later

        // and we return an object with another spy for our bar function
        return { bar: barSpy};
      }
    });

    if (global.foo) {
      global.foo.bar()
    }


    expect(fooSpy).toHaveBeenCalledTimes(2);
    expect(barSpy).toHaveBeenCalledTimes(1);
  });

  it('should be called once', () => {
    const fooSpy = jest.fn();
    Object.defineProperty(global, 'foo', {
      writconfigurableable: true,
      get() {
        fooSpy(); // we trigger the spy manually

        // we return undefined
        return undefined;
      }
    });

    if (global.foo) {
      global.foo.bar()
    }


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

You can see it working in here

Upvotes: 2

Related Questions