feat(core-typescript): split vitest base into node + jsdom flavors

Adds vitest.base.node and vitest.base.jsdom with safety defaults
(clearMocks, restoreMocks, mockReset, unstubGlobals, sequence.shuffle)
and coverage thresholds (80/75/80/80). Migrates all feature configs
to the new base. Existing baseVitestConfig kept as backwards-compat
re-export of nodeVitestConfig.

Spec: §6.2
This commit is contained in:
2026-05-05 14:04:19 +02:00
parent a533be3c3a
commit bf6affd404
18 changed files with 162 additions and 47 deletions

View File

@@ -25,6 +25,7 @@
},
"devDependencies": {
"@repo/core-eslint": "workspace:*",
"@repo/core-testing": "workspace:*",
"@repo/core-typescript": "workspace:*",
"@types/node": "^22.0.0",
"vitest": "^3.1.0"

View File

@@ -1,11 +1,9 @@
import path from "node:path";
import { baseVitestConfig } from "@repo/core-typescript/vitest.base";
import { mergeConfig } from "vitest/config";
import { nodeVitestConfig } from "@repo/core-typescript/vitest.base.node";
export default {
...baseVitestConfig,
export default mergeConfig(nodeVitestConfig, {
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
alias: { "@": path.resolve(__dirname, "./src") },
},
};
});

View File

@@ -25,6 +25,7 @@
},
"devDependencies": {
"@repo/core-eslint": "workspace:*",
"@repo/core-testing": "workspace:*",
"@repo/core-typescript": "workspace:*",
"@types/node": "^22.0.0",
"vitest": "^3.1.0"

View File

@@ -1,11 +1,9 @@
import path from "path";
import { baseVitestConfig } from "@repo/core-typescript/vitest.base";
import path from "node:path";
import { mergeConfig } from "vitest/config";
import { nodeVitestConfig } from "@repo/core-typescript/vitest.base.node";
export default {
...baseVitestConfig,
export default mergeConfig(nodeVitestConfig, {
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
alias: { "@": path.resolve(__dirname, "./src") },
},
};
});

View File

@@ -23,6 +23,7 @@
},
"devDependencies": {
"@repo/core-eslint": "workspace:*",
"@repo/core-testing": "workspace:*",
"@repo/core-typescript": "workspace:*",
"@types/node": "^22.0.0",
"vitest": "^3.1.0"

View File

@@ -1,3 +1,9 @@
import { baseVitestConfig } from "@repo/core-typescript/vitest.base";
import path from "node:path";
import { mergeConfig } from "vitest/config";
import { nodeVitestConfig } from "@repo/core-typescript/vitest.base.node";
export default baseVitestConfig;
export default mergeConfig(nodeVitestConfig, {
resolve: {
alias: { "@": path.resolve(__dirname, "./src") },
},
});

View File

@@ -7,7 +7,12 @@
"./base.json": "./base.json",
"./nextjs.json": "./nextjs.json",
"./react-library.json": "./react-library.json",
"./vitest.base": "./vitest.base.ts"
"./vitest.base": "./vitest.base.ts",
"./vitest.base.node": "./vitest.base.node.ts",
"./vitest.base.jsdom": "./vitest.base.jsdom.ts"
},
"scripts": {
"test": "vitest run"
},
"devDependencies": {
"vitest": "^3.1.0"

View File

@@ -0,0 +1,21 @@
import { describe, it, expect } from "vitest";
import { jsdomVitestConfig } from "./vitest.base.jsdom";
describe("jsdomVitestConfig", () => {
it("uses jsdom environment", () => {
expect(jsdomVitestConfig.test?.environment).toBe("jsdom");
});
it("loads the jsdom setup file", () => {
expect(jsdomVitestConfig.test?.setupFiles).toEqual(
expect.arrayContaining(["@repo/core-testing/setup/jsdom"]),
);
});
it("includes tsx files", () => {
expect(jsdomVitestConfig.test?.include).toEqual(
expect.arrayContaining(["src/**/*.test.{ts,tsx}", "tests/**/*.test.{ts,tsx}"]),
);
});
it("inherits clearMocks from node base", () => {
expect(jsdomVitestConfig.test?.clearMocks).toBe(true);
});
});

View File

@@ -0,0 +1,13 @@
import { defineConfig, mergeConfig } from "vitest/config";
import { nodeVitestConfig } from "./vitest.base.node.js";
export const jsdomVitestConfig = mergeConfig(
nodeVitestConfig,
defineConfig({
test: {
environment: "jsdom",
setupFiles: ["@repo/core-testing/setup/jsdom"],
include: ["src/**/*.test.{ts,tsx}", "tests/**/*.test.{ts,tsx}"],
},
}),
);

View File

@@ -0,0 +1,28 @@
import { describe, it, expect } from "vitest";
import { nodeVitestConfig } from "./vitest.base.node";
describe("nodeVitestConfig", () => {
it("uses node environment", () => {
expect(nodeVitestConfig.test?.environment).toBe("node");
});
it("enables clearMocks, restoreMocks, mockReset", () => {
expect(nodeVitestConfig.test?.clearMocks).toBe(true);
expect(nodeVitestConfig.test?.restoreMocks).toBe(true);
expect(nodeVitestConfig.test?.mockReset).toBe(true);
});
it("declares coverage thresholds", () => {
expect(nodeVitestConfig.test?.coverage?.thresholds).toMatchObject({
statements: 80, branches: 75, functions: 80, lines: 80,
});
});
it("includes src and tests glob", () => {
expect(nodeVitestConfig.test?.include).toEqual(
expect.arrayContaining(["src/**/*.test.ts", "tests/**/*.test.ts"]),
);
});
it("excludes factories and contracts from coverage", () => {
expect(nodeVitestConfig.test?.coverage?.exclude).toEqual(
expect.arrayContaining(["src/__factories__/**", "src/__contracts__/**"]),
);
});
});

View File

@@ -0,0 +1,29 @@
import { defineConfig } from "vitest/config";
export const nodeVitestConfig = defineConfig({
test: {
globals: true,
environment: "node",
include: ["src/**/*.test.ts", "tests/**/*.test.ts"],
setupFiles: ["@repo/core-testing/setup/node"],
clearMocks: true,
restoreMocks: true,
mockReset: true,
unstubGlobals: true,
sequence: { shuffle: true },
coverage: {
provider: "v8",
reporter: ["text", "html", "lcov"],
include: ["src/**"],
exclude: [
"src/**/*.test.{ts,tsx}",
"src/**/index.ts",
"src/__factories__/**",
"src/__contracts__/**",
],
thresholds: {
statements: 80, branches: 75, functions: 80, lines: 80,
},
},
},
});

View File

@@ -1,15 +1,3 @@
import { defineConfig } from "vitest/config";
export const baseVitestConfig = defineConfig({
test: {
globals: true,
environment: "node",
include: ["src/**/*.test.ts", "src/**/*.test.tsx", "tests/**/*.test.ts"],
coverage: {
provider: "v8",
reporter: ["text", "html"],
include: ["src/**"],
exclude: ["src/**/*.test.{ts,tsx}", "src/**/index.ts"],
},
},
});
// Backwards-compat re-export. New code should import from
// vitest.base.node or vitest.base.jsdom directly.
export { nodeVitestConfig as baseVitestConfig } from "./vitest.base.node.js";

View File

@@ -0,0 +1,13 @@
import { defineConfig } from "vitest/config";
// Core-typescript tests the vitest base configs themselves.
// They live at package root (not under src/), so we use a standalone config.
export default defineConfig({
test: {
globals: true,
environment: "node",
include: ["*.test.ts"],
clearMocks: true,
restoreMocks: true,
},
});

View File

@@ -25,6 +25,7 @@
},
"devDependencies": {
"@repo/core-eslint": "workspace:*",
"@repo/core-testing": "workspace:*",
"@repo/core-typescript": "workspace:*",
"@types/node": "^22.0.0",
"vitest": "^3.1.0"

View File

@@ -1,11 +1,9 @@
import path from "node:path";
import { baseVitestConfig } from "@repo/core-typescript/vitest.base";
import { mergeConfig } from "vitest/config";
import { nodeVitestConfig } from "@repo/core-typescript/vitest.base.node";
export default {
...baseVitestConfig,
export default mergeConfig(nodeVitestConfig, {
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
alias: { "@": path.resolve(__dirname, "./src") },
},
};
});

