Skip to content

feat(vitest): run a full workflow locally through .trigger()#1308

Open
toiroakr wants to merge 5 commits into
feat/using-mockfrom
feat/workflow-trigger-using-mock
Open

feat(vitest): run a full workflow locally through .trigger()#1308
toiroakr wants to merge 5 commits into
feat/using-mockfrom
feat/workflow-trigger-using-mock

Conversation

@toiroakr
Copy link
Copy Markdown
Contributor

@toiroakr toiroakr commented Jun 3, 2026

Summary

  • Stacked on feat/using-mock (feat(vitest): expose mock controllers as using-friendly factories #1282). workflow.mainJob.trigger() runs the
    real registered job bodies of a full workflow chain in a unit test with no
    mockWorkflow() needed
    and no deployment. In the tailor-runtime environment
    a default tailor.workflow runner provides this; outside it, .trigger() falls
    back to the same local runner — so it works with no env and no mock too.
  • Trigger inputs and outputs cross the same JSON boundary the platform uses, so a
    non-serializable payload fails the test exactly as it would in production.
  • mockWorkflow() overlays the default runner only when you need to override jobs
    with wf.setJobHandler(...) / wf.enqueueResult(...) (the rest still run their
    real bodies), set the env via wf.setEnv(...), assert on wf.triggeredJobs, or
    drive wait / resolve.
  • A build-time TAILOR_PLATFORM_BUNDLE gate, applied across every function
    bundler (workflow, resolver, executor, auth, seed, migrate, query, tailordb
    hooks, function), tree-shakes the test-only registry/serialize runner out of
    production bundles so no unsubstituted process.env reaches the Platform Web
    runtime. A bundler test asserts the gate folds it away.
  • Docs: testing.md "Running a full workflow locally" shows the no-mock flow.

Notes

toiroakr added 2 commits June 3, 2026 19:05
…ialize boundary

.trigger() now routes through the installed tailor.workflow shim with a global
job registry that runs real bodies by default, so a full workflow can run
locally via mockWorkflow(). Trigger args and results cross a JSON-serialize
boundary, surfacing non-serializable payloads as test failures the same way the
platform would. A build-time TAILOR_PLATFORM_BUNDLE gate, applied across every
function bundler, folds the test-only registry shim out of production bundles.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 3, 2026

🦋 Changeset detected

Latest commit: 5c5c268

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

This PR includes changesets to release 2 packages
Name Type
@tailor-platform/sdk Patch
@tailor-platform/create-sdk 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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

⚡ pkg.pr.new

@tailor-platform/sdk

pnpm add https://pkg.pr.new/@tailor-platform/sdk@5c5c268
pnpm dlx https://pkg.pr.new/@tailor-platform/sdk@5c5c268 --help

@tailor-platform/create-sdk

pnpm add https://pkg.pr.new/@tailor-platform/create-sdk@5c5c268
pnpm dlx https://pkg.pr.new/@tailor-platform/create-sdk@5c5c268 my-app

commit: 5c5c268

This comment was marked as outdated.

…ds no mockWorkflow

The tailor-runtime environment now installs a default tailor.workflow runner
(registry execution + the JSON serialize boundary), so workflow.mainJob.trigger()
runs the full chain locally without acquiring mockWorkflow(). mockWorkflow() now
only overlays that default to override responses, set the env, assert on
triggeredJobs, or drive wait/resolve. buildJobContext and WORKFLOW_TEST_ENV_KEY
move to the vi-free test-env-key module so both the environment realm and the
mock share them.

This comment was marked as outdated.

…n the JSON boundary

.trigger() falls back to running the registered job/workflow body locally across
the same JSON serialize boundary when no tailor.workflow shim is installed, so it
works without the tailor-runtime environment and without mockWorkflow() while
keeping the serialize boundary. The tailor-runtime default runner and this
fallback share one runner core in registry.ts.

Also hardens the boundary: align RegisteredJobBody context.invoker to optional
(matching the public WorkflowJobContext), validate the deprecated env-var is a
JSON object, throw a clear error when platformSerialize's root collapses to
undefined, preserve triggerWorkflow call arity so a forwarded undefined options
is recorded, and clarify the wait/resolve not-available message.

This comment was marked as resolved.

… a raw substring

The TAILOR_PLATFORM_BUNDLE fold now uses an anchored regex (leading lookbehind
rejecting a longer owner/identifier, trailing word boundary rejecting a longer
key like _BUNDLE_MODE) instead of a raw replaceAll. rolldown exposes no `define`
option, so a transform-level replace remains the mechanism; a unit test pins the
precise-match behavior. The exact token appearing inside a string literal is
accepted: it is an internal flag that never appears as a string in bundled
function code, and substituting `true` there would be harmless anyway.
@claude
Copy link
Copy Markdown

claude Bot commented Jun 5, 2026

📖 Docs Consistency Check

No inconsistencies found between documentation and implementation.

Checked Areas

Documentation Files:

  • packages/sdk/docs/testing.md - Updated correctly to reflect new .trigger() behavior
  • AGENTS.md - Workflow section is consistent (focuses on wait/resolve which still requires mockWorkflow())
  • packages/sdk/docs/services/workflow.md - Correctly references testing.md for testing guidance
  • packages/sdk/docs/services/auth.md - Only mentions production usage of workflow.trigger()
  • packages/sdk/docs/runtime.md - Lists runtime APIs, not testing-specific

Code Examples:

  • example/tests/bundled_execution.test.ts - Uses mockWorkflow() appropriately for job overrides
  • ✅ Template tests (packages/create-sdk/templates/workflow/) - Demonstrate both patterns correctly:
    • Integration tests without mockWorkflow() (lines 110-124 in order-fulfillment.test.ts)
    • Wait/resolve tests with mockWorkflow() (approval.test.ts)

Implementation:

  • ✅ Code comments correctly mark deprecated patterns
  • ✅ All bundlers include the new platformBundleDefinePlugin
  • ✅ Registry and runtime setup matches documented behavior

What Changed in This PR

The PR introduces the ability to run workflow jobs locally without mockWorkflow():

  1. New default behavior: workflow.mainJob.trigger() and job.trigger() now execute real job bodies locally with no mock needed
  2. JSON boundary enforcement: Trigger args/results cross the same JSON boundary as the platform, catching serialization issues in tests
  3. When to use mockWorkflow(): Only needed for overriding jobs, setting env, asserting on triggeredJobs, or handling wait/resolve

The documentation in testing.md was correctly updated to reflect these changes:

  • Line 129: Explains .trigger() runs real bodies by default
  • Lines 711-726: "Running a full workflow locally" section shows the no-mock pattern
  • Line 726: Clarifies when mockWorkflow() is still needed

Minor Enhancement Opportunity (Optional)

While not an inconsistency, AGENTS.md line 86 could optionally add a note about the new default .trigger() behavior. Currently it only discusses wait/resolve (which is accurate), but developers reading AGENTS.md might not realize they can now test full workflow chains without any mock unless they also read testing.md.

Re-run this check by adding the docs-check label to the PR.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants