Search code examples
angularjasminefetchkarma-runner

Expectation fails, when testing code in javascript fetch.then block


I try to verify that window.open() is called within a then block. Here is a minimal example.

import { fakeAsync, tick } from '@angular/core/testing';

function openWindow() {
  const linksource = `data:application/pdf;base64,somePDF`;
  fetch(linksource).then(() => {
    window.open();
  });
}

describe('Asynchronus Testing', () => {
  it('opens a window', fakeAsync(() => {
    // Dont actually open a window
    window.open = () => window;
    spyOn(window, 'open');

    openWindow();
    tick();

    expect(window.open).toHaveBeenCalled();
  }));
});

window.open() is actually called, but the expectation fails:

Error: Expected spy open to have been called.

The tick() is not helping even if I give it more time. I guess it is specific to fetch because the Promise.resolve().then() block works.


Solution

  • I have noticed the same thing with fakeAsync/tick where the tick does not control some promises.

    I would spy on fetch and make it return a random promise.

    describe('Asynchronus Testing', () => {
      it('opens a window', fakeAsync(() => {
        // Dont actually open a window
        window.open = () => window;
        spyOn(window, 'open');
        // !! spy on window fetch and return a random promise
        spyOn(window, 'fetch').and.returnValue(Promise.resolve({}));
    
        openWindow();
        tick();
    
        expect(window.open).toHaveBeenCalled();
      }));
    });
    

    It should hopefully work with that modification. You should also not be making Http calls in a unit test (general rule).