38

I am trying to migrate my tests from Jest to Vitest. I have a test suite that uses the dotenv package to pull in my .env variables.

I have this in my test suite

beforeAll(async () => {
        vi.clearAllMocks();
        cleanUpMetadata();
        dotenv.config();
        controller = new UserController(container.get<UserServiceLocator>(Symbol.for("UserServiceLocator")),
            container.get<EmailServiceLocator>(Symbol.for("EmailServiceLocator")));
    });

and this is the code in the test that has the undefined variable:

let requestObj = httpMocks.createRequest({
            cookies: {
                token: jwt.sign({ username: "testusername" }, process.env.JWT_SECRET_KEY!)
            }
        });

Is there something special to Vitest that I have to do in order to get my .env variables to be accessible?

11 Answers 11

36

You can include the dotenv package(if thats what you are using) into the vitest.config.ts file, it will look something like this below:

import { defineConfig } from 'vitest/config';
import { resolve } from 'path';

export default defineConfig({
  root: '.',
  esbuild: {
    tsconfigRaw: '{}',
  },
  test: {
    clearMocks: true,
    globals: true,
    setupFiles: ['dotenv/config'] //this line,
  },
  resolve: {
    alias: [{ find: '~', replacement: resolve(__dirname, 'src') }],
  },
});
Sign up to request clarification or add additional context in comments.

7 Comments

this works, this should be the accepted answer in 2024
why we need dotenv? node already can read .env
Also not everyone is using Node. IMO it is outdated in favor of Bun or Deno
@Nikos Node 20 was released after this answer was written 🙂
@RobinBozan Node 20 support requires passing a --env-file when running node so if you don't have the ability to do that, stick with the dotenv package as this comment suggests
@Ezekiel I understand but the command to run vitest is vitest, not node. I found some relevant discussion here: github.com/vitest-dev/vitest/issues/5756
|
17

For whoever lands here after removing the dotenv lib because Node v20.6.0+ handles .env files automatically, just use the loadEnv function from vite in your vitest.config.ts:

import { loadEnv } from 'vite';
import { defineConfig } from 'vitest/config';

export default defineConfig(({ mode }) => ({
    test: {
        // mode defines what ".env.{mode}" file to choose if exists
        env: loadEnv(mode, process.cwd(), ''),
    },
}));

Provided you use a default .env file.

3 Comments

technically this is working, but i having problem where it can get the if the value have special char. For my case seem is $
this works - too bad they don't have a simpler syntax for this. comes from here? vitest.dev/guide/features.html#environment-variables
I dont see why this is needed because Vite is alredy loading env file automatically. You just have to prefix your variables in env file with VITE_
8

I know this question is quite old, but my workaround to this was parsing my .env file inside vitest.config:

import { config } from "dotenv";
import tsconfigPaths from "vite-tsconfig-paths";
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    passWithNoTests: true,
    globals: true,
    coverage: {
      provider: "v8",
      exclude: ["**/tests/**"],
    },
    env: {
      ...config({ path: "./env/.testing.env" }).parsed,
    },
  },
  plugins: [tsconfigPaths()],
});

This allows me to have multiple config files using mergeConfig from Vitest in case of multiple testing environments.

If I'm not wrong you can also do this by setting up setup and teardown functions as a global setup files.

export async function setup() {
  // LOAD .ENV HERE
  app.listen(env.PORT, () => {
    console.log("Started testing server...");
  });
}

export async function teardown() {
  await app.stop();
}

EDIT1: Actually this last setup cannot load variables for the testing context. This setup happens to be a globalSetup config in vitest.config.ts that runs outside the tests context. It is meant to be used for external setups like starting a server, initializing a database connection or cleaning up a database.

Comments

7

I use the vite loadEnv function in vitest.config.ts and that works:

import { defineConfig } from 'vitest/config'
import { loadEnv } from 'vite'

export default defineConfig({
    test: {
        environment: 'jsdom',
        env: loadEnv('', process.cwd(), ''),
    },
})

