Skip to content

atomanyih/spy-on-async

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Aug 16, 2023
a6b4e28 · Aug 16, 2023

History

51 Commits
Aug 16, 2023
Aug 16, 2023
Aug 16, 2023
May 3, 2019
Apr 9, 2021
Apr 9, 2021
Feb 9, 2019
Apr 9, 2021
May 3, 2019
Aug 16, 2023
Aug 16, 2023
Apr 9, 2021
Aug 16, 2023
Aug 16, 2023

Repository files navigation

spy-on-async

Installation

npm install --save-dev spy-on-async

Usage

Designed to be used with jest.

setup:

Create a test setup file (or add to an existing one). This will ensure that a mocked method will not return a promise resolved from a previous test.

// ./path/to/resetAsyncMocks.ts
import {resetAllPromises} from "spy-on-async";

beforeEach(() => {
  resetAllPromises();
});
// jest.config.js
{
  "restoreMocks": true,
  "resetMocks": false,
  "clearMocks": false,
  "setupFilesAfterEnv": [
    "<rootDir>/path/to/resetAsyncMocks.ts,
  ]
}

resetMocks and clearMocks should be disabled by default. If they are enabled, this will remove the implementation from module mocks and make you sad.

spying on a method

// src/makeBananaBread.ts
import BananaMan from './BananaMan';

const makeBananaBread = async (numBananas: number) => {
  const bananas = await BananaMan.goBuyBananas(numBananas);

  return BananaMan.bakeBananaBread(bananas);
};

export default makeBananaBread;
// __tests__/makeBananaBread.spec.ts
import makeBananaBread from '../src/makeBananaBread';
import BananaMan from '../src/BananaMan';

describe('makeBananaBread', () => {
  it('calls some methods', async () => {
    const goBuyBananasSpy = spyOnAsync(BananaMan, 'goBuyBananas');
    const bakeBananaBreadSpy = spyOnAsync(BananaMan, 'bakeBananaBread');

    spyOnAsync(BananaMan, 'bakeBananaBread');

    const promise = makeBananaBread(2);

    expect(BananaMan.goBuyBananas).toHaveBeenCalledWith(2);

    await goBuyBananasSpy.mockResolveNext('bananas');
    // awaiting ensures the method continues execution before we do our next assertion

    expect(BananaMan.bakeBananaBread).toHaveBeenCalledWith('bananas');

    await bakeBananaBreadSpy.mockResolveNext('banana bread');

    expect(await promise).toEqual('banana bread');
  });
});

testing branching possibilities

// __tests__/makeBananaBread.test.js
import makeBananaBread from '../src/makeBananaBread';
import ModuleWithAsyncStuff from '../src/ModuleWithAsyncStuff';

describe('makeBananaBread', () => {
  let promise: Promise<BananaBread>;
  let goBuyBananasSpy: AsyncSpy<Banana>;
  let bakeBananaBreadSpy: AsyncSpy<BananaBread>;

  beforeEach(() => {
    goBuyBananasSpy = spyOnAsync(BananaMan, 'goBuyBananas');
    bakeBananaBreadSpy = spyOnAsync(BananaMan, 'bakeBananaBread');

    promise = makeBananaBread(2);
  });

  it('buys some bananas', async () => {
    expect(BananaMan.goBuyBananas).toHaveBeenCalledWith(2);
  });

  describe('when store has bananas', () => {
    beforeEach(async () => {
      await goBuyBananasSpy.mockResolveNext('bananas');
    });

    it('bakes those bananas', async () => {
      expect(BananaMan.bakeBananaBread).toHaveBeenCalledWith('bananas');
    });
  });

  describe('when store is out of bananas', () => {
    beforeEach(async () => {
      await goBuyBananasSpy.mockRejectNext('no bananas');
    });

    it('does not bake them bananas', async () => {
      await expect(promise).rejects.toBeDefined();
      expect(BananaMan.bakeBananaBread).not.toHaveBeenCalled();
    });
  });
});

Mocking a module

createAsyncMock can be used in jest manual mocks

import { createAsyncMock } from 'spy-on-async';

export const someMethod = createAsyncMock<ResolveType>();

Appendix

Accessing async spy from module

Though the examples above save the spy to a variable, you can also access the spy via the spied module:

await MockedModule.asyncMethod.mockResolveNext(value)

If you aren't writing typescript, this way is fluent and makes clear which module has been spied on. However, in typescript you need to cast the method as a mock. For whatever reason, it is necessary to first cast to jest.Mock. If anyone can fix this, I will give them a big ol hug.

await ((MockedModule.asyncMethod as jest.Mock) as AsyncMock).mockResolveNext(value)

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published