To use swc and vitest with nest-js, follow the
setup guide on the NestJS website.
At the end of this setup, you should be able to run e2e tests with a running
MongoDB instance, using the following command:
Copy
pnpm test:e2e# equivalent topnpm vitest run --config ./vitest.config.e2e.ts
vite-tsconfig-paths is used to resolve the paths defined in the
tsconfig.json file automatically.
Rename the file vitest.config.e2e.ts to vitest.config.e2e.mts since
@codspeed/vitest-plugin is only available in ESM. Apply the following
modifications to the file:
vitest.config.e2e.mts
Copy
import codspeedPlugin from "@codspeed/vitest-plugin";import swc from "unplugin-swc";import tsconfigPaths from "vite-tsconfig-paths";import { defineConfig } from "vitest/config";export default defineConfig({ plugins: [swc.vite(), tsconfigPaths(), codspeedPlugin()], test: { root: "./", passWithNoTests: true, include: ["**/*.e2e.spec.ts"], benchmark: { include: ["**/*.e2e.bench.ts"] }, // ensure we running only one test at a time since they are using the same database // this could be removed by using a different database for each test poolOptions: { forks: { singleFork: true } }, },});
This allows for a better experience when authoring benchmarks, as it provides a
way to ensure that everything went well. This is optional, you can remove the
assertions if you want:
Benchmarking is an experimental feature.Breaking changes might not follow SemVer, please pin Vitest's version when using it.[CodSpeed] bench detected but no instrumentation found DEV v1.2.0 /Users/user/projects/CodSpeedHQ/codspeed-nestjs-mongodb[CodSpeed] @codspeed/vitest-plugin v3.1.0 - setup[CodSpeed] running suite src/cats/cats.controller.e2e.bench.ts[CodSpeed] src/cats/cats.controller.e2e.bench.ts::Cats (bench)::GET /cats/name/:name done[CodSpeed] src/cats/cats.controller.e2e.bench.ts::Cats (bench)::GET /cats/breed/:breed done[CodSpeed] running suite src/cats/cats.controller.e2e.bench.ts done ✓ src/cats/cats.controller.e2e.bench.ts (2) 698ms · Cats (bench) (2)
name: CodSpeedon: # Run on pushes to the main branch push: branches: - "main" # Run on pull requests pull_request: workflow_dispatch:jobs: benchmarks: name: Run benchmarks runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v2 - uses: actions/setup-node@v3 with: cache: pnpm node-version-file: .nvmrc # easily setup a MongoDB cluster - uses: art049/mongodb-cluster-action@v0 id: mongodb-cluster-action - name: Install dependencies run: pnpm install - name: Run benchmarks uses: CodSpeedHQ/action@v3 with: token: ${{ secrets.CODSPEED_TOKEN }} instruments: mongodb mongo-uri-env-name: MONGO_URL run: | pnpm bench:e2e env: # we need the MONGO_URL to be set in the environment before actually running # the benchmark command so we set it here instead of inside the `run` command MONGO_URI: ${{ steps.mongodb-cluster-action.outputs.connection-string }}
With this configuration, the CodSpeed MongoDB instrument will be activated and
data from MongoDB queries will be sent to CodSpeed.
Instead of relying on an externally provided Docker instance, we can leverage
testcontainers to start a
MongoDB instance dynamically during the benchmarks.
For this setup, we assume that the state of the application is similar to the
one described in the above section.
Create a new file src/global.d.ts with the following content:
src/global.d.ts
Copy
declare var __MONGO_URI__: string;
This will make the globalThis.__MONGO_URI__ variable available in the whole
application with the correct type.
⚠️ Make sure to use var and not let or const, as otherwise the TypeScript
type will not be set.
Create a new file src/testUtils/setup-vitest.ts with the following content:
src/testUtils/setup-vitest.ts
Copy
import { setupInstruments } from "@codspeed/vitest-plugin";import { MongoDBContainer, StartedMongoDBContainer,} from "@testcontainers/mongodb";import { beforeAll } from "vitest";let mongodbContainer: StartedMongoDBContainer;async function setupMongoDB() { // if the database is already setup so we can skip this step if (globalThis.__MONGO_URI__) return; mongodbContainer = await new MongoDBContainer("mongo:7.0.5").start(); const mongoUrl = mongodbContainer.getConnectionString() + "/test?replicaSet=rs0&directConnection=true"; const { remoteAddr } = await setupInstruments({ mongoUrl }); globalThis.__MONGO_URI__ = remoteAddr;}async function setup() { await setupMongoDB();}beforeAll(async () => { await setup();});
testcontainers on macOS
On macOS, we recommend using colima to
run Docker containers. However there are
issues using testcontainers on macOS.
To bypass those issues, some environment variables need to be set when running
the tests:
To make testcontainers work on macOS with colima, the following environment variables need to be set:
We will add a function to enforce that they are set when running vitest. Add the following function to your src/testUtils/setup-vitest.ts file:
src/testUtils/setup-vitest.ts
Copy
function checkColimaTestcontainersDarwin() { if ( process.platform === "darwin" && (process.env.TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE === undefined || !process.env.NODE_OPTIONS.includes("--dns-result-order=ipv4first")) ) { throw new Error( 'On macOs, run with the following command to make testcontainers + colima work: `TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock NODE_OPTIONS="$NODE_OPTIONS --dns-result-order=ipv4first" <command>`' ); }}
And use it at the top of the the setupMongoDB function:
src/testUtils/setup-vitest.ts
Copy
async function setupMongoDB() { checkColimaTestcontainersDarwin(); ...}
Now the execution will stop with an explicit error message if the environment variables are not set when running on macOS.
Add the file as a setupFiles entry in vite.config.e2e.mts:
vitest.config.e2e.mts
Copy
import codspeedPlugin from "@codspeed/vitest-plugin";import swc from "unplugin-swc";import tsconfigPaths from "vite-tsconfig-paths";import { defineConfig } from "vitest/config";export default defineConfig({ plugins: [swc.vite(), tsconfigPaths(), codspeedPlugin()], test: { root: "./", passWithNoTests: true, include: ["**/*.e2e.spec.ts"], benchmark: { include: ["**/*.e2e.bench.ts"] }, // ensure we running only one test at a time since they are using the same database // this could be removed by using a different database for each test poolOptions: { forks: { singleFork: true } }, setupFiles: ["./src/testUtils/setup-vitest.ts"], },});
We can now change the src/app.module.ts file to use the
globalThis.__MONGO_URI__ variable instead of the MONGO_URL environment
variable when it is defined: