Skip to content

[vitest] Isolate test data and improve cleanup#1895

Merged
VaguelySerious merged 1 commit intomainfrom
peter/local-world-isolation
May 2, 2026
Merged

[vitest] Isolate test data and improve cleanup#1895
VaguelySerious merged 1 commit intomainfrom
peter/local-world-isolation

Conversation

@VaguelySerious
Copy link
Copy Markdown
Member

Summary

Closes #1818

Squashes the contents of #1818 (vitest project-context isolation + world-local recovery scoping by Tom Dale) together with two follow-up fixes for the e2e dev tests that surfaced once the vitest changes restored test isolation:

  • @workflow/vitest project-scoped context. workflow() resolves cwd, rootDir, dataDir, and outDir once and passes them through Vitest's per-project provided context. global-setup and setup-file consume that resolved state instead of reading process-wide env vars, so workspace projects and config reloads no longer leak paths into one another. Adds a unit test suite for the harness.
  • world-local recovery scoped by tag. paginatedFileSystemQuery now keeps fileIdFilter applied across cursor pages (previously dropped after page one). start() gains a recoverActiveRuns opt-out, used by the Vitest harness so worker startup does not re-enqueue stale runs before direct handlers are registered.
  • Dev test cleanup hardening. should include steps discovered from workflow imports now tears down in-test and waits for the deferred builder to drop the discovered step from the manifest before the next test file runs, instead of relying on afterEach. should rebuild on imported step dependency change swallows the Turbopack-on-Windows MODULE_UNPARSABLE flake by rewriting the api file to invalidate Turbopack's bad cache and retrying. Both addressed cases where the Windows E2E job would burn its full 30-minute timeout polling stuck workflow runs.

Test plan

  • All Tests CI checks pass on Windows (the Turbopack flake is the focus)
  • pnpm exec vitest run packages/vitest/src/index.test.ts packages/world-local/src/fs.test.ts packages/world-local/src/reenqueue.test.ts
  • pnpm exec tsc -p packages/vitest/tsconfig.json --noEmit
  • pnpm exec tsc -p packages/world-local/tsconfig.json --noEmit
  • Manual e2e against nextjs-turbopack workbench: dev tests + e2e.test.ts succeed against the same dev server (verified locally on macOS)

🤖 Generated with Claude Code

Move the @workflow/vitest harness from process-wide env vars to project-scoped
provided context. workflow() resolves cwd, rootDir, dataDir, and outDir once
and passes them through Vitest's per-project context; global-setup and
setup-file read that resolved state when building bundles and creating the
local test world.

On the recovery side, world-local now keeps fileIdFilter applied while
paginating and scopes startup recovery to the active tag. Adds an explicit
recoverActiveRuns opt-out and disables recovery in the Vitest harness so
worker startup does not re-enqueue stale runs before direct handlers are
registered.

Also tightens cleanup in two e2e dev tests so the deferred-builder /
Turbopack interaction does not leave the dev server in a broken state for
subsequent test files (which previously caused Windows e2e to hang for the
full 30-min job timeout).

Co-Authored-By: Tom Dale <tom@vercel.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 2, 2026

🦋 Changeset detected

