Skip to content

Commit dd07660

Browse files
kanadguptaclaude
andcommitted
chore(vitest): share one preset across the package configs
Every TypeScript workspace repeated the same Vitest scaffolding: istanbul coverage, passWithNoTests, the unit/integration/e2e include globs, and, in apps/cli and packages/config, the bun export-condition resolve blocks copied onto every inline project because Vitest 4 did not inherit them. vitest.shared.ts now owns that. definePackageConfig merges the shared defaults, and testProject(kind, overrides) declares one inline project per test kind with the file-suffix convention baked in. Vitest 5 inherits the declaring config into inline projects, so the duplicated resolve blocks and Dockerfile plugin entries are gone. The root config reuses the same run-level defaults and loads each package config as a nested project group. apps/cli-e2e also becomes a nested e2e project so it shows up as '@supabase/cli-e2e (e2e)' from the root and matches a '*(e2e)' filter; its lexicographic sequencer stays a run-level option for standalone runs. Its redundant node_modules exclude is dropped in favour of Vitest's defaults. vite is now an explicit root devDependency because the preset imports its default export-condition lists. Standalone per-package runs, the CI coverage commands, and a root run all collect the same projects and test counts as before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 30fa169 commit dd07660

13 files changed

Lines changed: 161 additions & 206 deletions

File tree

