diff --git a/packages/inngest/src/test/functions/hello-world/index.test.ts b/packages/inngest/src/test/functions/hello-world/index.test.ts index 53003f790..64ed9efe7 100644 --- a/packages/inngest/src/test/functions/hello-world/index.test.ts +++ b/packages/inngest/src/test/functions/hello-world/index.test.ts @@ -25,12 +25,14 @@ describe("run", () => { }, 60000); test("returns 'Hello, Inngest!'", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - output: JSON.stringify("Hello, Inngest!"), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "step", + }); + + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual("Hello, Inngest!"); }, 60000); }); diff --git a/packages/inngest/src/test/functions/parallel-reduce/index.test.ts b/packages/inngest/src/test/functions/parallel-reduce/index.test.ts index 9373e0fe7..78658aac4 100644 --- a/packages/inngest/src/test/functions/parallel-reduce/index.test.ts +++ b/packages/inngest/src/test/functions/parallel-reduce/index.test.ts @@ -26,25 +26,24 @@ describe("run", () => { ["blue", "red", "green"].forEach((team) => { test(`ran "Get ${team} team score" step`, async () => { - const step = await runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: `Get ${team} team score`, + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: `Get ${team} team score`, }); + expect(item).toBeDefined(); - expect(step).toBeDefined(); - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect(step.output).toEqual(expect.any(String)); + const output = await item?.getOutput(); + expect(output).toEqual({ data: expect.any(Number) }); }, 60000); }); test("Returned total score", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - output: JSON.stringify("150"), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "FunctionCompleted", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual(150); }, 60000); }); diff --git a/packages/inngest/src/test/functions/parallel-work/index.test.ts b/packages/inngest/src/test/functions/parallel-work/index.test.ts index ed0820f87..381158fbb 100644 --- a/packages/inngest/src/test/functions/parallel-work/index.test.ts +++ b/packages/inngest/src/test/functions/parallel-work/index.test.ts @@ -25,45 +25,44 @@ describe("run", () => { }, 60000); ["First", "Second", "Third"].forEach((scoreStep) => { - const name = `${scoreStep} score`; + const stepName = `${scoreStep} score`; - test(`ran "${name}" step`, async () => { - const step = await runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name, + test(`ran "${stepName}" step`, async () => { + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName, }); + expect(item).toBeDefined(); - expect(step).toBeDefined(); - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect(step.output).toEqual(expect.any(String)); + const output = await item?.getOutput(); + expect(output).toEqual({ data: expect.any(Number) }); }, 60000); }); const fruits = ["Apple", "Banana", "Orange"]; fruits.forEach((fruit) => { - const name = `Get ${fruit.toLowerCase()}`; + const stepName = `Get ${fruit.toLowerCase()}`; - test(`ran "${name}" step`, async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name, - output: JSON.stringify({ data: fruit }), - }) - ).resolves.toBeDefined(); + test(`ran "${stepName}" step`, async () => { + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName, + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: fruit }); }, 60000); }); test("Returned correct data", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - output: JSON.stringify([6, `${fruits.join(", ")}`]), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "FunctionCompleted", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual([6, `${fruits.join(", ")}`]); }, 60000); }); diff --git a/packages/inngest/src/test/functions/promise-all/index.test.ts b/packages/inngest/src/test/functions/promise-all/index.test.ts index 165c3ed6a..b56fa7217 100644 --- a/packages/inngest/src/test/functions/promise-all/index.test.ts +++ b/packages/inngest/src/test/functions/promise-all/index.test.ts @@ -25,35 +25,35 @@ describe("run", () => { }, 60000); test("ran Step 1", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "Step 1", - output: JSON.stringify({ data: 1 }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "Step 1", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: 1 }); }, 60000); test("ran Step 2", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "Step 2", - output: JSON.stringify({ data: 2 }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "Step 2", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: 2 }); }, 60000); test("ran Step 3", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "Step 3", - output: JSON.stringify({ data: 3 }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "Step 3", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: 3 }); }, 60000); }); diff --git a/packages/inngest/src/test/functions/promise-race/index.test.ts b/packages/inngest/src/test/functions/promise-race/index.test.ts index bad75fa9f..830558785 100644 --- a/packages/inngest/src/test/functions/promise-race/index.test.ts +++ b/packages/inngest/src/test/functions/promise-race/index.test.ts @@ -27,38 +27,38 @@ describe("run", () => { }, 60000); test("ran Step A", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "Step A", - output: JSON.stringify({ data: "A" }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "Step A", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: "A" }); }, 60000); test("ran Step B", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "Step B", - output: JSON.stringify({ data: "B" }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "Step B", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: "B" }); }, 60000); let winner: "A" | "B" | undefined; test("ran Step C", async () => { - const timelineItem = await runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "Step C", + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "Step C", }); - expect(timelineItem).toBeDefined(); - const output = JSON.parse(timelineItem.output); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); winner = output.data === "A is the winner!" ? "A" diff --git a/packages/inngest/src/test/functions/sequential-reduce/index.test.ts b/packages/inngest/src/test/functions/sequential-reduce/index.test.ts index 00973c833..da381b347 100644 --- a/packages/inngest/src/test/functions/sequential-reduce/index.test.ts +++ b/packages/inngest/src/test/functions/sequential-reduce/index.test.ts @@ -26,25 +26,24 @@ describe("run", () => { ["blue", "red", "green"].forEach((team) => { test(`ran "Get ${team} team score" step`, async () => { - const step = await runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: `Get ${team} team score`, + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: `Get ${team} team score`, }); + expect(item).toBeDefined(); - expect(step).toBeDefined(); - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect(step.output).toEqual(expect.any(String)); + const output = await item?.getOutput(); + expect(output).toEqual({ data: expect.any(Number) }); }, 60000); }); test("Returned total score", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - output: JSON.stringify("150"), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "FunctionCompleted", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual(150); }, 60000); }); diff --git a/packages/inngest/src/test/functions/undefined-data/index.test.ts b/packages/inngest/src/test/functions/undefined-data/index.test.ts index 3a6556244..613b1bf5b 100644 --- a/packages/inngest/src/test/functions/undefined-data/index.test.ts +++ b/packages/inngest/src/test/functions/undefined-data/index.test.ts @@ -25,68 +25,68 @@ describe("run", () => { }, 60000); test("ran step1", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "step1", - output: JSON.stringify({ data: null }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "step1", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: null }); }, 60000); test("ran step2res", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "step2res", - output: JSON.stringify({ data: "step2res" }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "step2res", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: "step2res" }); }, 60000); test("ran step2nores", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "step2nores", - output: JSON.stringify({ data: null }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "step2nores", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: null }); }, 60000); test("ran step2res2", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "step2res2", - output: JSON.stringify({ data: "step2res2" }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "step2res2", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: "step2res2" }); }, 60000); test("ran step2", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "step2", - output: JSON.stringify({ data: null }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "step2", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: null }); }, 60000); test("ran step3", async () => { - await expect( - runHasTimeline(runId, { - __typename: "StepEvent", - stepType: "COMPLETED", - name: "step3", - output: JSON.stringify({ data: null }), - }) - ).resolves.toBeDefined(); + const item = await runHasTimeline(runId, { + type: "StepCompleted", + stepName: "step3", + }); + expect(item).toBeDefined(); + + const output = await item?.getOutput(); + expect(output).toEqual({ data: null }); }, 60000); }); diff --git a/packages/inngest/src/test/helpers.ts b/packages/inngest/src/test/helpers.ts index 9076057cc..ca9c20f2e 100644 --- a/packages/inngest/src/test/helpers.ts +++ b/packages/inngest/src/test/helpers.ts @@ -875,6 +875,74 @@ export const eventRunWithName = async ( throw new Error("Event run not found"); }; +type HistoryItemType = + | "FunctionScheduled" + | "FunctionStarted" + | "FunctionCompleted" + | "FunctionFailed" + | "FunctionCancelled" + | "FunctionStatusUpdated" + | "StepScheduled" + | "StepStarted" + | "StepCompleted" + | "StepErrored" + | "StepFailed" + | "StepWaiting" + | "StepSleeping" + | "StepInvoking"; + +class TimelineItem { + public runId: string; + public id: string; + public type: string; + public stepName: string | null; + public createdAt: string; + + // Unsafe, but fine for testing. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + constructor(runId: string, item: any) { + this.runId = runId; + this.id = item.id; + this.type = item.type; + this.stepName = item.stepName; + this.createdAt = item.createdAt; + } + + public async getOutput() { + const res = await fetch("http://localhost:8288/v0/gql", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + query: `query GetRunTimelineOutput($runId: ID!, $historyItemId: ULID!) { + functionRun(query: {functionRunId: $runId}) { + historyItemOutput(id: $historyItemId) + } + }`, + variables: { + runId: this.runId, + historyItemId: this.id, + }, + operationName: "GetRunTimelineOutput", + }), + }); + + if (!res.ok) { + throw new Error(await res.text()); + } + + const data = await res.json(); + + const payload = data?.data?.functionRun?.historyItemOutput || "null"; + if (typeof payload !== "string") { + throw new Error("Invalid payload"); + } + + return JSON.parse(payload); + } +} + /** * A test helper used to query a local, unsecured dev server to see if a given * run has a particular item in its timeline. @@ -884,14 +952,10 @@ export const eventRunWithName = async ( export const runHasTimeline = async ( runId: string, timeline: { - __typename: "StepEvent" | "FunctionEvent"; - name?: string; - stepType?: string; - functionType?: string; - output?: string; + stepName?: string; + type: HistoryItemType; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any -): Promise => { +): Promise => { for (let i = 0; i < 140; i++) { const start = new Date(); @@ -903,19 +967,11 @@ export const runHasTimeline = async ( body: JSON.stringify({ query: `query GetRunTimeline($runId: ID!) { functionRun(query: {functionRunId: $runId}) { - timeline { - __typename - ... on StepEvent { - name - createdAt - stepType: type - output - } - ... on FunctionEvent { - createdAt - functionType: type - output - } + history { + id + type + stepName + createdAt } } }`, @@ -933,7 +989,7 @@ export const runHasTimeline = async ( const data = await res.json(); // eslint-disable-next-line @typescript-eslint/no-explicit-any - const timelineItem = data?.data?.functionRun?.timeline?.find((entry: any) => + const timelineItem = data?.data?.functionRun?.history?.find((entry: any) => Object.keys(timeline).every( // eslint-disable-next-line @typescript-eslint/no-explicit-any (key) => entry[key] === (timeline as any)[key] @@ -941,7 +997,7 @@ export const runHasTimeline = async ( ); if (timelineItem) { - return timelineItem; + return new TimelineItem(runId, timelineItem); } await waitUpTo(400, start);