Latest commit: 7ff87ae

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
Name Type
@workflow/vitest Patch
@workflow/world-local Patch
@workflow/cli Patch
@workflow/core Patch
@workflow/world-postgres Patch
workflow Patch
@workflow/world-testing Patch
@workflow/builders Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/web-shared Patch
@workflow/web Patch
@workflow/ai Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/nuxt Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview, Comment May 2, 2026 7:10am
example-nextjs-workflow-webpack Ready Ready Preview, Comment May 2, 2026 7:10am
example-workflow Ready Ready Preview, Comment May 2, 2026 7:10am
workbench-astro-workflow Ready Ready Preview, Comment May 2, 2026 7:10am
workbench-express-workflow Ready Ready Preview, Comment May 2, 2026 7:10am
workbench-fastify-workflow Ready Ready Preview, Comment May 2, 2026 7:10am
workbench-hono-workflow Ready Ready Preview, Comment May 2, 2026 7:10am
workbench-nitro-workflow Ready Ready Preview, Comment May 2, 2026 7:10am
workbench-nuxt-workflow Ready Ready Preview, Comment May 2, 2026 7:10am
workbench-sveltekit-workflow Ready Ready Preview, Comment May 2, 2026 7:10am
workbench-vite-workflow Ready Ready Preview, Comment May 2, 2026 7:10am
workflow-docs Ready Ready Preview, Comment, Open in v0 May 2, 2026 7:10am
workflow-swc-playground Ready Ready Preview, Comment May 2, 2026 7:10am
workflow-web Ready Ready Preview, Comment May 2, 2026 7:10am

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 2, 2026

🧪 E2E Test Results

All tests passed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 1000 0 67 1067
✅ 💻 Local Development 1078 0 86 1164
✅ 📦 Local Production 1078 0 86 1164
✅ 🐘 Local Postgres 1078 0 86 1164
✅ 🪟 Windows 97 0 0 97
✅ 📋 Other 273 0 18 291
Total 4604 0 343 4947

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 90 0 7
✅ example 90 0 7
✅ express 90 0 7
✅ fastify 90 0 7
✅ hono 90 0 7
✅ nextjs-turbopack 95 0 2
✅ nextjs-webpack 95 0 2
✅ nitro 90 0 7
✅ nuxt 90 0 7
✅ sveltekit 90 0 7
✅ vite 90 0 7
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 91 0 6
✅ express-stable 91 0 6
✅ fastify-stable 91 0 6
✅ hono-stable 91 0 6
✅ nextjs-turbopack-canary 78 0 19
✅ nextjs-turbopack-stable 97 0 0
✅ nextjs-webpack-canary 78 0 19
✅ nextjs-webpack-stable 97 0 0
✅ nitro-stable 91 0 6
✅ nuxt-stable 91 0 6
✅ sveltekit-stable 91 0 6
✅ vite-stable 91 0 6
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 91 0 6
✅ express-stable 91 0 6
✅ fastify-stable 91 0 6
✅ hono-stable 91 0 6
✅ nextjs-turbopack-canary 78 0 19
✅ nextjs-turbopack-stable 97 0 0
✅ nextjs-webpack-canary 78 0 19
✅ nextjs-webpack-stable 97 0 0
✅ nitro-stable 91 0 6
✅ nuxt-stable 91 0 6
✅ sveltekit-stable 91 0 6
✅ vite-stable 91 0 6
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 91 0 6
✅ express-stable 91 0 6
✅ fastify-stable 91 0 6
✅ hono-stable 91 0 6
✅ nextjs-turbopack-canary 78 0 19
✅ nextjs-turbopack-stable 97 0 0
✅ nextjs-webpack-canary 78 0 19
✅ nextjs-webpack-stable 97 0 0
✅ nitro-stable 91 0 6
✅ nuxt-stable 91 0 6
✅ sveltekit-stable 91 0 6
✅ vite-stable 91 0 6
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 97 0 0
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 91 0 6
✅ e2e-local-postgres-nest-stable 91 0 6
✅ e2e-local-prod-nest-stable 91 0 6

