Skip to content

feat(vitest): route workflow trigger through globalThis mock#1188

Closed
toiroakr wants to merge 21 commits into
mainfrom
fix/workflow-boarder
Closed

feat(vitest): route workflow trigger through globalThis mock#1188
toiroakr wants to merge 21 commits into
mainfrom
fix/workflow-boarder

Conversation

@toiroakr
Copy link
Copy Markdown
Contributor

@toiroakr toiroakr commented May 18, 2026

Summary

  • Mirror the Platform JSON serialization boundary in wjob.trigger() / wf.trigger() so vitest catches NaN/Infinity/BigInt/class-instance payloads the same way the real Platform does.
  • Route both wjob.trigger() and wf.trigger() through globalThis.tailor.workflow.triggerJobFunction / triggerWorkflow, matching the existing wait/resolve mock pattern.
  • Add a globalThis-keyed registry (registerJob / registerWorkflow) so the mock can look up bodies by name across module instances; bodies are registered as a side effect of createWorkflowJob / createWorkflow. The registry module also exports a shared getPlatformWorkflow() shim used by both job.ts and workflow.ts.
  • Add platformSerialize utility (with tests) used at the mock boundary to validate payloads and strip top-level undefined; root-level function / symbol values throw a specific TypeError instead of a generic message.
  • Unify mockTriggerWorkflow: the main job is now invoked via mockTriggerJobFunction, so it appears in triggeredJobs and honors setJobHandler / enqueueResult uniformly with other jobs.
  • Update docs/testing.md to describe the new uniform behavior, the body-fallback for the Workflow Mock when no handler/result is configured, and the tailor-runtime environment requirement.

Mirror the Platform JSON serialization boundary in workflow mocks so
tests catch invalid payloads (NaN/Infinity/BigInt/class instances) the
same way the real Platform does. Both wjob.trigger() and wf.trigger()
now delegate to globalThis.tailor.workflow.triggerJobFunction /
triggerWorkflow, matching the wait/resolve pattern.

- Add platformSerialize utility validating JSON-boundary safety
- Introduce a globalThis-keyed registry so the mock can look up job
  and workflow bodies by name across module instances
- Route wf.trigger() through mockTriggerJobFunction so main-job
  invocations are recorded in triggeredJobs and honor setJobHandler /
  enqueueResult uniformly
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 18, 2026

🦋 Changeset detected

Latest commit: 0b76ea0

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 May 18, 2026

⚡ pkg.pr.new

@tailor-platform/sdk

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

@tailor-platform/create-sdk

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

commit: 0b76ea0

@github-actions

This comment has been minimized.

…ialize errors

- Move getPlatformWorkflow() into registry.ts so job.ts / workflow.ts share one shim
- Note body fallback behaviour in the Workflow Mock docs section
- Throw specific TypeError messages for root-level function / symbol in platformSerialize
@github-actions

This comment has been minimized.

This comment was marked as outdated.

Resolve workflow-mock conflicts:
- Keep HEAD's globalThis-mock trigger routing; integrate main's
  workflowMock.setEnv() into the mock's buildJobContext (readWorkflowTestEnv
  with deprecated env-var fallback).
- Fix the nested integration Vitest config's @/ alias path math (broke when
  the dir moved from __tests__/integration to integration).
- Make mock triggerJobFunction synchronous (Promise only for async bodies)
  to match both the platform contract and runtime/workflow's typed wrapper.
- Drop the already-released wrap-trigger-job-function-in-promise changeset.
@github-actions

This comment has been minimized.

This comment was marked as outdated.

@github-actions

This comment has been minimized.

…c callbacks

The workflow mock wrapped the user resolve callback in an async function, so
test handlers that call `callback(...)` synchronously (the workflow template's
resolveApproval test and the docs/testing.md example) received a Promise instead
of the serialized value. Return the serialized result directly for sync
callbacks and only as a Promise for async ones, mirroring triggerJobFunction and
the platform's synchronous contract.

