From 8ca5cb559921c13167ce63fdb454884be7c8210a Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 28 Jan 2025 17:43:03 +0000 Subject: [PATCH] Do a typing pass on automation.spec.ts --- .../src/api/routes/tests/automation.spec.ts | 440 +++++++++--------- .../routes/tests/utilities/TestFunctions.ts | 9 - .../src/tests/utilities/TestConfiguration.ts | 6 +- .../src/tests/utilities/api/automation.ts | 91 +++- .../server/src/tests/utilities/api/index.ts | 48 +- .../server/src/tests/utilities/structures.ts | 64 +-- packages/types/src/api/web/app/automation.ts | 1 + 7 files changed, 363 insertions(+), 296 deletions(-) diff --git a/packages/server/src/api/routes/tests/automation.spec.ts b/packages/server/src/api/routes/tests/automation.spec.ts index 5c0b86d9a0..94517db67a 100644 --- a/packages/server/src/api/routes/tests/automation.spec.ts +++ b/packages/server/src/api/routes/tests/automation.spec.ts @@ -1,7 +1,6 @@ import { checkBuilderEndpoint, getAllTableRows, - clearAllAutomations, testAutomation, } from "./utilities/TestFunctions" import * as setup from "./utilities" @@ -12,9 +11,9 @@ import { import { configs, context, events } from "@budibase/backend-core" import sdk from "../../../sdk" import { - Automation, ConfigType, FieldType, + isDidNotTriggerResponse, SettingsConfig, Table, } from "@budibase/types" @@ -22,11 +21,13 @@ import { mocks } from "@budibase/backend-core/tests" import { removeDeprecated } from "../../../automations/utils" import { createAutomationBuilder } from "../../../automations/tests/utilities/AutomationTestBuilder" import { automations } from "@budibase/shared-core" +import { basicTable } from "../../../tests/utilities/structures" +import TestConfiguration from "../../../tests/utilities/TestConfiguration" const FilterConditions = automations.steps.filter.FilterConditions const MAX_RETRIES = 4 -let { +const { basicAutomation, newAutomation, automationTrigger, @@ -37,10 +38,11 @@ let { } = setup.structures describe("/automations", () => { - let request = setup.getRequest() - let config = setup.getConfig() + const config = new TestConfiguration() - afterAll(setup.afterAll) + afterAll(() => { + config.end() + }) beforeAll(async () => { await config.init() @@ -52,40 +54,26 @@ describe("/automations", () => { describe("get definitions", () => { it("returns a list of definitions for actions", async () => { - const res = await request - .get(`/api/automations/action/list`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - - expect(Object.keys(res.body).length).not.toEqual(0) + const res = await config.api.automation.getActions() + expect(Object.keys(res).length).not.toEqual(0) }) it("returns a list of definitions for triggerInfo", async () => { - const res = await request - .get(`/api/automations/trigger/list`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - - expect(Object.keys(res.body).length).not.toEqual(0) + const res = await config.api.automation.getTriggers() + expect(Object.keys(res).length).not.toEqual(0) }) it("returns all of the definitions in one", async () => { - const res = await request - .get(`/api/automations/definitions/list`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const { action, trigger } = await config.api.automation.getDefinitions() let definitionsLength = Object.keys( removeDeprecated(BUILTIN_ACTION_DEFINITIONS) ).length - expect(Object.keys(res.body.action).length).toBeGreaterThanOrEqual( + expect(Object.keys(action).length).toBeGreaterThanOrEqual( definitionsLength ) - expect(Object.keys(res.body.trigger).length).toEqual( + expect(Object.keys(trigger).length).toEqual( Object.keys(removeDeprecated(TRIGGER_DEFINITIONS)).length ) }) @@ -93,38 +81,27 @@ describe("/automations", () => { describe("create", () => { it("creates an automation with no steps", async () => { - const automation = newAutomation() - automation.definition.steps = [] + const { message, automation } = await config.api.automation.post( + newAutomation({ steps: [] }) + ) - const res = await request - .post(`/api/automations`) - .set(config.defaultHeaders()) - .send(automation) - .expect("Content-Type", /json/) - .expect(200) - - expect(res.body.message).toEqual("Automation created successfully") - expect(res.body.automation.name).toEqual("My Automation") - expect(res.body.automation._id).not.toEqual(null) + expect(message).toEqual("Automation created successfully") + expect(automation.name).toEqual("My Automation") + expect(automation._id).not.toEqual(null) expect(events.automation.created).toHaveBeenCalledTimes(1) expect(events.automation.stepCreated).not.toHaveBeenCalled() }) it("creates an automation with steps", async () => { - const automation = newAutomation() - automation.definition.steps.push(automationStep()) jest.clearAllMocks() - const res = await request - .post(`/api/automations`) - .set(config.defaultHeaders()) - .send(automation) - .expect("Content-Type", /json/) - .expect(200) + const { message, automation } = await config.api.automation.post( + newAutomation({ steps: [automationStep(), automationStep()] }) + ) - expect(res.body.message).toEqual("Automation created successfully") - expect(res.body.automation.name).toEqual("My Automation") - expect(res.body.automation._id).not.toEqual(null) + expect(message).toEqual("Automation created successfully") + expect(automation.name).toEqual("My Automation") + expect(automation._id).not.toEqual(null) expect(events.automation.created).toHaveBeenCalledTimes(1) expect(events.automation.stepCreated).toHaveBeenCalledTimes(2) }) @@ -241,13 +218,9 @@ describe("/automations", () => { describe("find", () => { it("should be able to find the automation", async () => { const automation = await config.createAutomation() - const res = await request - .get(`/api/automations/${automation._id}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body._id).toEqual(automation._id) - expect(res.body._rev).toEqual(automation._rev) + const { _id, _rev } = await config.api.automation.get(automation._id!) + expect(_id).toEqual(automation._id) + expect(_rev).toEqual(automation._rev) }) }) @@ -348,106 +321,104 @@ describe("/automations", () => { describe("trigger", () => { it("does not trigger an automation when not synchronous and in dev", async () => { - let automation = newAutomation() - automation = await config.createAutomation(automation) - const res = await request - .post(`/api/automations/${automation._id}/trigger`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(400) - - expect(res.body.message).toEqual( - "Only apps in production support this endpoint" + const { automation } = await config.api.automation.post(newAutomation()) + await config.api.automation.trigger( + automation._id!, + { + fields: {}, + timeout: 1000, + }, + { + status: 400, + body: { + message: "Only apps in production support this endpoint", + }, + } ) }) it("triggers a synchronous automation", async () => { mocks.licenses.useSyncAutomations() - let automation = collectAutomation() - automation = await config.createAutomation(automation) - const res = await request - .post(`/api/automations/${automation._id}/trigger`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - - expect(res.body.success).toEqual(true) - expect(res.body.value).toEqual([1, 2, 3]) + const { automation } = await config.api.automation.post( + collectAutomation() + ) + await config.api.automation.trigger( + automation._id!, + { + fields: {}, + timeout: 1000, + }, + { + status: 200, + body: { + success: true, + value: [1, 2, 3], + }, + } + ) }) it("should throw an error when attempting to trigger a disabled automation", async () => { mocks.licenses.useSyncAutomations() - let automation = collectAutomation() - automation = await config.createAutomation({ - ...automation, - disabled: true, - }) + const { automation } = await config.api.automation.post( + collectAutomation({ disabled: true }) + ) - const res = await request - .post(`/api/automations/${automation._id}/trigger`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(400) - - expect(res.body.message).toEqual("Automation is disabled") + await config.api.automation.trigger( + automation._id!, + { + fields: {}, + timeout: 1000, + }, + { + status: 400, + body: { + message: "Automation is disabled", + }, + } + ) }) it("triggers an asynchronous automation", async () => { - let automation = newAutomation() - automation = await config.createAutomation(automation) + const { automation } = await config.api.automation.post(newAutomation()) await config.publish() - const res = await request - .post(`/api/automations/${automation._id}/trigger`) - .set(config.defaultHeaders({}, true)) - .expect("Content-Type", /json/) - .expect(200) - - expect(res.body.message).toEqual( - `Automation ${automation._id} has been triggered.` + await config.withProdApp(() => + config.api.automation.trigger( + automation._id!, + { + fields: {}, + timeout: 1000, + }, + { + status: 200, + body: { + message: `Automation ${automation._id} has been triggered.`, + }, + } + ) ) }) }) describe("update", () => { - const update = async (automation: Automation) => { - return request - .put(`/api/automations`) - .set(config.defaultHeaders()) - .send(automation) - .expect("Content-Type", /json/) - .expect(200) - } - - const updateWithPost = async (automation: Automation) => { - return request - .post(`/api/automations`) - .set(config.defaultHeaders()) - .send(automation) - .expect("Content-Type", /json/) - .expect(200) - } - it("updates a automations name", async () => { - const automation = await config.createAutomation(newAutomation()) + const { automation } = await config.api.automation.post(basicAutomation()) automation.name = "Updated Name" jest.clearAllMocks() - const res = await update(automation) + const { automation: updatedAutomation, message } = + await config.api.automation.update(automation) - const automationRes = res.body.automation - const message = res.body.message + expect(updatedAutomation._id).toEqual(automation._id) + expect(updatedAutomation._rev).toBeDefined() + expect(updatedAutomation._rev).not.toEqual(automation._rev) - // doc attributes - expect(automationRes._id).toEqual(automation._id) - expect(automationRes._rev).toBeDefined() - expect(automationRes._rev).not.toEqual(automation._rev) - // content updates - expect(automationRes.name).toEqual("Updated Name") + expect(updatedAutomation.name).toEqual("Updated Name") expect(message).toEqual( `Automation ${automation._id} updated successfully.` ) - // events + expect(events.automation.created).not.toHaveBeenCalled() expect(events.automation.stepCreated).not.toHaveBeenCalled() expect(events.automation.stepDeleted).not.toHaveBeenCalled() @@ -455,26 +426,23 @@ describe("/automations", () => { }) it("updates a automations name using POST request", async () => { - const automation = await config.createAutomation(newAutomation()) + const { automation } = await config.api.automation.post(basicAutomation()) automation.name = "Updated Name" jest.clearAllMocks() - // the POST request will defer to the update - // when an id has been supplied. - const res = await updateWithPost(automation) + // the POST request will defer to the update when an id has been supplied. + const { automation: updatedAutomation, message } = + await config.api.automation.post(automation) - const automationRes = res.body.automation - const message = res.body.message - // doc attributes - expect(automationRes._id).toEqual(automation._id) - expect(automationRes._rev).toBeDefined() - expect(automationRes._rev).not.toEqual(automation._rev) - // content updates - expect(automationRes.name).toEqual("Updated Name") + expect(updatedAutomation._id).toEqual(automation._id) + expect(updatedAutomation._rev).toBeDefined() + expect(updatedAutomation._rev).not.toEqual(automation._rev) + + expect(updatedAutomation.name).toEqual("Updated Name") expect(message).toEqual( `Automation ${automation._id} updated successfully.` ) - // events + expect(events.automation.created).not.toHaveBeenCalled() expect(events.automation.stepCreated).not.toHaveBeenCalled() expect(events.automation.stepDeleted).not.toHaveBeenCalled() @@ -482,16 +450,14 @@ describe("/automations", () => { }) it("updates an automation trigger", async () => { - let automation = newAutomation() - automation = await config.createAutomation(automation) + const { automation } = await config.api.automation.post(newAutomation()) automation.definition.trigger = automationTrigger( TRIGGER_DEFINITIONS.WEBHOOK ) jest.clearAllMocks() - await update(automation) + await config.api.automation.update(automation) - // events expect(events.automation.created).not.toHaveBeenCalled() expect(events.automation.stepCreated).not.toHaveBeenCalled() expect(events.automation.stepDeleted).not.toHaveBeenCalled() @@ -499,16 +465,13 @@ describe("/automations", () => { }) it("adds automation steps", async () => { - let automation = newAutomation() - automation = await config.createAutomation(automation) + const { automation } = await config.api.automation.post(newAutomation()) automation.definition.steps.push(automationStep()) automation.definition.steps.push(automationStep()) jest.clearAllMocks() - // check the post request honours updates with same id - await update(automation) + await config.api.automation.update(automation) - // events expect(events.automation.stepCreated).toHaveBeenCalledTimes(2) expect(events.automation.created).not.toHaveBeenCalled() expect(events.automation.stepDeleted).not.toHaveBeenCalled() @@ -516,32 +479,25 @@ describe("/automations", () => { }) it("removes automation steps", async () => { - let automation = newAutomation() - automation.definition.steps.push(automationStep()) - automation = await config.createAutomation(automation) + const { automation } = await config.api.automation.post(newAutomation()) automation.definition.steps = [] jest.clearAllMocks() - // check the post request honours updates with same id - await update(automation) + await config.api.automation.update(automation) - // events - expect(events.automation.stepDeleted).toHaveBeenCalledTimes(2) + expect(events.automation.stepDeleted).toHaveBeenCalledTimes(1) expect(events.automation.stepCreated).not.toHaveBeenCalled() expect(events.automation.created).not.toHaveBeenCalled() expect(events.automation.triggerUpdated).not.toHaveBeenCalled() }) it("adds and removes automation steps", async () => { - let automation = newAutomation() - automation = await config.createAutomation(automation) + const { automation } = await config.api.automation.post(newAutomation()) automation.definition.steps = [automationStep(), automationStep()] jest.clearAllMocks() - // check the post request honours updates with same id - await update(automation) + await config.api.automation.update(automation) - // events expect(events.automation.stepCreated).toHaveBeenCalledTimes(2) expect(events.automation.stepDeleted).toHaveBeenCalledTimes(1) expect(events.automation.created).not.toHaveBeenCalled() @@ -551,16 +507,24 @@ describe("/automations", () => { describe("fetch", () => { it("return all the automations for an instance", async () => { - await clearAllAutomations(config) - const autoConfig = await config.createAutomation(basicAutomation()) - const res = await request - .get(`/api/automations`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const fetchResponse = await config.api.automation.fetch() + for (const auto of fetchResponse.automations) { + await config.api.automation.delete(auto) + } - expect(res.body.automations[0]).toEqual( - expect.objectContaining(autoConfig) + const { automation: automation1 } = await config.api.automation.post( + newAutomation() + ) + const { automation: automation2 } = await config.api.automation.post( + newAutomation() + ) + const { automation: automation3 } = await config.api.automation.post( + newAutomation() + ) + + const { automations } = await config.api.automation.fetch() + expect(automations).toEqual( + expect.arrayContaining([automation1, automation2, automation3]) ) }) @@ -575,29 +539,25 @@ describe("/automations", () => { describe("destroy", () => { it("deletes a automation by its ID", async () => { - const automation = await config.createAutomation() - const res = await request - .delete(`/api/automations/${automation._id}/${automation._rev}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const { automation } = await config.api.automation.post(newAutomation()) + const { id } = await config.api.automation.delete(automation) - expect(res.body.id).toEqual(automation._id) + expect(id).toEqual(automation._id) expect(events.automation.deleted).toHaveBeenCalledTimes(1) }) it("cannot delete a row action automation", async () => { - const automation = await config.createAutomation( + const { automation } = await config.api.automation.post( setup.structures.rowActionAutomation() ) - await request - .delete(`/api/automations/${automation._id}/${automation._rev}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(422, { + + await config.api.automation.delete(automation, { + status: 422, + body: { message: "Row actions automations cannot be deleted", status: 422, - }) + }, + }) expect(events.automation.deleted).not.toHaveBeenCalled() }) @@ -614,10 +574,19 @@ describe("/automations", () => { describe("checkForCollectStep", () => { it("should return true if a collect step exists in an automation", async () => { - let automation = collectAutomation() - await config.createAutomation(automation) - let res = await sdk.automations.utils.checkForCollectStep(automation) - expect(res).toEqual(true) + const { automation } = await config.api.automation.post( + collectAutomation() + ) + expect(sdk.automations.utils.checkForCollectStep(automation)).toEqual( + true + ) + }) + + it("should return false if a collect step does not exist in an automation", async () => { + const { automation } = await config.api.automation.post(newAutomation()) + expect(sdk.automations.utils.checkForCollectStep(automation)).toEqual( + false + ) }) }) @@ -628,28 +597,45 @@ describe("/automations", () => { ])( "triggers an update row automation and compares new to old rows with old city '%s' and new city '%s'", async ({ oldCity, newCity }) => { - const expectedResult = oldCity === newCity + let table = await config.api.table.save(basicTable()) - let table = await config.createTable() + const { automation } = await config.api.automation.post( + filterAutomation({ + definition: { + trigger: { + inputs: { + tableId: table._id, + }, + }, + steps: [ + { + inputs: { + condition: FilterConditions.EQUAL, + field: "{{ trigger.row.City }}", + value: "{{ trigger.oldRow.City }}", + }, + }, + ], + }, + }) + ) - let automation = await filterAutomation(config.getAppId()) - automation.definition.trigger.inputs.tableId = table._id - automation.definition.steps[0].inputs = { - condition: FilterConditions.EQUAL, - field: "{{ trigger.row.City }}", - value: "{{ trigger.oldRow.City }}", - } - automation = await config.createAutomation(automation) - let triggerInputs = { + const res = await config.api.automation.test(automation._id!, { + fields: {}, oldRow: { City: oldCity, }, row: { City: newCity, }, + }) + + if (isDidNotTriggerResponse(res)) { + throw new Error("Automation did not trigger") } - const res = await testAutomation(config, automation, triggerInputs) - expect(res.body.steps[1].outputs.result).toEqual(expectedResult) + + const expectedResult = oldCity === newCity + expect(res.steps[1].outputs.result).toEqual(expectedResult) } ) }) @@ -657,16 +643,18 @@ describe("/automations", () => { let table: Table beforeAll(async () => { - table = await config.createTable({ - name: "table", - type: "table", - schema: { - Approved: { - name: "Approved", - type: FieldType.BOOLEAN, + table = await config.api.table.save( + basicTable(undefined, { + name: "table", + type: "table", + schema: { + Approved: { + name: "Approved", + type: FieldType.BOOLEAN, + }, }, - }, - }) + }) + ) }) const testCases = [ @@ -712,33 +700,29 @@ describe("/automations", () => { it.each(testCases)( "$description", async ({ filters, row, oldRow, expectToRun }) => { - let automation = await updateRowAutomationWithFilters( - config.getAppId(), - table._id! - ) - automation.definition.trigger.inputs = { + let req = updateRowAutomationWithFilters(config.getAppId(), table._id!) + req.definition.trigger.inputs = { tableId: table._id, filters, } - automation = await config.createAutomation(automation) - const inputs = { - row: { - tableId: table._id, - ...row, - }, + const { automation } = await config.api.automation.post(req) + const res = await config.api.automation.test(automation._id!, { + fields: {}, oldRow: { tableId: table._id, ...oldRow, }, - } + row: { + tableId: table._id, + ...row, + }, + }) - const res = await testAutomation(config, automation, inputs) - - if (expectToRun) { - expect(res.body.steps[1].outputs.success).toEqual(true) + if (isDidNotTriggerResponse(res)) { + expect(expectToRun).toEqual(false) } else { - expect(res.body.outputs.success).toEqual(false) + expect(res.steps[1].outputs.success).toEqual(expectToRun) } } ) diff --git a/packages/server/src/api/routes/tests/utilities/TestFunctions.ts b/packages/server/src/api/routes/tests/utilities/TestFunctions.ts index 9d5417d041..a232fec859 100644 --- a/packages/server/src/api/routes/tests/utilities/TestFunctions.ts +++ b/packages/server/src/api/routes/tests/utilities/TestFunctions.ts @@ -53,15 +53,6 @@ export const clearAllApps = async ( }) } -export const clearAllAutomations = async (config: TestConfiguration) => { - const { automations } = await config.getAllAutomations() - for (let auto of automations) { - await context.doInAppContext(config.getAppId(), async () => { - await config.deleteAutomation(auto) - }) - } -} - export const wipeDb = async () => { const couchInfo = db.getCouchInfo() const nano = Nano({ diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 2d36e7855b..1f464b2ea4 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -258,7 +258,7 @@ export default class TestConfiguration { } } - async withApp(app: App | string, f: () => Promise) { + async withApp(app: App | string, f: () => Promise) { const oldAppId = this.appId this.appId = typeof app === "string" ? app : app.appId try { @@ -268,6 +268,10 @@ export default class TestConfiguration { } } + async withProdApp(f: () => Promise) { + return await this.withApp(this.getProdAppId(), f) + } + // UTILS _req | void, Res>( diff --git a/packages/server/src/tests/utilities/api/automation.ts b/packages/server/src/tests/utilities/api/automation.ts index 3f51385251..c4438560ae 100644 --- a/packages/server/src/tests/utilities/api/automation.ts +++ b/packages/server/src/tests/utilities/api/automation.ts @@ -1,8 +1,17 @@ import { Automation, + CreateAutomationResponse, + DeleteAutomationResponse, FetchAutomationResponse, + GetAutomationActionDefinitionsResponse, + GetAutomationStepDefinitionsResponse, + GetAutomationTriggerDefinitionsResponse, TestAutomationRequest, TestAutomationResponse, + TriggerAutomationRequest, + TriggerAutomationResponse, + UpdateAutomationRequest, + UpdateAutomationResponse, } from "@budibase/types" import { Expectations, TestAPI } from "./base" @@ -20,6 +29,39 @@ export class AutomationAPI extends TestAPI { return result } + getActions = async ( + expectations?: Expectations + ): Promise => { + return await this._get( + `/api/automations/actions/list`, + { + expectations, + } + ) + } + + getTriggers = async ( + expectations?: Expectations + ): Promise => { + return await this._get( + `/api/automations/triggers/list`, + { + expectations, + } + ) + } + + getDefinitions = async ( + expectations?: Expectations + ): Promise => { + return await this._get( + `/api/automations/definitions/list`, + { + expectations, + } + ) + } + fetch = async ( expectations?: Expectations ): Promise => { @@ -31,11 +73,14 @@ export class AutomationAPI extends TestAPI { post = async ( body: Automation, expectations?: Expectations - ): Promise => { - const result = await this._post(`/api/automations`, { - body, - expectations, - }) + ): Promise => { + const result = await this._post( + `/api/automations`, + { + body, + expectations, + } + ) return result } @@ -52,4 +97,40 @@ export class AutomationAPI extends TestAPI { } ) } + + trigger = async ( + id: string, + body: TriggerAutomationRequest, + expectations?: Expectations + ): Promise => { + return await this._post( + `/api/automations/${id}/trigger`, + { + expectations, + body, + } + ) + } + + update = async ( + body: UpdateAutomationRequest, + expectations?: Expectations + ): Promise => { + return await this._put(`/api/automations`, { + body, + expectations, + }) + } + + delete = async ( + automation: Automation, + expectations?: Expectations + ): Promise => { + return await this._delete( + `/api/automations/${automation._id!}/${automation._rev!}`, + { + expectations, + } + ) + } } diff --git a/packages/server/src/tests/utilities/api/index.ts b/packages/server/src/tests/utilities/api/index.ts index c5eede18d6..2fdf726b6c 100644 --- a/packages/server/src/tests/utilities/api/index.ts +++ b/packages/server/src/tests/utilities/api/index.ts @@ -19,43 +19,43 @@ import { PluginAPI } from "./plugin" import { WebhookAPI } from "./webhook" export default class API { - table: TableAPI - legacyView: LegacyViewAPI - viewV2: ViewV2API - row: RowAPI - permission: PermissionAPI - datasource: DatasourceAPI - screen: ScreenAPI application: ApplicationAPI - backup: BackupAPI attachment: AttachmentAPI - user: UserAPI + automation: AutomationAPI + backup: BackupAPI + datasource: DatasourceAPI + legacyView: LegacyViewAPI + permission: PermissionAPI + plugin: PluginAPI query: QueryAPI roles: RoleAPI - templates: TemplateAPI + row: RowAPI rowAction: RowActionAPI - automation: AutomationAPI - plugin: PluginAPI + screen: ScreenAPI + table: TableAPI + templates: TemplateAPI + user: UserAPI + viewV2: ViewV2API webhook: WebhookAPI constructor(config: TestConfiguration) { - this.table = new TableAPI(config) - this.legacyView = new LegacyViewAPI(config) - this.viewV2 = new ViewV2API(config) - this.row = new RowAPI(config) - this.permission = new PermissionAPI(config) - this.datasource = new DatasourceAPI(config) - this.screen = new ScreenAPI(config) this.application = new ApplicationAPI(config) - this.backup = new BackupAPI(config) this.attachment = new AttachmentAPI(config) - this.user = new UserAPI(config) + this.automation = new AutomationAPI(config) + this.backup = new BackupAPI(config) + this.datasource = new DatasourceAPI(config) + this.legacyView = new LegacyViewAPI(config) + this.permission = new PermissionAPI(config) + this.plugin = new PluginAPI(config) this.query = new QueryAPI(config) this.roles = new RoleAPI(config) - this.templates = new TemplateAPI(config) + this.row = new RowAPI(config) this.rowAction = new RowActionAPI(config) - this.automation = new AutomationAPI(config) - this.plugin = new PluginAPI(config) + this.screen = new ScreenAPI(config) + this.table = new TableAPI(config) + this.templates = new TemplateAPI(config) + this.user = new UserAPI(config) + this.viewV2 = new ViewV2API(config) this.webhook = new WebhookAPI(config) } } diff --git a/packages/server/src/tests/utilities/structures.ts b/packages/server/src/tests/utilities/structures.ts index 3058a706c1..0c74a0faa2 100644 --- a/packages/server/src/tests/utilities/structures.ts +++ b/packages/server/src/tests/utilities/structures.ts @@ -34,6 +34,7 @@ import { Webhook, WebhookActionType, BuiltinPermissionID, + DeepPartial, } from "@budibase/types" import { LoopInput } from "../../definitions/automations" import { merge } from "lodash" @@ -184,21 +185,12 @@ export function newAutomation({ steps, trigger, }: { steps?: AutomationStep[]; trigger?: AutomationTrigger } = {}) { - const automation = basicAutomation() - - if (trigger) { - automation.definition.trigger = trigger - } else { - automation.definition.trigger = automationTrigger() - } - - if (steps) { - automation.definition.steps = steps - } else { - automation.definition.steps = [automationStep()] - } - - return automation + return basicAutomation({ + definition: { + steps: steps || [automationStep()], + trigger: trigger || automationTrigger(), + }, + }) } export function rowActionAutomation() { @@ -211,8 +203,8 @@ export function rowActionAutomation() { return automation } -export function basicAutomation(appId?: string): Automation { - return { +export function basicAutomation(opts?: DeepPartial): Automation { + const baseAutomation: Automation = { name: "My Automation", screenId: "kasdkfldsafkl", live: true, @@ -241,8 +233,9 @@ export function basicAutomation(appId?: string): Automation { steps: [], }, type: "automation", - appId: appId!, + appId: "appId", } + return merge(baseAutomation, opts) } export function basicCronAutomation(appId: string, cron: string): Automation { @@ -387,16 +380,21 @@ export function loopAutomation( return automation as Automation } -export function collectAutomation(tableId?: string): Automation { - const automation: any = { +export function collectAutomation(opts?: DeepPartial): Automation { + const baseAutomation: Automation = { + appId: "appId", name: "looping", type: "automation", definition: { steps: [ { id: "b", - type: "ACTION", + name: "b", + tagline: "An automation action step", + icon: "Icon", + type: AutomationStepType.ACTION, internal: true, + description: "Execute script", stepId: AutomationActionStepId.EXECUTE_SCRIPT, inputs: { code: "return [1,2,3]", @@ -405,8 +403,12 @@ export function collectAutomation(tableId?: string): Automation { }, { id: "c", - type: "ACTION", + name: "c", + type: AutomationStepType.ACTION, + tagline: "An automation action step", + icon: "Icon", internal: true, + description: "Collect", stepId: AutomationActionStepId.COLLECT, inputs: { collection: "{{ literal steps.1.value }}", @@ -416,24 +418,28 @@ export function collectAutomation(tableId?: string): Automation { ], trigger: { id: "a", - type: "TRIGGER", + type: AutomationStepType.TRIGGER, event: AutomationEventType.ROW_SAVE, stepId: AutomationTriggerStepId.ROW_SAVED, + name: "trigger Step", + tagline: "An automation trigger", + description: "A trigger", + icon: "Icon", inputs: { - tableId, + tableId: "tableId", }, schema: TRIGGER_DEFINITIONS.ROW_SAVED.schema, }, }, } - return automation + return merge(baseAutomation, opts) } -export function filterAutomation(appId: string, tableId?: string): Automation { +export function filterAutomation(opts?: DeepPartial): Automation { const automation: Automation = { name: "looping", type: "automation", - appId, + appId: "appId", definition: { steps: [ { @@ -459,13 +465,13 @@ export function filterAutomation(appId: string, tableId?: string): Automation { event: AutomationEventType.ROW_SAVE, stepId: AutomationTriggerStepId.ROW_SAVED, inputs: { - tableId: tableId!, + tableId: "tableId", }, schema: TRIGGER_DEFINITIONS.ROW_SAVED.schema, }, }, } - return automation + return merge(automation, opts) } export function updateRowAutomationWithFilters( diff --git a/packages/types/src/api/web/app/automation.ts b/packages/types/src/api/web/app/automation.ts index b97dee0baf..f72966d100 100644 --- a/packages/types/src/api/web/app/automation.ts +++ b/packages/types/src/api/web/app/automation.ts @@ -75,6 +75,7 @@ export interface TestAutomationRequest { revision?: string fields: Record row?: Row + oldRow?: Row } export type TestAutomationResponse = AutomationResults | DidNotTriggerResponse