Mock specific config value in jest
Asked Answered
C

1

5

I have the following default/config.js file

/* eslint-disable @typescript-eslint/no-var-requires */
require('dotenv').config({
  path: require('find-config')('.env'),
});

module.exports = {
  cronInterval: process.env.CRON_INTERVAL,
  queueName: process.env.QUEUE_NAME || '',
  isVisible: process.env.IS_VISIBLE
};

In my index.ts, I have

import config from 'config';
import * as cron from 'node-cron';

const isVisible = config.get<boolean>('isVisible');
const queueName = config.get<string>('queueName');
const cronInterval = config.get<string>('cronInterval');

function startProcess(queueName) {
    cron.schedule(cronInterval, () => {});
}

// process starts here
if (isVisible) {
  startProcess(queueName);
} else {
  logger.info('Wont start')
}

In my unit tests I want to test for both cases of isVisible, while keeping the other config values as they are.

I tried

describe.only('isVisible', () => {
    beforeEach(() => {
        jest.mock('./../config/default.js', () => ({ 
            isVisible: false
        }));
    })
    it('should not run anything if not visible', () => {
        require('./../src/index');
        const scheduleSpy = jest.spyOn(cron, 'schedule');
        expect(scheduleSpy).not.toHaveBeenCalled();
    })
})

This didnt work for me, and it doesnt override the value of isVisible.

I know I could also mock the config.get function like config.get.mockReturnValue(false), but that would then override the values of cronInterval and queueName

Cherenkov answered 1/6, 2021 at 9:17 Comment(4)
Where does the config.get() method come from? How did you import config module in your index.ts file?Mawson
@slideshowp2 it's the config package npmjs.com/package/configCherenkov
@AngularDebutant, please change const to let for isVisible and import that file and try to change its value.Futures
You know there's a typo on your code, right? "isVibible: false"Capacitate
V
7

Here's one way I recently solved a similar need (conditionally needing the original module functionality) ...

let isVisible = false;

jest.mock('config', () => {
  // Require the original module!
  const originalConfig = jest.requireActual('config');

  return {
    __esModule: true, // for esModules
    get: jest.fn((key: string) => {
      // override result conditionally on input arguments
      if (key === 'isVisible') return isVisible;
      // otherwise return using original behavior
      return originalConfig.get(key);
    })
  };
});

Then in your tests:

it('isVisible=true', () => {
  isVisible = true;
  // test logic here
});

it('isVisible=false', () => {
  isVisible = false;
  // test logic here
});

Voyeurism answered 9/6, 2021 at 4:42 Comment(3)
Thanks, but for some reason, only the first test runs. I dont know if it has something to do with the require('./../src/index'); ? but the code in the file is called only once for both tests..Cherenkov
Mocking only knows about the path you give it... Sorequire('./../src/index') is different from require('config'). Also, as a general rule, it's easier to mock functions - rather than exported objects/arrays.Voyeurism
I ended up doing things a bit differently, but I accepted your answer as it solves the original question. Thanks.Cherenkov

© 2022 - 2024 — McMap. All rights reserved.