AGENTS.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,17 @@ Expected exceptions:
4747
}
4848
```
4949

50+
**vitest.config.ts:**
51+
52+
Package configs build on the repo-root `vitest.shared.ts` preset. `definePackageConfig` merges the
53+
shared defaults (bun export-condition resolution for workspace packages, istanbul coverage,
54+
`passWithNoTests`, console output only from failing tests), and `testProject("unit" | "integration" |
55+
"e2e" | "live", overrides)` declares one inline project per test kind with the repo's file-suffix
56+
convention baked in. Package-specific settings such as timeouts, setup files, serial execution, or
57+
Vite plugins go in the overrides. The root `vitest.config.mts` loads every package config as a nested
58+
project group, so `bun --bun vitest run --project '*(unit)'` from the repo root runs one kind across
59+
all workspaces while `pnpm test:unit` inside a package still works standalone.
60+
5061
## Config Naming Vocabulary
5162

5263
`@supabase/config` and its CLI consumer use three settled names:

apps/cli-e2e/vitest.config.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
1-
import { defineConfig } from "vitest/config";
21
import { BaseSequencer, type TestSpecification } from "vitest/node";
2+
import { definePackageConfig, testProject } from "../../vitest.shared.ts";
33

4-
export default defineConfig({
4+
export default definePackageConfig({
55
test: {
6-
passWithNoTests: true,
7-
include: ["**/*.e2e.test.ts"],
8-
exclude: ["**/node_modules/**"],
9-
fileParallelism: false,
10-
maxWorkers: 1,
11-
globalSetup: ["tests/setup.ts"],
12-
testTimeout: 60_000,
13-
hookTimeout: 30_000,
6+
// Replay fixtures are shared across files, so run them in a deterministic
7+
// lexicographic order. `sequence.sequencer` is a run-level option: it
8+
// applies to standalone runs of this package, not when the repo root loads
9+
// this config as a project.
1410
sequence: {
1511
sequencer: class extends BaseSequencer {
1612
override async sort(files: TestSpecification[]) {
1713
return [...files].sort((a, b) => a.moduleId.localeCompare(b.moduleId));
1814
}
1915
},
2016
},
17+
projects: [
18+
testProject("e2e", {
19+
test: {
20+
fileParallelism: false,
21+
maxWorkers: 1,
22+
globalSetup: ["tests/setup.ts"],
23+
testTimeout: 60_000,
24+
hookTimeout: 30_000,
25+
},
26+
}),
27+
],
2128
},
2229
});

apps/cli/vitest.config.ts

Lines changed: 13 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { readFileSync } from "node:fs";
2-
import { defaultClientConditions, defaultServerConditions } from "vite";
3-
import { defineConfig } from "vitest/config";
2+
import { definePackageConfig, testProject } from "../../vitest.shared.ts";
43

4+
// `src/shared/services/dockerfile-images.ts` imports the Go CLI's Dockerfile
5+
// with Bun's `{ type: "text" }` import attribute; Vite needs a loader for it.
56
function dockerfileTextPlugin() {
67
return {
78
name: "dockerfile-text-loader",
@@ -16,31 +17,10 @@ function dockerfileTextPlugin() {
1617
};
1718
}
1819

19-
// Workspace packages such as @supabase/config publish a `bun` export
20-
// condition pointing at their TypeScript source (see
21-
// packages/config/package.json's `exports` map); without it, Vite's resolver
22-
// falls through to the `default` condition and loads the built `dist/*.js`
23-
// output instead — which is stale, or missing entirely on a fresh clone
24-
// before the package has been built. Extending (not replacing) Vite's
25-
// default condition lists keeps every other package's exports resolution
26-
// unchanged. Required on every inline `test.projects` entry below too:
27-
// Vitest builds a separate Vite config per project and does not inherit
28-
// these from the root config (see PR #6366 finding 0).
29-
const workspacePackageResolve = { conditions: [...defaultClientConditions, "bun"] };
30-
const workspacePackageSsrResolve = { conditions: [...defaultServerConditions, "bun"] };
31-
32-
export default defineConfig({
33-
resolve: workspacePackageResolve,
34-
ssr: { resolve: workspacePackageSsrResolve },
20+
export default definePackageConfig({
3521
plugins: [dockerfileTextPlugin()],
3622
test: {
37-
passWithNoTests: true,
3823
coverage: {
39-
enabled: false,
40-
provider: "istanbul",
41-
include: ["src/**/*.ts"],
42-
reporter: ["text", "lcov"],
43-
reportsDirectory: "coverage",
4424
exclude: [
4525
"tests/**",
4626
"scripts/**",
@@ -56,53 +36,30 @@ export default defineConfig({
5636
],
5737
},
5838
projects: [
59-
{
60-
resolve: workspacePackageResolve,
61-
ssr: { resolve: workspacePackageSsrResolve },
62-
test: {
63-
name: "unit",
64-
include: ["**/*.unit.test.ts"],
65-
env: { FORCE_COLOR: "1" },
66-
},
67-
},
68-
{
69-
resolve: workspacePackageResolve,
70-
ssr: { resolve: workspacePackageSsrResolve },
71-
test: {
72-
name: "integration",
73-
include: ["**/*.integration.test.ts"],
74-
},
75-
},
76-
{
77-
resolve: workspacePackageResolve,
78-
ssr: { resolve: workspacePackageSsrResolve },
39+
testProject("unit", { test: { env: { FORCE_COLOR: "1" } } }),
40+
testProject("integration"),
41+
testProject("e2e", {
7942
test: {
80-
name: "e2e",
81-
include: ["**/*.e2e.test.ts"],
8243
fileParallelism: false,
8344
maxWorkers: 1,
8445
globalSetup: ["tests/e2e-global-setup.ts"],
8546
setupFiles: ["tests/e2e-setup.ts"],
8647
testTimeout: 120_000,
8748
hookTimeout: 120_000,
8849
},
89-
},
90-
{
91-
resolve: workspacePackageResolve,
92-
ssr: { resolve: workspacePackageSsrResolve },
50+
}),
51+
// Live tests run against one provisioned project on the configured
52+
// platform. They are never part of the default unit/integration/e2e
53+
// loop; an explicit run fails fast when required configuration is absent.
54+
testProject("live", {
9355
test: {
94-
// Live tests run against one provisioned project on the configured
95-
// platform. They are never part of the default unit/integration/e2e
96-
// loop; an explicit run fails fast when required configuration is absent.
97-
name: "live",
98-
include: ["**/*.live.test.ts"],
9956
fileParallelism: false,
10057
maxWorkers: 1,
10158
globalSetup: ["tests/live-global-setup.ts"],
10259
testTimeout: 300_000,
10360
hookTimeout: 300_000,
10461
},
105-
},
62+
}),
10663
],
10764
},
10865
});

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"turbo": "catalog:",
4242
"typescript": "catalog:",
4343
"verdaccio": "^6.10.0",
44+
"vite": "catalog:",
4445
"vitest": "catalog:"
4546
},
4647
"devEngines": {

packages/api/vitest.config.ts

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,5 @@
1-
import { defineConfig } from "vitest/config";
1+
import { definePackageConfig, testProject } from "../../vitest.shared.ts";
22

3-
export default defineConfig({
4-
test: {
5-
passWithNoTests: true,
6-
coverage: {
7-
enabled: false,
8-
provider: "istanbul",
9-
clean: false,
10-
include: ["src/**/*.ts"],
11-
reporter: ["text", "lcov"],
12-
reportsDirectory: "coverage",
13-
},
14-
projects: [
15-
{
16-
test: {
17-
name: "unit",
18-
include: ["**/*.unit.test.ts"],
19-
},
20-
},
21-
],
22-
},
3+
export default definePackageConfig({
4+
test: { projects: [testProject("unit")] },
235
});
Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,5 @@
1-
import { defineConfig } from "vitest/config";
1+
import { definePackageConfig, testProject } from "../../vitest.shared.ts";
22

3-
export default defineConfig({
4-
test: {
5-
passWithNoTests: true,
6-
coverage: {
7-
enabled: false,
8-
provider: "istanbul",
9-
clean: false,
10-
include: ["src/**/*.ts"],
11-
reporter: ["text", "lcov"],
12-
reportsDirectory: "coverage",
13-
},
14-
projects: [
15-
{
16-
test: {
17-
name: "unit",
18-
include: ["**/*.unit.test.ts"],
19-
},
20-
},
21-
],
22-
},
3+
export default definePackageConfig({
4+
test: { projects: [testProject("unit")] },
235
});

packages/config/vitest.config.ts

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,5 @@
1-
import { defaultClientConditions, defaultServerConditions } from "vite";
2-
import { defineConfig } from "vitest/config";
1+
import { definePackageConfig, testProject } from "../../vitest.shared.ts";
32

4-
// This package publishes a `bun` export condition pointing at its
5-
// TypeScript source (see package.json's `exports` map); without it, Vite's
6-
// resolver falls through to the `default` condition and loads the built
7-
// `dist/*.js` output instead — stale, or missing entirely on a fresh clone
8-
// before the package has been built. Extending (not replacing) Vite's
9-
// default condition lists keeps every other package's exports resolution
10-
// unchanged. Required on every inline `test.projects` entry too: Vitest
11-
// builds a separate Vite config per project and does not inherit these from
12-
// the root config (see PR #6366 finding 0).
13-
const workspacePackageResolve = { conditions: [...defaultClientConditions, "bun"] };
14-
const workspacePackageSsrResolve = { conditions: [...defaultServerConditions, "bun"] };
15-
16-
export default defineConfig({
17-
resolve: workspacePackageResolve,
18-
ssr: { resolve: workspacePackageSsrResolve },
19-
test: {
20-
passWithNoTests: true,
21-
coverage: {
22-
enabled: false,
23-
provider: "istanbul",
24-
clean: false,
25-
include: ["src/**/*.ts"],
26-
reporter: ["text", "lcov"],
27-
reportsDirectory: "coverage",
28-
},
29-
projects: [
30-
{
31-
resolve: workspacePackageResolve,
32-
ssr: { resolve: workspacePackageSsrResolve },
33-
test: {
34-
name: "unit",
35-
include: ["**/*.unit.test.ts"],
36-
},
37-
},
38-
],
39-
},
3+
export default definePackageConfig({
4+
test: { projects: [testProject("unit")] },
405
});
Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,5 @@
1-
import { defineConfig } from "vitest/config";
1+
import { definePackageConfig, testProject } from "../../vitest.shared.ts";
22

3-
export default defineConfig({
4-
test: {
5-
passWithNoTests: true,
6-
coverage: {
7-
enabled: false,
8-
provider: "istanbul",
9-
clean: false,
10-
include: ["src/**/*.ts"],
11-
reporter: ["text", "lcov"],
12-
reportsDirectory: "coverage",
13-
},
14-
projects: [
15-
{
16-
test: {
17-
name: "unit",
18-
include: ["**/*.unit.test.ts"],
19-
},
20-
},
21-
{
22-
test: {
23-
name: "integration",
24-
include: ["**/*.integration.test.ts"],
25-
},
26-
},
27-
],
28-
},
3+
export default definePackageConfig({
4+
test: { projects: [testProject("unit"), testProject("integration")] },
295
});

packages/stack/vitest.config.ts

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,13 @@
1-
import { defineConfig } from "vitest/config";
1+
import { definePackageConfig, testProject } from "../../vitest.shared.ts";
22

3-
export default defineConfig({
3+
export default definePackageConfig({
44
test: {
5-
passWithNoTests: true,
6-
coverage: {
7-
enabled: false,
8-
provider: "istanbul",
9-
clean: false,
10-
include: ["src/**/*.ts"],
11-
reporter: ["text", "lcov"],
12-
reportsDirectory: "coverage",
13-
},
145
projects: [
15-
{
16-
test: {
17-
name: "unit",
18-
include: ["**/*.unit.test.ts"],
19-
},
20-
},
21-
{
22-
test: {
23-
name: "integration",
24-
include: ["**/*.integration.test.ts"],
25-
testTimeout: 60_000,
26-
},
27-
},
28-
{
29-
test: {
30-
name: "e2e",
31-
include: ["**/*.e2e.test.ts"],
32-
fileParallelism: false,
33-
globalSetup: ["./tests/global-setup.ts"],
34-
},
35-
},
6+
testProject("unit"),
7+
testProject("integration", { test: { testTimeout: 60_000 } }),
8+
testProject("e2e", {
9+
test: { fileParallelism: false, globalSetup: ["./tests/global-setup.ts"] },
10+
}),
3611
],
3712
},
3813
});

pnpm-lock.yaml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)