diff --git a/e2e/ci-e2e/global-setup.ts b/e2e/ci-e2e/global-setup.ts
deleted file mode 100644
index 92893c11c..000000000
--- a/e2e/ci-e2e/global-setup.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-/* eslint-disable functional/immutable-data */
-
-const originalCI = process.env['CI'];
-
-export function setup() {
- // package is expected to run in CI environment
- process.env['CI'] = 'true';
-}
-
-export function teardown() {
- if (originalCI === undefined) {
- delete process.env['CI'];
- } else {
- process.env['CI'] = originalCI;
- }
-}
diff --git a/e2e/ci-e2e/tsconfig.test.json b/e2e/ci-e2e/tsconfig.test.json
index 5248dd739..307a55e79 100644
--- a/e2e/ci-e2e/tsconfig.test.json
+++ b/e2e/ci-e2e/tsconfig.test.json
@@ -8,7 +8,6 @@
"vitest.e2e.config.ts",
"tests/**/*.e2e.test.ts",
"tests/**/*.d.ts",
- "mocks/**/*.ts",
- "global-setup.ts"
+ "mocks/**/*.ts"
]
}
diff --git a/e2e/ci-e2e/vitest.e2e.config.ts b/e2e/ci-e2e/vitest.e2e.config.ts
index 90df62fed..cc856f443 100644
--- a/e2e/ci-e2e/vitest.e2e.config.ts
+++ b/e2e/ci-e2e/vitest.e2e.config.ts
@@ -1,22 +1,5 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createE2ETestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/ci-e2e',
- test: {
- reporters: ['basic'],
- testTimeout: 60_000,
- globals: true,
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- cache: {
- dir: '../../node_modules/.vitest',
- },
- environment: 'node',
- include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: './global-setup.ts',
- setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
- },
+export default createE2ETestConfig('ci-e2e', {
+ testTimeout: 60_000,
});
diff --git a/e2e/cli-e2e/vitest.e2e.config.ts b/e2e/cli-e2e/vitest.e2e.config.ts
index ab4256183..a4c7769c8 100644
--- a/e2e/cli-e2e/vitest.e2e.config.ts
+++ b/e2e/cli-e2e/vitest.e2e.config.ts
@@ -1,21 +1,5 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createE2ETestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/cli-e2e',
- test: {
- reporters: ['basic'],
- testTimeout: 20_000,
- globals: true,
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- cache: {
- dir: '../../node_modules/.vitest',
- },
- environment: 'node',
- include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
- },
+export default createE2ETestConfig('cli-e2e', {
+ testTimeout: 20_000,
});
diff --git a/e2e/create-cli-e2e/vitest.e2e.config.ts b/e2e/create-cli-e2e/vitest.e2e.config.ts
index 9eca9c7e9..a1bcedbb8 100644
--- a/e2e/create-cli-e2e/vitest.e2e.config.ts
+++ b/e2e/create-cli-e2e/vitest.e2e.config.ts
@@ -1,22 +1,5 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createE2ETestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/create-cli-e2e',
- test: {
- reporters: ['basic'],
- testTimeout: 20_000,
- hookTimeout: 20_000,
- globals: true,
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- cache: {
- dir: '../../node_modules/.vitest',
- },
- environment: 'node',
- include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
- },
+export default createE2ETestConfig('create-cli-e2e', {
+ testTimeout: 20_000,
});
diff --git a/e2e/nx-plugin-e2e/vitest.e2e.config.ts b/e2e/nx-plugin-e2e/vitest.e2e.config.ts
index b6fe4be83..b1b60a1aa 100644
--- a/e2e/nx-plugin-e2e/vitest.e2e.config.ts
+++ b/e2e/nx-plugin-e2e/vitest.e2e.config.ts
@@ -1,21 +1,5 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createE2ETestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/nx-plugin-e2e',
- test: {
- reporters: ['basic'],
- testTimeout: 80_000,
- globals: true,
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- cache: {
- dir: '../../node_modules/.vitest',
- },
- environment: 'node',
- include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
- },
+export default createE2ETestConfig('nx-plugin-e2e', {
+ testTimeout: 80_000,
});
diff --git a/e2e/plugin-coverage-e2e/vitest.e2e.config.ts b/e2e/plugin-coverage-e2e/vitest.e2e.config.ts
index 27a4a055d..d8321ccd7 100644
--- a/e2e/plugin-coverage-e2e/vitest.e2e.config.ts
+++ b/e2e/plugin-coverage-e2e/vitest.e2e.config.ts
@@ -1,21 +1,5 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createE2ETestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-coverage-e2e',
- test: {
- reporters: ['basic'],
- testTimeout: 40_000,
- globals: true,
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- cache: {
- dir: '../../node_modules/.vitest',
- },
- environment: 'node',
- include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
- },
+export default createE2ETestConfig('plugin-coverage-e2e', {
+ testTimeout: 40_000,
});
diff --git a/e2e/plugin-eslint-e2e/vitest.e2e.config.ts b/e2e/plugin-eslint-e2e/vitest.e2e.config.ts
index d54795b9b..b16df27c6 100644
--- a/e2e/plugin-eslint-e2e/vitest.e2e.config.ts
+++ b/e2e/plugin-eslint-e2e/vitest.e2e.config.ts
@@ -1,21 +1,5 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createE2ETestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-lighthouse-e2e',
- test: {
- reporters: ['basic'],
- testTimeout: 20_000,
- globals: true,
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- cache: {
- dir: '../../node_modules/.vitest',
- },
- environment: 'node',
- include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
- },
+export default createE2ETestConfig('plugin-eslint-e2e', {
+ testTimeout: 20_000,
});
diff --git a/e2e/plugin-js-packages-e2e/vitest.e2e.config.ts b/e2e/plugin-js-packages-e2e/vitest.e2e.config.ts
index d6c21a4da..30f03ebb5 100644
--- a/e2e/plugin-js-packages-e2e/vitest.e2e.config.ts
+++ b/e2e/plugin-js-packages-e2e/vitest.e2e.config.ts
@@ -1,21 +1,5 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createE2ETestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-js-packages-e2e',
- test: {
- reporters: ['basic'],
- testTimeout: 120_000,
- globals: true,
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- cache: {
- dir: '../../node_modules/.vitest',
- },
- environment: 'node',
- include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
- },
+export default createE2ETestConfig('plugin-js-packages-e2e', {
+ testTimeout: 120_000,
});
diff --git a/e2e/plugin-jsdocs-e2e/vitest.e2e.config.ts b/e2e/plugin-jsdocs-e2e/vitest.e2e.config.ts
index 9b069c338..2ccf45da4 100644
--- a/e2e/plugin-jsdocs-e2e/vitest.e2e.config.ts
+++ b/e2e/plugin-jsdocs-e2e/vitest.e2e.config.ts
@@ -1,21 +1,5 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createE2ETestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-jsdocs-e2e',
- test: {
- reporters: ['basic'],
- testTimeout: 20_000,
- globals: true,
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- cache: {
- dir: '../../node_modules/.vitest',
- },
- environment: 'node',
- include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
- },
+export default createE2ETestConfig('plugin-jsdocs-e2e', {
+ testTimeout: 20_000,
});
diff --git a/e2e/plugin-lighthouse-e2e/vitest.e2e.config.ts b/e2e/plugin-lighthouse-e2e/vitest.e2e.config.ts
index 302f6aa75..422d0003f 100644
--- a/e2e/plugin-lighthouse-e2e/vitest.e2e.config.ts
+++ b/e2e/plugin-lighthouse-e2e/vitest.e2e.config.ts
@@ -1,21 +1,5 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createE2ETestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-lighthouse-e2e',
- test: {
- reporters: ['basic'],
- testTimeout: 80_000,
- globals: true,
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- cache: {
- dir: '../../node_modules/.vitest',
- },
- environment: 'node',
- include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
- },
+export default createE2ETestConfig('plugin-lighthouse-e2e', {
+ testTimeout: 80_000,
});
diff --git a/e2e/plugin-typescript-e2e/vitest.e2e.config.ts b/e2e/plugin-typescript-e2e/vitest.e2e.config.ts
index c34d55a36..50fb4e0a1 100644
--- a/e2e/plugin-typescript-e2e/vitest.e2e.config.ts
+++ b/e2e/plugin-typescript-e2e/vitest.e2e.config.ts
@@ -1,26 +1,5 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createE2ETestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-typescript-e2e',
- test: {
- reporters: ['basic'],
- testTimeout: 20_000,
- globals: true,
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-typescript-e2e/e2e-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- cache: {
- dir: '../../node_modules/.vitest',
- },
- environment: 'node',
- include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
- },
+export default createE2ETestConfig('plugin-typescript-e2e', {
+ testTimeout: 20_000,
});
diff --git a/examples/plugins/vitest.int.config.ts b/examples/plugins/vitest.int.config.ts
index 3390c1dba..e36e7c452 100644
--- a/examples/plugins/vitest.int.config.ts
+++ b/examples/plugins/vitest.int.config.ts
@@ -1,30 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/examples-plugins',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/examples-plugins/int-tests',
- exclude: ['**/mocks/**', '**/mock/**', 'code-pushup.config.ts'],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/git.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createIntTestConfig('examples-plugins');
diff --git a/examples/plugins/vitest.unit.config.ts b/examples/plugins/vitest.unit.config.ts
index e49f12646..db3f979f3 100644
--- a/examples/plugins/vitest.unit.config.ts
+++ b/examples/plugins/vitest.unit.config.ts
@@ -1,31 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/examples-plugins',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/examples-plugins/unit-tests',
- exclude: ['**/mocks/**', '**/mock/**', 'code-pushup.config.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/git.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createUnitTestConfig('examples-plugins');
diff --git a/global-setup.ts b/global-setup.ts
index 65522d48f..76e5c8dea 100644
--- a/global-setup.ts
+++ b/global-setup.ts
@@ -1,3 +1,18 @@
-export async function setup() {
+/* eslint-disable functional/immutable-data */
+
+const originalCI = process.env['CI'];
+
+export function setup() {
process.env.TZ = 'UTC';
+
+ // package is expected to run in CI environment
+ process.env['CI'] = 'true';
+}
+
+export function teardown() {
+ if (originalCI === undefined) {
+ delete process.env['CI'];
+ } else {
+ process.env['CI'] = originalCI;
+ }
}
diff --git a/packages/ci/vitest.int.config.ts b/packages/ci/vitest.int.config.ts
index 88ea3988c..6e5eecf6d 100644
--- a/packages/ci/vitest.int.config.ts
+++ b/packages/ci/vitest.int.config.ts
@@ -1,29 +1,16 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/ci',
+let config = createIntTestConfig('ci');
+
+config = {
+ ...config,
test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/ci/int-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
+ ...config.test,
setupFiles: [
+ ...(config.test!.setupFiles || []),
'../../testing/test-setup/src/lib/logger.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
],
},
-});
+};
+
+export default config;
diff --git a/packages/ci/vitest.unit.config.ts b/packages/ci/vitest.unit.config.ts
index 854777d69..be6aa8cb1 100644
--- a/packages/ci/vitest.unit.config.ts
+++ b/packages/ci/vitest.unit.config.ts
@@ -1,32 +1,16 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/ci',
+let config = createUnitTestConfig('ci');
+
+config = {
+ ...config,
test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/ci/unit-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
+ ...config.test,
setupFiles: [
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/git.mock.ts',
+ ...(config.test!.setupFiles || []),
'../../testing/test-setup/src/lib/logger.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/extend/jest-extended.matcher.ts',
],
},
-});
+};
+
+export default config;
diff --git a/packages/cli/vitest.int.config.ts b/packages/cli/vitest.int.config.ts
index 491b566d2..e20715cb2 100644
--- a/packages/cli/vitest.int.config.ts
+++ b/packages/cli/vitest.int.config.ts
@@ -1,29 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/cli',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/cli/int-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createIntTestConfig('cli');
diff --git a/packages/cli/vitest.unit.config.ts b/packages/cli/vitest.unit.config.ts
index cd943a42b..43e719425 100644
--- a/packages/cli/vitest.unit.config.ts
+++ b/packages/cli/vitest.unit.config.ts
@@ -1,34 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/cli',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/cli/unit-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/cliui.mock.ts',
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/git.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/portal-client.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
- ],
- },
-});
+export default createUnitTestConfig('cli');
diff --git a/packages/core/vitest.int.config.ts b/packages/core/vitest.int.config.ts
index 7ff35029f..b129829a4 100644
--- a/packages/core/vitest.int.config.ts
+++ b/packages/core/vitest.int.config.ts
@@ -1,30 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/core',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/core/int-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/portal-client.mock.ts',
- ],
- },
-});
+export default createIntTestConfig('core');
diff --git a/packages/core/vitest.unit.config.ts b/packages/core/vitest.unit.config.ts
index c46850c41..e418e452d 100644
--- a/packages/core/vitest.unit.config.ts
+++ b/packages/core/vitest.unit.config.ts
@@ -1,36 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/core',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/core/unit-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/cliui.mock.ts',
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/git.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/portal-client.mock.ts',
- '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
- '../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
- '../../testing/test-setup/src/lib/extend/jest-extended.matcher.ts',
- ],
- },
-});
+export default createUnitTestConfig('core');
diff --git a/packages/create-cli/vitest.unit.config.ts b/packages/create-cli/vitest.unit.config.ts
index 3b327e222..fae682415 100644
--- a/packages/create-cli/vitest.unit.config.ts
+++ b/packages/create-cli/vitest.unit.config.ts
@@ -1,30 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/create-cli',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/create-cli/unit-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createUnitTestConfig('create-cli');
diff --git a/packages/models/src/lib/implementation/validate.unit.test.ts b/packages/models/src/lib/implementation/validate.unit.test.ts
index 96e36891c..6495e3800 100644
--- a/packages/models/src/lib/implementation/validate.unit.test.ts
+++ b/packages/models/src/lib/implementation/validate.unit.test.ts
@@ -6,6 +6,18 @@ import { ZodError, z } from 'zod';
import { SchemaValidationError, validate, validateAsync } from './validate.js';
describe('validate', () => {
+ beforeEach(() => {
+ // Set up memfs with package.json for tests that use async transforms
+ // This prevents unhandled rejections when async operations continue after validation errors
+ vol.fromJSON({ 'package.json': '{ "name": "test" }' }, '/test');
+ });
+
+ afterEach(async () => {
+ // Allow any lingering async operations from transforms to complete
+ // This prevents unhandled rejections in subsequent tests
+ await new Promise(resolve => setImmediate(resolve));
+ });
+
it('should return parsed data if valid', () => {
const configSchema = z
.object({
diff --git a/packages/models/vitest.unit.config.ts b/packages/models/vitest.unit.config.ts
index bc7f57676..1923730a5 100644
--- a/packages/models/vitest.unit.config.ts
+++ b/packages/models/vitest.unit.config.ts
@@ -1,30 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/models',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/models/unit-tests',
- exclude: ['mocks/**', '**/types.ts', 'zod2md.config.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createUnitTestConfig('models');
diff --git a/packages/nx-plugin/vitest.int.config.ts b/packages/nx-plugin/vitest.int.config.ts
index 0f9f0340b..96d09e577 100644
--- a/packages/nx-plugin/vitest.int.config.ts
+++ b/packages/nx-plugin/vitest.int.config.ts
@@ -1,28 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/nx-plugin',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/nx-plugin/int-tests',
- exclude: ['mocks/**', '**/types.ts', '**/__snapshots__/**'],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: [
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createIntTestConfig('nx-plugin');
diff --git a/packages/nx-plugin/vitest.unit.config.ts b/packages/nx-plugin/vitest.unit.config.ts
index b42185d97..25e47a0a0 100644
--- a/packages/nx-plugin/vitest.unit.config.ts
+++ b/packages/nx-plugin/vitest.unit.config.ts
@@ -1,29 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/nx-plugin',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/nx-plugin/unit-tests',
- exclude: ['mocks/**', '**/types.ts', '**/__snapshots__/**'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- setupFiles: [
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createUnitTestConfig('nx-plugin');
diff --git a/packages/plugin-coverage/vitest.int.config.ts b/packages/plugin-coverage/vitest.int.config.ts
index ca03251a4..bbf96c4fd 100644
--- a/packages/plugin-coverage/vitest.int.config.ts
+++ b/packages/plugin-coverage/vitest.int.config.ts
@@ -1,29 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-coverage',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-coverage/int-tests',
- exclude: ['mocks/**', '**/types.ts', '**/vitest.*.config.ts'],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createIntTestConfig('plugin-coverage');
diff --git a/packages/plugin-coverage/vitest.unit.config.ts b/packages/plugin-coverage/vitest.unit.config.ts
index 4e8c164fd..e6e8018e7 100644
--- a/packages/plugin-coverage/vitest.unit.config.ts
+++ b/packages/plugin-coverage/vitest.unit.config.ts
@@ -1,32 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-coverage',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-coverage/unit-tests',
- exclude: ['mocks/**', '**/types.ts', '**/vitest.*.config.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/cliui.mock.ts',
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
- ],
- },
-});
+export default createUnitTestConfig('plugin-coverage');
diff --git a/packages/plugin-eslint/vitest.int.config.ts b/packages/plugin-eslint/vitest.int.config.ts
index cad993f3e..e251e54f9 100644
--- a/packages/plugin-eslint/vitest.int.config.ts
+++ b/packages/plugin-eslint/vitest.int.config.ts
@@ -1,29 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-eslint',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-eslint/int-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createIntTestConfig('plugin-eslint');
diff --git a/packages/plugin-eslint/vitest.unit.config.ts b/packages/plugin-eslint/vitest.unit.config.ts
index a9baf4edb..ca304267e 100644
--- a/packages/plugin-eslint/vitest.unit.config.ts
+++ b/packages/plugin-eslint/vitest.unit.config.ts
@@ -1,32 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-eslint',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-eslint/unit-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/cliui.mock.ts',
- '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
- ],
- },
-});
+export default createUnitTestConfig('plugin-eslint');
diff --git a/packages/plugin-js-packages/vitest.int.config.ts b/packages/plugin-js-packages/vitest.int.config.ts
index 00e1f7be0..7d6d9bf8c 100644
--- a/packages/plugin-js-packages/vitest.int.config.ts
+++ b/packages/plugin-js-packages/vitest.int.config.ts
@@ -1,29 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-js-packages',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-js-packages/int-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createIntTestConfig('plugin-js-packages');
diff --git a/packages/plugin-js-packages/vitest.unit.config.ts b/packages/plugin-js-packages/vitest.unit.config.ts
index d75e48879..855c3ace3 100644
--- a/packages/plugin-js-packages/vitest.unit.config.ts
+++ b/packages/plugin-js-packages/vitest.unit.config.ts
@@ -1,30 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-js-packages',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-js-packages/unit-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createUnitTestConfig('plugin-js-packages');
diff --git a/packages/plugin-jsdocs/vitest.int.config.ts b/packages/plugin-jsdocs/vitest.int.config.ts
index 57d6dfc75..f7fb998ba 100644
--- a/packages/plugin-jsdocs/vitest.int.config.ts
+++ b/packages/plugin-jsdocs/vitest.int.config.ts
@@ -1,30 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-coverage',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-jsdocs/int-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/extend/path.matcher.ts',
- ],
- },
-});
+export default createIntTestConfig('plugin-jsdocs');
diff --git a/packages/plugin-jsdocs/vitest.unit.config.ts b/packages/plugin-jsdocs/vitest.unit.config.ts
index 0ead182dc..88a3855cc 100644
--- a/packages/plugin-jsdocs/vitest.unit.config.ts
+++ b/packages/plugin-jsdocs/vitest.unit.config.ts
@@ -1,32 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-coverage',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-jsdocs/unit-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/cliui.mock.ts',
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/extend/path.matcher.ts',
- ],
- },
-});
+export default createUnitTestConfig('plugin-jsdocs');
diff --git a/packages/plugin-lighthouse/vitest.unit.config.ts b/packages/plugin-lighthouse/vitest.unit.config.ts
index a53798020..16a9ae972 100644
--- a/packages/plugin-lighthouse/vitest.unit.config.ts
+++ b/packages/plugin-lighthouse/vitest.unit.config.ts
@@ -1,33 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-lighthouse',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-lighthouse/unit-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/cliui.mock.ts',
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/extend/path.matcher.ts',
- '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
- ],
- },
-});
+export default createUnitTestConfig('plugin-lighthouse');
diff --git a/packages/plugin-typescript/vitest.int.config.ts b/packages/plugin-typescript/vitest.int.config.ts
index 3573540d7..49425e520 100644
--- a/packages/plugin-typescript/vitest.int.config.ts
+++ b/packages/plugin-typescript/vitest.int.config.ts
@@ -1,35 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-typescript',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest/plugin-typescript',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-typescript/int-tests',
- exclude: [
- 'mocks/**',
- '**/types.ts',
- '**/index.ts',
- 'vitest.{unit,int}.config.ts',
- ],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/cliui.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/chrome-path.mock.ts',
- ],
- },
-});
+export default createIntTestConfig('plugin-typescript');
diff --git a/packages/plugin-typescript/vitest.unit.config.ts b/packages/plugin-typescript/vitest.unit.config.ts
index 2dcce41e8..6fa6ed0ef 100644
--- a/packages/plugin-typescript/vitest.unit.config.ts
+++ b/packages/plugin-typescript/vitest.unit.config.ts
@@ -1,37 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-typescript',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest/plugin-typescript',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-typescript/unit-tests',
- exclude: [
- 'mocks/**',
- '**/types.ts',
- '**/index.ts',
- 'vitest.{unit,int}.config.ts',
- ],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/cliui.mock.ts',
- '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createUnitTestConfig('plugin-typescript');
diff --git a/packages/utils/vitest.int.config.ts b/packages/utils/vitest.int.config.ts
index b72908490..2fd47c4e5 100644
--- a/packages/utils/vitest.int.config.ts
+++ b/packages/utils/vitest.int.config.ts
@@ -1,30 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createIntTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/utils',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/utils/int-tests',
- exclude: ['mocks/**', 'perf/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/cliui.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createIntTestConfig('utils');
diff --git a/packages/utils/vitest.unit.config.ts b/packages/utils/vitest.unit.config.ts
index f55eb2326..2c735217d 100644
--- a/packages/utils/vitest.unit.config.ts
+++ b/packages/utils/vitest.unit.config.ts
@@ -1,38 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/utils',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/utils/unit-tests',
- exclude: ['mocks/**', 'perf/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.{unit,type}.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- typecheck: {
- include: ['**/*.type.test.ts'],
- },
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/cliui.mock.ts',
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
- '../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
- '../../testing/test-setup/src/lib/extend/path.matcher.ts',
- '../../testing/test-setup/src/lib/extend/jest-extended.matcher.ts',
- ],
- },
-});
+export default createUnitTestConfig('utils');
diff --git a/testing/test-nx-utils/src/lib/utils/nx-plugin.unit.test.ts b/testing/test-nx-utils/src/lib/utils/nx-plugin.unit.test.ts
index 7710cfccf..013d06bcc 100644
--- a/testing/test-nx-utils/src/lib/utils/nx-plugin.unit.test.ts
+++ b/testing/test-nx-utils/src/lib/utils/nx-plugin.unit.test.ts
@@ -1,5 +1,5 @@
-import * as process from 'node:process';
import { describe, expect } from 'vitest';
+import { MEMFS_VOLUME } from '@code-pushup/test-utils';
import {
createNodesContext,
invokeCreateNodesOnVirtualFiles,
@@ -23,7 +23,7 @@ describe('createNodesContext', () => {
const context = createNodesContext();
expect(context).toStrictEqual(
expect.objectContaining({
- workspaceRoot: process.cwd(),
+ workspaceRoot: MEMFS_VOLUME,
nxJsonConfiguration: {},
}),
);
diff --git a/testing/test-nx-utils/src/lib/utils/nx.unit.test.ts b/testing/test-nx-utils/src/lib/utils/nx.unit.test.ts
index 7587f05fc..fd6593875 100644
--- a/testing/test-nx-utils/src/lib/utils/nx.unit.test.ts
+++ b/testing/test-nx-utils/src/lib/utils/nx.unit.test.ts
@@ -1,12 +1,12 @@
-import * as process from 'node:process';
import { createTreeWithEmptyWorkspace } from 'nx/src/generators/testing-utils/create-tree-with-empty-workspace';
import { describe, expect } from 'vitest';
+import { MEMFS_VOLUME } from '@code-pushup/test-utils';
import { executorContext, registerPluginInWorkspace } from './nx.js';
describe('executorContext', () => {
it('should create context for given project name', () => {
expect(executorContext('my-lib')).toStrictEqual({
- cwd: process.cwd(),
+ cwd: MEMFS_VOLUME,
isVerbose: false,
projectName: 'my-lib',
projectsConfigurations: {
diff --git a/testing/test-nx-utils/vitest.unit.config.ts b/testing/test-nx-utils/vitest.unit.config.ts
index 0e5103fa3..c7bd7a43a 100644
--- a/testing/test-nx-utils/vitest.unit.config.ts
+++ b/testing/test-nx-utils/vitest.unit.config.ts
@@ -1,24 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../node_modules/.vite/test-nx-utils',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/test-nx-utils/unit-tests',
- exclude: ['**/*.mock.{mjs,ts}', '**/*.config.{js,mjs,ts}'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.ts'],
- },
-});
+export default createUnitTestConfig('test-nx-utils');
diff --git a/testing/test-setup-config/README.md b/testing/test-setup-config/README.md
new file mode 100644
index 000000000..f9047bdbc
--- /dev/null
+++ b/testing/test-setup-config/README.md
@@ -0,0 +1,34 @@
+## Vitest Config Factory
+
+Standardized Vitest configuration for the Code PushUp monorepo.
+
+### Usage
+
+#### Unit tests:
+
+```typescript
+import { createUnitTestConfig } from '@code-pushup/test-setup-config';
+
+export default createUnitTestConfig('my-package');
+```
+
+#### Integration tests:
+
+```typescript
+import { createIntTestConfig } from '@code-pushup/test-setup-config';
+
+export default createIntTestConfig('my-package');
+```
+
+#### E2E tests:
+
+```typescript
+import { createE2ETestConfig } from '@code-pushup/test-setup-config';
+
+export default createE2ETestConfig('my-e2e');
+
+// With options:
+export default createE2ETestConfig('my-e2e', {
+ testTimeout: 60_000,
+});
+```
diff --git a/testing/test-setup-config/eslint.config.js b/testing/test-setup-config/eslint.config.js
new file mode 100644
index 000000000..2656b27cb
--- /dev/null
+++ b/testing/test-setup-config/eslint.config.js
@@ -0,0 +1,12 @@
+import tseslint from 'typescript-eslint';
+import baseConfig from '../../eslint.config.js';
+
+export default tseslint.config(...baseConfig, {
+ files: ['**/*.ts'],
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ tsconfigRootDir: import.meta.dirname,
+ },
+ },
+});
diff --git a/testing/test-setup-config/project.json b/testing/test-setup-config/project.json
new file mode 100644
index 000000000..c4b32ba8a
--- /dev/null
+++ b/testing/test-setup-config/project.json
@@ -0,0 +1,12 @@
+{
+ "name": "test-setup-config",
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "testing/test-setup/src",
+ "projectType": "library",
+ "targets": {
+ "build": {},
+ "lint": {},
+ "unit-test": {}
+ },
+ "tags": ["scope:shared", "type:testing"]
+}
diff --git a/testing/test-setup-config/src/index.ts b/testing/test-setup-config/src/index.ts
new file mode 100644
index 000000000..4c0219d3b
--- /dev/null
+++ b/testing/test-setup-config/src/index.ts
@@ -0,0 +1,14 @@
+export {
+ createUnitTestConfig,
+ createIntTestConfig,
+ createE2ETestConfig,
+} from './lib/vitest-setup-presets.js';
+
+export type { E2ETestOptions, TestKind } from './lib/vitest-config-factory.js';
+
+export {
+ createVitestConfig,
+ type E2ETestOptions as E2ETestOptionsAlias,
+} from './lib/vitest-config-factory.js';
+
+export { getSetupFiles } from './lib/vitest-setup-files.js';
diff --git a/testing/test-setup-config/src/lib/vitest-config-factory.ts b/testing/test-setup-config/src/lib/vitest-config-factory.ts
new file mode 100644
index 000000000..5bf1ad41c
--- /dev/null
+++ b/testing/test-setup-config/src/lib/vitest-config-factory.ts
@@ -0,0 +1,73 @@
+import type { CoverageOptions } from 'vitest';
+import { type UserConfig as ViteUserConfig } from 'vitest/config';
+import { getSetupFiles } from './vitest-setup-files.js';
+import { tsconfigPathAliases } from './vitest-tsconfig-path-aliases.js';
+
+export type TestKind = 'unit' | 'int' | 'e2e';
+
+export type E2ETestOptions = {
+ testTimeout?: number;
+};
+
+function getIncludePatterns(kind: TestKind): string[] {
+ switch (kind) {
+ case 'unit':
+ return [
+ 'src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
+ 'src/**/*.type.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
+ ];
+ case 'int':
+ return ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'];
+ case 'e2e':
+ return ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'];
+ }
+}
+
+function buildCoverageConfig(
+ projectKey: string,
+ kind: TestKind,
+): CoverageOptions | undefined {
+ if (kind === 'e2e') {
+ return undefined;
+ }
+
+ const exclude = ['mocks/**', '**/types.ts', 'perf/**'];
+ const reportsDirectory = `../../coverage/${projectKey}/${kind}-tests`;
+
+ return {
+ reporter: ['text', 'lcov'],
+ reportsDirectory,
+ exclude: exclude,
+ };
+}
+
+export function createVitestConfig(
+ projectKey: string,
+ kind: TestKind,
+ options?: E2ETestOptions,
+): ViteUserConfig {
+ const coverage = buildCoverageConfig(projectKey, kind);
+
+ return {
+ cacheDir: `../../node_modules/.vite/${projectKey}`,
+ test: {
+ reporters: ['basic'],
+ globals: true,
+ cache: {
+ dir: '../../node_modules/.vitest',
+ },
+ alias: tsconfigPathAliases(),
+ pool: 'threads',
+ poolOptions: { threads: { singleThread: true } },
+ environment: 'node',
+ include: getIncludePatterns(kind),
+ globalSetup: ['../../global-setup.ts'],
+ setupFiles: [...getSetupFiles(kind)],
+ ...(options?.testTimeout ? { testTimeout: options.testTimeout } : {}),
+ ...(coverage ? { coverage } : {}),
+ ...(kind === 'unit'
+ ? { typecheck: { include: ['**/*.type.test.ts'] } }
+ : {}),
+ },
+ };
+}
diff --git a/testing/test-setup-config/src/lib/vitest-config-factory.unit.test.ts b/testing/test-setup-config/src/lib/vitest-config-factory.unit.test.ts
new file mode 100644
index 000000000..efd688d88
--- /dev/null
+++ b/testing/test-setup-config/src/lib/vitest-config-factory.unit.test.ts
@@ -0,0 +1,339 @@
+import { describe, expect, it, vi } from 'vitest';
+import type { E2ETestOptions, TestKind } from './vitest-config-factory.js';
+import { createVitestConfig } from './vitest-config-factory.js';
+
+vi.mock('./vitest-tsconfig-path-aliases.js', () => ({
+ tsconfigPathAliases: vi
+ .fn()
+ .mockReturnValue([{ find: '@test/alias', replacement: '/mock/path' }]),
+}));
+
+describe('createVitestConfig', () => {
+ describe('unit test configuration', () => {
+ it('should create a complete unit test config with all defaults', () => {
+ const config = createVitestConfig('test-package', 'unit');
+
+ expect(config).toEqual({
+ cacheDir: '../../node_modules/.vite/test-package',
+ test: expect.objectContaining({
+ reporters: ['basic'],
+ globals: true,
+ cache: { dir: '../../node_modules/.vitest' },
+ alias: expect.any(Array),
+ pool: 'threads',
+ poolOptions: { threads: { singleThread: true } },
+ environment: 'node',
+ include: [
+ 'src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
+ 'src/**/*.type.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
+ ],
+ globalSetup: ['../../global-setup.ts'],
+ setupFiles: expect.arrayContaining([
+ '../../testing/test-setup/src/lib/console.mock.ts',
+ '../../testing/test-setup/src/lib/reset.mocks.ts',
+ '../../testing/test-setup/src/lib/fs.mock.ts',
+ ]),
+ coverage: expect.objectContaining({
+ reporter: ['text', 'lcov'],
+ reportsDirectory: '../../coverage/test-package/unit-tests',
+ exclude: ['mocks/**', '**/types.ts', 'perf/**'],
+ }),
+ typecheck: { include: ['**/*.type.test.ts'] },
+ }),
+ });
+ });
+
+ it('should include all required setup files for unit tests', () => {
+ const config = createVitestConfig('test-package', 'unit');
+
+ const setupFiles = config.test!.setupFiles;
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/console.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/reset.mocks.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/cliui.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/fs.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/git.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/portal-client.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/logger.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/jest-extended.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/path.matcher.ts',
+ );
+ });
+
+ it('should include type test pattern in unit tests', () => {
+ const config = createVitestConfig('test-package', 'unit');
+
+ expect(config.test!.include).toContain(
+ 'src/**/*.type.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
+ );
+ });
+
+ it('should enable typecheck for unit tests', () => {
+ const config = createVitestConfig('test-package', 'unit');
+
+ expect(config.test!.typecheck).toEqual({
+ include: ['**/*.type.test.ts'],
+ });
+ });
+
+ it('should always include perf/** in coverage exclusions', () => {
+ const config = createVitestConfig('test-package', 'unit');
+
+ expect(config.test!.coverage!.exclude).toContain('perf/**');
+ });
+ });
+
+ describe('integration test configuration', () => {
+ it('should create a complete integration test config', () => {
+ const config = createVitestConfig('test-package', 'int');
+
+ expect(config).toEqual({
+ cacheDir: '../../node_modules/.vite/test-package',
+ test: expect.objectContaining({
+ reporters: ['basic'],
+ globals: true,
+ include: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
+ globalSetup: ['../../global-setup.ts'],
+ coverage: expect.objectContaining({
+ reportsDirectory: '../../coverage/test-package/int-tests',
+ }),
+ }),
+ });
+ });
+
+ it('should include correct setup files for integration tests', () => {
+ const config = createVitestConfig('test-package', 'int');
+
+ const setupFiles = config.test!.setupFiles;
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/console.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/logger.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/fs.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/cliui.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/git.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/path.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
+ );
+ });
+
+ it('should not enable typecheck for integration tests', () => {
+ const config = createVitestConfig('test-package', 'int');
+
+ expect(config.test?.typecheck).toBeUndefined();
+ });
+ });
+
+ describe('e2e test configuration', () => {
+ it('should create e2e config without coverage by default', () => {
+ const config = createVitestConfig('test-package', 'e2e');
+
+ expect(config).toEqual({
+ cacheDir: '../../node_modules/.vite/test-package',
+ test: expect.objectContaining({
+ reporters: ['basic'],
+ globals: true,
+ include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
+ globalSetup: ['../../global-setup.ts'],
+ }),
+ });
+ expect(config.test?.coverage).toBeUndefined();
+ });
+
+ it('should include minimal setup files for e2e tests', () => {
+ const config = createVitestConfig('test-package', 'e2e');
+
+ const setupFiles = config.test!.setupFiles;
+ // Should only include reset mocks
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/reset.mocks.ts',
+ );
+ // Should NOT include console, fs, git, etc.
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/console.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/fs.mock.ts',
+ );
+ // Should include all matchers
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/path.matcher.ts',
+ );
+ });
+
+ it('should support custom testTimeout option', () => {
+ const options: E2ETestOptions = { testTimeout: 60_000 };
+ const config = createVitestConfig('test-package', 'e2e', options);
+
+ expect(config.test!.testTimeout).toBe(60_000);
+ });
+
+ it('should support multiple options together', () => {
+ const options: E2ETestOptions = {
+ testTimeout: 30_000,
+ };
+ const config = createVitestConfig('test-package', 'e2e', options);
+
+ expect(config.test!.testTimeout).toBe(30_000);
+ expect(config.test?.coverage).toBeUndefined();
+ });
+ });
+
+ describe('cacheDir naming', () => {
+ it('should use projectKey for cacheDir', () => {
+ const config = createVitestConfig('my-custom-name', 'unit');
+
+ expect(config.cacheDir).toBe('../../node_modules/.vite/my-custom-name');
+ });
+
+ it('should use projectKey for coverage directory', () => {
+ const config = createVitestConfig('my-package', 'unit');
+
+ expect(config.test!.coverage!.reportsDirectory).toBe(
+ '../../coverage/my-package/unit-tests',
+ );
+ });
+ });
+
+ describe('test kind variations', () => {
+ it('should handle all test kinds correctly', () => {
+ const testKinds: TestKind[] = ['unit', 'int', 'e2e'];
+
+ testKinds.forEach(kind => {
+ const config = createVitestConfig('test-package', kind);
+
+ const expectedIncludes = {
+ unit: [
+ 'src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
+ 'src/**/*.type.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
+ ],
+ int: ['src/**/*.int.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
+ e2e: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
+ };
+
+ expect(config.test!.include).toStrictEqual(expectedIncludes[kind]);
+
+ const expectedGlobalSetup = {
+ unit: ['../../global-setup.ts'],
+ int: ['../../global-setup.ts'],
+ e2e: ['../../global-setup.ts'],
+ };
+
+ expect(config.test!.globalSetup).toStrictEqual(
+ expectedGlobalSetup[kind],
+ );
+ });
+ });
+ });
+
+ describe('coverage configuration', () => {
+ it('should enable coverage for unit tests by default', () => {
+ const config = createVitestConfig('test-package', 'unit');
+
+ expect(config.test!.coverage).toBeDefined();
+ expect((config.test!.coverage as any).reporter).toEqual(['text', 'lcov']);
+ });
+
+ it('should enable coverage for integration tests by default', () => {
+ const config = createVitestConfig('test-package', 'int');
+
+ expect(config.test!.coverage).toBeDefined();
+ });
+
+ it('should disable coverage for e2e tests by default', () => {
+ const config = createVitestConfig('test-package', 'e2e');
+
+ expect(config.test?.coverage).toBeUndefined();
+ });
+
+ it('should always exclude mocks, types.ts, and perf folders', () => {
+ const config = createVitestConfig('test-package', 'unit');
+
+ expect(config.test!.coverage!.exclude).toEqual([
+ 'mocks/**',
+ '**/types.ts',
+ 'perf/**',
+ ]);
+ });
+ });
+
+ describe('relative paths', () => {
+ it('should use relative paths for all file references', () => {
+ const config = createVitestConfig('test-package', 'unit');
+
+ // Setup files should be relative
+ const setupFiles = config.test!.setupFiles;
+ expect(setupFiles).toBeDefined();
+ expect(setupFiles![0]).toMatch(/^\.\.\/\.\.\//);
+
+ // GlobalSetup should be relative
+ expect(config.test!.globalSetup![0]).toBe('../../global-setup.ts');
+
+ // Cache dirs should be relative
+ expect(config.cacheDir).toMatch(/^\.\.\/\.\.\//);
+ expect((config.test!.cache as any).dir).toMatch(/^\.\.\/\.\.\//);
+
+ // Coverage directory should be relative
+ expect(config.test!.coverage!.reportsDirectory).toMatch(/^\.\.\/\.\.\//);
+ });
+ });
+
+ describe('edge cases', () => {
+ it('should handle empty projectKey gracefully', () => {
+ const config = createVitestConfig('', 'unit');
+
+ expect(config.cacheDir).toBe('../../node_modules/.vite/');
+ expect(config.test!.coverage!.reportsDirectory).toBe(
+ '../../coverage//unit-tests',
+ );
+ });
+
+ it('should handle projectKey with special characters', () => {
+ const config = createVitestConfig('my-special_package.v2', 'unit');
+
+ expect(config.cacheDir).toBe(
+ '../../node_modules/.vite/my-special_package.v2',
+ );
+ });
+
+ it('should not modify config when no options provided to e2e', () => {
+ const config = createVitestConfig('test-package', 'e2e');
+
+ expect(config.test?.testTimeout).toBeUndefined();
+ expect(config.test?.globalSetup).toEqual(['../../global-setup.ts']);
+ });
+ });
+});
diff --git a/testing/test-setup-config/src/lib/vitest-setup-files.ts b/testing/test-setup-config/src/lib/vitest-setup-files.ts
new file mode 100644
index 000000000..2f67c4c6d
--- /dev/null
+++ b/testing/test-setup-config/src/lib/vitest-setup-files.ts
@@ -0,0 +1,80 @@
+import type { TestKind } from './vitest-config-factory.js';
+
+/**
+ * Custom matchers that extend Vitest's assertion library.
+ *
+ * These paths are relative to the config file location,
+ * which is why they use `../../` to navigate to the workspace root first.
+ */
+const CUSTOM_MATCHERS = [
+ '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
+ '../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
+ '../../testing/test-setup/src/lib/extend/jest-extended.matcher.ts',
+ '../../testing/test-setup/src/lib/extend/path.matcher.ts',
+] as const;
+
+/**
+ * Setup files for unit tests.
+ *
+ * These paths are relative to the config file location (typically `packages//vitest.unit.config.ts`),
+ * which is why they use `../../` to navigate to the workspace root first.
+ */
+const UNIT_TEST_SETUP_FILES = [
+ '../../testing/test-setup/src/lib/fs.mock.ts',
+ '../../testing/test-setup/src/lib/console.mock.ts',
+ '../../testing/test-setup/src/lib/reset.mocks.ts',
+ '../../testing/test-setup/src/lib/cliui.mock.ts',
+ '../../testing/test-setup/src/lib/git.mock.ts',
+ '../../testing/test-setup/src/lib/portal-client.mock.ts',
+ '../../testing/test-setup/src/lib/logger.mock.ts',
+ ...CUSTOM_MATCHERS,
+] as const;
+
+/**
+ * Setup files for integration tests.
+ *
+ * These paths are relative to the config file location (typically `packages//vitest.int.config.ts`),
+ * which is why they use `../../` to navigate to the workspace root first.
+
+ */
+const INT_TEST_SETUP_FILES = [
+ '../../testing/test-setup/src/lib/console.mock.ts',
+ '../../testing/test-setup/src/lib/reset.mocks.ts',
+ '../../testing/test-setup/src/lib/chrome-path.mock.ts',
+ '../../testing/test-setup/src/lib/logger.mock.ts',
+ ...CUSTOM_MATCHERS,
+] as const;
+
+/**
+ * Setup files for E2E tests.
+ *
+ * These paths are relative to the config file location (typically `e2e//vitest.e2e.config.ts`),
+ * which is why they use `../../` to navigate to the workspace root first.
+ */
+const E2E_TEST_SETUP_FILES = [
+ '../../testing/test-setup/src/lib/reset.mocks.ts',
+ ...CUSTOM_MATCHERS,
+] as const;
+
+/**
+ * Returns the appropriate setup files for the given test kind.
+ *
+ * @param kind - The type of test (unit, int, or e2e)
+ * @returns Array of setup file paths relative to the config file location
+ *
+ * @example
+ * ```typescript
+ * const setupFiles = getSetupFiles('unit');
+ * // Returns all unit test setup files including mocks and matchers
+ * ```
+ */
+export function getSetupFiles(kind: TestKind): readonly string[] {
+ switch (kind) {
+ case 'unit':
+ return UNIT_TEST_SETUP_FILES;
+ case 'int':
+ return INT_TEST_SETUP_FILES;
+ case 'e2e':
+ return E2E_TEST_SETUP_FILES;
+ }
+}
diff --git a/testing/test-setup-config/src/lib/vitest-setup-files.unit.test.ts b/testing/test-setup-config/src/lib/vitest-setup-files.unit.test.ts
new file mode 100644
index 000000000..f585bc0b5
--- /dev/null
+++ b/testing/test-setup-config/src/lib/vitest-setup-files.unit.test.ts
@@ -0,0 +1,185 @@
+import { describe, expect, it } from 'vitest';
+import { getSetupFiles } from './vitest-setup-files.js';
+
+describe('vitest-setup-files', () => {
+ describe('getSetupFiles', () => {
+ describe('unit test setup files', () => {
+ it('should return all required setup files for unit tests', () => {
+ const setupFiles = getSetupFiles('unit');
+
+ expect(setupFiles).toHaveLength(11);
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/console.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/reset.mocks.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/cliui.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/fs.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/git.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/portal-client.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/logger.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/jest-extended.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/path.matcher.ts',
+ );
+ });
+ });
+
+ describe('integration test setup files', () => {
+ it('should return exactly 8 setup files with essential mocks and custom matchers', () => {
+ const setupFiles = getSetupFiles('int');
+
+ expect(setupFiles).toHaveLength(8);
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/console.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/reset.mocks.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/chrome-path.mock.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/logger.mock.ts',
+ );
+ });
+
+ it('should include custom matchers for integration tests', () => {
+ const setupFiles = getSetupFiles('int');
+
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/jest-extended.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/path.matcher.ts',
+ );
+ });
+
+ it('should NOT include fs, cliui, git, and portal-client mocks for integration tests', () => {
+ const setupFiles = getSetupFiles('int');
+
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/fs.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/cliui.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/git.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/portal-client.mock.ts',
+ );
+ });
+ });
+
+ describe('e2e test setup files', () => {
+ it('should return exactly 5 setup files with minimal mocks', () => {
+ const setupFiles = getSetupFiles('e2e');
+
+ expect(setupFiles).toHaveLength(5);
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/reset.mocks.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/ui-logger.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/markdown-table.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/jest-extended.matcher.ts',
+ );
+ expect(setupFiles).toContain(
+ '../../testing/test-setup/src/lib/extend/path.matcher.ts',
+ );
+ });
+
+ it('should NOT include any other mocks for e2e tests', () => {
+ const setupFiles = getSetupFiles('e2e');
+
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/console.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/fs.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/git.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/cliui.mock.ts',
+ );
+ expect(setupFiles).not.toContain(
+ '../../testing/test-setup/src/lib/portal-client.mock.ts',
+ );
+ });
+ });
+
+ describe('relative paths', () => {
+ it('should return paths relative to config file location', () => {
+ const unitFiles = getSetupFiles('unit');
+ const intFiles = getSetupFiles('int');
+ const e2eFiles = getSetupFiles('e2e');
+
+ [...unitFiles, ...intFiles, ...e2eFiles].forEach(path => {
+ expect(path).toMatch(/^\.\.\/\.\.\//);
+ });
+ });
+ });
+
+ describe('return type', () => {
+ it('should return a readonly array', () => {
+ const setupFiles = getSetupFiles('unit');
+
+ expect(Array.isArray(setupFiles)).toBe(true);
+ });
+ });
+
+ describe('test kind differences', () => {
+ it('should return different setup files for different test kinds', () => {
+ const unitFiles = getSetupFiles('unit');
+ const intFiles = getSetupFiles('int');
+ const e2eFiles = getSetupFiles('e2e');
+
+ expect(unitFiles.length).not.toBe(intFiles.length);
+ expect(intFiles.length).not.toBe(e2eFiles.length);
+ expect(unitFiles.length).not.toBe(e2eFiles.length);
+ });
+
+ it('should show hierarchy: unit has most, e2e has least', () => {
+ const unitFiles = getSetupFiles('unit');
+ const intFiles = getSetupFiles('int');
+ const e2eFiles = getSetupFiles('e2e');
+
+ expect(unitFiles.length).toBeGreaterThan(intFiles.length);
+ expect(intFiles.length).toBeGreaterThan(e2eFiles.length);
+ });
+ });
+ });
+});
diff --git a/testing/test-setup-config/src/lib/vitest-setup-presets.ts b/testing/test-setup-config/src/lib/vitest-setup-presets.ts
new file mode 100644
index 000000000..ed26d7bbb
--- /dev/null
+++ b/testing/test-setup-config/src/lib/vitest-setup-presets.ts
@@ -0,0 +1,59 @@
+import type { UserConfig as ViteUserConfig } from 'vitest/config';
+import {
+ type E2ETestOptions,
+ createVitestConfig,
+} from './vitest-config-factory.js';
+
+/**
+ * Creates a standardized Vitest configuration for unit tests.
+ *
+ * @param projectKey - The project name (used for cache and coverage directory naming)
+ * @returns Vitest configuration object
+ *
+ * @example
+ * ```typescript
+ * export default createUnitTestConfig('my-package');
+ * ```
+ */
+export function createUnitTestConfig(projectKey: string): ViteUserConfig {
+ return createVitestConfig(projectKey, 'unit');
+}
+
+/**
+ * Creates a standardized Vitest configuration for integration tests.
+ *
+ * @param projectKey - The project name (used for cache and coverage directory naming)
+ * @returns Vitest configuration object
+ *
+ * @example
+ * ```typescript
+ * export default createIntTestConfig('my-package');
+ * ```
+ */
+export function createIntTestConfig(projectKey: string): ViteUserConfig {
+ return createVitestConfig(projectKey, 'int');
+}
+
+/**
+ * Creates a standardized Vitest configuration for E2E tests.
+ *
+ * @param projectKey - The project name (used for cache and coverage directory naming)
+ * @param options - Optional configuration for E2E tests
+ * @returns Vitest configuration object
+ *
+ * @example
+ * ```typescript
+ * // Basic usage
+ * export default createE2ETestConfig('my-e2e');
+ *
+ * // With options
+ * export default createE2ETestConfig('my-e2e', {
+ * testTimeout: 60_000,
+ * });
+ */
+export function createE2ETestConfig(
+ projectKey: string,
+ options?: E2ETestOptions,
+): ViteUserConfig {
+ return createVitestConfig(projectKey, 'e2e', options);
+}
diff --git a/testing/test-setup-config/src/lib/vitest-setup-presets.unit.test.ts b/testing/test-setup-config/src/lib/vitest-setup-presets.unit.test.ts
new file mode 100644
index 000000000..e94b7e3e9
--- /dev/null
+++ b/testing/test-setup-config/src/lib/vitest-setup-presets.unit.test.ts
@@ -0,0 +1,154 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+import * as configFactory from './vitest-config-factory.js';
+import {
+ createE2ETestConfig,
+ createIntTestConfig,
+ createUnitTestConfig,
+} from './vitest-setup-presets.js';
+
+vi.mock('./vitest-config-factory.js', () => ({
+ createVitestConfig: vi.fn().mockReturnValue('mocked-config'),
+}));
+
+const MOCK_PROJECT_KEY = 'test-package';
+
+describe('vitest-setup-presets', () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ describe('createUnitTestConfig', () => {
+ it('should call createVitestConfig with unit kind', () => {
+ const result = createUnitTestConfig(MOCK_PROJECT_KEY);
+
+ expect(configFactory.createVitestConfig).toHaveBeenCalledWith(
+ MOCK_PROJECT_KEY,
+ 'unit',
+ );
+ expect(result).toBe('mocked-config');
+ });
+
+ it('should handle different project names', () => {
+ createUnitTestConfig('my-custom-package');
+
+ expect(configFactory.createVitestConfig).toHaveBeenCalledWith(
+ 'my-custom-package',
+ 'unit',
+ );
+ });
+
+ it('should handle empty projectKey', () => {
+ createUnitTestConfig('');
+
+ expect(configFactory.createVitestConfig).toHaveBeenCalledWith('', 'unit');
+ });
+ });
+
+ describe('createIntTestConfig', () => {
+ it('should call createVitestConfig with int kind', () => {
+ const result = createIntTestConfig(MOCK_PROJECT_KEY);
+
+ expect(configFactory.createVitestConfig).toHaveBeenCalledWith(
+ MOCK_PROJECT_KEY,
+ 'int',
+ );
+ expect(result).toBe('mocked-config');
+ });
+
+ it('should handle different project names', () => {
+ createIntTestConfig('integration-package');
+
+ expect(configFactory.createVitestConfig).toHaveBeenCalledWith(
+ 'integration-package',
+ 'int',
+ );
+ });
+ });
+
+ describe('createE2ETestConfig', () => {
+ it('should call createVitestConfig with e2e kind and no options', () => {
+ const result = createE2ETestConfig(MOCK_PROJECT_KEY);
+
+ expect(configFactory.createVitestConfig).toHaveBeenCalledWith(
+ MOCK_PROJECT_KEY,
+ 'e2e',
+ undefined,
+ );
+ expect(result).toBe('mocked-config');
+ });
+
+ it('should pass options to createVitestConfig', () => {
+ const options = {
+ testTimeout: 60_000,
+ };
+
+ createE2ETestConfig(MOCK_PROJECT_KEY, options);
+
+ expect(configFactory.createVitestConfig).toHaveBeenCalledWith(
+ MOCK_PROJECT_KEY,
+ 'e2e',
+ options,
+ );
+ });
+
+ it('should handle testTimeout option', () => {
+ createE2ETestConfig(MOCK_PROJECT_KEY, { testTimeout: 30_000 });
+
+ expect(configFactory.createVitestConfig).toHaveBeenCalledWith(
+ MOCK_PROJECT_KEY,
+ 'e2e',
+ { testTimeout: 30_000 },
+ );
+ });
+ });
+
+ describe('function naming', () => {
+ it('should use clear descriptive names', () => {
+ expect(createUnitTestConfig).toBeDefined();
+ expect(createIntTestConfig).toBeDefined();
+ expect(createE2ETestConfig).toBeDefined();
+ });
+ });
+
+ describe('integration with factory', () => {
+ it('should call factory with correct test kinds', () => {
+ createUnitTestConfig('pkg1');
+ createIntTestConfig('pkg2');
+ createE2ETestConfig('pkg3');
+
+ expect(configFactory.createVitestConfig).toHaveBeenNthCalledWith(
+ 1,
+ 'pkg1',
+ 'unit',
+ );
+ expect(configFactory.createVitestConfig).toHaveBeenNthCalledWith(
+ 2,
+ 'pkg2',
+ 'int',
+ );
+ expect(configFactory.createVitestConfig).toHaveBeenNthCalledWith(
+ 3,
+ 'pkg3',
+ 'e2e',
+ undefined,
+ );
+ });
+
+ it('should return whatever the factory returns', () => {
+ const mockConfigs = {
+ unit: { test: 'unit-config' },
+ int: { test: 'int-config' },
+ e2e: { test: 'e2e-config' },
+ };
+
+ vi.mocked(configFactory.createVitestConfig)
+ .mockReturnValueOnce(mockConfigs.unit as any)
+ .mockReturnValueOnce(mockConfigs.int as any)
+ .mockReturnValueOnce(mockConfigs.e2e as any);
+
+ expect(createUnitTestConfig('test')).toBe(mockConfigs.unit);
+ expect(createIntTestConfig('test')).toBe(mockConfigs.int);
+ expect(createE2ETestConfig('test')).toBe(mockConfigs.e2e);
+ });
+ });
+});
diff --git a/tools/vitest-tsconfig-path-aliases.ts b/testing/test-setup-config/src/lib/vitest-tsconfig-path-aliases.ts
similarity index 55%
rename from tools/vitest-tsconfig-path-aliases.ts
rename to testing/test-setup-config/src/lib/vitest-tsconfig-path-aliases.ts
index ac8be04df..f1a9cc0c3 100644
--- a/tools/vitest-tsconfig-path-aliases.ts
+++ b/testing/test-setup-config/src/lib/vitest-tsconfig-path-aliases.ts
@@ -1,20 +1,29 @@
+import path from 'node:path';
import { loadConfig } from 'tsconfig-paths';
import type { Alias, AliasOptions } from 'vite';
+/**
+ * Loads TypeScript path aliases from tsconfig.base.json for use in Vitest.
+ * Uses process.cwd() as the workspace root to load the tsconfig.
+ */
export function tsconfigPathAliases(): AliasOptions {
- const result = loadConfig('tsconfig.base.json');
+ const tsconfigPath = path.resolve(process.cwd(), 'tsconfig.base.json');
+ const result = loadConfig(tsconfigPath);
+
if (result.resultType === 'failed') {
throw new Error(
`Failed to load path aliases from tsconfig for Vitest: ${result.message}`,
);
}
+
return Object.entries(result.paths)
.map(([key, value]) => [key, value[0]])
.filter((pair): pair is [string, string] => pair[1] != null)
.map(
([importPath, relativePath]): Alias => ({
find: importPath,
- replacement: new URL(`../${relativePath}`, import.meta.url).pathname,
+ // Make paths relative to workspace root (../../ from config file)
+ replacement: path.resolve(process.cwd(), relativePath),
}),
);
}
diff --git a/testing/test-setup-config/tsconfig.json b/testing/test-setup-config/tsconfig.json
new file mode 100644
index 000000000..465306e46
--- /dev/null
+++ b/testing/test-setup-config/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "module": "ESNext",
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.lib.json"
+ },
+ {
+ "path": "./tsconfig.test.json"
+ }
+ ]
+}
diff --git a/testing/test-setup-config/tsconfig.lib.json b/testing/test-setup-config/tsconfig.lib.json
new file mode 100644
index 000000000..3cc313086
--- /dev/null
+++ b/testing/test-setup-config/tsconfig.lib.json
@@ -0,0 +1,15 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../dist/out-tsc",
+ "declaration": true,
+ "types": ["node"]
+ },
+ "include": ["src/**/*.ts"],
+ "exclude": [
+ "vitest.unit.config.ts",
+ "src/vitest.d.ts",
+ "src/**/*.unit.test.ts",
+ "src/**/*.int.test.ts"
+ ]
+}
diff --git a/testing/test-setup-config/tsconfig.test.json b/testing/test-setup-config/tsconfig.test.json
new file mode 100644
index 000000000..5fddc20ae
--- /dev/null
+++ b/testing/test-setup-config/tsconfig.test.json
@@ -0,0 +1,14 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"]
+ },
+ "include": [
+ "vitest.unit.config.ts",
+ "src/vitest.d.ts",
+ "src/**/*.unit.test.ts",
+ "src/**/*.d.ts",
+ "src/**/*.int.test.ts"
+ ]
+}
diff --git a/testing/test-setup-config/vitest.unit.config.ts b/testing/test-setup-config/vitest.unit.config.ts
new file mode 100644
index 000000000..0f76d26b5
--- /dev/null
+++ b/testing/test-setup-config/vitest.unit.config.ts
@@ -0,0 +1,3 @@
+import { createUnitTestConfig } from './src/index.js';
+
+export default createUnitTestConfig('test-setup-config');
diff --git a/testing/test-setup/README.md b/testing/test-setup/README.md
index db0ce1eba..c3b1e60e0 100644
--- a/testing/test-setup/README.md
+++ b/testing/test-setup/README.md
@@ -4,6 +4,10 @@ This library contains test setup.
More on this subject as well as all the testing strategy principles can be found on the GitHub [wiki](https://github.com/code-pushup/cli/wiki/Testing-Strategy#mocking).
+## Shared config
+
+See [`@code-pushup/test-setup-config` docs](../test-setup-config/README.md) on how to use our Vitest config factory.
+
## Mock setup
In this library you can find all files that can be used in `setupFiles` property of `vitest.config.(unit|int|e2e).ts` files. Currently include:
diff --git a/testing/test-setup/src/lib/chrome-path.mock.ts b/testing/test-setup/src/lib/chrome-path.mock.ts
index dbe1542af..c31788adf 100644
--- a/testing/test-setup/src/lib/chrome-path.mock.ts
+++ b/testing/test-setup/src/lib/chrome-path.mock.ts
@@ -15,9 +15,12 @@ beforeEach(async () => {
error.message.includes('No Chrome installations found.')
) {
const chromium = await import('chromium');
- console.info(
- `${error.message} Using chromium from node_modules instead: ${chromium.path}`,
- );
+ // console.info may be overridden by multi-progress-bars or other libraries
+ if (typeof console.info === 'function') {
+ console.info(
+ `${error.message} Using chromium from node_modules instead: ${chromium.path}`,
+ );
+ }
vi.stubEnv('CHROME_PATH', chromium.path);
} else {
throw error;
diff --git a/testing/test-setup/src/lib/logger.mock.ts b/testing/test-setup/src/lib/logger.mock.ts
index 8e2e00ad7..6efe9f92f 100644
--- a/testing/test-setup/src/lib/logger.mock.ts
+++ b/testing/test-setup/src/lib/logger.mock.ts
@@ -1,9 +1,11 @@
import { type MockInstance, afterAll, beforeAll, vi } from 'vitest';
-import { logger } from '@code-pushup/utils';
const loggerSpies: MockInstance[] = [];
-beforeAll(() => {
+beforeAll(async () => {
+ const { logger }: typeof import('@code-pushup/utils') =
+ await vi.importActual('@code-pushup/utils');
+
// TODO: use vi.mockObject after Vitest update: https://vitest.dev/api/vi.html#vi-mockobject-3-2-0
if (process.env['NX_VERBOSE_LOGGING'] === 'true') {
// only track calls, but preserve original implementation so logs are printed
diff --git a/testing/test-setup/vitest.unit.config.ts b/testing/test-setup/vitest.unit.config.ts
index a275ed108..3ed3fa745 100644
--- a/testing/test-setup/vitest.unit.config.ts
+++ b/testing/test-setup/vitest.unit.config.ts
@@ -1,29 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../node_modules/.vite/test-setup',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/test-setup/unit-tests',
- exclude: ['**/*.mock.{mjs,ts}', '**/*.config.{js,mjs,ts}'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.ts'],
- setupFiles: [
- '../test-setup/src/lib/reset.mocks.ts',
- '../test-setup/src/lib/extend/path.matcher.ts',
- '../test-setup/src/lib/extend/markdown-table.matcher.ts',
- ],
- },
-});
+export default createUnitTestConfig('test-setup');
diff --git a/testing/test-utils/src/lib/utils/os-agnostic-paths.unit.test.ts b/testing/test-utils/src/lib/utils/os-agnostic-paths.unit.test.ts
index 4925084fd..6a9d6ee85 100644
--- a/testing/test-utils/src/lib/utils/os-agnostic-paths.unit.test.ts
+++ b/testing/test-utils/src/lib/utils/os-agnostic-paths.unit.test.ts
@@ -10,7 +10,7 @@ import {
import { osAgnosticPath } from './os-agnostic-paths.js';
describe('osAgnosticPath', () => {
- const cwdSpy: MockInstance<[], string> = vi.spyOn(process, 'cwd');
+ let cwdSpy: MockInstance<[], string>;
it('should forward nullish paths on Linux/macOS and Windows', () => {
expect(osAgnosticPath(undefined)).toBeUndefined();
@@ -20,11 +20,12 @@ describe('osAgnosticPath', () => {
const unixCwd = '/Users/jerry';
beforeEach(() => {
+ cwdSpy = vi.spyOn(process, 'cwd');
cwdSpy.mockReturnValue(unixCwd);
});
afterEach(() => {
- cwdSpy.mockReset();
+ cwdSpy.mockRestore();
});
it('should convert a path within the CWD to an OS-agnostic path on Linux/macOS', () => {
@@ -74,11 +75,12 @@ describe('osAgnosticPath', () => {
const windowsCWD = String.raw`D:\users\jerry`;
beforeEach(() => {
+ cwdSpy = vi.spyOn(process, 'cwd');
cwdSpy.mockReturnValue(windowsCWD);
});
afterEach(() => {
- cwdSpy.mockReset();
+ cwdSpy.mockRestore();
});
it('should return paths outside of CWD on Windows', () => {
diff --git a/testing/test-utils/src/lib/utils/test-folder-setup.ts b/testing/test-utils/src/lib/utils/test-folder-setup.ts
index 7b4750b35..8e3853011 100644
--- a/testing/test-utils/src/lib/utils/test-folder-setup.ts
+++ b/testing/test-utils/src/lib/utils/test-folder-setup.ts
@@ -1,4 +1,3 @@
-import { logger } from '@nx/devkit';
import { bold } from 'ansis';
import { mkdir, rm, stat } from 'node:fs/promises';
@@ -11,7 +10,7 @@ export async function teardownTestFolder(dirName: string) {
try {
const stats = await stat(dirName);
if (!stats.isDirectory()) {
- logger.warn(
+ console.warn(
`⚠️ You are trying to delete a file instead of a directory - ${bold(
dirName,
)}.`,
@@ -30,7 +29,7 @@ export async function teardownTestFolder(dirName: string) {
retryDelay: 100,
});
} catch {
- logger.warn(
+ console.warn(
`⚠️ Failed to delete test artefact ${bold(
dirName,
)} so the folder is still in the file system!\nIt may require a deletion before running e2e tests again.`,
diff --git a/testing/test-utils/vitest.unit.config.ts b/testing/test-utils/vitest.unit.config.ts
index 990029cec..61d9b2a20 100644
--- a/testing/test-utils/vitest.unit.config.ts
+++ b/testing/test-utils/vitest.unit.config.ts
@@ -1,24 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../node_modules/.vite/test-utils',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/test-utils/unit-tests',
- exclude: ['**/*.mock.{mjs,ts}', '**/*.config.{js,mjs,ts}'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.ts'],
- },
-});
+export default createUnitTestConfig('test-utils');
diff --git a/tools/eslint-formatter-multi/vitest.unit.config.ts b/tools/eslint-formatter-multi/vitest.unit.config.ts
index 75295eb74..3ef0b549a 100644
--- a/tools/eslint-formatter-multi/vitest.unit.config.ts
+++ b/tools/eslint-formatter-multi/vitest.unit.config.ts
@@ -1,32 +1,3 @@
-///
-import { defineConfig } from 'vitest/config';
-// eslint-disable-next-line import/no-useless-path-segments
-import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js';
+import { createUnitTestConfig } from '../../testing/test-setup-config/src/index.js';
-export default defineConfig({
- cacheDir: '../../node_modules/.vite/plugin-eslint',
- test: {
- reporters: ['basic'],
- globals: true,
- cache: {
- dir: '../../node_modules/.vitest',
- },
- alias: tsconfigPathAliases(),
- pool: 'threads',
- poolOptions: { threads: { singleThread: true } },
- coverage: {
- reporter: ['text', 'lcov'],
- reportsDirectory: '../../coverage/plugin-eslint/unit-tests',
- exclude: ['mocks/**', '**/types.ts'],
- },
- environment: 'node',
- include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
- exclude: ['src/index.ts'],
- globalSetup: ['../../global-setup.ts'],
- setupFiles: [
- '../../testing/test-setup/src/lib/console.mock.ts',
- '../../testing/test-setup/src/lib/fs.mock.ts',
- '../../testing/test-setup/src/lib/reset.mocks.ts',
- ],
- },
-});
+export default createUnitTestConfig('eslint-formatter-multi');
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 7f3b4d21f..4bca1c69f 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -39,6 +39,9 @@
"@code-pushup/nx-plugin": ["packages/nx-plugin/src/index.ts"],
"@code-pushup/test-nx-utils": ["testing/test-nx-utils/src/index.ts"],
"@code-pushup/test-setup": ["testing/test-setup/src/index.ts"],
+ "@code-pushup/test-setup-config": [
+ "testing/test-setup-config/src/index.ts"
+ ],
"@code-pushup/test-utils": ["testing/test-utils/src/index.ts"],
"@code-pushup/typescript-plugin": [
"packages/plugin-typescript/src/index.ts"