📋 View full workflow run

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 2, 2026

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 0.036s (-16.0% 🟢) 1.005s (~) 0.968s 10 1.00x
💻 Local Next.js (Turbopack) 0.048s 1.006s 0.958s 10 1.33x
🐘 Postgres Next.js (Turbopack) 0.059s 1.011s 0.953s 10 1.62x
🐘 Postgres Express 0.061s (+4.7%) 1.010s (~) 0.950s 10 1.68x
🐘 Postgres Nitro 0.063s (-34.2% 🟢) 1.010s (-3.1%) 0.948s 10 1.73x
💻 Local Express 0.319s (+620.3% 🔺) 1.032s (+2.7%) 0.712s 10 8.81x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 0.211s (-10.2% 🟢) 1.752s (-17.9% 🟢) 1.541s 10 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 1.095s (-3.2%) 2.005s (~) 0.910s 10 1.00x
💻 Local Next.js (Turbopack) 1.118s 2.007s 0.889s 10 1.02x
🐘 Postgres Next.js (Turbopack) 1.137s 2.009s 0.872s 10 1.04x
🐘 Postgres Express 1.148s (~) 2.011s (~) 0.864s 10 1.05x
🐘 Postgres Nitro 1.152s (+1.1%) 2.011s (~) 0.859s 10 1.05x
💻 Local Express 1.980s (+75.9% 🔺) 2.133s (+6.4% 🔺) 0.154s 10 1.81x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.180s (+16.3% 🔺) 4.004s (+5.2% 🔺) 1.823s 10 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 10.649s (-2.7%) 11.023s (~) 0.374s 3 1.00x
💻 Local Next.js (Turbopack) 10.851s 11.024s 0.173s 3 1.02x
🐘 Postgres Next.js (Turbopack) 10.860s 11.019s 0.159s 3 1.02x
🐘 Postgres Express 10.919s (~) 11.019s (~) 0.100s 3 1.03x
🐘 Postgres Nitro 10.935s (+0.6%) 11.026s (~) 0.092s 3 1.03x
💻 Local Express 16.822s (+54.0% 🔺) 17.112s (+55.2% 🔺) 0.291s 2 1.58x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 17.000s (~) 19.075s (-4.7%) 2.075s 2 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 14.216s (-5.6% 🟢) 15.029s (-6.2% 🟢) 0.813s 4 1.00x
🐘 Postgres Next.js (Turbopack) 14.502s 15.024s 0.522s 4 1.02x
🐘 Postgres Express 14.582s (~) 15.022s (~) 0.440s 4 1.03x
🐘 Postgres Nitro 14.620s (~) 15.021s (~) 0.401s 4 1.03x
💻 Local Next.js (Turbopack) 14.661s 15.031s 0.370s 4 1.03x
💻 Local Express 30.130s (+101.3% 🔺) 30.656s (+104.0% 🔺) 0.526s 2 2.12x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 32.681s (-35.0% 🟢) 35.075s (-33.3% 🟢) 2.394s 2 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 13.820s 14.025s 0.205s 7 1.00x
🐘 Postgres Express 13.836s (-1.2%) 14.022s (-3.9%) 0.185s 7 1.00x
🐘 Postgres Nitro 14.148s (+1.3%) 15.027s (+5.0% 🔺) 0.879s 6 1.02x
💻 Local Nitro 14.853s (-11.5% 🟢) 15.027s (-11.8% 🟢) 0.174s 6 1.07x
💻 Local Next.js (Turbopack) 16.247s 17.032s 0.785s 6 1.18x
💻 Local Express 44.650s (+168.9% 🔺) 45.194s (+165.4% 🔺) 0.545s 2 3.23x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 56.779s (-53.2% 🟢) 58.992s (-52.3% 🟢) 2.213s 2 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.225s 2.009s 0.784s 15 1.00x
🐘 Postgres Express 1.256s (~) 2.010s (~) 0.754s 15 1.03x
🐘 Postgres Nitro 1.283s (+0.6%) 2.009s (~) 0.726s 15 1.05x
💻 Local Nitro 1.475s (-9.6% 🟢) 2.006s (-3.3%) 0.530s 15 1.20x
💻 Local Next.js (Turbopack) 1.586s 2.074s 0.487s 15 1.30x
💻 Local Express 3.067s (+106.0% 🔺) 3.581s (+78.6% 🔺) 0.515s 9 2.50x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.532s (-11.5% 🟢) 4.226s (-8.6% 🟢) 1.694s 8 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.324s (-1.6%) 3.009s (~) 0.686s 10 1.00x
🐘 Postgres Next.js (Turbopack) 2.387s 3.009s 0.623s 10 1.03x
🐘 Postgres Nitro 2.387s (+1.5%) 3.009s (~) 0.622s 10 1.03x
💻 Local Nitro 2.731s (-13.1% 🟢) 3.108s (-20.0% 🟢) 0.377s 10 1.18x
💻 Local Next.js (Turbopack) 2.807s 3.564s 0.758s 9 1.21x
💻 Local Express 5.304s (+79.6% 🔺) 5.746s (+66.4% 🔺) 0.442s 7 2.28x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.390s (-34.0% 🟢) 4.463s (-12.7% 🟢) 2.073s 7 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.464s (-0.6%) 4.011s (~) 0.547s 8 1.00x
🐘 Postgres Nitro 3.496s (~) 4.010s (~) 0.515s 8 1.01x
🐘 Postgres Next.js (Turbopack) 3.627s 4.011s 0.384s 8 1.05x
💻 Local Nitro 7.718s (-7.6% 🟢) 8.269s (-8.3% 🟢) 0.551s 4 2.23x
💻 Local Next.js (Turbopack) 8.091s 8.771s 0.680s 4 2.34x
💻 Local Express 28.956s (+247.3% 🔺) 35.190s (+289.9% 🔺) 6.234s 1 8.36x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.045s (-28.2% 🟢) 5.060s (-17.4% 🟢) 2.015s 6 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.211s 2.009s 0.798s 15 1.00x
🐘 Postgres Nitro 1.254s (~) 2.009s (~) 0.755s 15 1.04x
🐘 Postgres Express 1.258s (~) 2.007s (~) 0.750s 15 1.04x
💻 Local Next.js (Turbopack) 1.530s 2.006s 0.476s 15 1.26x
💻 Local Nitro 1.873s (~) 2.392s (+2.2%) 0.519s 13 1.55x
💻 Local Express 4.771s (+151.9% 🔺) 5.230s (+121.3% 🔺) 0.459s 6 3.94x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.281s (-11.6% 🟢) 4.049s (-6.9% 🟢) 1.768s 8 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.341s (~) 3.009s (~) 0.669s 10 1.00x
🐘 Postgres Nitro 2.363s (+1.0%) 3.010s (~) 0.647s 10 1.01x
🐘 Postgres Next.js (Turbopack) 2.396s 3.007s 0.612s 10 1.02x
💻 Local Nitro 2.697s (-12.0% 🟢) 3.008s (-22.6% 🟢) 0.311s 10 1.15x
💻 Local Next.js (Turbopack) 3.047s 3.759s 0.712s 8 1.30x
💻 Local Express 12.971s (+314.1% 🔺) 13.445s (+257.4% 🔺) 0.474s 3 5.54x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.390s (-25.1% 🟢) 4.335s (-9.5% 🟢) 1.944s 7 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.474s (-0.7%) 4.009s (~) 0.534s 8 1.00x
🐘 Postgres Nitro 3.497s (~) 4.011s (~) 0.515s 8 1.01x
🐘 Postgres Next.js (Turbopack) 3.625s 4.011s 0.386s 8 1.04x
💻 Local Nitro 7.806s (-14.6% 🟢) 8.015s (-20.0% 🟢) 0.210s 4 2.25x
💻 Local Next.js (Turbopack) 8.633s 9.270s 0.637s 4 2.48x
💻 Local Express 37.597s (+327.2% 🔺) 38.199s (+311.9% 🔺) 0.602s 1 10.82x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.816s (-56.1% 🟢) 4.597s (-43.8% 🟢) 1.781s 7 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 0.701s (-28.6% 🟢) 1.004s (-8.2% 🟢) 0.304s 60 1.00x
🐘 Postgres Next.js (Turbopack) 0.790s 1.006s 0.216s 60 1.13x
🐘 Postgres Express 0.814s (-3.0%) 1.023s (~) 0.209s 59 1.16x
🐘 Postgres Nitro 0.846s (+3.1%) 1.007s (~) 0.161s 60 1.21x
💻 Local Next.js (Turbopack) 0.876s 1.039s 0.163s 58 1.25x
💻 Local Express 5.085s (+416.7% 🔺) 5.677s (+427.6% 🔺) 0.591s 11 7.26x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 9.376s (-50.7% 🟢) 11.200s (-47.5% 🟢) 1.823s 6 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.887s 2.029s 0.141s 45 1.00x
🐘 Postgres Express 1.918s (-2.9%) 2.124s (-5.9% 🟢) 0.206s 43 1.02x
🐘 Postgres Nitro 2.050s (+6.3% 🔺) 2.736s (+30.3% 🔺) 0.686s 33 1.09x
💻 Local Nitro 2.272s (-25.1% 🟢) 3.007s (-20.0% 🟢) 0.735s 30 1.20x
💻 Local Next.js (Turbopack) 2.725s 3.008s 0.283s 30 1.44x
💻 Local Express 17.794s (+490.0% 🔺) 18.499s (+416.0% 🔺) 0.705s 5 9.43x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 27.950s (-19.1% 🟢) 30.591s (-16.9% 🟢) 2.641s 3 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 3.839s 4.042s 0.203s 30 1.00x
🐘 Postgres Express 3.893s (-2.4%) 4.076s (-6.7% 🟢) 0.183s 30 1.01x
🐘 Postgres Nitro 4.130s (+0.6%) 4.942s (+7.3% 🔺) 0.812s 25 1.08x
💻 Local Nitro 7.321s (-21.3% 🟢) 8.015s (-20.0% 🟢) 0.694s 15 1.91x
💻 Local Next.js (Turbopack) 8.678s 9.018s 0.340s 14 2.26x
💻 Local Express 44.180s (+379.7% 🔺) 44.534s (+344.5% 🔺) 0.355s 3 11.51x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 73.931s (-43.1% 🟢) 78.038s (-41.0% 🟢) 4.107s 2 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 0.251s 1.007s 0.756s 60 1.00x
🐘 Postgres Express 0.284s (+0.5%) 1.006s (~) 0.722s 60 1.13x
🐘 Postgres Nitro 0.295s (+4.1%) 1.007s (~) 0.712s 60 1.18x
💻 Local Next.js (Turbopack) 0.574s 1.005s 0.431s 60 2.29x
💻 Local Nitro 0.611s (+1.1%) 1.021s (~) 0.410s 59 2.44x
💻 Local Express 3.353s (+498.4% 🔺) 4.041s (+302.4% 🔺) 0.688s 16 13.37x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.431s (-26.8% 🟢) 3.532s (-2.9%) 2.101s 17 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 0.481s 1.006s 0.526s 90 1.00x
🐘 Postgres Express 0.495s (-2.9%) 1.006s (~) 0.512s 90 1.03x
🐘 Postgres Nitro 0.518s (+4.4%) 1.007s (~) 0.488s 90 1.08x
💻 Local Nitro 2.432s (-4.2%) 3.008s (~) 0.575s 30 5.06x
💻 Local Next.js (Turbopack) 2.583s 3.010s 0.426s 30 5.37x
💻 Local Express 10.002s (+298.0% 🔺) 11.583s (+284.9% 🔺) 1.581s 8 20.80x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.968s (-2.6%) 4.869s (+1.3%) 1.901s 19 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.785s (-4.1%) 1.007s (-1.0%) 0.222s 120 1.00x
🐘 Postgres Next.js (Turbopack) 0.793s 1.015s 0.223s 119 1.01x
🐘 Postgres Nitro 0.858s (+8.5% 🔺) 1.011s (~) 0.153s 119 1.09x
💻 Local Nitro 10.439s (-6.7% 🟢) 10.933s (-6.3% 🟢) 0.494s 11 13.30x
💻 Local Next.js (Turbopack) 10.942s 11.393s 0.451s 11 13.94x
💻 Local Express 25.204s (+125.2% 🔺) 26.108s (+118.7% 🔺) 0.904s 5 32.11x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 6.481s (-12.7% 🟢) 8.708s (-5.8% 🟢) 2.227s 14 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express

Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 0.140s (-34.5% 🟢) 1.004s (~) 0.009s (-24.0% 🟢) 1.015s (~) 0.875s 10 1.00x
💻 Local Next.js (Turbopack) 0.175s 1.003s 0.013s 1.019s 0.844s 10 1.25x
🐘 Postgres Next.js (Turbopack) 0.199s 1.001s 0.001s 1.011s 0.812s 10 1.42x
🐘 Postgres Express 0.203s (-1.0%) 0.995s (~) 0.002s (+12.5% 🔺) 1.010s (~) 0.807s 10 1.45x
🐘 Postgres Nitro 0.219s (+6.7% 🔺) 0.992s (-0.8%) 0.002s (+13.3% 🔺) 1.011s (~) 0.792s 10 1.56x
💻 Local Express 1.016s (+410.1% 🔺) 1.720s (+71.2% 🔺) 0.167s (+1276.0% 🔺) 1.894s (+86.1% 🔺) 0.879s 10 7.26x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.508s (-39.8% 🟢) 2.963s (-27.6% 🟢) 1.704s (+77.3% 🔺) 5.111s (-8.6% 🟢) 3.602s 10 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: Express