This comment was marked as outdated.

@github-actions

This comment has been minimized.

This comment was marked as outdated.

createWorkflowJob now bundles a small globalThis-registry shim (~230-320B per
job) so the vitest mock can look up job bodies by name. The recorded baselines
had already drifted ~10KB below current sizes from accumulated growth on main,
exhausting the 10KB buffer, so fetch-customer/process-payment tipped over.
Update the workflow-job baselines to current sizes; the 10KB regression buffer
is preserved.
@github-actions

This comment has been minimized.

This comment was marked as outdated.

@github-actions

This comment has been minimized.

…RM_BUNDLE

Replace the globalThis.__TAILOR_PLATFORM_BUNDLE__ sentinel with
process.env.TAILOR_PLATFORM_BUNDLE, which the workflow bundler substitutes to
true before minify/DCE. Drops the bespoke global declaration; in tests the env
var is simply unset so the registry/trigger shim runs as before.

This comment was marked as outdated.

toiroakr added 7 commits June 2, 2026 21:28
Option B shrank the workflow-job bundles back under the original baselines, so
the bumped values are no longer needed; revert the file to main to keep the PR
diff minimal.
…ndler

The function test-run bundler did not fold `process.env.TAILOR_PLATFORM_BUNDLE`,
so createWorkflowJob's guard reached the Platform Web runtime (no `process`) and
crashed — failing the SDK E2E 'runs workflow job by name' test. Extract a shared
platformBundleDefinePlugin and apply it in both the workflow deploy bundler and
the test-run bundler, and add a unit guard asserting the flag is folded away.
@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Comment on lines +19 to +21
export function platformSerialize<T>(value: T): T {
// Top-level undefined is allowed (jobs may take no input).
if (value === undefined) return undefined as T;
Comment on lines +3 to +6
// Fold `process.env.TAILOR_PLATFORM_BUNDLE` to `true` so the minifier DCEs the
// test-only workflow registry/trigger shim. Apply in every bundler that builds
// runnable functions; a missed path leaves the env read in place and fails
// loudly on the Platform's Web runtime (no `process`), which an e2e catches.
toiroakr added 2 commits June 3, 2026 09:29
…dler

Move the shared plugin to cli/shared and wire it into the resolver, executor,
auth, seed, migrate, query, and tailordb-hooks bundlers (in addition to workflow
deploy and function test-run). Any bundler that could pull in createWorkflow(Job)
now folds the platform-bundle flag, so the unsubstituted process.env read can
never reach the Platform Web runtime. A surviving read fails loudly in e2e.
…mise type

In a platform bundle .trigger() is rewritten away, but the dead stub was a
synchronous throw while the type is Promise-returning. Make it async so any
stray call rejects rather than throws synchronously.
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@remiposo remiposo left a comment

Choose a reason for hiding this comment

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

[imo]
Is it acceptable that workflow testing becomes impossible without using tailor-runtime?
Personally, I think it would be simpler and more desirable to have jobs called as plain function calls locally. The JSON serialization issue could be addressed simply by wrapping the function call, and that alone should not be a reason to require globalThis mocking.
If using globalThis eliminates the need for AST manipulation during bundling, that would be a compelling reason to do it — but otherwise I'm not convinced.

@toiroakr toiroakr assigned toiroakr and unassigned remiposo Jun 3, 2026
…njectMocks)

Correct the overly strong 'requires the tailor-runtime environment' note:
workflow .trigger() mocking also works in a plain test via injectMocks(globalThis),
not only under the tailor-runtime environment.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

Code Metrics Report (packages/sdk)

main (32a99be) #1188 (2a3c8db) +/-
Coverage 64.6% 64.8% +0.1%
Code to Test Ratio 1:0.4 1:0.4 +0.0
Details
  |                    | main (32a99be) | #1188 (2a3c8db) |  +/-  |
  |--------------------|----------------|-----------------|-------|
