Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon How do you mock asynchronous functions with async/await syntax in TypeScript


How do you mock asynchronous functions with async/await syntax in TypeScript


To mock asynchronous functions with async/await syntax in TypeScript, you can use the following techniques:

1. Using `jest.fn().mockResolvedValue()` or `jest.fn().mockRejectedValue()`:

typescript
// myModule.ts
export async function fetchData(): Promise<string> {
  // Asynchronous implementation
  return await makeApiCall();
}

private async makeApiCall(): Promise<string> {
  // Asynchronous API call implementation
  return 'data from API';
}

// myModule.test.ts
import { fetchData, makeApiCall } from './myModule';
import * as jest from 'jest';

describe('fetchData', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  test('should fetch data successfully', async () => {
    // Mock the private makeApiCall method
    jest.spyOn(this, 'makeApiCall').mockResolvedValue('mocked data');

    const result = await fetchData();
    expect(result).toBe('mocked data');
    expect(makeApiCall).toHaveBeenCalled();
  });

  test('should handle error in fetchData', async () => {
    // Mock the private makeApiCall method to reject with an error
    jest.spyOn(this, 'makeApiCall').mockRejectedValue(new Error('API error'));

    await expect(fetchData()).rejects.toThrow('API error');
    expect(makeApiCall).toHaveBeenCalled();
  });
});

2. Using `jest.fn().mockImplementation()`:

typescript
// myModule.ts
export async function fetchData(): Promise<string> {
  // Asynchronous implementation
  return await makeApiCall();
}

private async makeApiCall(): Promise<string> {
  // Asynchronous API call implementation
  return 'data from API';
}

// myModule.test.ts
import { fetchData, makeApiCall } from './myModule';
import * as jest from 'jest';

describe('fetchData', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  test('should fetch data successfully', async () => {
    // Mock the private makeApiCall method
    jest.spyOn(this, 'makeApiCall').mockImplementation(async () => {
      return 'mocked data';
    });

    const result = await fetchData();
    expect(result).toBe('mocked data');
    expect(makeApiCall).toHaveBeenCalled();
  });

  test('should handle error in fetchData', async () => {
    // Mock the private makeApiCall method to reject with an error
    jest.spyOn(this, 'makeApiCall').mockImplementation(async () => {
      throw new Error('API error');
    });

    await expect(fetchData()).rejects.toThrow('API error');
    expect(makeApiCall).toHaveBeenCalled();
  });
});

In both examples, we use Jest's mocking capabilities to replace the implementation of the asynchronous `makeApiCall` function, which is called by the `fetchData` function. This allows us to control the behavior of the asynchronous function during testing, either by resolving with a mocked value or rejecting with an error.

The key points are:

1. Use `jest.spyOn()` to create a spy on the asynchronous function you want to mock.
2. Use `mockResolvedValue()` or `mockRejectedValue()` to set the resolved or rejected value of the mocked function.
3. Alternatively, use `mockImplementation()` to provide a custom asynchronous implementation for the mocked function.
4. Verify the behavior of the `fetchData` function by asserting the result or the expected error.
5. Remember to clean up the mocks after each test using `jest.clearAllMocks()`.

By using these techniques, you can effectively mock asynchronous functions with async/await syntax in TypeScript and ensure that your tests cover the expected behavior, including error handling.

Citations:
[1] https://instil.co/blog/typescript-testing-tips-mocking-functions-with-jest/
[2] https://domenicoluciani.com/2022/06/17/how-to-mock-with-jest-typescript.html
[3] https://www.benmvp.com/blog/using-jest-mock-functions-typescript/
[4] https://www.salto.io/blog-posts/typescript-unit-testing-pitfalls-with-jest-and-how-to-work-around-them
[5] https://www.reddit.com/r/typescript/comments/184de6g/making_tests_bearable_in_typescript/