stream pipeline with 5 transform steps (1MB)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.602s (-4.4%) 1.007s (~) 0.004s (+1.3%) 1.022s (~) 0.420s 59 1.00x
🐘 Postgres Next.js (Turbopack) 0.612s 1.010s 0.006s 1.026s 0.414s 59 1.02x
🐘 Postgres Nitro 0.649s (+4.0%) 1.006s (~) 0.006s (+44.7% 🔺) 1.025s (~) 0.376s 59 1.08x
💻 Local Next.js (Turbopack) 0.672s 1.012s 0.010s 1.025s 0.354s 59 1.12x
💻 Local Nitro 0.684s (-18.5% 🟢) 1.011s (~) 0.009s (~) 1.115s (~) 0.431s 54 1.14x
💻 Local Express 2.926s (+286.5% 🔺) 3.319s (+222.6% 🔺) 0.031s (+232.8% 🔺) 3.640s (+250.1% 🔺) 0.714s 18 4.86x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.914s (-39.8% 🟢) 5.513s (-31.2% 🟢) 0.677s (+65.6% 🔺) 6.617s (-25.1% 🟢) 2.703s 10 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: Express

10 parallel streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 0.884s 1.053s 0.000s 1.060s 0.176s 57 1.00x
🐘 Postgres Express 0.964s (~) 1.192s (-6.7% 🟢) 0.000s (-8.0% 🟢) 1.208s (-7.5% 🟢) 0.244s 50 1.09x
🐘 Postgres Nitro 1.033s (+6.6% 🔺) 1.520s (+21.8% 🔺) 0.000s (+20.0% 🔺) 1.535s (+22.1% 🔺) 0.502s 40 1.17x
💻 Local Nitro 1.180s (-3.5%) 2.018s (~) 0.000s (+300.0% 🔺) 2.020s (~) 0.840s 30 1.33x
💻 Local Next.js (Turbopack) 1.276s 2.021s 0.000s 2.024s 0.748s 30 1.44x
💻 Local Express 6.982s (+470.0% 🔺) 6.982s (+245.6% 🔺) 0.001s (+333.3% 🔺) 7.553s (+273.5% 🔺) 0.571s 9 7.90x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.910s (-22.2% 🟢) 4.343s (-14.9% 🟢) 0.000s (-100.0% 🟢) 4.822s (-12.8% 🟢) 1.912s 13 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: Express

