Skip to content

Commit 10610cf

Browse files
committed
Add workflow tests with introspection
1 parent 2775cc4 commit 10610cf

File tree

6 files changed

+926
-26
lines changed

6 files changed

+926
-26
lines changed
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1-
interface Env {
2-
TEST_WORKFLOW: Workflow;
1+
declare namespace Cloudflare {
2+
interface Env {
3+
TEST_WORKFLOW: Workflow;
4+
TEST_LONG_WORKFLOW: Workflow;
5+
}
36
}
7+
interface Env extends Cloudflare.Env {}

fixtures/vitest-pool-workers-examples/workflows/src/index.ts

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,79 @@ import {
77

88
export class TestWorkflow extends WorkflowEntrypoint<Env> {
99
async run(_event: Readonly<WorkflowEvent<unknown>>, step: WorkflowStep) {
10-
console.log("ola");
10+
console.log("Starting running...");
11+
12+
await step.do("step one", async () => {
13+
return "result of step one";
14+
});
15+
1116
return "test-workflow";
1217
}
1318
}
1419

15-
export default class TestNamedEntrypoint extends WorkerEntrypoint<Env> {
16-
async fetch(request: Request) {
20+
export class TestLongWorkflow extends WorkflowEntrypoint<Env, Params> {
21+
async run(event: Readonly<WorkflowEvent<unknown>>, step: WorkflowStep) {
22+
console.log("Starting running...");
23+
24+
await step.sleep("sleep for a while", "10 seconds");
25+
26+
await step.do(
27+
"my step",
28+
{
29+
retries: {
30+
limit: 5,
31+
delay: 50,
32+
backoff: "constant",
33+
},
34+
timeout: "1 second",
35+
},
36+
async () => {
37+
console.log("if my outcome gets mocked, this shouldn't be logging");
38+
return "result of my step";
39+
}
40+
);
41+
42+
await step.sleep("sleep for a day", "8 hours");
43+
44+
if (event.payload === "run event") {
45+
await step.waitForEvent("my event", {
46+
type: "event",
47+
timeout: "10 seconds",
48+
});
49+
}
50+
51+
await step.sleep("sleep for a while", "5 seconds");
52+
53+
return "test-workflow";
54+
}
55+
}
56+
57+
export default {
58+
async fetch(request: Request, env: Env) {
1759
const maybeId = new URL(request.url).searchParams.get("id");
1860
if (maybeId !== null) {
19-
const instance = await this.env.TEST_WORKFLOW.get(maybeId);
61+
const instance = await env.TEST_WORKFLOW.get(maybeId);
2062

2163
return Response.json(await instance.status());
2264
}
2365

24-
const workflow = await this.env.TEST_WORKFLOW.create();
66+
if (request.url.endsWith("/long-workflow")) {
67+
const workflow = await env.TEST_LONG_WORKFLOW.create();
68+
return new Response(JSON.stringify({ id: workflow.id }));
69+
}
70+
71+
if (request.url.endsWith("/long-workflow-batch")) {
72+
const workflows = await env.TEST_LONG_WORKFLOW.createBatch([
73+
{},
74+
{ id: "321" },
75+
{},
76+
]);
77+
const ids = workflows.map((workflow) => workflow.id);
78+
return new Response(JSON.stringify({ ids: ids }));
79+
}
80+
81+
const workflow = await env.TEST_WORKFLOW.create();
2582

2683
return new Response(JSON.stringify({ id: workflow.id }));
27-
}
28-
}
84+
},
85+
};
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
declare module "cloudflare:test" {
22
// Controls the type of `import("cloudflare:test").env`
3-
interface ProvidedEnv extends Env {
4-
TEST_WORKFLOW: Workflow;
5-
}
3+
interface ProvidedEnv extends Env {}
64
}
Lines changed: 99 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,107 @@
1-
import { SELF } from "cloudflare:test";
2-
import { expect, it, vi } from "vitest";
1+
import {
2+
env,
3+
introspectWorkflow,
4+
introspectWorkflowInstance,
5+
SELF,
6+
} from "cloudflare:test";
7+
import {
8+
afterEach,
9+
assert,
10+
beforeEach,
11+
describe,
12+
expect,
13+
it,
14+
vi,
15+
} from "vitest";
316

4-
it("should be able to trigger a workflow", async () => {
5-
const res = await SELF.fetch("https://mock-worker.local");
17+
describe("Test Workflow", () => {
18+
it("should be able to trigger a workflow", async () => {
19+
const res = await SELF.fetch("https://mock-worker.local");
620

7-
expect(res.status).toBe(200);
21+
expect(res.status).toBe(200);
22+
});
23+
24+
it("workflow should reach the end and be successful", async () => {
25+
const res = await SELF.fetch("https://mock-worker.local");
26+
27+
const json = await res.json<{ id: string }>();
28+
29+
await vi.waitUntil(async () => {
30+
const res = await SELF.fetch(`https://mock-worker.local?id=${json.id}`);
31+
32+
const statusJson = await res.json<{ status: string }>();
33+
console.log(statusJson);
34+
return statusJson.status === "complete";
35+
}, 1000);
36+
});
37+
38+
it("workflow should reach the end and be successful with introspector", async () => {
39+
const introspector = await introspectWorkflow(env.TEST_WORKFLOW);
40+
41+
await SELF.fetch("https://mock-worker.local");
42+
43+
const instances = introspector.get();
44+
assert(instances.length === 1);
45+
46+
const instance = instances[0];
47+
await instance.waitForStatus("complete");
48+
await instance.cleanUp();
49+
});
850
});
951

10-
it("workflow should reach the end and be successful", async () => {
11-
const res = await SELF.fetch("https://mock-worker.local");
52+
describe("Test long Workflow", () => {
53+
const STEP_NAME = "my step";
54+
const mockResult = "mocked result";
55+
56+
let introspector: Awaited<ReturnType<typeof introspectWorkflow>>;
57+
let instances: Awaited<ReturnType<typeof introspectWorkflowInstance>>[];
58+
59+
beforeEach(async () => {
60+
// CONFIG:
61+
introspector = await introspectWorkflow(env.TEST_LONG_WORKFLOW);
62+
introspector.modifyAll(async (m) => {
63+
await m.disableSleeps();
64+
await m.mockStepResult({ name: STEP_NAME }, mockResult);
65+
});
66+
});
67+
68+
afterEach(async () => {
69+
// CLEANUP:
70+
// Instance introspectors should be clean to prevent persisted state across tests
71+
for (const instance of instances) {
72+
instance.cleanUp();
73+
}
74+
75+
// Workflow introspector should be cleaned at the end of/after each test
76+
introspector.cleanUp();
77+
});
78+
79+
it("workflow should be able to introspect and reach the end and be successful", async () => {
80+
await SELF.fetch("https://mock-worker.local/long-workflow");
81+
82+
instances = introspector.get();
83+
assert(instances.length === 1);
84+
85+
// ASSERTIONS:
86+
const instance = instances[0];
87+
expect(await instance.waitForStepResult({ name: STEP_NAME })).toEqual(
88+
mockResult
89+
);
90+
await instance.waitForStatus("complete");
91+
});
1292

13-
const json = await res.json<{ id: string }>();
93+
it("workflow batch should be able to introspect and reach the end and be successful", async () => {
94+
await SELF.fetch("https://mock-worker.local/long-workflow-batch");
1495

15-
await vi.waitUntil(async () => {
16-
const res = await SELF.fetch(`https://mock-worker.local?id=${json.id}`);
96+
instances = introspector.get();
97+
assert(instances.length === 3);
1798

18-
const statusJson = await res.json<{ status: string }>();
19-
console.log(statusJson);
20-
return statusJson.status === "complete";
21-
}, 1000);
99+
// ASSERTIONS:
100+
for (const instance of instances) {
101+
expect(await instance.waitForStepResult({ name: STEP_NAME })).toEqual(
102+
mockResult
103+
);
104+
await instance.waitForStatus("complete");
105+
}
106+
});
22107
});

0 commit comments

Comments
 (0)