Using a custom environment in vitest for database connections

Photo by John Barkiple on Unsplash

I like to use vitest to do api testing. I think it's much easier than using postman or insomnia. The problem is they really need to run in parallel and for that you ideally need a connection string for each test file.

Here is how to configure a test environment for vitest.

Vitest and node versions

I've tested this with

  • vitest version 0.33.0
  • node 18

Creating a package

The test environment must be in a separate project with its own package.json.

Add a folder "vitest-environment-mongoose" to your project.

Add a file "mongoose-test-environment.ts" to the folder.

import type { Environment } from "vitest";

export default <Environment>{
  name: "mongoose-env",
  transformMode: "ssr",
  async setup() {
    await mongoose.connect(process.env.DATABASE_URI, {});

    return {
      async teardown() {
        if (mongoose.connection.readyState === 1) {
          await mongoose.connection.close();
        }
      },
    };
  },
};

Add a package.json with the following contents.

{
  "name": "vitest-environment-mongoose",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "main": "mongoose-test-environment.ts",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "vitest": "0.34.1"
  }
}

Finally add a tsconfig file.

{
  "compilerOptions": {
    "module": "ESNext",
    "declaration": true,
    "removeComments": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "allowJs": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictPropertyInitialization": true,
    "noUnusedLocals": true,
    "alwaysStrict": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "skipLibCheck": true,
    "skipDefaultLibCheck": true,
    "resolveJsonModule": true,
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "inlineSources": false,
    "target": "ES2022",
    "lib": ["ES2022"],
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./"
  }
}

Add the environment to your vitest config

You have to tell vitest to use the environment. For example you might only want to apply it to files that have "integration" in the name.

/// <reference types="vitest" />
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    globals: true,
    useAtomics: true,
    environment: "node", // the default environment
    include: ["**/*.{test,spec,test.integration}.?(c|m)[t]s?(x)"],
    environmentMatchGlobs: [["src/**/*test.integration.ts", "mongoose"]], // Files to use mongoose environment
  },
});