From d01bd54fd135067500e1b40f4d109ef66152ca26 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 22 Jul 2024 16:40:00 +0200 Subject: [PATCH 01/11] Use name (not display name) on saving --- .../automation/AutomationPanel/AutomationNavItem.svelte | 2 +- .../automation/AutomationPanel/AutomationPanel.svelte | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte b/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte index 31f86f5d78..db0b5bfab1 100644 --- a/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte +++ b/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte @@ -89,7 +89,7 @@ on:contextmenu={openContextMenu} {icon} iconColor={"var(--spectrum-global-color-gray-900)"} - text={automation.name} + text={automation.displayName} selected={automation._id === $selectedAutomation?._id} hovering={automation._id === $contextMenuStore.id} on:click={() => automationStore.actions.select(automation._id)} diff --git a/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte b/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte index 718a0dbcb5..e017e6a26a 100644 --- a/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte +++ b/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte @@ -19,13 +19,13 @@ }) .map(automation => ({ ...automation, - name: + displayName: $automationStore.automationDisplayData[automation._id].displayName || automation.name, })) .sort((a, b) => { - const lowerA = a.name.toLowerCase() - const lowerB = b.name.toLowerCase() + const lowerA = a.displayName.toLowerCase() + const lowerB = b.displayName.toLowerCase() return lowerA > lowerB ? 1 : -1 }) From 703e2c1873b7e0033b52a98de691caa14f36c777 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 22 Jul 2024 17:20:30 +0200 Subject: [PATCH 02/11] Prevent renaming row actions --- .../server/src/sdk/app/automations/crud.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/server/src/sdk/app/automations/crud.ts b/packages/server/src/sdk/app/automations/crud.ts index f3dd3e7a3c..875c7d4a9d 100644 --- a/packages/server/src/sdk/app/automations/crud.ts +++ b/packages/server/src/sdk/app/automations/crud.ts @@ -1,4 +1,9 @@ -import { Automation, Webhook, WebhookActionType } from "@budibase/types" +import { + Automation, + AutomationTriggerStepId, + Webhook, + WebhookActionType, +} from "@budibase/types" import { generateAutomationID, getAutomationParams } from "../../../db/utils" import { deleteEntityMetadata } from "../../../utilities" import { MetadataTypes } from "../../../constants" @@ -117,7 +122,6 @@ export async function create(automation: Automation) { export async function update(automation: Automation) { automation = { ...automation } - if (!automation._id || !automation._rev) { throw new HTTPError("_id or _rev fields missing", 400) } @@ -281,4 +285,14 @@ function guardInvalidUpdatesAndThrow( } }) } + + if (isRowAction(automation) && automation.name !== oldAutomation.name) { + throw new Error("Row actions cannot be renamed") + } +} + +function isRowAction(automation: Automation) { + const result = + automation.definition.trigger.stepId === AutomationTriggerStepId.ROW_ACTION + return result } From 1081d415fa1b38ec7b1209e858dff7251be90874 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 22 Jul 2024 17:37:02 +0200 Subject: [PATCH 03/11] Refetch builder data --- .../builder/src/stores/builder/automations.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/builder/src/stores/builder/automations.js b/packages/builder/src/stores/builder/automations.js index c1cb963ac4..57c823da9b 100644 --- a/packages/builder/src/stores/builder/automations.js +++ b/packages/builder/src/stores/builder/automations.js @@ -104,19 +104,8 @@ const automationActions = store => ({ }, save: async automation => { const response = await API.updateAutomation(automation) - store.update(state => { - const updatedAutomation = response.automation - const existingIdx = state.automations.findIndex( - existing => existing._id === automation._id - ) - if (existingIdx !== -1) { - state.automations.splice(existingIdx, 1, updatedAutomation) - return state - } else { - state.automations = [...state.automations, updatedAutomation] - } - return state - }) + + await store.actions.fetch() return response.automation }, delete: async automation => { From 94281724827a209b902590e6a31f451ec6ba4df0 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 22 Jul 2024 18:27:27 +0200 Subject: [PATCH 04/11] Prevent duplicate --- .../automation/AutomationPanel/AutomationNavItem.svelte | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte b/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte index db0b5bfab1..b8d9c66cf3 100644 --- a/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte +++ b/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte @@ -57,7 +57,9 @@ name: "Duplicate", keyBind: null, visible: true, - disabled: automation.definition.trigger.name === "Webhook", + disabled: + automation.definition.trigger.name === "Webhook" || + automation.definition.trigger.name === "Row Action", callback: duplicateAutomation, }, { From d60140087134fec60db62c48642b49d596bebbbc Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 10:21:09 +0200 Subject: [PATCH 05/11] Don't allow edit or delete actions for row actions --- .../AutomationPanel/AutomationNavItem.svelte | 86 ++++++++++--------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte b/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte index b8d9c66cf3..25f1a3648b 100644 --- a/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte +++ b/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte @@ -35,47 +35,53 @@ } const getContextMenuItems = () => { - return [ - { - icon: "Delete", - name: "Delete", - keyBind: null, - visible: true, - disabled: false, - callback: confirmDeleteDialog.show, + const isRowAction = automation.definition.trigger.name === "Row Action" + const result = [] + if (!isRowAction) { + result.push( + ...[ + { + icon: "Delete", + name: "Delete", + keyBind: null, + visible: true, + disabled: false, + callback: confirmDeleteDialog.show, + }, + { + icon: "Edit", + name: "Edit", + keyBind: null, + visible: true, + disabled: false, + callback: updateAutomationDialog.show, + }, + { + icon: "Duplicate", + name: "Duplicate", + keyBind: null, + visible: true, + disabled: automation.definition.trigger.name === "Webhook", + callback: duplicateAutomation, + }, + ] + ) + } + + result.push({ + icon: automation.disabled ? "CheckmarkCircle" : "Cancel", + name: automation.disabled ? "Activate" : "Pause", + keyBind: null, + visible: true, + disabled: false, + callback: () => { + automationStore.actions.toggleDisabled( + automation._id, + automation.disabled + ) }, - { - icon: "Edit", - name: "Edit", - keyBind: null, - visible: true, - disabled: false, - callback: updateAutomationDialog.show, - }, - { - icon: "Duplicate", - name: "Duplicate", - keyBind: null, - visible: true, - disabled: - automation.definition.trigger.name === "Webhook" || - automation.definition.trigger.name === "Row Action", - callback: duplicateAutomation, - }, - { - icon: automation.disabled ? "CheckmarkCircle" : "Cancel", - name: automation.disabled ? "Activate" : "Pause", - keyBind: null, - visible: true, - disabled: false, - callback: () => { - automationStore.actions.toggleDisabled( - automation._id, - automation.disabled - ) - }, - }, - ] + }) + return result } const openContextMenu = e => { From d9029da533b97c46ee117e1dd724b7db8bb62b89 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 10:28:57 +0200 Subject: [PATCH 06/11] Don't allow deleting row action automations --- packages/server/src/api/controllers/automation.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index 6d1f3125fd..673359699a 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -12,6 +12,7 @@ import { UserCtx, DeleteAutomationResponse, FetchAutomationResponse, + AutomationTriggerStepId, } from "@budibase/types" import { getActionDefinitions as actionDefs } from "../../automations/actions" import sdk from "../../sdk" @@ -94,6 +95,13 @@ export async function find(ctx: UserCtx) { export async function destroy(ctx: UserCtx) { const automationId = ctx.params.id + const automation = await sdk.automations.get(ctx.params.id) + if ( + automation.definition.trigger.stepId === AutomationTriggerStepId.ROW_ACTION + ) { + ctx.throw("Row actions cannot be renamed", 403) + } + ctx.body = await sdk.automations.remove(automationId, ctx.params.rev) builderSocket?.emitAutomationDeletion(ctx, automationId) } From 8678db18e238c5f06065604e8359656d80b38464 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 10:46:11 +0200 Subject: [PATCH 07/11] Add tests --- .../server/src/api/controllers/automation.ts | 2 +- .../src/api/routes/tests/automation.spec.ts | 13 +++++++ .../sdk/app/automations/tests/index.spec.ts | 35 ++++++++++++++++++- .../server/src/tests/utilities/structures.ts | 15 +++++++- 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index 673359699a..2e7914f60b 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -99,7 +99,7 @@ export async function destroy(ctx: UserCtx) { if ( automation.definition.trigger.stepId === AutomationTriggerStepId.ROW_ACTION ) { - ctx.throw("Row actions cannot be renamed", 403) + ctx.throw("Row actions cannot be deleted", 403) } ctx.body = await sdk.automations.remove(automationId, ctx.params.rev) diff --git a/packages/server/src/api/routes/tests/automation.spec.ts b/packages/server/src/api/routes/tests/automation.spec.ts index f0c3d6e1c5..a82bc68465 100644 --- a/packages/server/src/api/routes/tests/automation.spec.ts +++ b/packages/server/src/api/routes/tests/automation.spec.ts @@ -425,6 +425,19 @@ describe("/automations", () => { expect(events.automation.deleted).toHaveBeenCalledTimes(1) }) + it("cannot delete a row action automation", async () => { + const automation = await config.createAutomation( + setup.structures.rowActionAutomation() + ) + await request + .delete(`/api/automations/${automation._id}/${automation._rev}`) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(403, { message: "Row actions cannot be deleted", status: 403 }) + + expect(events.automation.deleted).not.toHaveBeenCalled() + }) + it("should apply authorization to endpoint", async () => { const automation = await config.createAutomation() await checkBuilderEndpoint({ diff --git a/packages/server/src/sdk/app/automations/tests/index.spec.ts b/packages/server/src/sdk/app/automations/tests/index.spec.ts index 124a5d9276..868dfb30ac 100644 --- a/packages/server/src/sdk/app/automations/tests/index.spec.ts +++ b/packages/server/src/sdk/app/automations/tests/index.spec.ts @@ -1,5 +1,6 @@ import { sample } from "lodash/fp" -import { Automation } from "@budibase/types" +import { Automation, AutomationTriggerStepId } from "@budibase/types" +import { generator } from "@budibase/backend-core/tests" import automationSdk from "../" import { structures } from "../../../../api/routes/tests/utilities" import TestConfiguration from "../../../../tests/utilities/TestConfiguration" @@ -12,6 +13,38 @@ describe("automation sdk", () => { }) describe("update", () => { + it("can rename existing automations", async () => { + await config.doInContext(config.getAppId(), async () => { + const automation = structures.newAutomation() + + const response = await automationSdk.create(automation) + + const newName = generator.guid() + const update = { ...response, name: newName } + const result = await automationSdk.update(update) + expect(result.name).toEqual(newName) + }) + }) + + it("cannot rename row action automations", async () => { + await config.doInContext(config.getAppId(), async () => { + const automation = structures.newAutomation({ + trigger: { + ...structures.automationTrigger(), + stepId: AutomationTriggerStepId.ROW_ACTION, + }, + }) + + const response = await automationSdk.create(automation) + + const newName = generator.guid() + const update = { ...response, name: newName } + await expect(automationSdk.update(update)).rejects.toThrow( + "Row actions cannot be renamed" + ) + }) + }) + it.each([ ["trigger", (a: Automation) => a.definition.trigger], ["step", (a: Automation) => a.definition.steps[0]], diff --git a/packages/server/src/tests/utilities/structures.ts b/packages/server/src/tests/utilities/structures.ts index 970df2e2c9..16ab049eb4 100644 --- a/packages/server/src/tests/utilities/structures.ts +++ b/packages/server/src/tests/utilities/structures.ts @@ -158,7 +158,10 @@ export function automationTrigger( } } -export function newAutomation({ steps, trigger }: any = {}) { +export function newAutomation({ + steps, + trigger, +}: { steps?: AutomationStep[]; trigger?: AutomationTrigger } = {}) { const automation = basicAutomation() if (trigger) { @@ -176,6 +179,16 @@ export function newAutomation({ steps, trigger }: any = {}) { return automation } +export function rowActionAutomation() { + const automation = newAutomation({ + trigger: { + ...automationTrigger(), + stepId: AutomationTriggerStepId.ROW_ACTION, + }, + }) + return automation +} + export function basicAutomation(appId?: string): Automation { return { name: "My Automation", From 35bbccec67635bbe64eee482119400ae721929bd Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 11:59:14 +0200 Subject: [PATCH 08/11] Return 400 instead of 403 --- packages/server/src/api/controllers/automation.ts | 2 +- packages/server/src/api/routes/tests/automation.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index 2e7914f60b..35799e5dee 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -99,7 +99,7 @@ export async function destroy(ctx: UserCtx) { if ( automation.definition.trigger.stepId === AutomationTriggerStepId.ROW_ACTION ) { - ctx.throw("Row actions cannot be deleted", 403) + ctx.throw("Row actions cannot be deleted", 400) } ctx.body = await sdk.automations.remove(automationId, ctx.params.rev) diff --git a/packages/server/src/api/routes/tests/automation.spec.ts b/packages/server/src/api/routes/tests/automation.spec.ts index a82bc68465..8fccb32299 100644 --- a/packages/server/src/api/routes/tests/automation.spec.ts +++ b/packages/server/src/api/routes/tests/automation.spec.ts @@ -433,7 +433,7 @@ describe("/automations", () => { .delete(`/api/automations/${automation._id}/${automation._rev}`) .set(config.defaultHeaders()) .expect("Content-Type", /json/) - .expect(403, { message: "Row actions cannot be deleted", status: 403 }) + .expect(400, { message: "Row actions cannot be deleted", status: 400 }) expect(events.automation.deleted).not.toHaveBeenCalled() }) From b4767cea7c7808901280958112dd4b1ee04b0b76 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 12:07:05 +0200 Subject: [PATCH 09/11] Add checks to shared-core --- .../server/src/api/controllers/automation.ts | 6 ++---- .../server/src/sdk/app/automations/crud.ts | 19 ++++++------------- .../server/src/sdk/app/automations/utils.ts | 7 +++---- .../src/sdk/documents/automations.ts | 7 +++++++ .../shared-core/src/sdk/documents/index.ts | 1 + 5 files changed, 19 insertions(+), 21 deletions(-) create mode 100644 packages/shared-core/src/sdk/documents/automations.ts diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index 35799e5dee..ab5b6e3fd7 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -1,4 +1,5 @@ import * as triggers from "../../automations/triggers" +import { sdk as coreSdk } from "@budibase/shared-core" import { DocumentType } from "../../db/utils" import { updateTestHistory, removeDeprecated } from "../../automations/utils" import { setTestFlag, clearTestFlag } from "../../utilities/redis" @@ -12,7 +13,6 @@ import { UserCtx, DeleteAutomationResponse, FetchAutomationResponse, - AutomationTriggerStepId, } from "@budibase/types" import { getActionDefinitions as actionDefs } from "../../automations/actions" import sdk from "../../sdk" @@ -96,9 +96,7 @@ export async function destroy(ctx: UserCtx) { const automationId = ctx.params.id const automation = await sdk.automations.get(ctx.params.id) - if ( - automation.definition.trigger.stepId === AutomationTriggerStepId.ROW_ACTION - ) { + if (coreSdk.automations.isRowAction(automation)) { ctx.throw("Row actions cannot be deleted", 400) } diff --git a/packages/server/src/sdk/app/automations/crud.ts b/packages/server/src/sdk/app/automations/crud.ts index 875c7d4a9d..ee7e3a3506 100644 --- a/packages/server/src/sdk/app/automations/crud.ts +++ b/packages/server/src/sdk/app/automations/crud.ts @@ -1,9 +1,5 @@ -import { - Automation, - AutomationTriggerStepId, - Webhook, - WebhookActionType, -} from "@budibase/types" +import { Automation, Webhook, WebhookActionType } from "@budibase/types" +import { sdk } from "@budibase/shared-core" import { generateAutomationID, getAutomationParams } from "../../../db/utils" import { deleteEntityMetadata } from "../../../utilities" import { MetadataTypes } from "../../../constants" @@ -286,13 +282,10 @@ function guardInvalidUpdatesAndThrow( }) } - if (isRowAction(automation) && automation.name !== oldAutomation.name) { + if ( + sdk.automations.isRowAction(automation) && + automation.name !== oldAutomation.name + ) { throw new Error("Row actions cannot be renamed") } } - -function isRowAction(automation: Automation) { - const result = - automation.definition.trigger.stepId === AutomationTriggerStepId.ROW_ACTION - return result -} diff --git a/packages/server/src/sdk/app/automations/utils.ts b/packages/server/src/sdk/app/automations/utils.ts index 52ed935f3b..ad06e55418 100644 --- a/packages/server/src/sdk/app/automations/utils.ts +++ b/packages/server/src/sdk/app/automations/utils.ts @@ -2,9 +2,9 @@ import { Automation, AutomationActionStepId, AutomationBuilderData, - AutomationTriggerStepId, TableRowActions, } from "@budibase/types" +import { sdk as coreSdk } from "@budibase/shared-core" export function checkForCollectStep(automation: Automation) { return automation.definition.steps.some( @@ -39,14 +39,13 @@ export async function getBuilderData( const result: Record = {} for (const automation of automations) { - const { trigger } = automation.definition - const isRowAction = trigger.stepId === AutomationTriggerStepId.ROW_ACTION + const isRowAction = coreSdk.automations.isRowAction(automation) if (!isRowAction) { result[automation._id!] = { displayName: automation.name } continue } - const { tableId, rowActionId } = trigger.inputs + const { tableId, rowActionId } = automation.definition.trigger.inputs const tableName = await getTableName(tableId) diff --git a/packages/shared-core/src/sdk/documents/automations.ts b/packages/shared-core/src/sdk/documents/automations.ts new file mode 100644 index 0000000000..93e08c86e0 --- /dev/null +++ b/packages/shared-core/src/sdk/documents/automations.ts @@ -0,0 +1,7 @@ +import { Automation, AutomationTriggerStepId } from "@budibase/types" + +export function isRowAction(automation: Automation) { + const result = + automation.definition.trigger.stepId === AutomationTriggerStepId.ROW_ACTION + return result +} diff --git a/packages/shared-core/src/sdk/documents/index.ts b/packages/shared-core/src/sdk/documents/index.ts index d20631eef4..4b17c1ea08 100644 --- a/packages/shared-core/src/sdk/documents/index.ts +++ b/packages/shared-core/src/sdk/documents/index.ts @@ -1,2 +1,3 @@ export * as applications from "./applications" +export * as automations from "./automations" export * as users from "./users" From af0b69e8b6940a3a984aa83bb4e4e5712383e6d3 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 12:09:53 +0200 Subject: [PATCH 10/11] Reuse --- .../automation/AutomationPanel/AutomationNavItem.svelte | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte b/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte index 25f1a3648b..df5ac3bd98 100644 --- a/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte +++ b/packages/builder/src/components/automation/AutomationPanel/AutomationNavItem.svelte @@ -6,6 +6,7 @@ contextMenuStore, } from "stores/builder" import { notifications, Icon } from "@budibase/bbui" + import { sdk } from "@budibase/shared-core" import ConfirmDialog from "components/common/ConfirmDialog.svelte" import UpdateAutomationModal from "components/automation/AutomationPanel/UpdateAutomationModal.svelte" import NavItem from "components/common/NavItem.svelte" @@ -35,7 +36,7 @@ } const getContextMenuItems = () => { - const isRowAction = automation.definition.trigger.name === "Row Action" + const isRowAction = sdk.automations.isRowAction(automation) const result = [] if (!isRowAction) { result.push( From a03094db330b8158c2b1be4ea1c3c46844c84e7f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 12:21:52 +0200 Subject: [PATCH 11/11] Use 422 instead of 400 trying to delete row action automations --- packages/server/src/api/controllers/automation.ts | 2 +- packages/server/src/api/routes/tests/automation.spec.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index ab5b6e3fd7..6177868303 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -97,7 +97,7 @@ export async function destroy(ctx: UserCtx) { const automation = await sdk.automations.get(ctx.params.id) if (coreSdk.automations.isRowAction(automation)) { - ctx.throw("Row actions cannot be deleted", 400) + ctx.throw("Row actions automations cannot be deleted", 422) } ctx.body = await sdk.automations.remove(automationId, ctx.params.rev) diff --git a/packages/server/src/api/routes/tests/automation.spec.ts b/packages/server/src/api/routes/tests/automation.spec.ts index 8fccb32299..990828dcde 100644 --- a/packages/server/src/api/routes/tests/automation.spec.ts +++ b/packages/server/src/api/routes/tests/automation.spec.ts @@ -433,7 +433,10 @@ describe("/automations", () => { .delete(`/api/automations/${automation._id}/${automation._rev}`) .set(config.defaultHeaders()) .expect("Content-Type", /json/) - .expect(400, { message: "Row actions cannot be deleted", status: 400 }) + .expect(422, { + message: "Row actions automations cannot be deleted", + status: 422, + }) expect(events.automation.deleted).not.toHaveBeenCalled() })