fan-out fan-in 10 streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.781s (~) 2.221s (+2.0%) 0.000s (NaN%) 2.231s (+1.5%) 0.451s 27 1.00x
🐘 Postgres Next.js (Turbopack) 1.788s 2.106s 0.000s 2.113s 0.325s 29 1.00x
🐘 Postgres Nitro 1.850s (+3.3%) 2.142s (~) 0.000s (+100.0% 🔺) 2.153s (-1.0%) 0.303s 28 1.04x
💻 Local Nitro 3.481s (+2.8%) 4.033s (~) 0.000s (-25.0% 🟢) 4.036s (~) 0.555s 15 1.95x
💻 Local Next.js (Turbopack) 3.673s 4.233s 0.001s 4.237s 0.563s 15 2.06x
💻 Local Express 9.983s (+187.9% 🔺) 10.586s (+162.5% 🔺) 0.002s (+87.5% 🔺) 10.596s (+162.5% 🔺) 0.613s 6 5.61x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 4.217s (-8.1% 🟢) 5.721s (-5.0%) 0.000s (NaN%) 6.376s (-1.3%) 2.159s 10 1.00x
▲ Vercel Next.js (Turbopack) ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: Express

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World 🥇 Fastest Framework Wins
💻 Local Nitro 18/21
🐘 Postgres Next.js (Turbopack) 14/21
▲ Vercel Express 21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 🐘 Postgres 19/21
Next.js (Turbopack) 🐘 Postgres 17/21
Nitro 🐘 Postgres 15/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run

