Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ packages/cli-*/bin/

# Turbo
.turbo/

# Vitest 5 artifact directory (blob reports, attachments, html/json output)
.vitest/
11 changes: 11 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ Expected exceptions:
}
```

**vitest.config.ts:**

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

## Config Naming Vocabulary

`@supabase/config` and its CLI consumer use three settled names:
Expand Down
27 changes: 17 additions & 10 deletions apps/cli-e2e/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { defineConfig } from "vitest/config";
import { BaseSequencer, type TestSpecification } from "vitest/node";
import { definePackageConfig, testProject } from "../../vitest.shared.ts";

export default defineConfig({
export default definePackageConfig({
test: {
passWithNoTests: true,
include: ["**/*.e2e.test.ts"],
exclude: ["**/node_modules/**"],
fileParallelism: false,
maxWorkers: 1,
globalSetup: ["tests/setup.ts"],
testTimeout: 60_000,
hookTimeout: 30_000,
// Replay fixtures are shared across files, so run them in a deterministic
// lexicographic order. `sequence.sequencer` is a run-level option: it
// applies to standalone runs of this package, not when the repo root loads
// this config as a project.
sequence: {
sequencer: class extends BaseSequencer {
override async sort(files: TestSpecification[]) {
return [...files].sort((a, b) => a.moduleId.localeCompare(b.moduleId));
}
},
},
projects: [
testProject("e2e", {
test: {
fileParallelism: false,
maxWorkers: 1,
globalSetup: ["tests/setup.ts"],
testTimeout: 60_000,
hookTimeout: 30_000,
},
}),
],
},
});
69 changes: 13 additions & 56 deletions apps/cli/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { readFileSync } from "node:fs";
import { defaultClientConditions, defaultServerConditions } from "vite";
import { defineConfig } from "vitest/config";
import { definePackageConfig, testProject } from "../../vitest.shared.ts";

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

// Workspace packages such as @supabase/config publish a `bun` export
// condition pointing at their TypeScript source (see
// packages/config/package.json's `exports` map); without it, Vite's resolver
// falls through to the `default` condition and loads the built `dist/*.js`
// output instead — which is stale, or missing entirely on a fresh clone
// before the package has been built. Extending (not replacing) Vite's
// default condition lists keeps every other package's exports resolution
// unchanged. Required on every inline `test.projects` entry below too:
// Vitest builds a separate Vite config per project and does not inherit
// these from the root config (see PR #6366 finding 0).
const workspacePackageResolve = { conditions: [...defaultClientConditions, "bun"] };
const workspacePackageSsrResolve = { conditions: [...defaultServerConditions, "bun"] };

export default defineConfig({
resolve: workspacePackageResolve,
ssr: { resolve: workspacePackageSsrResolve },
export default definePackageConfig({
plugins: [dockerfileTextPlugin()],
test: {
passWithNoTests: true,
coverage: {
enabled: false,
provider: "istanbul",
include: ["src/**/*.ts"],
reporter: ["text", "lcov"],
reportsDirectory: "coverage",
exclude: [
"tests/**",
"scripts/**",
Expand All @@ -56,53 +36,30 @@ export default defineConfig({
],
},
projects: [
{
resolve: workspacePackageResolve,
ssr: { resolve: workspacePackageSsrResolve },
test: {
name: "unit",
include: ["**/*.unit.test.ts"],
env: { FORCE_COLOR: "1" },
},
},
{
resolve: workspacePackageResolve,
ssr: { resolve: workspacePackageSsrResolve },
test: {
name: "integration",
include: ["**/*.integration.test.ts"],
},
},
{
resolve: workspacePackageResolve,
ssr: { resolve: workspacePackageSsrResolve },
testProject("unit", { test: { env: { FORCE_COLOR: "1" } } }),
testProject("integration"),
testProject("e2e", {
test: {
name: "e2e",
include: ["**/*.e2e.test.ts"],
fileParallelism: false,
maxWorkers: 1,
globalSetup: ["tests/e2e-global-setup.ts"],
setupFiles: ["tests/e2e-setup.ts"],
testTimeout: 120_000,
hookTimeout: 120_000,
},
},
{
resolve: workspacePackageResolve,
ssr: { resolve: workspacePackageSsrResolve },
}),
// Live tests run against one provisioned project on the configured
// platform. They are never part of the default unit/integration/e2e
// loop; an explicit run fails fast when required configuration is absent.
testProject("live", {
test: {
// Live tests run against one provisioned project on the configured
// platform. They are never part of the default unit/integration/e2e
// loop; an explicit run fails fast when required configuration is absent.
name: "live",
include: ["**/*.live.test.ts"],
fileParallelism: false,
maxWorkers: 1,
globalSetup: ["tests/live-global-setup.ts"],
testTimeout: 300_000,
hookTimeout: 300_000,
},
},
}),
],
},
});
5 changes: 3 additions & 2 deletions knip.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
"exclude": ["catalogReferences"],
"workspaces": {
".": {
"entry": [".github/scripts/**/*.ts", "tools/*.ts", "tools/release/*.ts"],
"entry": [".github/scripts/**/*.ts", "tools/*.ts", "tools/release/*.ts", "vitest.config.mts"],
"ignore": [".repos/**", "apps/cli-go/**"],
"ignoreBinaries": ["go"],
"ignoreDependencies": ["verdaccio"]
"ignoreDependencies": ["verdaccio"],
"vitest": false
},
"apps/cli": {
"entry": [
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"turbo": "catalog:",
"typescript": "catalog:",
"verdaccio": "^6.10.0",
"vite": "catalog:",
"vitest": "catalog:"
},
"devEngines": {
Expand Down
24 changes: 3 additions & 21 deletions packages/api/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
import { defineConfig } from "vitest/config";
import { definePackageConfig, testProject } from "../../vitest.shared.ts";

export default defineConfig({
test: {
passWithNoTests: true,
coverage: {
enabled: false,
provider: "istanbul",
clean: false,
include: ["src/**/*.ts"],
reporter: ["text", "lcov"],
reportsDirectory: "coverage",
},
projects: [
{
test: {
name: "unit",
include: ["**/*.unit.test.ts"],
},
},
],
},
export default definePackageConfig({
test: { projects: [testProject("unit")] },
});
24 changes: 3 additions & 21 deletions packages/cli-test-helpers/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
import { defineConfig } from "vitest/config";
import { definePackageConfig, testProject } from "../../vitest.shared.ts";

export default defineConfig({
test: {
passWithNoTests: true,
coverage: {
enabled: false,
provider: "istanbul",
clean: false,
include: ["src/**/*.ts"],
reporter: ["text", "lcov"],
reportsDirectory: "coverage",
},
projects: [
{
test: {
name: "unit",
include: ["**/*.unit.test.ts"],
},
},
],
},
export default definePackageConfig({
test: { projects: [testProject("unit")] },
});
41 changes: 3 additions & 38 deletions packages/config/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,5 @@
import { defaultClientConditions, defaultServerConditions } from "vite";
import { defineConfig } from "vitest/config";
import { definePackageConfig, testProject } from "../../vitest.shared.ts";

// This package publishes a `bun` export condition pointing at its
// TypeScript source (see package.json's `exports` map); without it, Vite's
// resolver falls through to the `default` condition and loads the built
// `dist/*.js` output instead — stale, or missing entirely on a fresh clone
// before the package has been built. Extending (not replacing) Vite's
// default condition lists keeps every other package's exports resolution
// unchanged. Required on every inline `test.projects` entry too: Vitest
// builds a separate Vite config per project and does not inherit these from
// the root config (see PR #6366 finding 0).
const workspacePackageResolve = { conditions: [...defaultClientConditions, "bun"] };
const workspacePackageSsrResolve = { conditions: [...defaultServerConditions, "bun"] };

export default defineConfig({
resolve: workspacePackageResolve,
ssr: { resolve: workspacePackageSsrResolve },
test: {
passWithNoTests: true,
coverage: {
enabled: false,
provider: "istanbul",
clean: false,
include: ["src/**/*.ts"],
reporter: ["text", "lcov"],
reportsDirectory: "coverage",
},
projects: [
{
resolve: workspacePackageResolve,
ssr: { resolve: workspacePackageSsrResolve },
test: {
name: "unit",
include: ["**/*.unit.test.ts"],
},
},
],
},
export default definePackageConfig({
test: { projects: [testProject("unit")] },
});
30 changes: 3 additions & 27 deletions packages/process-compose/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,5 @@
import { defineConfig } from "vitest/config";
import { definePackageConfig, testProject } from "../../vitest.shared.ts";

export default defineConfig({
test: {
passWithNoTests: true,
coverage: {
enabled: false,
provider: "istanbul",
clean: false,
include: ["src/**/*.ts"],
reporter: ["text", "lcov"],
reportsDirectory: "coverage",
},
projects: [
{
test: {
name: "unit",
include: ["**/*.unit.test.ts"],
},
},
{
test: {
name: "integration",
include: ["**/*.integration.test.ts"],
},
},
],
},
export default definePackageConfig({
test: { projects: [testProject("unit"), testProject("integration")] },
});
39 changes: 7 additions & 32 deletions packages/stack/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,13 @@
import { defineConfig } from "vitest/config";
import { definePackageConfig, testProject } from "../../vitest.shared.ts";

export default defineConfig({
export default definePackageConfig({
test: {
passWithNoTests: true,
coverage: {
enabled: false,
provider: "istanbul",
clean: false,
include: ["src/**/*.ts"],
reporter: ["text", "lcov"],
reportsDirectory: "coverage",
},
projects: [
{
test: {
name: "unit",
include: ["**/*.unit.test.ts"],
},
},
{
test: {
name: "integration",
include: ["**/*.integration.test.ts"],
testTimeout: 60_000,
},
},
{
test: {
name: "e2e",
include: ["**/*.e2e.test.ts"],
fileParallelism: false,
globalSetup: ["./tests/global-setup.ts"],
},
},
testProject("unit"),
testProject("integration", { test: { testTimeout: 60_000 } }),
testProject("e2e", {
test: { fileParallelism: false, globalSetup: ["./tests/global-setup.ts"] },
}),
],
},
});
Loading
Loading