简体   繁体   中英

Jasmine: how to test async function?

In my NodeJS app I've got the following heplers.ts file with one method, wait :

export const wait = async (ms: number) => {
  return new Promise(resolve => {
    setTimeout(resolve, ms);
  });
};

I'm currently writing a unit test to this file and this is what I have now:

import { setProcessEnv } from 'spec/helpers';
import { wait } from '../../util/helpers';

describe('Helper methods', () => {
  beforeEach(() => {
    jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
    setProcessEnv();
  });

  it('should wait a specified amount of time', async () => {
    const TIMEOUT = 10000;
    jasmine.clock().install();  // First install the clock

    await wait(TIMEOUT);

    jasmine.clock().tick(10000); // waits till 10000 milliseconds

    expect(wait).toHaveBeenCalled();
    
    jasmine.clock().uninstall(); // uninstall clock when done
  });
  
});

But I'm constantly receiving

Error: Timeout - Async function did not complete within 20000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)

I've increased jasmine.DEFAULT_TIMEOUT_INTERVAL to 20000 ms, but it still didn't work. How such async functions could be tested?

I've found coupes examples, but they didn't work in my case: How to test a function which has a setTimeout with jasmine?

UPDATE

This is my latest version that doesn't throw an error, but the problem is that it doesn't cover return statement lines ( return new Promise(... ):

it('should wait a specified amount of time', async () => {
     const TIMEOUT = 10000;

    // jasmine.clock().install();  // First install the clock
    const wait = jasmine.createSpy();

    await wait(TIMEOUT);

    // jasmine.clock().tick(1000); // waits till 10000 milliseconds
    expect(wait).toHaveBeenCalled();
    expect(wait).toHaveBeenCalledWith(TIMEOUT);
    
    // jasmine.clock().uninstall(); // uninstall clock when done
  });

The problem is that by using jasmine's custom clock you need to manually call .tick() to move the time forward. Since you immediately await the wait call, the setTimeout within wait will not be reached. Thus, the promise never resolves, as you call .tick() after awaiting the promise.

You can fix this by not immediately awaiting the the promise returned from wait but instead assigning it to a variable and then moving the time ahead. Then, await the promise and check if wait has been called:

describe('Helper methods', () => {

    it('should wait a specified amount of time', async () => {
        const TIMEOUT = 10000;
        jasmine.clock().install();  // First install the clock

        const waitPromise =  wait(TIMEOUT);
        jasmine.clock().tick(10000); // waits till 10000 milliseconds

        await waitPromise; // now await the promise

        expect(wait).toHaveBeenCalled();

        jasmine.clock().uninstall(); // uninstall clock when done
    });
});

Note that in the above code no spy has been set up on wait , so .toHaveBeenCalled will probably fail. Check this link if you need help setting up a spy on a function: https://stackoverflow.com/a/43532075/3761628


To answer the updated question: You've incorrectly set up the spy. You need to change it to something like:

import { setProcessEnv } from 'spec/helpers';
import * as WaitFunction from from '../../util/helpers';
...
it('should wait a specified amount of time', async () => {
    const TIMEOUT = 10000;    
    
    const waitSpy = spyOn(WaitFunction, 'wait').and.callThrough();

    await WaitFunction.wait(TIMEOUT);

    expect(waitSpy).toHaveBeenCalled();
    expect(waitSpy).toHaveBeenCalledWith(TIMEOUT);
    
  });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM