@inngest/test
Version:
Tooling for testing Inngest functions.
139 lines • 5.88 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InngestTestRun = void 0;
const v1_1 = require("inngest/components/execution/v1");
const promises_1 = require("inngest/helpers/promises");
const util_1 = require("./util");
/**
* A test run that allows you to wait for specific checkpoints in a run that
* covers many executions.
*
* @TODO We may need to separate run execution by {@link ExecutionVersion}.
*/
class InngestTestRun {
constructor(options) {
this.options = options;
}
/**
* Keep executing the function until a specific checkpoint is reached.
*
* @TODO What if the thing we're waiting for has already happened?
*/
waitFor(
/**
* The checkpoint to wait for.
*/
checkpoint,
/**
* An optional subset of the checkpoint to match against. Any checkpoint of
* this type will be matched.
*
* When providing a `subset`, use `expect` tooling such as
* `expect.stringContaining` to match partial values.
*/
subset) {
return __awaiter(this, void 0, void 0, function* () {
let finished = false;
const runningState = {
events: this.options.testEngine["options"].events,
steps: this.options.testEngine["options"].steps,
};
const { promise, resolve, reject } = (0, promises_1.createDeferredPromise)();
const finish = (output) => {
finished = true;
if (output.result.type !== checkpoint) {
return reject(output);
}
resolve(output);
};
/**
* Make sure we sanitize any given ID to prehash it for the user. This is
* abstracted from the user entirely so they shouldn't be expected to be
* providing hashes.
*/
const sanitizedSubset = subset && Object.assign(Object.assign(Object.assign({}, subset), ("step" in subset &&
typeof subset.step === "object" &&
subset.step !== null &&
"id" in subset.step &&
typeof subset.step.id === "string" && {
step: Object.assign(Object.assign({}, subset.step), { id: v1_1._internals.hashId(subset.step.id) }),
})), ("steps" in subset &&
Array.isArray(subset.steps) && {
steps: subset.steps.map((step) => (Object.assign(Object.assign({}, step), { id: v1_1._internals.hashId(step.id) }))),
}));
const processChain = (targetStepId) => __awaiter(this, void 0, void 0, function* () {
if (finished) {
return;
}
const exec = yield this.options.testEngine["individualExecution"](Object.assign(Object.assign({}, runningState), { targetStepId }));
if (exec.result.type === checkpoint &&
(!sanitizedSubset || (0, util_1.isDeeplyEqual)(sanitizedSubset, exec.result))) {
return finish(exec);
}
InngestTestRun.updateState(runningState, exec.result);
const resultHandlers = {
"function-resolved": () => finish(exec),
"function-rejected": () => finish(exec),
"step-not-found": () => processChain(),
"steps-found": () => {
// run all
const result = exec.result;
result.steps.forEach((step) => {
processChain(step.id);
});
},
"step-ran": () => {
const result = exec.result;
// if this is an error, we should stop. Later we model retries.
if (result.step.error) {
return finish(exec);
}
processChain();
},
};
resultHandlers[exec.result.type]();
});
// kick off
processChain();
return promise;
});
}
/**
* Given existing state and an execution result, mutate the state.
*/
static updateState(options, checkpoint) {
var _a;
if (checkpoint.type === "steps-found") {
const steps = checkpoint
.steps;
if (steps.length > 1) {
options.disableImmediateExecution = true;
}
}
else if (checkpoint.type === "step-ran") {
const step = checkpoint.step;
(_a = options.steps) !== null && _a !== void 0 ? _a : (options.steps = []);
options.steps.push({
id: step.id,
idIsHashed: true,
handler: () => {
if (step.error) {
throw step.error;
}
return step.data;
},
});
}
}
}
exports.InngestTestRun = InngestTestRun;
//# sourceMappingURL=InngestTestRun.js.map