@VaguelySerious VaguelySerious marked this pull request as ready for review May 2, 2026 07:29
@VaguelySerious VaguelySerious changed the title WIP: Isolate vitest test harness and harden dev test cleanup [vitest] Isolate test data and improve cleanup May 2, 2026
Copy link
Copy Markdown
Member

@TooTallNate TooTallNate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three coherent fixes wrapped into one PR — vitest project-context isolation, world-local recovery scoped by tag, and Windows-specific dev-test cleanup hardening. Verified each piece independently.

Vitest project-context isolation

The shape is right: WorkflowTestOptions resolves to a ResolvedWorkflowTestOptions shape (cwd / rootDir / dataDir / outDir, all absolute), gets passed via Vitest's provide/inject (per-project context), and is consumed by both global-setup.ts and setup-file.ts. No process env vars touched. The new test confirms process.env.WORKFLOW_VITEST_* stays clean.

resolveWorkflowTestOptions is idempotent (resolving an already-resolved object is a no-op since path.resolve of an absolute path returns itself), so the double-resolution from readProvidedWorkflowTestOptions is safe.

Path resolution: cwd defaults to process.cwd(); rootDir defaults to cwd (resolved relative to cwd if provided); dataDir/outDir default to <rootDir>/.workflow-data and <rootDir>/.workflow-vitest (resolved relative to cwd if provided). Consistent with the docs table.

