vitest.base.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import path from "node:path";
  2. import { fileURLToPath } from "node:url";
  3. import { defineConfig } from "vitest/config";
  4. const __dirname = path.dirname(fileURLToPath(import.meta.url));
  5. const root = path.resolve(__dirname, "..");
  6. // ---------------------------------------------------------------------------
  7. // Shared resolve alias
  8. // ---------------------------------------------------------------------------
  9. export function sharedResolve(opts?: { includeMessages?: boolean }) {
  10. const alias: Record<string, string> = {
  11. "@": path.resolve(root, "src"),
  12. "server-only": path.resolve(root, "tests/server-only.mock.ts"),
  13. };
  14. if (opts?.includeMessages) {
  15. alias["@messages"] = path.resolve(root, "messages");
  16. }
  17. return { alias };
  18. }
  19. // ---------------------------------------------------------------------------
  20. // Shared helpers
  21. // ---------------------------------------------------------------------------
  22. const setupFiles = [path.resolve(root, "tests/setup.ts")];
  23. const resolveSnapshotPath = (testPath: string, snapExtension: string) => {
  24. return testPath.replace(/\.test\.([tj]sx?)$/, `${snapExtension}.$1`);
  25. };
  26. const defaultTestExclude = [
  27. "node_modules",
  28. ".next",
  29. "dist",
  30. "build",
  31. "coverage",
  32. "**/*.d.ts",
  33. "tests/integration/**",
  34. ];
  35. // ---------------------------------------------------------------------------
  36. // Factory: scoped coverage config (8 specialized configs)
  37. // ---------------------------------------------------------------------------
  38. interface CoverageConfigOptions {
  39. name: string;
  40. environment: "node" | "happy-dom";
  41. testFiles: string[];
  42. sourceFiles: string[];
  43. thresholds: {
  44. lines: number;
  45. functions: number;
  46. branches: number;
  47. statements: number;
  48. };
  49. coverageExclude?: string[];
  50. coverageReporters?: string[];
  51. /** Override the default test exclude list (e.g. my-usage omits tests/integration/**) */
  52. testExclude?: string[];
  53. }
  54. export function createCoverageConfig(opts: CoverageConfigOptions) {
  55. return defineConfig({
  56. test: {
  57. globals: true,
  58. environment: opts.environment,
  59. setupFiles,
  60. include: opts.testFiles,
  61. exclude: opts.testExclude ?? defaultTestExclude,
  62. coverage: {
  63. provider: "v8",
  64. reporter: opts.coverageReporters ?? ["text", "html", "json"],
  65. reportsDirectory: path.resolve(root, `coverage/${opts.name}`),
  66. include: opts.sourceFiles,
  67. exclude: [
  68. "node_modules/",
  69. "tests/",
  70. "**/*.d.ts",
  71. ".next/",
  72. ...(opts.coverageExclude ?? []),
  73. ],
  74. thresholds: opts.thresholds,
  75. },
  76. reporters: ["verbose"],
  77. isolate: true,
  78. mockReset: true,
  79. restoreMocks: true,
  80. clearMocks: true,
  81. resolveSnapshotPath,
  82. },
  83. resolve: sharedResolve(),
  84. });
  85. }
  86. // ---------------------------------------------------------------------------
  87. // Factory: test runner config (e2e / integration)
  88. // ---------------------------------------------------------------------------
  89. interface TestRunnerConfigOptions {
  90. environment: "node" | "happy-dom";
  91. testFiles: string[];
  92. testTimeout?: number;
  93. hookTimeout?: number;
  94. extraExclude?: string[];
  95. api?: {
  96. host?: string;
  97. port?: number;
  98. strictPort?: boolean;
  99. };
  100. }
  101. export function createTestRunnerConfig(opts: TestRunnerConfigOptions) {
  102. const baseExclude = ["node_modules", ".next", "dist", "build", "coverage", "**/*.d.ts"];
  103. return defineConfig({
  104. test: {
  105. globals: true,
  106. environment: opts.environment,
  107. setupFiles,
  108. ...(opts.api ? { api: opts.api, open: false } : {}),
  109. testTimeout: opts.testTimeout ?? 10000,
  110. hookTimeout: opts.hookTimeout ?? 10000,
  111. maxConcurrency: 5,
  112. pool: "threads",
  113. include: opts.testFiles,
  114. exclude: [...baseExclude, ...(opts.extraExclude ?? [])],
  115. reporters: ["verbose"],
  116. isolate: true,
  117. mockReset: true,
  118. restoreMocks: true,
  119. clearMocks: true,
  120. resolveSnapshotPath,
  121. },
  122. resolve: sharedResolve(),
  123. });
  124. }