James Ives
James Ives

Reputation: 3365

Mocking the same value between different tests

I have a file called constants with a series of string values that get imported into the file where init() is defined. I want to setup my test so that the string values are different between each run. Right now I can only seem to have them be the same for all test runs.

jest.mock('../src/constants', () => ({
  build: 'dist',
  action: {
    pusher: {
      name: 'montezuma',
      email: 'best@cat'
    },
    gitHubToken: 'exists'
  }
}));

describe('git', () => {
  describe('init', () => {
    it('should execute three commands', async () => {
      await init();

      expect(execute).toBeCalledTimes(3);
    });

    it('should fail if the deployment folder begins with /', async () => {
      // I want the values of constants to be different in here.
    });
  });
});

How can I set it up so action and build have different values in each test run? I've tried moving the jest.mock call into each it statement but that doesn't seem to work. Is there a better pattern for this?

Upvotes: 0

Views: 352

Answers (1)

Lin Du
Lin Du

Reputation: 102267

You can use jest.spyOn(object, methodName, accessType?) to mock the return value for each unit test case.

E.g.

contants.ts:

export function get() {
  return {
    build: 'dist',
    action: {
      pusher: {
        name: 'montezuma',
        email: 'best@cat'
      },
      gitHubToken: 'exists'
    }
  };
}

index.ts:

import { get } from './constants';

export async function init() {
  return get();
}

index.spec.ts:

import { init } from './';
import * as constants from './constants';

describe('git', () => {
  describe('init', () => {
    afterEach(() => {
      jest.restoreAllMocks();
    });
    it('t-1', async () => {
      const mConstants = {
        build: '/',
        action: {
          pusher: {
            name: 'asd',
            email: 'as@cat'
          },
          gitHubToken: 'ccsa'
        }
      };
      const spy = jest.spyOn(constants, 'get').mockReturnValueOnce(mConstants);
      const actualValue = await init();
      expect(actualValue).toEqual(mConstants);
      expect(spy).toBeCalledTimes(1);
    });

    it('t-2', async () => {
      const mConstants = {
        build: 'build',
        action: {
          pusher: {
            name: 'zzz',
            email: 'www@cat'
          },
          gitHubToken: 'xxx'
        }
      };
      const spy = jest.spyOn(constants, 'get').mockReturnValueOnce(mConstants);
      const actualValue = await init();
      expect(actualValue).toEqual(mConstants);
      expect(spy).toBeCalledTimes(1);
    });
  });
});

Unit test result:

 PASS  src/stackoverflow/58758771/index.spec.ts (7.685s)
  git
    init
      ✓ t-1 (5ms)
      ✓ t-2 (2ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        8.829s

Update, we can also change the constants object for each unit test case.

Before running the unit test, we should store the original constants. After each test case is finished, we should restore the original constants. I use lodash.cloneDeep method to make a deep clone for constants.

constants.ts:

export const constants = {
  build: 'dist',
  action: {
    pusher: {
      name: 'montezuma',
      email: 'best@cat'
    },
    gitHubToken: 'exists'
  }
};

index.ts:

import { constants } from './constants';

export async function init() {
  return constants;
}

index.spec.ts:

import { init } from './';
import { constants } from './constants';
import _ from 'lodash';

const originalConstants = _.cloneDeep(constants);

describe('git', () => {
  afterEach(() => {
    _.assignIn(constants, originalConstants);
  });
  describe('init', () => {
    it('t-1', async () => {
      Object.assign(constants, {
        build: '/',
        action: {
          ...constants.action,
          pusher: { ...constants.action.pusher, name: 'aaa', email: 'aaa@cat' },
          gitHubToken: 'bbb'
        }
      });
      const actualValue = await init();
      expect(actualValue).toEqual({
        build: '/',
        action: {
          pusher: {
            name: 'aaa',
            email: 'aaa@cat'
          },
          gitHubToken: 'bbb'
        }
      });
    });

    it('should restore original contants', () => {
      expect(constants).toEqual({
        build: 'dist',
        action: {
          pusher: {
            name: 'montezuma',
            email: 'best@cat'
          },
          gitHubToken: 'exists'
        }
      });
    });
  });
});

Unit test result:

PASS  src/stackoverflow/58758771/v2/index.spec.ts (10.734s)
  git
    init
      ✓ t-1 (7ms)
      ✓ should restore original contants (1ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        12.509s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58758771

Upvotes: 1

Related Questions