Skip to content

Module pattern variable returning undefined in test?

I have the following code below which returns certain data depending on NODE_ENV:

config.js

export const Config = (() => {
    let data;

    switch (process.env.NODE_ENV) {
        case 'development':
            data = '123';
            break;
        case 'production':
            data = '456'
            break;
        default:
            break;
    }

    return {
        data
    };
})();

This works well in my component when I set NODE_ENV. However in my test, I keep getting undefined as a result.

config.test.js

describe('Config', () => {
    test('returns correct data if NODE_ENV is development', () => {
        process.env = { ...process.env, NODE_ENV: 'development' };

        expect(Config.data).toBe('123'); // returns undefined, expected '123'
    });

    test('returns correct data if NODE_ENV is production', () => {
        process.env = { ...process.env, NODE_ENV: 'production' };

        expect(Config.data).toBe('456'); // returns undefined, expected '456'
    });
});

Again, Config.data works fine in my React component when I start it up, but I guess I need to somehow initialize this for it to work in my tests? Any advice would be appreciated!

Answer

First of all, you need to make sure the config module is imported after setting the process.env. So you need to use const { Config } = require('./config') rather than import { Config } from './config'; Because imports are hoisted, and when the IIFE execute, the process.env is not prepared.

Another note is module caching.

Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.

Provided require.cache is not modified, multiple calls to require('foo') will not cause the module code to be executed multiple times. This is an important feature. With it, “partially done” objects can be returned, thus allowing transitive dependencies to be loaded even when they would cause cycles.

There is an IIFE in your config module, it only executes once when you require('./config') multiple times. The value of process.env in IIFE is also cached. So, you need to use jest.resetModules() to clear the module cache.

E.g.

config.js:

export const Config = (() => {
  let data;
  console.log(process.env.NODE_ENV);
  switch (process.env.NODE_ENV) {
    case 'development':
      data = '123';
      break;
    case 'production':
      data = '456';
      break;
    default:
      break;
  }
  return { data };
})();

config.test.js:

describe('Config', () => {
  let Config;
  beforeEach(() => {
    jest.resetModules();
  });
  test('returns correct data if NODE_ENV is development', () => {
    process.env = { ...process.env, NODE_ENV: 'development' };
    Config = require('./config').Config;
    expect(Config.data).toBe('123');
  });

  test('returns correct data if NODE_ENV is production', () => {
    process.env = { ...process.env, NODE_ENV: 'production' };
    Config = require('./config').Config;
    expect(Config.data).toBe('456');
  });
});

Test result:

 PASS  stackoverflow/71733750/config.test.ts
  Config
    ✓ returns correct data if NODE_ENV is development (15 ms)
    ✓ returns correct data if NODE_ENV is production (2 ms)

  console.log
    development

      at stackoverflow/71733750/config.ts:29:11

  console.log
    production

      at stackoverflow/71733750/config.ts:29:11

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |     100 |      100 |     100 |     100 |                   
 config.ts |     100 |      100 |     100 |     100 |                   
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        1.354 s

You can try to remove jest.resetModules() to check the logs.