How to Mock process.env in Jest

How to Mock process.env in Jest

Learn how to mock environment variables in a NodeJs project while implementing Jest tests that depend on environmental variables.

🌐
You can find the source code at the end of the post.

Table of contents

  • What Is process.env?
  • Why Mock process.env?
  • Mock process.env in Jest Tests
  • Conclusion

What Is process.env?

In NodeJs, process.env is basically a global object that holds the state of the system's environmental variables, being available at runtime to our application.

Why Mock process.env?

Most of the time when developing an application we don't really need the process.env variable or it's properties values, but in some parts of the application we do need them, for example if we need to grab the app's version in runtime or the app's port to start a server of some kind.

To make sure that the app behaves the way we want it to, we need to test it thoroughly and this mean we need to test the parts of the app that rely on this object and this is the case where we need to mock process.env to test different cases the app can run into.

Mock process.env in Jest Tests

For the sake of this post, we will have a very simple NodeJs app that has one file with two functions; appEnv and appVersion which will print out the app's env and version respectively.

Create a file named app.js and copy the following content into it:

function appEnv() {
  const currentEnv = process.env.NODE_ENV

  if (!currentEnv) {
    throw new Error('NODE_ENV is not defined')
  }

  return `App is running on ${currentEnv} environment`
}

function appVersion() {
  const currentAppVersion = process.env.APP_VERSION

  if (!currentAppVersion) {
    throw new Error('APP_VERSION is not defined')
  }

  return `App's version is ${currentAppVersion}`
}

module.exports = { appEnv, appVersion }

As you can see, we only print out the values here, and if the value is undefined we throw an error, pretty simple.

Now that we got this out of the way, we can start.
Mocking process.env is actually pretty simple, but first we need to know where we can set those values for our tests after that we will mock them in our tests.

App Wide Mocking

The default values for every test can be set in one of Jest's setup files, when this is done, the setup file will be executed before each test file.

To setup Jest setup-files execute the following steps:

First, create a jest.config.js file in the root of the directory (besides package.json).
Content of the config file would be:

module.exports = {
  setupFiles: ['<rootDir>/jest-setup.js'],
}

Then, create a setup-jest.js file in the root of the directory too.
Content of the file should be our default values:

process.env.NODE_ENV = 'local'
process.env.APP_VERSION = 'v0.1'

Now we did setup the default values for the whole app's tests env, Let's mock them!

First, create a test file named app.test.js next to app.js file.
Then we can start our tests in a dedicated test suite (App Tests - Default ENV Values) as you can see below:

const { appEnv, appVersion } = require('./app')

describe('App Tests - Default ENV Values', () => {
  const originalEnv = process.env

  afterEach(() => {
    // Reset process.env after each test case
    process.env = originalEnv
  })

  describe('APP_VERSION Tests', () => {
    it('should return default value when APP_VERSION', () => {
      const result = appVersion()

      expect(result).toBe(`App's version is v0.1`)
    })

    it('should throw an error if APP_VERSION is not defined', () => {
      process.env = { APP_VERSION: undefined }
      // OR process.env = {}

      expect(appVersion).toThrow('APP_VERSION is not defined')
    })
  })

  describe('NODE_ENV Tests', () => {
    it('should return default value when NODE_ENV', () => {
      const result = appEnv()

      expect(result).toBe('App is running on local environment')
    })

    it('should throw an error if NODE_ENV is not defined', () => {
      process.env = { NODE_ENV: undefined }
      // OR process.env = {}

      expect(appEnv).toThrow('NODE_ENV is not defined')
    })
  })
})

Now let's talk about the above tests, first we created a test group named App Tests - Default ENV Values which contains two other groups APP_VERSION Tests and NODE_ENV Tests.

Before we dive into the tests, notice we have a variable to hold the original env object's value, that's important because in some tests we do override the process.env properties and we need to reset it to the original value after each test case.

Our first test case, in both groups, ensures that our env variables are correct and picked up from the setup file we had earlier.

Second test case again in both groups is different, we override the process.env value to set undefined values for our properties (NODE_ENV & APP_VERSION) and those tests should ensure that our code will throw an error when those values are missing from env variable.

Per Test File Mocking

Now since we mocked the app-wide env variable, let's find out how to mock the env variables in a test file/suite in case we don't have a setup file or we just want to test different values other than the values in the setup file.

In the same app.test.js file, we can add another group named App Tests - Manual ENV Values right next to App Tests - Default ENV Values (just to keep the test file clean and clear).

describe('App Tests - Manual ENV Values', () => {
  const originalEnv = process.env

  beforeEach(() => {
    // Override process.env object before each test case:
    process.env = {
      NODE_ENV: 'prod',
      APP_VERSION: 'v1.0',
    }
    // By default the value of process.env.NODE_ENV is test when running tests with jest
  })

  afterEach(() => {
    // Reset process.env value after each test case
    process.env = originalEnv
  })

  describe('APP_VERSION Tests', () => {
    it('should return correct value when APP_VERSION is defined', () => {
      const result = appVersion()

      expect(result).toBe(`App's version is v1.0`)
    })

    it('should throw an error if APP_VERSION is not defined', () => {
      process.env = { APP_VERSION: undefined }
      // OR process.env = {}

      expect(appVersion).toThrow('APP_VERSION is not defined')
    })
  })

  describe('NODE_ENV Tests', () => {
    it('should return correct value when NODE_ENV is defined', () => {
      const result = appEnv()

      expect(result).toBe('App is running on prod environment')
    })

    it('should throw an error if NODE_ENV is not defined', () => {
      process.env = { NODE_ENV: undefined }
      // OR process.env = {}

      expect(appEnv).toThrow('NODE_ENV is not defined')
    })
  })
})

Again, let's talk about our new test group.

Actually, not much changed, In the new test group we mock or set custom values for the process.env object before each test case which allows us to have more control over the values in our test file instead of the globally set variables.

Conclusion

At last, in this post we saw how we can set our env variables globally while testing our application along with a per-test mock of the env object.

Source code can be found here.

As always, I hope you learned something.

Found this useful? feel free to share it with your friends.

Join the newsletter from to notify you of new posts and updates.

Like the post? consider buying us a coffee ❤️.