+ | Coverage           |          64.6% |           64.8% | +0.1% |
  |   Files            |            381 |             384 |    +3 |
  |   Lines            |          13180 |           13257 |   +77 |
+ |   Covered          |           8517 |            8591 |   +74 |
+ | Code to Test Ratio |          1:0.4 |           1:0.4 |  +0.0 |
  |   Code             |          87952 |           88414 |  +462 |
+ |   Test             |          37763 |           38037 |  +274 |

Code coverage of files in pull request scope (89.3% → 89.9%)

Files Coverage +/- Status
packages/sdk/src/cli/bundler/query/query-bundler.ts 91.6% 0.0% modified
packages/sdk/src/cli/commands/function/bundle.ts 96.4% 0.0% modified
packages/sdk/src/cli/commands/generate/seed/bundler.ts 92.3% 0.0% modified
packages/sdk/src/cli/commands/tailordb/migrate/bundler.ts 91.6% 0.0% modified
packages/sdk/src/cli/services/auth/bundler.ts 96.4% 0.0% modified
packages/sdk/src/cli/services/executor/bundler.ts 85.1% 0.0% modified
packages/sdk/src/cli/services/resolver/bundler.ts 94.8% 0.0% modified
packages/sdk/src/cli/services/tailordb/hooks-validate-bundler.ts 82.6% 0.0% modified
packages/sdk/src/cli/services/workflow/bundler.ts 93.9% 0.0% modified
packages/sdk/src/cli/shared/platform-bundle-plugin.ts 100.0% +100.0% added
packages/sdk/src/configure/services/workflow/job.ts 87.5% -12.5% modified
packages/sdk/src/configure/services/workflow/registry.ts 95.4% +95.4% added
packages/sdk/src/configure/services/workflow/workflow.ts 80.0% +46.6% modified
packages/sdk/src/utils/platform-serialize.ts 100.0% +100.0% added
packages/sdk/src/vitest/mock.ts 91.2% +0.2% modified

SDK Configure Bundle Size

main (32a99be) #1188 (2a3c8db) +/-
configure-index-size 18KB 18.25KB 0.25KB
dependency-chunks-size 34.47KB 36.05KB 1.58KB
total-bundle-size 52.47KB 54.3KB 1.83KB

Runtime Performance

main (32a99be) #1188 (2a3c8db) +/-
Generate Median 2,795ms 2,742ms -53ms
Generate Max 2,814ms 2,771ms -43ms
Apply Build Median 2,840ms 2,788ms -52ms
Apply Build Max 2,867ms 2,820ms -47ms

Type Performance (instantiations)

main (32a99be) #1188 (2a3c8db) +/-
tailordb-basic 35,147 36,982 1,835
tailordb-optional 3,841 3,841 0
tailordb-relation 7,428 7,428 0
tailordb-validate 2,566 2,566 0
tailordb-hooks 5,767 5,767 0
tailordb-object 12,136 12,136 0
tailordb-enum 2,462 2,462 0
resolver-basic 9,424 9,424 0
resolver-nested 26,111 26,111 0
resolver-array 18,187 18,187 0
executor-schedule 4,234 4,234 0
executor-webhook 873 873 0
executor-record 8,166 8,166 0
executor-resolver 4,369 4,369 0
executor-operation-function 868 868 0
executor-operation-gql 869 869 0
executor-operation-webhook 888 888 0
executor-operation-workflow 1,714 1,714 0

Reported by octocov

@toiroakr
Copy link
Copy Markdown
Contributor Author

toiroakr commented Jun 3, 2026

The statement that tailor-runtime is required was an error in the docs.
In reality, injecting a mock is sufficient.

Based on the assumption of #1282, it seems possible to organize this more cleanly, so I will recreate this as a PR directed toward that.

@toiroakr
Copy link
Copy Markdown
Contributor Author

toiroakr commented Jun 3, 2026

Superseded by #1308, which re-implements this feature on top of the using mockWorkflow() factory API (#1282). Please follow #1308.

@toiroakr toiroakr closed this Jun 3, 2026
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