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<void>) {
+  async withApp<R>(app: App | string, f: () => Promise<R>) {
     const oldAppId = this.appId
     this.appId = typeof app === "string" ? app : app.appId
     try {
@@ -268,6 +268,10 @@ export default class TestConfiguration {
     }
   }
 
+  async withProdApp<R>(f: () => Promise<R>) {
+    return await this.withApp(this.getProdAppId(), f)
+  }
+
   // UTILS
 
   _req<Req extends Record<string, any> | 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<GetAutomationActionDefinitionsResponse> => {
+    return await this._get<GetAutomationActionDefinitionsResponse>(
+      `/api/automations/actions/list`,
+      {
+        expectations,
+      }
+    )
+  }
+
+  getTriggers = async (
+    expectations?: Expectations
+  ): Promise<GetAutomationTriggerDefinitionsResponse> => {
+    return await this._get<GetAutomationTriggerDefinitionsResponse>(
+      `/api/automations/triggers/list`,
+      {
+        expectations,
+      }
+    )
+  }
+
+  getDefinitions = async (
+    expectations?: Expectations
+  ): Promise<GetAutomationStepDefinitionsResponse> => {
+    return await this._get<GetAutomationStepDefinitionsResponse>(
+      `/api/automations/definitions/list`,
+      {
+        expectations,
+      }
+    )
+  }
+
   fetch = async (
     expectations?: Expectations
   ): Promise<FetchAutomationResponse> => {
@@ -31,11 +73,14 @@ export class AutomationAPI extends TestAPI {
   post = async (
     body: Automation,
     expectations?: Expectations
-  ): Promise<Automation> => {
-    const result = await this._post<Automation>(`/api/automations`, {
-      body,
-      expectations,
-    })
+  ): Promise<CreateAutomationResponse> => {
+    const result = await this._post<CreateAutomationResponse>(
+      `/api/automations`,
+      {
+        body,
+        expectations,
+      }
+    )
     return result
   }
 
@@ -52,4 +97,40 @@ export class AutomationAPI extends TestAPI {
       }
     )
   }
+
+  trigger = async (
+    id: string,
+    body: TriggerAutomationRequest,
+    expectations?: Expectations
+  ): Promise<TriggerAutomationResponse> => {
+    return await this._post<TriggerAutomationResponse>(
+      `/api/automations/${id}/trigger`,
+      {
+        expectations,
+        body,
+      }
+    )
+  }
+
+  update = async (
+    body: UpdateAutomationRequest,
+    expectations?: Expectations
+  ): Promise<UpdateAutomationResponse> => {
+    return await this._put<UpdateAutomationResponse>(`/api/automations`, {
+      body,
+      expectations,
+    })
+  }
+
+  delete = async (
+    automation: Automation,
+    expectations?: Expectations
+  ): Promise<DeleteAutomationResponse> => {
+    return await this._delete<DeleteAutomationResponse>(
+      `/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>): 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>): 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>): 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<string, any>
   row?: Row
+  oldRow?: Row
 }
 export type TestAutomationResponse = AutomationResults | DidNotTriggerResponse