Recovery scoped by tag

The bug existed: on main, createLocalWorld() calls createStorage() twice (once stored as storage, once spread into the world). They're separate instances with separate instrumentObject wrappers. Recovery (storage.runs) wouldn't see updates that consumers made through the spread instance, and adding a fileIdFilter wrapper to storage.runs wouldn't be visible to consumers. The PR collapses this to a single storage and uses ...storage for the spread, fixing the latent duplication.

The new LocalListWorkflowRunsParams extends the public ListWorkflowRunsParams with an internal fileIdFilter. Kept off the public Storage['runs']['list'] surface via a separate LocalRunsStorage type, with LocalStorage structurally assignable to Storage. This is the right way to add a backend-private field without leaking it to @workflow/world consumers.

The paginatedFileSystemQuery change is the load-bearing piece: filteredFileIds is now applied to both the no-cursor branch and the cursor-paginated branch (via candidateFileIds = filteredFileIds). Test "keeps fileIdFilter applied on later cursor pages" exercises this directly with multiple ULID-stamped files, verifying that page 2 still respects the filter.

recoverActiveRuns: false opt-out for the vitest harness is the right control: tests register direct handlers AFTER setupWorkflowTests() starts, and stale runs in the data dir would otherwise be dispatched before handlers are wired up. The reordering of world.start() to happen after world.registerHandler() (with the inline comment explaining the future hazard if anyone re-enables recovery) is good defensive practice.

