diff --git a/apps/service/src/__tests__/workflow.test.ts b/apps/service/src/__tests__/workflow.test.ts index eaf2db62f..b8c1343b9 100644 --- a/apps/service/src/__tests__/workflow.test.ts +++ b/apps/service/src/__tests__/workflow.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, beforeAll, afterAll } from 'vitest' +import { describe, it, expect, beforeAll, afterAll, inject } from 'vitest' import { TestWorkflowEnvironment } from '@temporalio/testing' import { Worker } from '@temporalio/worker' import path from 'node:path' @@ -31,10 +31,14 @@ function stubActivities(overrides: Partial = {}): SyncActivities let testEnv: TestWorkflowEnvironment beforeAll(async () => { - testEnv = await TestWorkflowEnvironment.createLocal() -}, 120_000) + // Connect to the shared dev server started in vitest.global-setup.ts instead of + // spawning a new one per file — avoids concurrent startup races under file parallelism. + const address = inject('temporalTestServerAddress') + testEnv = await TestWorkflowEnvironment.createFromExistingServer({ address }) +}, 30_000) afterAll(async () => { + // teardown() on an existing-server env only closes connections, not the server itself. await testEnv?.teardown() }) diff --git a/apps/service/src/api/app.test.ts b/apps/service/src/api/app.test.ts index 8a0f9c87a..eccc4629e 100644 --- a/apps/service/src/api/app.test.ts +++ b/apps/service/src/api/app.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, beforeAll, afterAll } from 'vitest' +import { describe, expect, it, beforeAll, afterAll, inject } from 'vitest' import type { WorkflowClient } from '@temporalio/client' import { TestWorkflowEnvironment } from '@temporalio/testing' import { Worker } from '@temporalio/worker' @@ -90,7 +90,10 @@ let worker: Worker let workerRunning: Promise beforeAll(async () => { - testEnv = await TestWorkflowEnvironment.createLocal() + // Connect to the shared dev server started in vitest.global-setup.ts instead of + // spawning a new one per file — avoids concurrent startup races under file parallelism. + const address = inject('temporalTestServerAddress') + testEnv = await TestWorkflowEnvironment.createFromExistingServer({ address }) worker = await Worker.create({ connection: testEnv.nativeConnection, taskQueue: 'test-api', @@ -103,6 +106,7 @@ beforeAll(async () => { afterAll(async () => { worker?.shutdown() await workerRunning + // teardown() on an existing-server env only closes connections, not the server itself. await testEnv?.teardown() }) diff --git a/apps/service/vitest.config.ts b/apps/service/vitest.config.ts index 592756e35..eab0960f4 100644 --- a/apps/service/vitest.config.ts +++ b/apps/service/vitest.config.ts @@ -2,6 +2,7 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { + globalSetup: ['./vitest.global-setup.ts'], exclude: ['**/node_modules/**', '**/dist/**', '**/*.integration.test.ts'], testTimeout: 60_000, hookTimeout: 60_000, diff --git a/apps/service/vitest.d.ts b/apps/service/vitest.d.ts new file mode 100644 index 000000000..e23ea7281 --- /dev/null +++ b/apps/service/vitest.d.ts @@ -0,0 +1,7 @@ +import 'vitest' + +declare module 'vitest' { + export interface ProvidedContext { + temporalTestServerAddress: string + } +} diff --git a/apps/service/vitest.global-setup.ts b/apps/service/vitest.global-setup.ts new file mode 100644 index 000000000..2e51d81c9 --- /dev/null +++ b/apps/service/vitest.global-setup.ts @@ -0,0 +1,20 @@ +/** + * Vitest global setup: starts ONE Temporal dev server for the entire test run. + * + * Each test file connects to this shared server via TestWorkflowEnvironment.createFromExistingServer() + * rather than calling createLocal() per-file, which avoids concurrent startup races under + * Vitest's default file parallelism. + */ +import { TestWorkflowEnvironment } from '@temporalio/testing' +import type { GlobalSetupContext } from 'vitest/node' + +let env: TestWorkflowEnvironment | undefined + +export async function setup({ provide }: GlobalSetupContext) { + env = await TestWorkflowEnvironment.createLocal() + provide('temporalTestServerAddress', env.address) +} + +export async function teardown() { + await env?.teardown() +} diff --git a/e2e/docs.test.ts b/e2e/docs.test.ts index f63b293d9..7a73ec57d 100644 --- a/e2e/docs.test.ts +++ b/e2e/docs.test.ts @@ -7,11 +7,7 @@ const ROOT = join(import.meta.dirname, '..') // All plan and design files must start with YYYY-MM-DD- const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}-[\w-]+\.md$/ -const CHECKED_DIRS = [ - 'docs/plans/active', - 'docs/plans/completed', - 'docs/design', -] +const CHECKED_DIRS = ['docs/plans/active', 'docs/plans/completed', 'docs/design'] for (const dir of CHECKED_DIRS) { describe(`${dir} naming convention`, () => {