I have the following jest.config.ts:
import type { Config } from "jest";
import nextJest from "next/jest.js";
const createJestConfig = nextJest({ dir: "./" });
const config: Config = {
projects: [
{
displayName: "backend",
testMatch: ["<rootDir>/tests/**/*.test.ts"],
testEnvironment: "node",
clearMocks: true,
preset: "ts-jest",
globalSetup: "<rootDir>/tests/globalSetup.ts",
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
},
{
displayName: "frontend",
testMatch: ["<rootDir>/src/**/*.test.{ts,tsx}"],
testEnvironment: "jsdom",
clearMocks: true,
preset: "ts-jest",
setupFilesAfterEnv: ["<rootDir>/src/jest.setup.ts"],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
},
],
};
export default createJestConfig(config);
This works for my backend tests, but fails to compile any jsx. After a bunch of fiddling, I figured out that the issue is with using nextJest
alongside projects. The following frontend only config works:
import type { Config } from "jest";
import nextJest from "next/jest.js";
const createJestConfig = nextJest({ dir: "./" });
const config: Config = {
displayName: "frontend",
testMatch: ["<rootDir>/src/**/*.test.{ts,tsx}"],
testEnvironment: "jsdom",
clearMocks: true,
preset: "ts-jest",
setupFilesAfterEnv: ["<rootDir>/src/jest.setup.ts"],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
};
export default createJestConfig(config);
It looks like whatever modifications nextJest
makes to the config, it doesn't know how to do that for projects.
Is there a way to still use nextJest
? Or at least a clean way to reproduce whatever transformations nextJest
is doing to my jest config?
I know I can just print the working config that nextJest
generates and manually build my jest.config.ts
from that, but that seems messy and brittle and I'd really like to avoid it if possible!
The process of writing up the question got my brain working, and I worked out a reasonable solution:
import type { Config } from "jest";
import nextJest from "next/jest.js";
const createJestConfig = nextJest({ dir: "./" });
const buildConfig = async (config: Config): Promise<Config> => {
return await createJestConfig(config)();
};
export default async (): Promise<Config> => {
const backendConfig = await buildConfig({
displayName: "backend",
testMatch: ["<rootDir>/tests/**/*.test.ts"],
testEnvironment: "node",
clearMocks: true,
preset: "ts-jest",
globalSetup: "<rootDir>/tests/globalSetup.ts",
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
});
const frontendConfig = await buildConfig({
displayName: "frontend",
testMatch: ["<rootDir>/src/**/*.test.{ts,tsx}"],
testEnvironment: "jsdom",
clearMocks: true,
preset: "ts-jest",
setupFilesAfterEnv: ["<rootDir>/src/jest.setup.ts"],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
});
const config: Config = {
projects: [backendConfig, frontendConfig],
};
return config;
};
Each entry in projects is in fact a Config object, so this should be a reliable way to do this. I suppose I can't be 100% confident that at some point nextJest won't add properties that belong on the root config, but not the projects, but for now it's definitely fine.