View File

@@ -25,6 +25,7 @@
},
"devDependencies": {
"@repo/core-eslint": "workspace:*",
"@repo/core-testing": "workspace:*",
"@repo/core-typescript": "workspace:*",
"@types/node": "^22.0.0",
"vitest": "^3.1.0"

View File

@@ -1,11 +1,9 @@
import path from "node:path";
import { baseVitestConfig } from "@repo/core-typescript/vitest.base";
import { mergeConfig } from "vitest/config";
import { nodeVitestConfig } from "@repo/core-typescript/vitest.base.node";
export default {
...baseVitestConfig,
export default mergeConfig(nodeVitestConfig, {
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
alias: { "@": path.resolve(__dirname, "./src") },
},
};
});

15
pnpm-lock.yaml generated
View File

@@ -256,6 +256,9 @@ importers:
'@repo/core-eslint':
specifier: workspace:*
version: link:../core-eslint
'@repo/core-testing':
specifier: workspace:*
version: link:../core-testing
'@repo/core-typescript':
specifier: workspace:*
version: link:../core-typescript
@@ -290,6 +293,9 @@ importers:
'@repo/core-eslint':
specifier: workspace:*
version: link:../core-eslint
'@repo/core-testing':
specifier: workspace:*
version: link:../core-testing
'@repo/core-typescript':
specifier: workspace:*
version: link:../core-typescript
@@ -413,6 +419,9 @@ importers:
'@repo/core-eslint':
specifier: workspace:*
version: link:../core-eslint
'@repo/core-testing':
specifier: workspace:*
version: link:../core-testing
'@repo/core-typescript':
specifier: workspace:*
version: link:../core-typescript
@@ -570,6 +579,9 @@ importers:
'@repo/core-eslint':
specifier: workspace:*
version: link:../core-eslint
'@repo/core-testing':
specifier: workspace:*
version: link:../core-testing
'@repo/core-typescript':
specifier: workspace:*
version: link:../core-typescript
@@ -620,6 +632,9 @@ importers:
'@repo/core-eslint':
specifier: workspace:*
version: link:../core-eslint
'@repo/core-testing':
specifier: workspace:*
version: link:../core-testing
'@repo/core-typescript':
specifier: workspace:*
version: link:../core-typescript