1 Comment

if you want to load .env.test for testing only and not affecting production mode you have to use loadEnv('test', process.cwd(), '')
4

If you are using dotEnv

  1. Load the env with config()/dotenv.config() up to you
  2. point the your envs in the config
import { defineConfig } from 'vitest/config'
import { config } from 'dotenv'
//#1
config()

export default defineConfig({
  test: {
    ...
   //#2
    env: process.env,
    ...
  }
})

Comments

4

Thanks to the discussion linked by @RobinBozan, I was able to load my .env file before vitest runs in Node.js v20+. I added the following scripts to my package.json:

{
  "scripts": {
    "vitest": "node --env-file=.env ./node_modules/vitest/vitest.mjs",
    "test": "yarn vitest run"
  }
}

Now, I run my test suite with:

yarn test

Output:

yarn run v1.22.22
$ yarn vitest run
$ node --env-file=.env ./node_modules/vitest/vitest.mjs run

...

I'm using yarn to execute my scripts here, but you can use your package manager's equivalent, such as npx.

Comments

1

vitest will automatically load your .env file(s) from the project root directory, which probably isn't the same directory as your test files. Your file structure might look something like this:

🗁 project
  🖹 .env
  🖹 package.json
  🖹 vite.config.json
  🗁 src/
    🖹 myCode.js
  🗁 test/
    🖹 myCode.test.js

In node, you access a variable using import.meta.env.VITE_MY_VARIABLE_NAME. In HTML, use the special syntax %VITE_MY_VARIABLE_NAME%.

If you're still getting undefined variables, add the VITE_ prefix to your variable name, which tells vite the value is safe to expose.

4 Comments

doesn't work......
no, VITE_ is only for the client, not tests
Yes vite does read variables from .env files (N.B. .env.test, not .env.testing!). But it doesn't expose them on process.env, nor import.meta.env, unless prefixed with VITE_ (envPrefix). Interestingly SvelteKit's $env contain unprefixed variables as well.
You are right, using import.meta.env works with variables defined with VITE prefix... But why using plain process.env doesnt work (with variables without VITE prefix) ? The only way to make process.env to work is by adding a vitest.config file...
1

Load environment variables

  • This example is work next.js but should work aswell with dotenv
  • vitest.config.ts
// ==== VITEST ====
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'

// ==== NEXT.JS ====
import { loadEnvConfig } from '@next/env'
loadEnvConfig(process.cwd())

export default defineConfig({
    plugins: [tsconfigPaths(), react()],
    test: {
        environment: 'node',
        globalSetup: 'test/setup-tests.ts'
    }
})
  • environment must be node. jsdom will not work

1 Comment

This is great. Thank you!. We're using Next.js - and didn't want a direct dependency on Vite and so '@next/env' did the trick. For interest we had to load it this way... import nextEnv from '@next/env' const { loadEnvConfig } = nextEnv loadEnvConfig(process.cwd())
0
import.meta.env.%VARIABLE_NAME%

Got it from here: https://stackoverflow.com/a/70711231

Comments

0

In Node.js Assuming you want to access your env variable VAR you should prefix it with VITE_ like:

VITE_VAR=123

then you can access it regularly with process.env.VITE_VAR

3 Comments

Do you have a link to an official documentation stating this ?
Oh ok I see. But that's not what OP is asking. They want to access their "business code" env variable. Therefore, they won't rename JWT_SECRET_KEY to VITE_JWT_SECRET_KEY. Instead, they need to inject the actual env vars into Vite so their function has them available without even knowing it's being executed by Vite (see my answer below).
0
import tsconfigPaths from 'vite-tsconfig-paths';
import { defineConfig } from 'vitest/config';

import { config } from 'dotenv';

const env = config({ path: '.env.test' });

export default defineConfig({
  plugins: [tsconfigPaths()],
  test: {
    include: ['src/**/*.test.ts', 'stacks/**/*.test.ts'],
    env: env.parsed
  },
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.