diff --git a/packages/server/src/automations/tests/createRow.spec.ts b/packages/server/src/automations/tests/createRow.spec.ts index bcf9845669..bd78de2217 100644 --- a/packages/server/src/automations/tests/createRow.spec.ts +++ b/packages/server/src/automations/tests/createRow.spec.ts @@ -1,6 +1,7 @@ import * as setup from "./utilities" import { basicTableWithAttachmentField } from "../../tests/utilities/structures" import { objectStore } from "@budibase/backend-core" +import { createAutomationBuilder } from "./utilities/AutomationTestBuilder" async function uploadTestFile(filename: string) { let bucket = "testbucket" @@ -13,6 +14,7 @@ async function uploadTestFile(filename: string) { return presignedUrl } + describe("test the create row action", () => { let table: any let row: any @@ -31,30 +33,78 @@ describe("test the create row action", () => { afterAll(setup.afterAll) it("should be able to run the action", async () => { - const res = await setup.runStep(config, setup.actions.CREATE_ROW.stepId, { - row, + const result = await createAutomationBuilder({ + name: "Test Create Row Flow", + appId: config.getAppId(), + config, }) - expect(res.id).toBeDefined() - expect(res.revision).toBeDefined() - expect(res.success).toEqual(true) - const gottenRow = await config.api.row.get(table._id, res.id) + .appAction({ fields: { status: "new" } }) + .serverLog({ text: "Starting create row flow" }, { stepName: "StartLog" }) + .createRow({ row }, { stepName: "CreateRow" }) + .serverLog( + { text: "Row created with ID: {{ stepsByName.CreateRow.row._id }}" }, + { stepName: "CreationLog" } + ) + .run() + + expect(result.steps[1].outputs.success).toBeDefined() + expect(result.steps[1].outputs.id).toBeDefined() + expect(result.steps[1].outputs.revision).toBeDefined() + const gottenRow = await config.api.row.get( + table._id, + result.steps[1].outputs.id + ) expect(gottenRow.name).toEqual("test") expect(gottenRow.description).toEqual("test") + expect(result.steps[2].outputs.message).toContain( + "Row created with ID: " + result.steps[1].outputs.id + ) }) it("should return an error (not throw) when bad info provided", async () => { - const res = await setup.runStep(config, setup.actions.CREATE_ROW.stepId, { - row: { - tableId: "invalid", - invalid: "invalid", - }, + const result = await createAutomationBuilder({ + name: "Test Create Row Error Flow", + appId: config.getAppId(), + config, }) - expect(res.success).toEqual(false) + .appAction({ fields: { status: "error" } }) + .serverLog({ text: "Starting error test flow" }, { stepName: "StartLog" }) + .createRow( + { + row: { + tableId: "invalid", + invalid: "invalid", + }, + }, + { stepName: "CreateRow" } + ) + .run() + + expect(result.steps[1].outputs.success).toEqual(false) }) it("should check invalid inputs return an error", async () => { - const res = await setup.runStep(config, setup.actions.CREATE_ROW.stepId, {}) - expect(res.success).toEqual(false) + const result = await createAutomationBuilder({ + name: "Test Create Row Invalid Flow", + appId: config.getAppId(), + config, + }) + .appAction({ fields: { status: "invalid" } }) + .serverLog({ text: "Testing invalid input" }, { stepName: "StartLog" }) + .createRow({ row: {} }, { stepName: "CreateRow" }) + .filter({ + field: "{{ stepsByName.CreateRow.success }}", + condition: "equal", + value: true, + }) + .serverLog( + { text: "This log should not appear" }, + { stepName: "SkippedLog" } + ) + .run() + + expect(result.steps[1].outputs.success).toEqual(false) + expect(result.steps.length).toBeLessThan(4) }) it("should check that an attachment field is sent to storage and parsed", async () => { @@ -76,13 +126,33 @@ describe("test the create row action", () => { ] attachmentRow.file_attachment = attachmentObject - const res = await setup.runStep(config, setup.actions.CREATE_ROW.stepId, { - row: attachmentRow, + const result = await createAutomationBuilder({ + name: "Test Create Row Attachment Flow", + appId: config.getAppId(), + config, }) + .appAction({ fields: { type: "attachment" } }) + .serverLog( + { text: "Processing attachment upload" }, + { stepName: "StartLog" } + ) + .createRow({ row: attachmentRow }, { stepName: "CreateRow" }) + .filter({ + field: "{{ stepsByName.CreateRow.success }}", + condition: "equal", + value: true, + }) + .serverLog( + { + text: "Attachment uploaded with key: {{ stepsByName.CreateRow.row.file_attachment.0.key }}", + }, + { stepName: "UploadLog" } + ) + .run() - expect(res.success).toEqual(true) - expect(res.row.file_attachment[0]).toHaveProperty("key") - let s3Key = res.row.file_attachment[0].key + expect(result.steps[1].outputs.success).toEqual(true) + expect(result.steps[1].outputs.row.file_attachment[0]).toHaveProperty("key") + let s3Key = result.steps[1].outputs.row.file_attachment[0].key const client = objectStore.ObjectStore(objectStore.ObjectStoreBuckets.APPS) @@ -111,13 +181,53 @@ describe("test the create row action", () => { } attachmentRow.single_file_attachment = attachmentObject - const res = await setup.runStep(config, setup.actions.CREATE_ROW.stepId, { - row: attachmentRow, + const result = await createAutomationBuilder({ + name: "Test Create Row Single Attachment Flow", + appId: config.getAppId(), + config, }) + .appAction({ fields: { type: "single-attachment" } }) + .serverLog( + { text: "Processing single attachment" }, + { stepName: "StartLog" } + ) + .createRow({ row: attachmentRow }, { stepName: "CreateRow" }) + .branch({ + success: { + steps: stepBuilder => + stepBuilder + .serverLog( + { text: "Single attachment processed" }, + { stepName: "ProcessLog" } + ) + .serverLog( + { + text: "File key: {{ stepsByName.CreateRow.row.single_file_attachment.key }}", + }, + { stepName: "KeyLog" } + ), + condition: { + equal: { "{{ stepsByName.CreateRow.success }}": true }, + }, + }, + error: { + steps: stepBuilder => + stepBuilder.serverLog( + { text: "Failed to process attachment" }, + { stepName: "ErrorLog" } + ), + condition: { + equal: { "{{ stepsByName.CreateRow.success }}": false }, + }, + }, + }) + .run() - expect(res.success).toEqual(true) - expect(res.row.single_file_attachment).toHaveProperty("key") - let s3Key = res.row.single_file_attachment.key + expect(result.steps[1].outputs.success).toEqual(true) + expect(result.steps[1].outputs.row.single_file_attachment).toHaveProperty( + "key" + ) + let s3Key = result.steps[1].outputs.row.single_file_attachment.key const client = objectStore.ObjectStore(objectStore.ObjectStoreBuckets.APPS) @@ -146,13 +256,50 @@ describe("test the create row action", () => { } attachmentRow.single_file_attachment = attachmentObject - const res = await setup.runStep(config, setup.actions.CREATE_ROW.stepId, { - row: attachmentRow, + const result = await createAutomationBuilder({ + name: "Test Create Row Invalid Attachment Flow", + appId: config.getAppId(), + config, }) + .appAction({ fields: { type: "invalid-attachment" } }) + .serverLog( + { text: "Testing invalid attachment keys" }, + { stepName: "StartLog" } + ) + .createRow({ row: attachmentRow }, { stepName: "CreateRow" }) + .branch({ + success: { + steps: stepBuilder => + stepBuilder.serverLog( + { text: "Unexpected success" }, + { stepName: "UnexpectedLog" } + ), + condition: { + equal: { "{{ stepsByName.CreateRow.success }}": true }, + }, + }, + error: { + steps: stepBuilder => + stepBuilder + .serverLog( + { text: "Expected error occurred" }, + { stepName: "ErrorLog" } + ) + .serverLog( + { text: "Error: {{ stepsByName.CreateRow.response }}" }, + { stepName: "ErrorDetailsLog" } + ), + condition: { + equal: { "{{ stepsByName.CreateRow.success }}": false }, + }, + }, + }) + .run() - expect(res.success).toEqual(false) - expect(res.response).toEqual( + expect(result.steps[1].outputs.success).toEqual(false) + expect(result.steps[1].outputs.response).toEqual( 'Error: Attachments must have both "url" and "filename" keys. You have provided: wrongKey, anotherWrongKey' ) + expect(result.steps[2].outputs.status).toEqual("No branch condition met") }) }) diff --git a/packages/server/src/automations/tests/deleteRow.spec.ts b/packages/server/src/automations/tests/deleteRow.spec.ts index dd13aa49c1..cabf590421 100644 --- a/packages/server/src/automations/tests/deleteRow.spec.ts +++ b/packages/server/src/automations/tests/deleteRow.spec.ts @@ -1,52 +1,65 @@ +import { createAutomationBuilder } from "./utilities/AutomationTestBuilder" import * as setup from "./utilities" describe("test the delete row action", () => { - let table: any - let row: any - let inputs: any - let config = setup.getConfig() + let table: any, + row: any, + config = setup.getConfig() - beforeEach(async () => { + beforeAll(async () => { await config.init() table = await config.createTable() row = await config.createRow() - inputs = { - tableId: table._id, - id: row._id, - revision: row._rev, - } }) afterAll(setup.afterAll) - it("should be able to run the action", async () => { - const res = await setup.runStep( - config, - setup.actions.DELETE_ROW.stepId, - inputs - ) - expect(res.success).toEqual(true) - expect(res.response).toBeDefined() - expect(res.row._id).toEqual(row._id) - }) + it("should be able to run the delete row action", async () => { + const builder = createAutomationBuilder({ + name: "Delete Row Automation", + }) - it("check usage quota attempts", async () => { - await setup.runInProd(async () => { - await setup.runStep(config, setup.actions.DELETE_ROW.stepId, inputs) + await builder + .appAction({ fields: {} }) + .deleteRow({ + tableId: table._id, + id: row._id, + revision: row._rev, + }) + .run() + + await config.api.row.get(table._id, row._id, { + status: 404, }) }) it("should check invalid inputs return an error", async () => { - const res = await setup.runStep(config, setup.actions.DELETE_ROW.stepId, {}) - expect(res.success).toEqual(false) + const builder = createAutomationBuilder({ + name: "Invalid Inputs Automation", + }) + + const results = await builder + .appAction({ fields: {} }) + .deleteRow({ tableId: "", id: "", revision: "" }) + .run() + + expect(results.steps[0].outputs.success).toEqual(false) }) it("should return an error when table doesn't exist", async () => { - const res = await setup.runStep(config, setup.actions.DELETE_ROW.stepId, { - tableId: "invalid", - id: "invalid", - revision: "invalid", + const builder = createAutomationBuilder({ + name: "Nonexistent Table Automation", }) - expect(res.success).toEqual(false) + + const results = await builder + .appAction({ fields: {} }) + .deleteRow({ + tableId: "invalid", + id: "invalid", + revision: "invalid", + }) + .run() + + expect(results.steps[0].outputs.success).toEqual(false) }) }) diff --git a/packages/server/src/automations/tests/updateRow.spec.ts b/packages/server/src/automations/tests/updateRow.spec.ts index 457bf60533..45f78826f6 100644 --- a/packages/server/src/automations/tests/updateRow.spec.ts +++ b/packages/server/src/automations/tests/updateRow.spec.ts @@ -8,58 +8,83 @@ import { Table, TableSourceType, } from "@budibase/types" +import { createAutomationBuilder } from "./utilities/AutomationTestBuilder" import * as setup from "./utilities" import * as uuid from "uuid" describe("test the update row action", () => { - let table: Table, row: Row, inputs: any - let config = setup.getConfig() + let table: Table, + row: Row, + config = setup.getConfig() beforeAll(async () => { await config.init() table = await config.createTable() row = await config.createRow() - inputs = { - rowId: row._id, - row: { - ...row, - name: "Updated name", - // put a falsy option in to be removed - description: "", - }, - } }) afterAll(setup.afterAll) - it("should be able to run the action", async () => { - const res = await setup.runStep( - config, - setup.actions.UPDATE_ROW.stepId, - inputs + it("should be able to run the update row action", async () => { + const builder = createAutomationBuilder({ + name: "Update Row Automation", + }) + + const results = await builder + .appAction({ fields: {} }) + .updateRow({ + rowId: row._id!, + row: { + ...row, + name: "Updated name", + description: "", + }, + meta: {}, + }) + .run() + + expect(results.steps[0].outputs.success).toEqual(true) + const updatedRow = await config.api.row.get( + table._id!, + results.steps[0].outputs.id ) - expect(res.success).toEqual(true) - const updatedRow = await config.api.row.get(table._id!, res.id) expect(updatedRow.name).toEqual("Updated name") expect(updatedRow.description).not.toEqual("") }) it("should check invalid inputs return an error", async () => { - const res = await setup.runStep(config, setup.actions.UPDATE_ROW.stepId, {}) - expect(res.success).toEqual(false) + const builder = createAutomationBuilder({ + name: "Invalid Inputs Automation", + }) + + const results = await builder + .appAction({ fields: {} }) + .updateRow({ meta: {}, row: {}, rowId: "" }) + .run() + + expect(results.steps[0].outputs.success).toEqual(false) }) it("should return an error when table doesn't exist", async () => { - const res = await setup.runStep(config, setup.actions.UPDATE_ROW.stepId, { - row: { _id: "invalid" }, - rowId: "invalid", + const builder = createAutomationBuilder({ + name: "Nonexistent Table Automation", }) - expect(res.success).toEqual(false) + + const results = await builder + .appAction({ fields: {} }) + .updateRow({ + row: { _id: "invalid" }, + rowId: "invalid", + meta: {}, + }) + .run() + + expect(results.steps[0].outputs.success).toEqual(false) }) it("should not overwrite links if those links are not set", async () => { - let linkField: FieldSchema = { + const linkField: FieldSchema = { type: FieldType.LINK, name: "", fieldName: "", @@ -71,7 +96,7 @@ describe("test the update row action", () => { tableId: InternalTable.USER_METADATA, } - let table = await config.api.table.save({ + const table = await config.api.table.save({ name: uuid.v4(), type: "table", sourceType: TableSourceType.INTERNAL, @@ -82,23 +107,22 @@ describe("test the update row action", () => { }, }) - let user1 = await config.createUser() - let user2 = await config.createUser() + const user1 = await config.createUser() + const user2 = await config.createUser() - let row = await config.api.row.save(table._id!, { + const row = await config.api.row.save(table._id!, { user1: [{ _id: user1._id }], user2: [{ _id: user2._id }], }) - let getResp = await config.api.row.get(table._id!, row._id!) - expect(getResp.user1[0]._id).toEqual(user1._id) - expect(getResp.user2[0]._id).toEqual(user2._id) + const builder = createAutomationBuilder({ + name: "Link Preservation Automation", + }) - let stepResp = await setup.runStep( - config, - setup.actions.UPDATE_ROW.stepId, - { - rowId: row._id, + const results = await builder + .appAction({ fields: {} }) + .updateRow({ + rowId: row._id!, row: { _id: row._id, _rev: row._rev, @@ -106,17 +130,19 @@ describe("test the update row action", () => { user1: [user2._id], user2: "", }, - } - ) - expect(stepResp.success).toEqual(true) + meta: {}, + }) + .run() - getResp = await config.api.row.get(table._id!, row._id!) + expect(results.steps[0].outputs.success).toEqual(true) + + const getResp = await config.api.row.get(table._id!, row._id!) expect(getResp.user1[0]._id).toEqual(user2._id) expect(getResp.user2[0]._id).toEqual(user2._id) }) - it("should overwrite links if those links are not set and we ask it do", async () => { - let linkField: FieldSchema = { + it("should overwrite links if those links are not set and we ask it to", async () => { + const linkField: FieldSchema = { type: FieldType.LINK, name: "", fieldName: "", @@ -128,7 +154,7 @@ describe("test the update row action", () => { tableId: InternalTable.USER_METADATA, } - let table = await config.api.table.save({ + const table = await config.api.table.save({ name: uuid.v4(), type: "table", sourceType: TableSourceType.INTERNAL, @@ -139,23 +165,22 @@ describe("test the update row action", () => { }, }) - let user1 = await config.createUser() - let user2 = await config.createUser() + const user1 = await config.createUser() + const user2 = await config.createUser() - let row = await config.api.row.save(table._id!, { + const row = await config.api.row.save(table._id!, { user1: [{ _id: user1._id }], user2: [{ _id: user2._id }], }) - let getResp = await config.api.row.get(table._id!, row._id!) - expect(getResp.user1[0]._id).toEqual(user1._id) - expect(getResp.user2[0]._id).toEqual(user2._id) + const builder = createAutomationBuilder({ + name: "Link Overwrite Automation", + }) - let stepResp = await setup.runStep( - config, - setup.actions.UPDATE_ROW.stepId, - { - rowId: row._id, + const results = await builder + .appAction({ fields: {} }) + .updateRow({ + rowId: row._id!, row: { _id: row._id, _rev: row._rev, @@ -170,11 +195,12 @@ describe("test the update row action", () => { }, }, }, - } - ) - expect(stepResp.success).toEqual(true) + }) + .run() - getResp = await config.api.row.get(table._id!, row._id!) + expect(results.steps[0].outputs.success).toEqual(true) + + const getResp = await config.api.row.get(table._id!, row._id!) expect(getResp.user1[0]._id).toEqual(user2._id) expect(getResp.user2).toBeUndefined() })