From 62f38b32021686d13ee690131685eb4e8de016f3 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 12 Feb 2025 12:50:59 +0000 Subject: [PATCH] Cleaning up loop.spec.ts, moved tests from automation.spec.ts to more appropriate places. --- .../src/automations/tests/automation.spec.ts | 100 ------------------ .../automationUtils.spec.ts | 26 +++++ .../src/automations/tests/steps/loop.spec.ts | 67 ++++++------ .../tests/triggers/appAction.spec.ts | 29 +++++ .../tests/utilities/AutomationTestBuilder.ts | 13 ++- packages/types/src/sdk/automations/index.ts | 1 + 6 files changed, 100 insertions(+), 136 deletions(-) delete mode 100644 packages/server/src/automations/tests/automation.spec.ts rename packages/server/src/automations/{unitTests => tests}/automationUtils.spec.ts (82%) diff --git a/packages/server/src/automations/tests/automation.spec.ts b/packages/server/src/automations/tests/automation.spec.ts deleted file mode 100644 index 7cd49f664f2..00000000000 --- a/packages/server/src/automations/tests/automation.spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -jest.mock("../../threads/automation") -jest.mock("../../utilities/redis", () => ({ - init: jest.fn(), - checkTestFlag: () => { - return false - }, - shutdown: jest.fn(), -})) - -jest.spyOn(global.console, "error") - -import "../../environment" -import * as automation from "../index" -import * as thread from "../../threads/automation" -import * as triggers from "../triggers" -import { basicAutomation } from "../../tests/utilities/structures" -import { wait } from "../../utilities" -import { makePartial } from "../../tests/utilities" -import { cleanInputValues } from "../automationUtils" -import { Automation } from "@budibase/types" -import TestConfiguration from "../../tests/utilities/TestConfiguration" - -describe("Run through some parts of the automations system", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await automation.init() - await config.init() - }) - - afterAll(async () => { - await automation.shutdown() - config.end() - }) - - it("should be able to init in builder", async () => { - const automation: Automation = { - ...basicAutomation(), - appId: config.appId!, - } - const fields: any = { a: 1, appId: config.appId } - await triggers.externalTrigger(automation, fields) - await wait(100) - expect(thread.execute).toHaveBeenCalled() - }) - - it("should check coercion", async () => { - const table = await config.createTable() - const automation: any = basicAutomation() - automation.definition.trigger.inputs.tableId = table._id - automation.definition.trigger.stepId = "APP" - automation.definition.trigger.inputs.fields = { a: "number" } - const fields: any = { - appId: config.getAppId(), - fields: { - a: "1", - }, - } - await triggers.externalTrigger(automation, fields) - await wait(100) - expect(thread.execute).toHaveBeenCalledWith( - makePartial({ - data: { - event: { - fields: { - a: 1, - }, - }, - }, - }), - expect.any(Function) - ) - }) - - it("should be able to clean inputs with the utilities", () => { - // can't clean without a schema - let output = cleanInputValues({ a: "1" }) - expect(output.a).toBe("1") - output = cleanInputValues( - { a: "1", b: "true", c: "false", d: 1, e: "help" }, - { - properties: { - a: { - type: "number", - }, - b: { - type: "boolean", - }, - c: { - type: "boolean", - }, - }, - } - ) - expect(output.a).toBe(1) - expect(output.b).toBe(true) - expect(output.c).toBe(false) - expect(output.d).toBe(1) - }) -}) diff --git a/packages/server/src/automations/unitTests/automationUtils.spec.ts b/packages/server/src/automations/tests/automationUtils.spec.ts similarity index 82% rename from packages/server/src/automations/unitTests/automationUtils.spec.ts rename to packages/server/src/automations/tests/automationUtils.spec.ts index e855fd4be00..456feb6e7a9 100644 --- a/packages/server/src/automations/unitTests/automationUtils.spec.ts +++ b/packages/server/src/automations/tests/automationUtils.spec.ts @@ -119,5 +119,31 @@ describe("automationUtils", () => { schema, }) }) + + it("should be able to clean inputs with the utilities", () => { + // can't clean without a schema + let output = cleanInputValues({ a: "1" }) + expect(output.a).toBe("1") + output = cleanInputValues( + { a: "1", b: "true", c: "false", d: 1, e: "help" }, + { + properties: { + a: { + type: "number", + }, + b: { + type: "boolean", + }, + c: { + type: "boolean", + }, + }, + } + ) + expect(output.a).toBe(1) + expect(output.b).toBe(true) + expect(output.c).toBe(false) + expect(output.d).toBe(1) + }) }) }) diff --git a/packages/server/src/automations/tests/steps/loop.spec.ts b/packages/server/src/automations/tests/steps/loop.spec.ts index 1f985bd504c..f8af7dcf9fc 100644 --- a/packages/server/src/automations/tests/steps/loop.spec.ts +++ b/packages/server/src/automations/tests/steps/loop.spec.ts @@ -1,17 +1,13 @@ import * as automation from "../../index" -import * as triggers from "../../triggers" -import { basicTable, loopAutomation } from "../../../tests/utilities/structures" -import { context } from "@budibase/backend-core" +import { basicTable } from "../../../tests/utilities/structures" import { Table, LoopStepType, - AutomationResults, ServerLogStepOutputs, CreateRowStepOutputs, FieldType, } from "@budibase/types" import * as loopUtils from "../../loopUtils" -import { LoopInput } from "../../../definitions/automations" import { createAutomationBuilder } from "../utilities/AutomationTestBuilder" import TestConfiguration from "../../../tests/utilities/TestConfiguration" @@ -34,41 +30,46 @@ describe("Attempt to run a basic loop automation", () => { config.end() }) - async function runLoop(loopOpts?: LoopInput): Promise { - const appId = config.getAppId() - return await context.doInAppContext(appId, async () => { - const params = { fields: { appId } } - const result = await triggers.externalTrigger( - loopAutomation(table._id!, loopOpts), - params, - { getResponses: true } - ) - if ("outputs" in result && !result.outputs.success) { - throw new Error("Unable to proceed - failed to return anything.") - } - return result as AutomationResults - }) - } - it("attempt to run a basic loop", async () => { - const resp = await runLoop() - expect(resp.steps[2].outputs.iterations).toBe(1) + const result = await createAutomationBuilder(config) + .onAppAction() + .queryRows({ + tableId: table._id!, + }) + .loop({ + option: LoopStepType.ARRAY, + binding: "{{ steps.1.rows }}", + }) + .serverLog({ text: "log statement" }) + .test({ fields: {} }) + + expect(result.steps[1].outputs.iterations).toBe(1) }) it("test a loop with a string", async () => { - const resp = await runLoop({ - option: LoopStepType.STRING, - binding: "a,b,c", - }) - expect(resp.steps[2].outputs.iterations).toBe(3) + const result = await createAutomationBuilder(config) + .onAppAction() + .loop({ + option: LoopStepType.STRING, + binding: "a,b,c", + }) + .serverLog({ text: "log statement" }) + .test({ fields: {} }) + + expect(result.steps[0].outputs.iterations).toBe(3) }) it("test a loop with a binding that returns an integer", async () => { - const resp = await runLoop({ - option: LoopStepType.ARRAY, - binding: "{{ 1 }}", - }) - expect(resp.steps[2].outputs.iterations).toBe(1) + const result = await createAutomationBuilder(config) + .onAppAction() + .loop({ + option: LoopStepType.ARRAY, + binding: "{{ 1 }}", + }) + .serverLog({ text: "log statement" }) + .test({ fields: {} }) + + expect(result.steps[0].outputs.iterations).toBe(1) }) it("should run an automation with a trigger, loop, and create row step", async () => { diff --git a/packages/server/src/automations/tests/triggers/appAction.spec.ts b/packages/server/src/automations/tests/triggers/appAction.spec.ts index ab258434db6..2247868c445 100644 --- a/packages/server/src/automations/tests/triggers/appAction.spec.ts +++ b/packages/server/src/automations/tests/triggers/appAction.spec.ts @@ -42,4 +42,33 @@ describe("app action trigger", () => { }) ) }) + + it("should correct coerce values based on the schema", async () => { + const { automation } = await createAutomationBuilder(config) + .onAppAction({ + fields: { text: "string", number: "number", boolean: "boolean" }, + }) + .serverLog({ + text: "{{ fields.text }} {{ fields.number }} {{ fields.boolean }}", + }) + .save() + + await config.api.application.publish() + + const jobs = await captureAutomationResults(automation, async () => { + await config.withProdApp(async () => { + await config.api.automation.trigger(automation._id!, { + fields: { text: "1", number: "2", boolean: "true" }, + timeout: 1000, + }) + }) + }) + + expect(jobs).toHaveLength(1) + expect(jobs[0].data.event.fields).toEqual({ + text: "1", + number: 2, + boolean: true, + }) + }) }) diff --git a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts index 78fb05cf7e3..d707430a355 100644 --- a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts +++ b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts @@ -145,13 +145,13 @@ class StepBuilder< TStep extends AutomationTriggerStepId > extends BranchStepBuilder { private readonly config: TestConfiguration - private readonly trigger: AutomationTrigger + private readonly _trigger: AutomationTrigger private _name: string | undefined = undefined constructor(config: TestConfiguration, trigger: AutomationTrigger) { super() this.config = config - this.trigger = trigger + this._trigger = trigger } name(n: string): this { @@ -165,7 +165,7 @@ class StepBuilder< name, definition: { steps: this.steps, - trigger: this.trigger, + trigger: this._trigger, stepNames: this.stepNames, }, type: "automation", @@ -182,6 +182,13 @@ class StepBuilder< const runner = await this.save() return await runner.test(triggerOutput) } + + async trigger( + request: TriggerAutomationRequest + ): Promise { + const runner = await this.save() + return await runner.trigger(request) + } } class AutomationRunner { diff --git a/packages/types/src/sdk/automations/index.ts b/packages/types/src/sdk/automations/index.ts index ba79d470210..917e158e057 100644 --- a/packages/types/src/sdk/automations/index.ts +++ b/packages/types/src/sdk/automations/index.ts @@ -15,6 +15,7 @@ export interface AutomationDataEvent { oldRow?: Row user?: UserBindings timestamp?: number + fields?: Record } export interface AutomationData {