1// Alchemy modifications are licensed under Apache-2.0.
2// This file includes third-party code; see /THIRD_PARTY_LICENSES.md.
3// Alchemy modifications: uses Array<T> syntax for non-tuple array types to match the repository convention.
4import { env } from "cloudflare:workers";
5import { setTestWorkflowCallback } from "./test-entry.ts";
6import type {
7 DatabaseInstance,
8 DatabaseVersion,
9 DatabaseWorkflow,
10 Engine,
11} from "../engine.ts";
12import type { WorkflowStep } from "cloudflare:workers";
13
14// Track fire-and-forget init() RPC promises so they can be settled
15// in afterAll hooks before vitest tears down miniflare
16const pendingInits: Array<Promise<unknown>> = [];
17
18/**
19 * Await all tracked init promises (with a timeout safety net).
20 * Call this in afterAll() for every test file that uses runWorkflow().
21 */
22export async function settlePendingWorkflows(): Promise<void> {
23 await Promise.allSettled(pendingInits);
24 pendingInits.length = 0;
25}
26
27export async function runWorkflow(
28 instanceId: string,
29 callback: (event: unknown, step: WorkflowStep) => Promise<unknown>,
30): Promise<DurableObjectStub<Engine>> {
31 const engineId = env.ENGINE.idFromName(instanceId);
32 const engineStub = env.ENGINE.get(engineId);
33
34 setTestWorkflowCallback(callback);
35
36 // Fire-and-forget: suppress all rejections to prevent unhandled
37 // rejections inside workerd (which crash the HTTP server on Windows).
38 // Abort errors (pause, terminate, restart) are expected; workflow
39 // errors (NonRetryableError, step failures) are also expected for
40 // tests that intentionally trigger them. Tests validate correctness
41 // through separate log/status assertions, not through init()'s result.
42 const initPromise = engineStub
43 .init(
44 12346,
45 {} as DatabaseWorkflow,
46 {} as DatabaseVersion,
47 { id: instanceId } as DatabaseInstance,
48 { payload: {}, timestamp: new Date(), instanceId, workflowName: "" },
49 )
50 .catch(() => {});
51
52 pendingInits.push(initPromise);
53
54 return engineStub;
55}
56
57export async function runWorkflowAndAwait(
58 instanceId: string,
59 callback: (event: unknown, step: WorkflowStep) => Promise<unknown>,
60): Promise<DurableObjectStub<Engine>> {
61 const engineId = env.ENGINE.idFromName(instanceId);
62 const engineStub = env.ENGINE.get(engineId);
63
64 setTestWorkflowCallback(callback);
65
66 await engineStub
67 .init(
68 12346,
69 {} as DatabaseWorkflow,
70 {} as DatabaseVersion,
71 { id: instanceId } as DatabaseInstance,
72 { payload: {}, timestamp: new Date(), instanceId, workflowName: "" },
73 )
74 .catch(() => {});
75
76 return engineStub;
77}