From cb3bf7b9ff807509492a60149ca6785f4bbb009b Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:38:12 +0000 Subject: [PATCH 1/7] Fix `@inngest/test` sometimes not parsing the first error when using `.execute()` --- packages/test/src/InngestTestEngine.ts | 72 +++++++++++++++++++------- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/packages/test/src/InngestTestEngine.ts b/packages/test/src/InngestTestEngine.ts index c5b642ca..fad98194 100644 --- a/packages/test/src/InngestTestEngine.ts +++ b/packages/test/src/InngestTestEngine.ts @@ -209,33 +209,69 @@ export class InngestTestEngine { */ inlineOpts?: InngestTestEngine.ExecuteOptions ): Promise { - const { run } = await this.individualExecution(inlineOpts); + const output = await this.individualExecution(inlineOpts); - return run - .waitFor("function-resolved") - .then((output) => { + const resolutionHandler = ( + output: InngestTestEngine.ExecutionOutput<"function-resolved"> + ) => { + return { + ctx: output.ctx, + state: output.state, + result: output.result.data, + }; + }; + + const rejectionHandler = ( + output: InngestTestEngine.ExecutionOutput<"function-rejected">, + error: unknown = output.result.error + ) => { + if ( + typeof output === "object" && + output !== null && + "ctx" in output && + "state" in output + ) { return { ctx: output.ctx, state: output.state, - result: output.result.data, + error, }; - }) - .catch((rejectedOutput) => { + } + + throw output; + }; + + if (output.result.type === "function-resolved") { + return resolutionHandler( + output as InngestTestEngine.ExecutionOutput<"function-resolved"> + ); + } else if (output.result.type === "function-rejected") { + return rejectionHandler( + output as InngestTestEngine.ExecutionOutput<"function-rejected"> + ); + } else if (output.result.type === "step-ran") { + try { if ( - typeof rejectedOutput === "object" && - rejectedOutput !== null && - "ctx" in rejectedOutput && - "state" in rejectedOutput + ( + (output as InngestTestEngine.ExecutionOutput<"step-ran">).result + .step.error as any + ).name === "NonRetriableError" ) { - return { - ctx: rejectedOutput.ctx, - state: rejectedOutput.state, - error: rejectedOutput.error, - }; + return rejectionHandler( + output as InngestTestEngine.ExecutionOutput<"function-rejected">, + (output as InngestTestEngine.ExecutionOutput<"step-ran">).result + .step.error + ); } + } catch (err) { + // no-op + } + } - throw rejectedOutput; - }); + return output.run + .waitFor("function-resolved") + .then(resolutionHandler) + .catch(rejectionHandler); } /** From 5d2e1bedcbac675f864f0c6890b996d0eed55042 Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:04:05 +0000 Subject: [PATCH 2/7] Fix `@inngest/test` sometimes not memoizing steps --- packages/test/src/InngestTestEngine.ts | 10 +++++----- packages/test/src/InngestTestRun.ts | 8 +++++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/test/src/InngestTestEngine.ts b/packages/test/src/InngestTestEngine.ts index fad98194..a4047508 100644 --- a/packages/test/src/InngestTestEngine.ts +++ b/packages/test/src/InngestTestEngine.ts @@ -91,6 +91,7 @@ export namespace InngestTestEngine { export interface MockedStep { id: string; + idIsHashed?: boolean; handler: () => any; } @@ -251,11 +252,10 @@ export class InngestTestEngine { ); } else if (output.result.type === "step-ran") { try { + // Any error halts execution until retries are modelled if ( - ( - (output as InngestTestEngine.ExecutionOutput<"step-ran">).result - .step.error as any - ).name === "NonRetriableError" + (output as InngestTestEngine.ExecutionOutput<"step-ran">).result.step + .error ) { return rejectionHandler( output as InngestTestEngine.ExecutionOutput<"function-rejected">, @@ -407,7 +407,7 @@ export class InngestTestEngine { const steps = (options.steps || []).map((step) => { return { ...step, - id: _internals.hashId(step.id), + id: step.idIsHashed ? step.id : _internals.hashId(step.id), }; }); diff --git a/packages/test/src/InngestTestRun.ts b/packages/test/src/InngestTestRun.ts index f7314982..8d64dbd5 100644 --- a/packages/test/src/InngestTestRun.ts +++ b/packages/test/src/InngestTestRun.ts @@ -167,10 +167,16 @@ export class InngestTestRun { "step-ran": () => { const result = exec.result as InngestTestRun.Checkpoint<"step-ran">; + // if this is an error, we should stop. Later we model retries. + if (result.step.error) { + return finish(exec); + } + // add to our running state runningState.steps ??= []; runningState.steps.push({ - id: result.step.name as string, // TODO we need the non-hashed ID here, or a way to map it + id: result.step.id, + idIsHashed: true, handler: () => { if (result.step.error) { throw result.step.error; From 5136698086b88b11b8d2d0d04356f08b4cbc8b73 Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:06:36 +0000 Subject: [PATCH 3/7] Remove needless `try` --- packages/test/src/InngestTestEngine.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/test/src/InngestTestEngine.ts b/packages/test/src/InngestTestEngine.ts index a4047508..9f833732 100644 --- a/packages/test/src/InngestTestEngine.ts +++ b/packages/test/src/InngestTestEngine.ts @@ -251,20 +251,16 @@ export class InngestTestEngine { output as InngestTestEngine.ExecutionOutput<"function-rejected"> ); } else if (output.result.type === "step-ran") { - try { - // Any error halts execution until retries are modelled - if ( + // Any error halts execution until retries are modelled + if ( + (output as InngestTestEngine.ExecutionOutput<"step-ran">).result.step + .error + ) { + return rejectionHandler( + output as InngestTestEngine.ExecutionOutput<"function-rejected">, (output as InngestTestEngine.ExecutionOutput<"step-ran">).result.step .error - ) { - return rejectionHandler( - output as InngestTestEngine.ExecutionOutput<"function-rejected">, - (output as InngestTestEngine.ExecutionOutput<"step-ran">).result - .step.error - ); - } - } catch (err) { - // no-op + ); } } From c3f3bab7332897332c8dd1b0440c69c2c6f96432 Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:36:50 +0000 Subject: [PATCH 4/7] Fix typing incompat across minor versions --- packages/test/src/InngestTestEngine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/test/src/InngestTestEngine.ts b/packages/test/src/InngestTestEngine.ts index 9f833732..4b5f78df 100644 --- a/packages/test/src/InngestTestEngine.ts +++ b/packages/test/src/InngestTestEngine.ts @@ -29,7 +29,7 @@ export namespace InngestTestEngine { * TODO Potentially later allow many functions such that we can invoke and * send events. */ - function: InngestFunction.Any; + function: InngestFunction; /** * The event payloads to send to the function. If none is given, an From 7c26431c32e314e3f6a68e0abccc5faf050aacb6 Mon Sep 17 00:00:00 2001 From: Jack Williams <1736957+jpwilliams@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:37:10 +0000 Subject: [PATCH 5/7] Fix `@inngest/test` not memoizing state on first call --- packages/test/src/InngestTestEngine.ts | 2 + packages/test/src/InngestTestRun.ts | 56 ++++++++++++++++---------- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/packages/test/src/InngestTestEngine.ts b/packages/test/src/InngestTestEngine.ts index 4b5f78df..48220586 100644 --- a/packages/test/src/InngestTestEngine.ts +++ b/packages/test/src/InngestTestEngine.ts @@ -508,6 +508,8 @@ export class InngestTestEngine { Promise.resolve({}) as Promise ); + InngestTestRun["updateState"](options, result); + const run = new InngestTestRun({ testEngine: this.clone(options), }); diff --git a/packages/test/src/InngestTestRun.ts b/packages/test/src/InngestTestRun.ts index 8d64dbd5..2d4c55bc 100644 --- a/packages/test/src/InngestTestRun.ts +++ b/packages/test/src/InngestTestRun.ts @@ -145,21 +145,17 @@ export class InngestTestRun { return finish(exec); } + InngestTestRun.updateState(runningState, exec.result); + const resultHandlers: Record void> = { "function-resolved": () => finish(exec), "function-rejected": () => finish(exec), - "step-not-found": () => { - processChain(); - }, + "step-not-found": () => processChain(), "steps-found": () => { // run all const result = exec.result as InngestTestRun.Checkpoint<"steps-found">; - if (result.steps.length > 1) { - runningState.disableImmediateExecution = true; - } - result.steps.forEach((step) => { processChain(step.id); }); @@ -172,20 +168,6 @@ export class InngestTestRun { return finish(exec); } - // add to our running state - runningState.steps ??= []; - runningState.steps.push({ - id: result.step.id, - idIsHashed: true, - handler: () => { - if (result.step.error) { - throw result.step.error; - } - - return result.step.data; - }, - }); - processChain(); }, }; @@ -198,4 +180,36 @@ export class InngestTestRun { return promise; } + + /** + * Given existing state and an execution result, mutate the state. + */ + protected static updateState( + options: InngestTestEngine.InlineOptions, + checkpoint: InngestTestRun.Checkpoint + ): void { + if (checkpoint.type === "steps-found") { + const steps = (checkpoint as InngestTestRun.Checkpoint<"steps-found">) + .steps; + + if (steps.length > 1) { + options.disableImmediateExecution = true; + } + } else if (checkpoint.type === "step-ran") { + const step = (checkpoint as InngestTestRun.Checkpoint<"step-ran">).step; + + options.steps ??= []; + options.steps.push({ + id: step.id, + idIsHashed: true, + handler: () => { + if (step.error) { + throw step.error; + } + + return step.data; + }, + }); + } + } } From 35fdba5ffd97c1155444b5412635ed3dfa9cbeb6 Mon Sep 17 00:00:00 2001 From: Jack Williams Date: Tue, 12 Nov 2024 12:38:08 +0000 Subject: [PATCH 6/7] Create spicy-parents-drive.md --- .changeset/spicy-parents-drive.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/spicy-parents-drive.md diff --git a/.changeset/spicy-parents-drive.md b/.changeset/spicy-parents-drive.md new file mode 100644 index 00000000..0160b37c --- /dev/null +++ b/.changeset/spicy-parents-drive.md @@ -0,0 +1,5 @@ +--- +"@inngest/test": patch +--- + +Fix immediate function/step failures not returning `error` correctly From 0888c05a7c07bd7e07d5594ea153d94eaddd4524 Mon Sep 17 00:00:00 2001 From: Jack Williams Date: Tue, 12 Nov 2024 12:38:34 +0000 Subject: [PATCH 7/7] Create angry-pants-brush.md --- .changeset/angry-pants-brush.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/angry-pants-brush.md diff --git a/.changeset/angry-pants-brush.md b/.changeset/angry-pants-brush.md new file mode 100644 index 00000000..938656ed --- /dev/null +++ b/.changeset/angry-pants-brush.md @@ -0,0 +1,5 @@ +--- +"@inngest/test": patch +--- + +Fix the first step in a run running twice