The new hasTag(fileId, tag) helper is a clean primitive — wrun_ABC.vitest-0 matches vitest-0, untagged fileIds never match. Three new tests cover: tag isolation between two workers, tag filtering across pagination (25 tagged + 5 untagged + 5 differently-tagged runs), and recovery skip when recoverActiveRuns: false.

Dev-test cleanup hardening

These are Windows-specific Turbopack flake fixes, well-explained by inline comments at every behavior change:

  • afterEach reorders restore-then-delete to avoid leaving the dev server with broken imports between deletes (Turbopack on Windows caches the parse failure).
  • The "imported step hot-reload" test catches triggerWorkflowRun failures during polling, rewrites the api file to invalidate Turbopack's cache, and continues polling. Conservative — only rewrites on error, doesn't bail.
  • The "discovered via workflow imports" test does in-test cleanup (instead of afterEach) so the deferred builder has time to drop the discovered step before the next test file's dev server requests start failing.

Timeout was bumped 30s → 60s on the third one. Reasonable for the additional polling.

Test verification

Ran on the PR branch:

  • pnpm test in packages/vitest: 5 new tests pass.
  • pnpm test in packages/world-local: all 339 tests pass (including the new pagination filter test and the three tag-recovery tests).

Incidental cleanup

vitest moves from a non-listed-but-locked dependency to a proper devDep. Consumers continue to resolve it via the existing peerDependencies (vitest: >=3.0.0). No surface change for users of @workflow/vitest.

Nits (non-blocking)

The two changesets swift-cobras-repair.md and moody-rivers-play.md have somewhat overlapping content — one's the package-version bumps, the other's the empty-changeset note about the dev-test cleanup. Slightly confusing to have both, but it preserves attribution from the original PR(s) so probably worth keeping.

@VaguelySerious VaguelySerious merged commit 2f52d14 into main May 2, 2026
156 of 164 checks passed
@VaguelySerious VaguelySerious deleted the peter/local-world-isolation branch May 2, 2026 10:30
@pranaygp pranaygp added the backport-stable Cherry-pick this PR to the stable branch when merged label May 2, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 2, 2026

Backport to stable failed — the cherry-pick had conflicts that could not be resolved automatically.

To resolve manually:

git fetch origin stable
git checkout stable
git cherry-pick 2f52d14f3844c999f6b89baeb8e04289d6dd34a9
# Fix conflicts, then:
git cherry-pick --continue
git push origin stable

pranaygp added a commit that referenced this pull request May 2, 2026
…ignal

* origin/main:
  [vitest] [world-local] Fix local-world data recovery isolation (#1895)
  ci: switch Vercel deployment-protection bypass to OIDC Trusted Sources (#1882)
  Add additional tests for event consumer fixes for hook/sleep/step race conditions (#1528)

# Conflicts:
#	packages/core/src/workflow.test.ts
pranaygp added a commit that referenced this pull request May 2, 2026
…lier-errors-followups

* origin-https/main:
  [vitest] [world-local] Fix local-world data recovery isolation (#1895)
  ci: switch Vercel deployment-protection bypass to OIDC Trusted Sources (#1882)
  Add additional tests for event consumer fixes for hook/sleep/step race conditions (#1528)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-stable Cherry-pick this PR to the stable branch when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants