Merge remote-tracking branch 'origin/execute-script-v2' into execute-script-v2-frontend

This commit is contained in:
Dean 2025-02-07 10:47:41 +00:00
commit 8b04a56dd6
29 changed files with 495 additions and 864 deletions

View File

@ -103,11 +103,8 @@ describe("/automations", () => {
})
it("Should ensure you can't have a branch as not a last step", async () => {
const automation = createAutomationBuilder({
name: "String Equality Branching",
appId: config.getAppId(),
})
.appAction({ fields: { status: "active" } })
const automation = createAutomationBuilder(config)
.onAppAction()
.branch({
activeBranch: {
steps: stepBuilder =>
@ -130,11 +127,8 @@ describe("/automations", () => {
})
it("Should check validation on an automation that has a branch step with no children", async () => {
const automation = createAutomationBuilder({
name: "String Equality Branching",
appId: config.getAppId(),
})
.appAction({ fields: { status: "active" } })
const automation = createAutomationBuilder(config)
.onAppAction()
.branch({})
.serverLog({ text: "Inactive user" })
.build()
@ -149,11 +143,8 @@ describe("/automations", () => {
})
it("Should check validation on a branch step with empty conditions", async () => {
const automation = createAutomationBuilder({
name: "String Equality Branching",
appId: config.getAppId(),
})
.appAction({ fields: { status: "active" } })
const automation = createAutomationBuilder(config)
.onAppAction()
.branch({
activeBranch: {
steps: stepBuilder =>
@ -173,11 +164,8 @@ describe("/automations", () => {
})
it("Should check validation on an branch that has a condition that is not valid", async () => {
const automation = createAutomationBuilder({
name: "String Equality Branching",
appId: config.getAppId(),
})
.appAction({ fields: { status: "active" } })
const automation = createAutomationBuilder(config)
.onAppAction()
.branch({
activeBranch: {
steps: stepBuilder =>
@ -248,12 +236,8 @@ describe("/automations", () => {
})
it("should be able to access platformUrl, logoUrl and company in the automation", async () => {
const result = await createAutomationBuilder({
name: "Test Automation",
appId: config.getAppId(),
config,
})
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.serverLog({
text: "{{ settings.url }}",
})
@ -263,7 +247,7 @@ describe("/automations", () => {
.serverLog({
text: "{{ settings.company }}",
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.message).toEndWith("https://example.com")
expect(result.steps[1].outputs.message).toEndWith(

View File

@ -24,8 +24,8 @@ describe("Branching automations", () => {
const branch2LogId = "33333333-3333-3333-3333-333333333333"
const branch2Id = "44444444-4444-4444-4444-444444444444"
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.serverLog(
{ text: "Starting automation" },
{ stepName: "FirstLog", stepId: firstLogId }
@ -76,15 +76,15 @@ describe("Branching automations", () => {
},
},
})
.run()
.test({ fields: {} })
expect(results.steps[3].outputs.status).toContain("branch1 branch taken")
expect(results.steps[4].outputs.message).toContain("Branch 1.1")
})
it("should execute correct branch based on string equality", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: { status: "active" } })
const results = await createAutomationBuilder(config)
.onAppAction()
.branch({
activeBranch: {
steps: stepBuilder => stepBuilder.serverLog({ text: "Active user" }),
@ -100,7 +100,7 @@ describe("Branching automations", () => {
},
},
})
.run()
.test({ fields: { status: "active" } })
expect(results.steps[0].outputs.status).toContain(
"activeBranch branch taken"
)
@ -108,8 +108,8 @@ describe("Branching automations", () => {
})
it("should handle multiple conditions with AND operator", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: { status: "active", role: "admin" } })
const results = await createAutomationBuilder(config)
.onAppAction()
.branch({
activeAdminBranch: {
steps: stepBuilder =>
@ -130,14 +130,14 @@ describe("Branching automations", () => {
},
},
})
.run()
.test({ fields: { status: "active", role: "admin" } })
expect(results.steps[1].outputs.message).toContain("Active admin user")
})
it("should handle multiple conditions with OR operator", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: { status: "test", role: "user" } })
const results = await createAutomationBuilder(config)
.onAppAction()
.branch({
specialBranch: {
steps: stepBuilder => stepBuilder.serverLog({ text: "Special user" }),
@ -162,14 +162,14 @@ describe("Branching automations", () => {
},
},
})
.run()
.test({ fields: { status: "test", role: "user" } })
expect(results.steps[1].outputs.message).toContain("Special user")
})
it("should stop the branch automation when no conditions are met", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: { status: "test", role: "user" } })
const results = await createAutomationBuilder(config)
.onAppAction()
.createRow({ row: { name: "Test", tableId: table._id } })
.branch({
specialBranch: {
@ -195,7 +195,7 @@ describe("Branching automations", () => {
},
},
})
.run()
.test({ fields: { status: "test", role: "user" } })
expect(results.steps[1].outputs.status).toEqual(
AutomationStatus.NO_CONDITION_MET
@ -204,8 +204,8 @@ describe("Branching automations", () => {
})
it("evaluate multiple conditions", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: { test_trigger: true } })
const results = await createAutomationBuilder(config)
.onAppAction()
.serverLog({ text: "Starting automation" }, { stepId: "aN6znRYHG" })
.branch({
specialBranch: {
@ -239,14 +239,14 @@ describe("Branching automations", () => {
},
},
})
.run()
.test({ fields: { test_trigger: true } })
expect(results.steps[2].outputs.message).toContain("Special user")
})
it("evaluate multiple conditions with interpolated text", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: { test_trigger: true } })
const results = await createAutomationBuilder(config)
.onAppAction()
.serverLog({ text: "Starting automation" }, { stepId: "aN6znRYHG" })
.branch({
specialBranch: {
@ -276,7 +276,7 @@ describe("Branching automations", () => {
},
},
})
.run()
.test({ fields: { test_trigger: true } })
expect(results.steps[2].outputs.message).toContain("Special user")
})

View File

@ -21,47 +21,44 @@ describe("Execute Script Automations", () => {
afterAll(setup.afterAll)
it("should execute a basic script and return the result", async () => {
const builder = createAutomationBuilder({
name: "Basic Script Execution",
})
config.name = "Basic Script Execution"
const builder = createAutomationBuilder(config)
const results = await builder
.appAction({ fields: {} })
.onAppAction()
.executeScriptV2({ code: encodeJS("return 2 + 2") })
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.value).toEqual(4)
})
it("should access bindings from previous steps", async () => {
const builder = createAutomationBuilder({
name: "Access Bindings",
})
config.name = "Access Bindings"
const builder = createAutomationBuilder(config)
const results = await builder
.appAction({ fields: { data: [1, 2, 3] } })
.onAppAction()
.executeScriptV2(
{
code: encodeJS(`return $("trigger.fields.data").map(x => x * 2)`),
},
{ stepId: "binding-script-step" }
)
.run()
.test({ fields: { data: [1, 2, 3] } })
expect(results.steps[0].outputs.value).toEqual([2, 4, 6])
})
it("should handle script execution errors gracefully", async () => {
const builder = createAutomationBuilder({
name: "Handle Script Errors",
})
config.name = "Handle Script Errors"
const builder = createAutomationBuilder(config)
const results = await builder
.appAction({ fields: {} })
.onAppAction()
.executeScriptV2({
code: encodeJS("return nonexistentVariable.map(x => x)"),
})
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.response).toContain(
"ReferenceError: nonexistentVariable is not defined"
@ -70,12 +67,11 @@ describe("Execute Script Automations", () => {
})
it("should handle conditional logic in scripts", async () => {
const builder = createAutomationBuilder({
name: "Conditional Script Logic",
})
config.name = "Conditional Script Logic"
const builder = createAutomationBuilder(config)
const results = await builder
.appAction({ fields: { value: 10 } })
.onAppAction()
.executeScriptV2({
code: encodeJS(`
if ($("trigger.fields.value") > 5) {
@ -85,18 +81,17 @@ describe("Execute Script Automations", () => {
}
`),
})
.run()
.test({ fields: { value: 10 } })
expect(results.steps[0].outputs.value).toEqual("Value is greater than 5")
})
it("should use multiple steps and validate script execution", async () => {
const builder = createAutomationBuilder({
name: "Multi-Step Script Execution",
})
config.name = "Multi-Step Script Execution"
const builder = createAutomationBuilder(config)
const results = await builder
.appAction({ fields: {} })
.onAppAction()
.serverLog(
{ text: "Starting multi-step automation" },
{ stepId: "start-log-step" }
@ -117,7 +112,7 @@ describe("Execute Script Automations", () => {
.serverLog({
text: `Final result is {{ steps.ScriptingStep1.value }}`,
})
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.message).toContain(
"Starting multi-step automation"
@ -128,16 +123,15 @@ describe("Execute Script Automations", () => {
})
it("should fail if the code has not been encoded as a handlebars template", async () => {
const builder = createAutomationBuilder({
name: "Invalid Code Encoding",
})
config.name = "Invalid Code Encoding"
const builder = createAutomationBuilder(config)
const results = await builder
.appAction({ fields: {} })
.onAppAction()
.executeScriptV2({
code: "return 2 + 2",
})
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.response.message).toEqual(
"Expected code to be a {{ js }} template block"
@ -146,16 +140,15 @@ describe("Execute Script Automations", () => {
})
it("does not process embedded handlebars templates", async () => {
const builder = createAutomationBuilder({
name: "Embedded Handlebars",
})
config.name = "Embedded Handlebars"
const builder = createAutomationBuilder(config)
const results = await builder
.appAction({ fields: {} })
.onAppAction()
.executeScriptV2({
code: encodeJS(`return "{{ triggers.row.whatever }}"`),
})
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.value).toEqual(
"{{ triggers.row.whatever }}"

View File

@ -29,14 +29,8 @@ describe("Automation Scenarios", () => {
it("should trigger an automation which then creates a row", async () => {
const table = await config.api.table.save(basicTable())
const results = await createAutomationBuilder({ config })
.rowUpdated(
{ tableId: table._id! },
{
row: { name: "Test", description: "TEST" },
id: "1234",
}
)
const results = await createAutomationBuilder(config)
.onRowUpdated({ tableId: table._id! })
.createRow({
row: {
name: "{{trigger.row.name}}",
@ -44,7 +38,10 @@ describe("Automation Scenarios", () => {
tableId: table._id,
},
})
.run()
.test({
row: { name: "Test", description: "TEST" },
id: "1234",
})
expect(results.steps).toHaveLength(1)
@ -65,12 +62,12 @@ describe("Automation Scenarios", () => {
}
await config.api.row.save(table._id!, row)
await config.api.row.save(table._id!, row)
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.queryRows({
tableId: table._id!,
})
.run()
.test({ fields: {} })
expect(results.steps).toHaveLength(1)
expect(results.steps[0].outputs.rows).toHaveLength(2)
@ -84,8 +81,8 @@ describe("Automation Scenarios", () => {
}
await config.api.row.save(table._id!, row)
await config.api.row.save(table._id!, row)
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.queryRows({
tableId: table._id!,
})
@ -96,7 +93,7 @@ describe("Automation Scenarios", () => {
.queryRows({
tableId: table._id!,
})
.run()
.test({ fields: {} })
expect(results.steps).toHaveLength(3)
expect(results.steps[1].outputs.success).toBeTruthy()
@ -126,8 +123,8 @@ describe("Automation Scenarios", () => {
},
})
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.createRow(
{
row: {
@ -156,7 +153,7 @@ describe("Automation Scenarios", () => {
},
{ stepName: "QueryRowsStep" }
)
.run()
.test({ fields: {} })
expect(results.steps).toHaveLength(3)
@ -195,8 +192,8 @@ describe("Automation Scenarios", () => {
}
await config.api.row.save(table._id!, row)
await config.api.row.save(table._id!, row)
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.queryRows(
{
tableId: table._id!,
@ -210,7 +207,7 @@ describe("Automation Scenarios", () => {
.queryRows({
tableId: table._id!,
})
.run()
.test({ fields: {} })
expect(results.steps).toHaveLength(3)
expect(results.steps[1].outputs.success).toBeTruthy()
@ -245,8 +242,8 @@ describe("Automation Scenarios", () => {
})
it("should stop an automation if the condition is not met", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.createRow({
row: {
name: "Equal Test",
@ -263,7 +260,7 @@ describe("Automation Scenarios", () => {
value: 20,
})
.serverLog({ text: "Equal condition met" })
.run()
.test({ fields: {} })
expect(results.steps[2].outputs.success).toBeTrue()
expect(results.steps[2].outputs.result).toBeFalse()
@ -271,8 +268,8 @@ describe("Automation Scenarios", () => {
})
it("should continue the automation if the condition is met", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.createRow({
row: {
name: "Not Equal Test",
@ -289,7 +286,7 @@ describe("Automation Scenarios", () => {
value: 20,
})
.serverLog({ text: "Not Equal condition met" })
.run()
.test({ fields: {} })
expect(results.steps[2].outputs.success).toBeTrue()
expect(results.steps[2].outputs.result).toBeTrue()
@ -338,8 +335,8 @@ describe("Automation Scenarios", () => {
it.each(testCases)(
"should pass the filter when condition is $condition",
async ({ condition, value, rowValue, expectPass }) => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.createRow({
row: {
name: `${condition} Test`,
@ -358,7 +355,7 @@ describe("Automation Scenarios", () => {
.serverLog({
text: `${condition} condition ${expectPass ? "passed" : "failed"}`,
})
.run()
.test({ fields: {} })
expect(results.steps[2].outputs.result).toBe(expectPass)
if (expectPass) {
@ -373,25 +370,22 @@ describe("Automation Scenarios", () => {
it("Check user is passed through from row trigger", async () => {
const table = await config.api.table.save(basicTable())
const results = await createAutomationBuilder({ config })
.rowUpdated(
{ tableId: table._id! },
{
row: { name: "Test", description: "TEST" },
id: "1234",
}
)
const results = await createAutomationBuilder(config)
.onRowUpdated({ tableId: table._id! })
.serverLog({ text: "{{ [user].[email] }}" })
.run()
.test({
row: { name: "Test", description: "TEST" },
id: "1234",
})
expect(results.steps[0].outputs.message).toContain("example.com")
})
it("Check user is passed through from app trigger", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.serverLog({ text: "{{ [user].[email] }}" })
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.message).toContain("example.com")
})
@ -460,10 +454,8 @@ if (descriptions.length) {
queryVerb: "read",
})
const results = await createAutomationBuilder({ config })
.appAction({
fields: {},
})
const results = await createAutomationBuilder(config)
.onAppAction()
.executeQuery({
query: {
queryId: query._id!,
@ -483,7 +475,7 @@ if (descriptions.length) {
.queryRows({
tableId: newTable._id!,
})
.run()
.test({ fields: {} })
expect(results.steps).toHaveLength(3)

View File

@ -24,8 +24,8 @@ describe("Execute Bash Automations", () => {
})
it("should use trigger data in bash command and pass output to subsequent steps", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: { command: "hello world" } })
const result = await createAutomationBuilder(config)
.onAppAction()
.bash(
{ code: "echo '{{ trigger.fields.command }}'" },
{ stepName: "Echo Command" }
@ -34,7 +34,7 @@ describe("Execute Bash Automations", () => {
{ text: "Bash output was: {{ steps.[Echo Command].stdout }}" },
{ stepName: "Log Output" }
)
.run()
.test({ fields: { command: "hello world" } })
expect(result.steps[0].outputs.stdout).toEqual("hello world\n")
expect(result.steps[1].outputs.message).toContain(
@ -43,8 +43,8 @@ describe("Execute Bash Automations", () => {
})
it("should chain multiple bash commands using previous outputs", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: { filename: "testfile.txt" } })
const result = await createAutomationBuilder(config)
.onAppAction()
.bash(
{ code: "echo 'initial content' > {{ trigger.fields.filename }}" },
{ stepName: "Create File" }
@ -57,15 +57,15 @@ describe("Execute Bash Automations", () => {
{ code: "rm {{ trigger.fields.filename }}" },
{ stepName: "Cleanup" }
)
.run()
.test({ fields: { filename: "testfile.txt" } })
expect(result.steps[1].outputs.stdout).toEqual("INITIAL CONTENT\n")
expect(result.steps[1].outputs.success).toEqual(true)
})
it("should integrate bash output with row operations", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.queryRows(
{
tableId: table._id!,
@ -83,7 +83,7 @@ describe("Execute Bash Automations", () => {
{ text: "{{ steps.[Process Row Data].stdout }}" },
{ stepName: "Log Result" }
)
.run()
.test({ fields: {} })
expect(result.steps[1].outputs.stdout).toContain(
"Row data: test row - test description"
@ -94,8 +94,8 @@ describe("Execute Bash Automations", () => {
})
it("should handle bash output in conditional logic", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: { threshold: "5" } })
const result = await createAutomationBuilder(config)
.onAppAction()
.bash(
{ code: "echo $(( {{ trigger.fields.threshold }} + 5 ))" },
{ stepName: "Calculate Value" }
@ -113,7 +113,7 @@ describe("Execute Bash Automations", () => {
{ text: "Value was {{ steps.[Check Value].value }}" },
{ stepName: "Log Result" }
)
.run()
.test({ fields: { threshold: "5" } })
expect(result.steps[0].outputs.stdout).toEqual("10\n")
expect(result.steps[1].outputs.value).toEqual("high")
@ -121,14 +121,14 @@ describe("Execute Bash Automations", () => {
})
it("should handle null values gracefully", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.bash(
// @ts-expect-error - testing null input
{ code: null },
{ stepName: "Null Command" }
)
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.stdout).toBe(
"Budibase bash automation failed: Invalid inputs"

View File

@ -40,15 +40,15 @@ describe("test the create row action", () => {
})
it("should be able to run the action", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: { status: "new" } })
const result = await createAutomationBuilder(config)
.onAppAction()
.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()
.test({ fields: { status: "new" } })
expect(result.steps[1].outputs.success).toBeDefined()
expect(result.steps[1].outputs.id).toBeDefined()
@ -66,8 +66,8 @@ describe("test the create row action", () => {
})
it("should return an error (not throw) when bad info provided", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: { status: "error" } })
const result = await createAutomationBuilder(config)
.onAppAction()
.serverLog({ text: "Starting error test flow" }, { stepName: "StartLog" })
.createRow(
{
@ -78,14 +78,14 @@ describe("test the create row action", () => {
},
{ stepName: "CreateRow" }
)
.run()
.test({ fields: { status: "error" } })
expect(result.steps[1].outputs.success).toEqual(false)
})
it("should check invalid inputs return an error", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: { status: "invalid" } })
const result = await createAutomationBuilder(config)
.onAppAction()
.serverLog({ text: "Testing invalid input" }, { stepName: "StartLog" })
.createRow({ row: {} }, { stepName: "CreateRow" })
.filter({
@ -97,7 +97,7 @@ describe("test the create row action", () => {
{ text: "This log should not appear" },
{ stepName: "SkippedLog" }
)
.run()
.test({ fields: { status: "invalid" } })
expect(result.steps[1].outputs.success).toEqual(false)
expect(result.steps.length).toBeLessThan(4)
@ -122,8 +122,8 @@ describe("test the create row action", () => {
]
attachmentRow.file_attachment = attachmentObject
const result = await createAutomationBuilder({ config })
.appAction({ fields: { type: "attachment" } })
const result = await createAutomationBuilder(config)
.onAppAction()
.serverLog(
{ text: "Processing attachment upload" },
{ stepName: "StartLog" }
@ -140,7 +140,7 @@ describe("test the create row action", () => {
},
{ stepName: "UploadLog" }
)
.run()
.test({ fields: { type: "attachment" } })
expect(result.steps[1].outputs.success).toEqual(true)
expect(result.steps[1].outputs.row.file_attachment[0]).toHaveProperty("key")
@ -173,8 +173,8 @@ describe("test the create row action", () => {
}
attachmentRow.single_file_attachment = attachmentObject
const result = await createAutomationBuilder({ config })
.appAction({ fields: { type: "single-attachment" } })
const result = await createAutomationBuilder(config)
.onAppAction()
.serverLog(
{ text: "Processing single attachment" },
{ stepName: "StartLog" }
@ -209,7 +209,7 @@ describe("test the create row action", () => {
},
},
})
.run()
.test({ fields: { type: "single-attachment" } })
expect(result.steps[1].outputs.success).toEqual(true)
expect(result.steps[1].outputs.row.single_file_attachment).toHaveProperty(
@ -244,8 +244,8 @@ describe("test the create row action", () => {
}
attachmentRow.single_file_attachment = attachmentObject
const result = await createAutomationBuilder({ config })
.appAction({ fields: { type: "invalid-attachment" } })
const result = await createAutomationBuilder(config)
.onAppAction()
.serverLog(
{ text: "Testing invalid attachment keys" },
{ stepName: "StartLog" }
@ -278,7 +278,7 @@ describe("test the create row action", () => {
},
},
})
.run()
.test({ fields: { type: "invalid-attachment" } })
expect(result.steps[1].outputs.success).toEqual(false)
expect(result.steps[1].outputs.response).toEqual(

View File

@ -27,7 +27,7 @@ describe("cron automations", () => {
})
it("should initialise the automation timestamp", async () => {
await createAutomationBuilder({ config }).cron({ cron: "* * * * *" }).save()
await createAutomationBuilder(config).onCron({ cron: "* * * * *" }).save()
tk.travel(Date.now() + oneMinuteInMs)
await config.publish()

View File

@ -16,10 +16,10 @@ describe("test the delay logic", () => {
const time = 100
const before = performance.now()
await createAutomationBuilder({ config })
.appAction({ fields: {} })
await createAutomationBuilder(config)
.onAppAction()
.delay({ time })
.run()
.test({ fields: {} })
const now = performance.now()

View File

@ -20,14 +20,14 @@ describe("test the delete row action", () => {
})
it("should be able to run the delete row action", async () => {
await createAutomationBuilder({ config })
.appAction({ fields: {} })
await createAutomationBuilder(config)
.onAppAction()
.deleteRow({
tableId: table._id!,
id: row._id!,
revision: row._rev,
})
.run()
.test({ fields: {} })
await config.api.row.get(table._id!, row._id!, {
status: 404,
@ -35,23 +35,23 @@ describe("test the delete row action", () => {
})
it("should check invalid inputs return an error", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.deleteRow({ tableId: "", id: "", revision: "" })
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.success).toEqual(false)
})
it("should return an error when table doesn't exist", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.deleteRow({
tableId: "invalid",
id: "invalid",
revision: "invalid",
})
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.success).toEqual(false)
})

View File

@ -19,14 +19,14 @@ describe("test the outgoing webhook action", () => {
it("should be able to run the action", async () => {
nock("http://www.example.com/").post("/").reply(200, { foo: "bar" })
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.discord({
url: "http://www.example.com",
username: "joe_bloggs",
content: "Hello, world",
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.response.foo).toEqual("bar")
expect(result.steps[0].outputs.success).toEqual(true)
})

View File

@ -20,33 +20,33 @@ describe("Execute Script Automations", () => {
})
it("should execute a basic script and return the result", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.executeScript({ code: "return 2 + 2" })
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.value).toEqual(4)
})
it("should access bindings from previous steps", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: { data: [1, 2, 3] } })
const results = await createAutomationBuilder(config)
.onAppAction()
.executeScript(
{
code: "return trigger.fields.data.map(x => x * 2)",
},
{ stepId: "binding-script-step" }
)
.run()
.test({ fields: { data: [1, 2, 3] } })
expect(results.steps[0].outputs.value).toEqual([2, 4, 6])
})
it("should handle script execution errors gracefully", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.executeScript({ code: "return nonexistentVariable.map(x => x)" })
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.response).toContain(
"ReferenceError: nonexistentVariable is not defined"
@ -55,8 +55,8 @@ describe("Execute Script Automations", () => {
})
it("should handle conditional logic in scripts", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: { value: 10 } })
const results = await createAutomationBuilder(config)
.onAppAction()
.executeScript({
code: `
if (trigger.fields.value > 5) {
@ -66,14 +66,14 @@ describe("Execute Script Automations", () => {
}
`,
})
.run()
.test({ fields: { value: 10 } })
expect(results.steps[0].outputs.value).toEqual("Value is greater than 5")
})
it("should use multiple steps and validate script execution", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.serverLog(
{ text: "Starting multi-step automation" },
{ stepId: "start-log-step" }
@ -94,7 +94,7 @@ describe("Execute Script Automations", () => {
.serverLog({
text: `Final result is {{ steps.ScriptingStep1.value }}`,
})
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.message).toContain(
"Starting multi-step automation"

View File

@ -42,10 +42,10 @@ describe("test the filter logic", () => {
[new Date().toISOString(), ">", new Date(-10000).toISOString()],
]
it.each(pass)("should pass %p %p %p", async (field, condition, value) => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.filter({ field, condition: stringToFilterCondition(condition), value })
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.result).toEqual(true)
expect(result.steps[0].outputs.success).toEqual(true)
@ -60,10 +60,10 @@ describe("test the filter logic", () => {
[{}, "==", {}],
]
it.each(fail)("should fail %p %p %p", async (field, condition, value) => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.filter({ field, condition: stringToFilterCondition(condition), value })
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.result).toEqual(false)
expect(result.steps[0].outputs.success).toEqual(true)

View File

@ -72,18 +72,8 @@ describe("Attempt to run a basic loop automation", () => {
})
it("should run an automation with a trigger, loop, and create row step", async () => {
const results = await createAutomationBuilder({ config })
.rowSaved(
{ tableId: table._id! },
{
row: {
name: "Trigger Row",
description: "This row triggers the automation",
},
id: "1234",
revision: "1",
}
)
const results = await createAutomationBuilder(config)
.onRowSaved({ tableId: table._id! })
.loop({
option: LoopStepType.ARRAY,
binding: [1, 2, 3],
@ -95,7 +85,14 @@ describe("Attempt to run a basic loop automation", () => {
tableId: table._id,
},
})
.run()
.test({
row: {
name: "Trigger Row",
description: "This row triggers the automation",
},
id: "1234",
revision: "1",
})
expect(results.trigger).toBeDefined()
expect(results.steps).toHaveLength(1)
@ -115,18 +112,8 @@ describe("Attempt to run a basic loop automation", () => {
})
it("should run an automation where a loop step is between two normal steps to ensure context correctness", async () => {
const results = await createAutomationBuilder({ config })
.rowSaved(
{ tableId: table._id! },
{
row: {
name: "Trigger Row",
description: "This row triggers the automation",
},
id: "1234",
revision: "1",
}
)
const results = await createAutomationBuilder(config)
.onRowSaved({ tableId: table._id! })
.queryRows({
tableId: table._id!,
})
@ -136,7 +123,14 @@ describe("Attempt to run a basic loop automation", () => {
})
.serverLog({ text: "Message {{loop.currentItem}}" })
.serverLog({ text: "{{steps.1.rows.0._id}}" })
.run()
.test({
row: {
name: "Trigger Row",
description: "This row triggers the automation",
},
id: "1234",
revision: "1",
})
results.steps[1].outputs.items.forEach(
(output: ServerLogStepOutputs, index: number) => {
@ -151,14 +145,14 @@ describe("Attempt to run a basic loop automation", () => {
})
it("if an incorrect type is passed to the loop it should return an error", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.loop({
option: LoopStepType.ARRAY,
binding: "1, 2, 3",
})
.serverLog({ text: "Message {{loop.currentItem}}" })
.run()
.test({ fields: {} })
expect(results.steps[0].outputs).toEqual({
success: false,
@ -167,15 +161,15 @@ describe("Attempt to run a basic loop automation", () => {
})
it("ensure the loop stops if the failure condition is reached", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.loop({
option: LoopStepType.ARRAY,
binding: ["test", "test2", "test3"],
failure: "test2",
})
.serverLog({ text: "Message {{loop.currentItem}}" })
.run()
.test({ fields: {} })
expect(results.steps[0].outputs).toEqual(
expect.objectContaining({
@ -186,8 +180,8 @@ describe("Attempt to run a basic loop automation", () => {
})
it("ensure the loop stops if the max iterations are reached", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.loop({
option: LoopStepType.ARRAY,
binding: ["test", "test2", "test3"],
@ -195,14 +189,14 @@ describe("Attempt to run a basic loop automation", () => {
})
.serverLog({ text: "{{loop.currentItem}}" })
.serverLog({ text: "{{steps.1.iterations}}" })
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.iterations).toBe(2)
})
it("should run an automation with loop and max iterations to ensure context correctness further down the tree", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.loop({
option: LoopStepType.ARRAY,
binding: ["test", "test2", "test3"],
@ -210,24 +204,14 @@ describe("Attempt to run a basic loop automation", () => {
})
.serverLog({ text: "{{loop.currentItem}}" })
.serverLog({ text: "{{steps.1.iterations}}" })
.run()
.test({ fields: {} })
expect(results.steps[1].outputs.message).toContain("- 2")
})
it("should run an automation where a loop is successfully run twice", async () => {
const results = await createAutomationBuilder({ config })
.rowSaved(
{ tableId: table._id! },
{
row: {
name: "Trigger Row",
description: "This row triggers the automation",
},
id: "1234",
revision: "1",
}
)
const results = await createAutomationBuilder(config)
.onRowSaved({ tableId: table._id! })
.loop({
option: LoopStepType.ARRAY,
binding: [1, 2, 3],
@ -244,7 +228,14 @@ describe("Attempt to run a basic loop automation", () => {
binding: "Message 1,Message 2,Message 3",
})
.serverLog({ text: "{{loop.currentItem}}" })
.run()
.test({
row: {
name: "Trigger Row",
description: "This row triggers the automation",
},
id: "1234",
revision: "1",
})
expect(results.trigger).toBeDefined()
expect(results.steps).toHaveLength(2)
@ -278,8 +269,8 @@ describe("Attempt to run a basic loop automation", () => {
})
it("should run an automation where a loop is used twice to ensure context correctness further down the tree", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.loop({
option: LoopStepType.ARRAY,
binding: [1, 2, 3],
@ -292,7 +283,7 @@ describe("Attempt to run a basic loop automation", () => {
})
.serverLog({ text: "{{loop.currentItem}}" })
.serverLog({ text: "{{steps.3.iterations}}" })
.run()
.test({ fields: {} })
// We want to ensure that bindings are corr
expect(results.steps[1].outputs.message).toContain("- 3")
@ -300,8 +291,8 @@ describe("Attempt to run a basic loop automation", () => {
})
it("should use automation names to loop with", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.loop(
{
option: LoopStepType.ARRAY,
@ -317,7 +308,7 @@ describe("Attempt to run a basic loop automation", () => {
{ text: "{{steps.FirstLoopLog.iterations}}" },
{ stepName: "FirstLoopIterationLog" }
)
.run()
.test({ fields: {} })
expect(results.steps[1].outputs.message).toContain("- 3")
})
@ -352,8 +343,8 @@ describe("Attempt to run a basic loop automation", () => {
await config.api.row.bulkImport(table._id!, { rows })
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.queryRows({
tableId: table._id!,
})
@ -373,7 +364,7 @@ describe("Attempt to run a basic loop automation", () => {
.queryRows({
tableId: table._id!,
})
.run()
.test({ fields: {} })
const expectedRows = [
{ name: "Updated Row 1", value: 1 },
@ -432,8 +423,8 @@ describe("Attempt to run a basic loop automation", () => {
await config.api.row.bulkImport(table._id!, { rows })
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.queryRows(
{
tableId: table._id!,
@ -456,7 +447,7 @@ describe("Attempt to run a basic loop automation", () => {
.queryRows({
tableId: table._id!,
})
.run()
.test({ fields: {} })
const expectedRows = [
{ name: "Updated Row 1", value: 1 },
@ -515,8 +506,8 @@ describe("Attempt to run a basic loop automation", () => {
await config.api.row.bulkImport(table._id!, { rows })
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.queryRows({
tableId: table._id!,
})
@ -531,7 +522,7 @@ describe("Attempt to run a basic loop automation", () => {
.queryRows({
tableId: table._id!,
})
.run()
.test({ fields: {} })
expect(results.steps).toHaveLength(3)

View File

@ -19,13 +19,13 @@ describe("test the outgoing webhook action", () => {
it("should be able to run the action", async () => {
nock("http://www.example.com/").post("/").reply(200, { foo: "bar" })
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.make({
url: "http://www.example.com",
body: null,
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.response.foo).toEqual("bar")
expect(result.steps[0].outputs.success).toEqual(true)
@ -46,26 +46,26 @@ describe("test the outgoing webhook action", () => {
.post("/", payload)
.reply(200, { foo: "bar" })
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.make({
body: { value: JSON.stringify(payload) },
url: "http://www.example.com",
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.response.foo).toEqual("bar")
expect(result.steps[0].outputs.success).toEqual(true)
})
it("should return a 400 if the JSON payload string is malformed", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.make({
body: { value: "{ invalid json }" },
url: "http://www.example.com",
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.httpStatus).toEqual(400)
expect(result.steps[0].outputs.response).toEqual("Invalid payload JSON")

View File

@ -20,14 +20,14 @@ describe("test the outgoing webhook action", () => {
it("should be able to run the action and default to 'get'", async () => {
nock("http://www.example.com/").get("/").reply(200, { foo: "bar" })
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.n8n({
url: "http://www.example.com",
body: { test: "IGNORE_ME" },
authorization: "",
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.response).toEqual({ foo: "bar" })
expect(result.steps[0].outputs.httpStatus).toEqual(200)
@ -39,29 +39,29 @@ describe("test the outgoing webhook action", () => {
.post("/", { name: "Adam", age: 9 })
.reply(200)
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.n8n({
url: "http://www.example.com",
body: { value: JSON.stringify({ name: "Adam", age: 9 }) },
method: HttpMethod.POST,
authorization: "",
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toEqual(true)
})
it("should return a 400 if the JSON payload string is malformed", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.n8n({
url: "http://www.example.com",
body: { value: "{ value1 1 }" },
method: HttpMethod.POST,
authorization: "",
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.httpStatus).toEqual(400)
expect(result.steps[0].outputs.response).toEqual("Invalid payload JSON")
@ -73,15 +73,15 @@ describe("test the outgoing webhook action", () => {
.head("/", body => body === "")
.reply(200)
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.n8n({
url: "http://www.example.com",
method: HttpMethod.HEAD,
body: { test: "IGNORE_ME" },
authorization: "",
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toEqual(true)
})

View File

@ -57,10 +57,10 @@ describe("test the openai action", () => {
// means it goes through the "legacy" path which requires you to set your
// own API key. We don't count this against your quota.
const result = await expectAIUsage(0, () =>
createAutomationBuilder({ config })
.appAction({ fields: {} })
createAutomationBuilder(config)
.onAppAction()
.openai({ prompt: "Hello, world", model: Model.GPT_4O_MINI })
.run()
.test({ fields: {} })
)
expect(result.steps[0].outputs.response).toEqual("This is a test")
@ -69,10 +69,10 @@ describe("test the openai action", () => {
it("should present the correct error message when a prompt is not provided", async () => {
const result = await expectAIUsage(0, () =>
createAutomationBuilder({ config })
.appAction({ fields: {} })
createAutomationBuilder(config)
.onAppAction()
.openai({ prompt: "", model: Model.GPT_4O_MINI })
.run()
.test({ fields: {} })
)
expect(result.steps[0].outputs.response).toEqual(
@ -85,10 +85,10 @@ describe("test the openai action", () => {
mockChatGPTError()
const result = await expectAIUsage(0, () =>
createAutomationBuilder({ config })
.appAction({ fields: {} })
createAutomationBuilder(config)
.onAppAction()
.openai({ prompt: "Hello, world", model: Model.GPT_4O_MINI })
.run()
.test({ fields: {} })
)
expect(result.steps[0].outputs.response).toEqual(
@ -108,10 +108,10 @@ describe("test the openai action", () => {
// calculation we use to approximate cost. This uses Budibase's OpenAI API
// key, so we charge users for it.
const result = await expectAIUsage(14, () =>
createAutomationBuilder({ config })
.appAction({ fields: {} })
createAutomationBuilder(config)
.onAppAction()
.openai({ model: Model.GPT_4O_MINI, prompt: "Hello, world" })
.run()
.test({ fields: {} })
)
expect(result.steps[0].outputs.response).toEqual("This is a test")

View File

@ -23,15 +23,15 @@ describe("test the outgoing webhook action", () => {
.post("/", { a: 1 })
.reply(200, { foo: "bar" })
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.outgoingWebhook({
requestMethod: RequestType.POST,
url: "http://www.example.com",
requestBody: JSON.stringify({ a: 1 }),
headers: {},
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toEqual(true)
expect(result.steps[0].outputs.httpStatus).toEqual(200)
@ -39,15 +39,15 @@ describe("test the outgoing webhook action", () => {
})
it("should return an error if something goes wrong in fetch", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.outgoingWebhook({
requestMethod: RequestType.GET,
url: "www.invalid.com",
requestBody: "",
headers: {},
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toEqual(false)
})
})

View File

@ -28,11 +28,8 @@ describe("Test a query step automation", () => {
})
it("should be able to run the query step", async () => {
const result = await createAutomationBuilder({
name: "Basic Query Test",
config,
})
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.queryRows(
{
tableId: table._id!,
@ -47,7 +44,7 @@ describe("Test a query step automation", () => {
},
{ stepName: "Query All Rows" }
)
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toBe(true)
expect(result.steps[0].outputs.rows).toBeDefined()
@ -56,11 +53,8 @@ describe("Test a query step automation", () => {
})
it("Returns all rows when onEmptyFilter has no value and no filters are passed", async () => {
const result = await createAutomationBuilder({
name: "Empty Filter Test",
config,
})
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.queryRows(
{
tableId: table._id!,
@ -71,7 +65,7 @@ describe("Test a query step automation", () => {
},
{ stepName: "Query With Empty Filter" }
)
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toBe(true)
expect(result.steps[0].outputs.rows).toBeDefined()
@ -80,11 +74,8 @@ describe("Test a query step automation", () => {
})
it("Returns no rows when onEmptyFilter is RETURN_NONE and theres no filters", async () => {
const result = await createAutomationBuilder({
name: "Return None Test",
config,
})
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.queryRows(
{
tableId: table._id!,
@ -97,7 +88,7 @@ describe("Test a query step automation", () => {
},
{ stepName: "Query With Return None" }
)
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toBe(true)
expect(result.steps[0].outputs.rows).toBeDefined()
@ -105,11 +96,8 @@ describe("Test a query step automation", () => {
})
it("Returns no rows when onEmptyFilters RETURN_NONE and a filter is passed with a null value", async () => {
const result = await createAutomationBuilder({
name: "Null Filter Test",
config,
})
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.queryRows(
{
tableId: table._id!,
@ -126,7 +114,7 @@ describe("Test a query step automation", () => {
},
{ stepName: "Query With Null Filter" }
)
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toBe(true)
expect(result.steps[0].outputs.rows).toBeDefined()
@ -134,11 +122,8 @@ describe("Test a query step automation", () => {
})
it("Returns rows when onEmptyFilter is RETURN_ALL and no filter is passed", async () => {
const result = await createAutomationBuilder({
name: "Return All Test",
config,
})
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.queryRows(
{
tableId: table._id!,
@ -150,7 +135,7 @@ describe("Test a query step automation", () => {
},
{ stepName: "Query With Return All" }
)
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toBe(true)
expect(result.steps[0].outputs.rows).toBeDefined()
@ -165,11 +150,8 @@ describe("Test a query step automation", () => {
await config.api.row.save(tableWithSpaces._id!, {
name: NAME,
})
const result = await createAutomationBuilder({
name: "Return All Test",
config,
})
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.queryRows(
{
tableId: tableWithSpaces._id!,
@ -178,7 +160,7 @@ describe("Test a query step automation", () => {
},
{ stepName: "Query table with spaces" }
)
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toBe(true)
expect(result.steps[0].outputs.rows).toBeDefined()
expect(result.steps[0].outputs.rows.length).toBe(1)

View File

@ -13,10 +13,10 @@ describe("test the server log action", () => {
})
it("should be able to log the text", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.serverLog({ text: "Hello World" })
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.message).toEqual(
`App ${config.getAppId()} - Hello World`
)

View File

@ -17,27 +17,27 @@ describe("Test triggering an automation from another automation", () => {
})
it("should trigger an other server log automation", async () => {
const automation = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const { automation } = await createAutomationBuilder(config)
.onAppAction()
.serverLog({ text: "Hello World" })
.save()
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.triggerAutomationRun({
automation: {
automationId: automation._id!,
},
timeout: env.getDefaults().AUTOMATION_THREAD_TIMEOUT,
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toBe(true)
})
it("should fail gracefully if the automation id is incorrect", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.triggerAutomationRun({
automation: {
// @ts-expect-error - incorrect on purpose
@ -45,7 +45,7 @@ describe("Test triggering an automation from another automation", () => {
},
timeout: env.getDefaults().AUTOMATION_THREAD_TIMEOUT,
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toBe(false)
})

View File

@ -30,8 +30,8 @@ describe("test the update row action", () => {
})
it("should be able to run the update row action", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.updateRow({
rowId: row._id!,
row: {
@ -41,7 +41,7 @@ describe("test the update row action", () => {
},
meta: {},
})
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.success).toEqual(true)
const updatedRow = await config.api.row.get(
@ -53,23 +53,23 @@ describe("test the update row action", () => {
})
it("should check invalid inputs return an error", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.updateRow({ meta: {}, row: {}, rowId: "" })
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.success).toEqual(false)
})
it("should return an error when table doesn't exist", async () => {
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.updateRow({
row: { _id: "invalid" },
rowId: "invalid",
meta: {},
})
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.success).toEqual(false)
})
@ -106,8 +106,8 @@ describe("test the update row action", () => {
user2: [{ _id: user2._id }],
})
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.updateRow({
rowId: row._id!,
row: {
@ -119,7 +119,7 @@ describe("test the update row action", () => {
},
meta: {},
})
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.success).toEqual(true)
@ -160,8 +160,8 @@ describe("test the update row action", () => {
user2: [{ _id: user2._id }],
})
const results = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const results = await createAutomationBuilder(config)
.onAppAction()
.updateRow({
rowId: row._id!,
row: {
@ -179,7 +179,7 @@ describe("test the update row action", () => {
},
},
})
.run()
.test({ fields: {} })
expect(results.steps[0].outputs.success).toEqual(true)

View File

@ -20,10 +20,10 @@ describe("test the outgoing webhook action", () => {
it("should be able to run the action", async () => {
nock("http://www.example.com/").post("/").reply(200, { foo: "bar" })
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.zapier({ url: "http://www.example.com", body: null })
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.response.foo).toEqual("bar")
expect(result.steps[0].outputs.success).toEqual(true)
@ -44,26 +44,26 @@ describe("test the outgoing webhook action", () => {
.post("/", { ...payload, platform: "budibase" })
.reply(200, { foo: "bar" })
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.zapier({
url: "http://www.example.com",
body: { value: JSON.stringify(payload) },
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.response.foo).toEqual("bar")
expect(result.steps[0].outputs.success).toEqual(true)
})
it("should return a 400 if the JSON payload string is malformed", async () => {
const result = await createAutomationBuilder({ config })
.appAction({ fields: {} })
const result = await createAutomationBuilder(config)
.onAppAction()
.zapier({
url: "http://www.example.com",
body: { value: "{ invalid json }" },
})
.run()
.test({ fields: {} })
expect(result.steps[0].outputs.success).toEqual(false)
expect(result.steps[0].outputs.response).toEqual("Invalid payload JSON")

View File

@ -6,7 +6,7 @@ import { Job } from "bull"
describe("cron trigger", () => {
const config = new TestConfiguration()
beforeEach(async () => {
beforeAll(async () => {
await config.init()
})
@ -24,8 +24,8 @@ describe("cron trigger", () => {
})
})
await createAutomationBuilder({ config })
.cron({ cron: "* * * * *" })
await createAutomationBuilder(config)
.onCron({ cron: "* * * * *" })
.serverLog({
text: "Hello, world!",
})
@ -44,8 +44,8 @@ describe("cron trigger", () => {
})
it("should fail if the cron expression is invalid", async () => {
await createAutomationBuilder({ config })
.cron({ cron: "* * * * * *" })
await createAutomationBuilder(config)
.onCron({ cron: "* * * * * *" })
.serverLog({
text: "Hello, world!",
})

View File

@ -1,4 +1,3 @@
import * as automation from "../../index"
import { Table, Webhook, WebhookActionType } from "@budibase/types"
import { createAutomationBuilder } from "../utilities/AutomationTestBuilder"
import { mocks } from "@budibase/backend-core/tests"
@ -12,8 +11,8 @@ describe("Branching automations", () => {
let webhook: Webhook
async function createWebhookAutomation() {
const automation = await createAutomationBuilder({ config })
.webhook({ body: { parameter: "string" } })
const { automation } = await createAutomationBuilder(config)
.onWebhook({ body: { parameter: "string" } })
.createRow({
row: { tableId: table._id!, name: "{{ trigger.parameter }}" },
})
@ -37,7 +36,6 @@ describe("Branching automations", () => {
}
beforeEach(async () => {
await automation.init()
await config.init()
table = await config.createTable()
})

View File

@ -2,8 +2,6 @@ import { v4 as uuidv4 } from "uuid"
import { BUILTIN_ACTION_DEFINITIONS } from "../../actions"
import { TRIGGER_DEFINITIONS } from "../../triggers"
import {
AppActionTriggerInputs,
AppActionTriggerOutputs,
Automation,
AutomationActionStepId,
AutomationResults,
@ -12,57 +10,19 @@ import {
AutomationTrigger,
AutomationTriggerDefinition,
AutomationTriggerInputs,
AutomationTriggerOutputs,
AutomationTriggerStepId,
BashStepInputs,
Branch,
BranchStepInputs,
CollectStepInputs,
CreateRowStepInputs,
CronTriggerInputs,
CronTriggerOutputs,
DelayStepInputs,
DeleteRowStepInputs,
DiscordStepInputs,
ExecuteQueryStepInputs,
ExecuteScriptStepInputs,
FilterStepInputs,
isDidNotTriggerResponse,
LoopStepInputs,
MakeIntegrationInputs,
n8nStepInputs,
OpenAIStepInputs,
OutgoingWebhookStepInputs,
QueryRowsStepInputs,
RowCreatedTriggerInputs,
RowCreatedTriggerOutputs,
RowDeletedTriggerInputs,
RowDeletedTriggerOutputs,
RowUpdatedTriggerInputs,
RowUpdatedTriggerOutputs,
SearchFilters,
ServerLogStepInputs,
SmtpEmailStepInputs,
TestAutomationRequest,
TriggerAutomationStepInputs,
UpdateRowStepInputs,
WebhookTriggerInputs,
WebhookTriggerOutputs,
ZapierStepInputs,
} from "@budibase/types"
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
import * as setup from "../utilities"
import { automations } from "@budibase/shared-core"
type TriggerOutputs =
| RowCreatedTriggerOutputs
| RowUpdatedTriggerOutputs
| RowDeletedTriggerOutputs
| AppActionTriggerOutputs
| WebhookTriggerOutputs
| CronTriggerOutputs
| undefined
type StepBuilderFunction = (stepBuilder: StepBuilder) => void
type StepBuilderFunction = <TStep extends AutomationTriggerStepId>(
stepBuilder: BranchStepBuilder<TStep>
) => void
type BranchConfig = {
[key: string]: {
@ -71,311 +31,108 @@ type BranchConfig = {
}
}
class BaseStepBuilder {
protected steps: AutomationStep[] = []
protected stepNames: { [key: string]: string } = {}
class TriggerBuilder {
private readonly config: TestConfiguration
protected step<TStep extends AutomationActionStepId>(
stepId: TStep,
stepSchema: Omit<AutomationStep, "id" | "stepId" | "inputs">,
inputs: AutomationStepInputs<TStep>,
opts?: { stepName?: string; stepId?: string }
): this {
const id = opts?.stepId || uuidv4()
this.steps.push({
...stepSchema,
inputs: inputs as any,
id,
stepId,
name: opts?.stepName || stepSchema.name,
})
if (opts?.stepName) {
this.stepNames[id] = opts.stepName
}
return this
constructor(config: TestConfiguration) {
this.config = config
}
protected trigger<
TStep extends AutomationTriggerStepId,
TInput = AutomationTriggerInputs<TStep>
>(stepId: TStep) {
return (inputs: TInput) => {
const definition: AutomationTriggerDefinition =
TRIGGER_DEFINITIONS[stepId]
const trigger: AutomationTrigger = {
...definition,
stepId,
inputs: (inputs || {}) as any,
id: uuidv4(),
}
return new StepBuilder<TStep>(this.config, trigger)
}
}
onAppAction = this.trigger(AutomationTriggerStepId.APP)
onRowSaved = this.trigger(AutomationTriggerStepId.ROW_SAVED)
onRowUpdated = this.trigger(AutomationTriggerStepId.ROW_UPDATED)
onRowDeleted = this.trigger(AutomationTriggerStepId.ROW_DELETED)
onWebhook = this.trigger(AutomationTriggerStepId.WEBHOOK)
onCron = this.trigger(AutomationTriggerStepId.CRON)
}
class BranchStepBuilder<TStep extends AutomationTriggerStepId> {
protected readonly steps: AutomationStep[] = []
protected readonly stepNames: { [key: string]: string } = {}
protected step<TStep extends AutomationActionStepId>(stepId: TStep) {
return (
inputs: AutomationStepInputs<TStep>,
opts?: { stepName?: string; stepId?: string }
) => {
const schema = BUILTIN_ACTION_DEFINITIONS[stepId]
const id = opts?.stepId || uuidv4()
this.steps.push({
...schema,
inputs: inputs as any,
id,
stepId,
name: opts?.stepName || schema.name,
})
if (opts?.stepName) {
this.stepNames[id] = opts.stepName
}
return this
}
}
createRow = this.step(AutomationActionStepId.CREATE_ROW)
updateRow = this.step(AutomationActionStepId.UPDATE_ROW)
deleteRow = this.step(AutomationActionStepId.DELETE_ROW)
sendSmtpEmail = this.step(AutomationActionStepId.SEND_EMAIL_SMTP)
executeQuery = this.step(AutomationActionStepId.EXECUTE_QUERY)
queryRows = this.step(AutomationActionStepId.QUERY_ROWS)
loop = this.step(AutomationActionStepId.LOOP)
serverLog = this.step(AutomationActionStepId.SERVER_LOG)
executeScript = this.step(AutomationActionStepId.EXECUTE_SCRIPT)
executeScriptV2 = this.step(AutomationActionStepId.EXECUTE_SCRIPT_V2)
filter = this.step(AutomationActionStepId.FILTER)
bash = this.step(AutomationActionStepId.EXECUTE_BASH)
openai = this.step(AutomationActionStepId.OPENAI)
collect = this.step(AutomationActionStepId.COLLECT)
zapier = this.step(AutomationActionStepId.zapier)
triggerAutomationRun = this.step(
AutomationActionStepId.TRIGGER_AUTOMATION_RUN
)
outgoingWebhook = this.step(AutomationActionStepId.OUTGOING_WEBHOOK)
n8n = this.step(AutomationActionStepId.n8n)
make = this.step(AutomationActionStepId.integromat)
discord = this.step(AutomationActionStepId.discord)
delay = this.step(AutomationActionStepId.DELAY)
protected addBranchStep(branchConfig: BranchConfig): void {
const branchStepInputs: BranchStepInputs = {
branches: [] as Branch[],
const inputs: BranchStepInputs = {
branches: [],
children: {},
}
Object.entries(branchConfig).forEach(([key, branch]) => {
const stepBuilder = new StepBuilder()
branch.steps(stepBuilder)
let branchId = uuidv4()
branchStepInputs.branches.push({
name: key,
condition: branch.condition,
id: branchId,
})
branchStepInputs.children![branchId] = stepBuilder.build()
})
const branchStep: AutomationStep = {
for (const [name, branch] of Object.entries(branchConfig)) {
const builder = new BranchStepBuilder<TStep>()
branch.steps(builder)
let id = uuidv4()
inputs.branches.push({ name, condition: branch.condition, id })
inputs.children![id] = builder.steps
}
this.steps.push({
...automations.steps.branch.definition,
id: uuidv4(),
stepId: AutomationActionStepId.BRANCH,
inputs: branchStepInputs,
}
this.steps.push(branchStep)
}
// STEPS
createRow(
inputs: CreateRowStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.CREATE_ROW,
BUILTIN_ACTION_DEFINITIONS.CREATE_ROW,
inputs,
opts
)
}
updateRow(
inputs: UpdateRowStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.UPDATE_ROW,
BUILTIN_ACTION_DEFINITIONS.UPDATE_ROW,
inputs,
opts
)
}
deleteRow(
inputs: DeleteRowStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.DELETE_ROW,
BUILTIN_ACTION_DEFINITIONS.DELETE_ROW,
inputs,
opts
)
}
sendSmtpEmail(
inputs: SmtpEmailStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.SEND_EMAIL_SMTP,
BUILTIN_ACTION_DEFINITIONS.SEND_EMAIL_SMTP,
inputs,
opts
)
}
executeQuery(
inputs: ExecuteQueryStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.EXECUTE_QUERY,
BUILTIN_ACTION_DEFINITIONS.EXECUTE_QUERY,
inputs,
opts
)
}
queryRows(
inputs: QueryRowsStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.QUERY_ROWS,
BUILTIN_ACTION_DEFINITIONS.QUERY_ROWS,
inputs,
opts
)
}
loop(
inputs: LoopStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.LOOP,
BUILTIN_ACTION_DEFINITIONS.LOOP,
inputs,
opts
)
}
serverLog(
input: ServerLogStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.SERVER_LOG,
BUILTIN_ACTION_DEFINITIONS.SERVER_LOG,
input,
opts
)
}
/**
* @deprecated Use `executeScriptV2` instead
*/
executeScript(
input: ExecuteScriptStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.EXECUTE_SCRIPT,
BUILTIN_ACTION_DEFINITIONS.EXECUTE_SCRIPT,
input,
opts
)
}
executeScriptV2(
input: ExecuteScriptStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.EXECUTE_SCRIPT_V2,
BUILTIN_ACTION_DEFINITIONS.EXECUTE_SCRIPT_V2,
input,
opts
)
}
filter(input: FilterStepInputs): this {
return this.step(
AutomationActionStepId.FILTER,
BUILTIN_ACTION_DEFINITIONS.FILTER,
input
)
}
bash(
input: BashStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.EXECUTE_BASH,
BUILTIN_ACTION_DEFINITIONS.EXECUTE_BASH,
input,
opts
)
}
openai(
input: OpenAIStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.OPENAI,
BUILTIN_ACTION_DEFINITIONS.OPENAI,
input,
opts
)
}
collect(
input: CollectStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.COLLECT,
BUILTIN_ACTION_DEFINITIONS.COLLECT,
input,
opts
)
}
zapier(
input: ZapierStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.zapier,
BUILTIN_ACTION_DEFINITIONS.zapier,
input,
opts
)
}
triggerAutomationRun(
input: TriggerAutomationStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.TRIGGER_AUTOMATION_RUN,
BUILTIN_ACTION_DEFINITIONS.TRIGGER_AUTOMATION_RUN,
input,
opts
)
}
outgoingWebhook(
input: OutgoingWebhookStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.OUTGOING_WEBHOOK,
BUILTIN_ACTION_DEFINITIONS.OUTGOING_WEBHOOK,
input,
opts
)
}
n8n(
input: n8nStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.n8n,
BUILTIN_ACTION_DEFINITIONS.n8n,
input,
opts
)
}
make(
input: MakeIntegrationInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.integromat,
BUILTIN_ACTION_DEFINITIONS.integromat,
input,
opts
)
}
discord(
input: DiscordStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.discord,
BUILTIN_ACTION_DEFINITIONS.discord,
input,
opts
)
}
delay(
input: DelayStepInputs,
opts?: { stepName?: string; stepId?: string }
): this {
return this.step(
AutomationActionStepId.DELAY,
BUILTIN_ACTION_DEFINITIONS.DELAY,
input,
opts
)
}
}
class StepBuilder extends BaseStepBuilder {
build(): AutomationStep[] {
return this.steps
})
}
branch(branchConfig: BranchConfig): this {
@ -384,160 +141,77 @@ class StepBuilder extends BaseStepBuilder {
}
}
class AutomationBuilder extends BaseStepBuilder {
private automationConfig: Automation
private config: TestConfiguration
private triggerOutputs: TriggerOutputs
private triggerSet = false
class StepBuilder<
TStep extends AutomationTriggerStepId
> extends BranchStepBuilder<TStep> {
private readonly config: TestConfiguration
private readonly trigger: AutomationTrigger
private _name: string | undefined = undefined
constructor(
options: { name?: string; appId?: string; config?: TestConfiguration } = {}
) {
constructor(config: TestConfiguration, trigger: AutomationTrigger) {
super()
this.config = options.config || setup.getConfig()
this.automationConfig = {
name: options.name || `Test Automation ${uuidv4()}`,
definition: {
steps: [],
trigger: {} as AutomationTrigger,
stepNames: {},
},
type: "automation",
appId: options.appId ?? this.config.getAppId(),
}
this.config = config
this.trigger = trigger
}
// TRIGGERS
rowSaved(inputs: RowCreatedTriggerInputs, outputs: RowCreatedTriggerOutputs) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.ROW_SAVED,
AutomationTriggerStepId.ROW_SAVED,
inputs,
outputs
)
}
rowUpdated(
inputs: RowUpdatedTriggerInputs,
outputs: RowUpdatedTriggerOutputs
) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.ROW_UPDATED,
AutomationTriggerStepId.ROW_UPDATED,
inputs,
outputs
)
}
rowDeleted(
inputs: RowDeletedTriggerInputs,
outputs: RowDeletedTriggerOutputs
) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.ROW_DELETED,
AutomationTriggerStepId.ROW_DELETED,
inputs,
outputs
)
}
appAction(outputs: AppActionTriggerOutputs, inputs?: AppActionTriggerInputs) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.APP,
AutomationTriggerStepId.APP,
inputs,
outputs
)
}
webhook(outputs: WebhookTriggerOutputs, inputs?: WebhookTriggerInputs) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.WEBHOOK,
AutomationTriggerStepId.WEBHOOK,
inputs,
outputs
)
}
cron(inputs: CronTriggerInputs, outputs?: CronTriggerOutputs) {
this.triggerOutputs = outputs
return this.trigger(
TRIGGER_DEFINITIONS.CRON,
AutomationTriggerStepId.CRON,
inputs,
outputs
)
}
private trigger<TStep extends AutomationTriggerStepId>(
triggerSchema: AutomationTriggerDefinition,
stepId: TStep,
inputs?: AutomationTriggerInputs<TStep>,
outputs?: TriggerOutputs
): this {
if (this.triggerSet) {
throw new Error("Only one trigger can be set for an automation.")
}
this.automationConfig.definition.trigger = {
...triggerSchema,
stepId,
inputs: inputs || ({} as any),
id: uuidv4(),
}
this.triggerOutputs = outputs
this.triggerSet = true
return this
}
branch(branchConfig: BranchConfig): this {
this.addBranchStep(branchConfig)
name(n: string): this {
this._name = n
return this
}
build(): Automation {
this.automationConfig.definition.steps = this.steps
this.automationConfig.definition.stepNames = this.stepNames
return this.automationConfig
const name = this._name || `Test Automation ${uuidv4()}`
return {
name,
definition: {
steps: this.steps,
trigger: this.trigger,
stepNames: this.stepNames,
},
type: "automation",
appId: this.config.getAppId(),
}
}
async save() {
if (!Object.keys(this.automationConfig.definition.trigger).length) {
throw new Error("Please add a trigger to this automation test")
}
this.automationConfig.definition.steps = this.steps
const { automation } = await this.config.api.automation.post(this.build())
return automation
return new AutomationRunner<TStep>(this.config, automation)
}
async run() {
const automation = await this.save()
async test(triggerOutput: AutomationTriggerOutputs<TStep>) {
const runner = await this.save()
return await runner.test(triggerOutput)
}
}
class AutomationRunner<TStep extends AutomationTriggerStepId> {
private readonly config: TestConfiguration
readonly automation: Automation
constructor(config: TestConfiguration, automation: Automation) {
this.config = config
this.automation = automation
}
async test(triggerOutput: AutomationTriggerOutputs<TStep>) {
const response = await this.config.api.automation.test(
automation._id!,
this.triggerOutputs as TestAutomationRequest
this.automation._id!,
// TODO: figure out why this cast is needed.
triggerOutput as TestAutomationRequest
)
if (isDidNotTriggerResponse(response)) {
throw new Error(response.message)
}
const results: AutomationResults = response as AutomationResults
// Remove the trigger step from the response.
results.steps.shift()
return {
trigger: results.trigger,
steps: results.steps,
}
return response
}
}
export function createAutomationBuilder(options?: {
name?: string
appId?: string
config?: TestConfiguration
}) {
return new AutomationBuilder(options)
export function createAutomationBuilder(config: TestConfiguration) {
return new TriggerBuilder(config)
}

View File

@ -98,6 +98,7 @@ export default class TestConfiguration {
request?: supertest.SuperTest<supertest.Test>
started: boolean
appId?: string
name?: string
allApps: App[]
app?: App
prodApp?: App

View File

@ -217,10 +217,8 @@ export function basicAutomation(opts?: DeepPartial<Automation>): Automation {
icon: "test",
description: "test",
type: AutomationStepType.TRIGGER,
inputs: {},
id: "test",
inputs: {
fields: {},
},
schema: {
inputs: {
properties: {},

View File

@ -254,10 +254,6 @@ export type OutgoingWebhookStepInputs = {
headers: string | Record<string, string>
}
export type AppActionTriggerInputs = {
fields: object
}
export type AppActionTriggerOutputs = {
fields: object
}

View File

@ -45,13 +45,18 @@ import {
OpenAIStepInputs,
OpenAIStepOutputs,
LoopStepInputs,
AppActionTriggerInputs,
CronTriggerInputs,
RowUpdatedTriggerInputs,
RowCreatedTriggerInputs,
RowDeletedTriggerInputs,
BranchStepInputs,
BaseAutomationOutputs,
AppActionTriggerOutputs,
CronTriggerOutputs,
RowDeletedTriggerOutputs,
RowCreatedTriggerOutputs,
RowUpdatedTriggerOutputs,
WebhookTriggerOutputs,
} from "./StepInputsOutputs"
export type ActionImplementations<T extends Hosting> = {
@ -337,7 +342,7 @@ export type AutomationTriggerDefinition = Omit<
export type AutomationTriggerInputs<T extends AutomationTriggerStepId> =
T extends AutomationTriggerStepId.APP
? AppActionTriggerInputs
? void | Record<string, any>
: T extends AutomationTriggerStepId.CRON
? CronTriggerInputs
: T extends AutomationTriggerStepId.ROW_ACTION
@ -352,6 +357,23 @@ export type AutomationTriggerInputs<T extends AutomationTriggerStepId> =
? Record<string, any>
: never
export type AutomationTriggerOutputs<T extends AutomationTriggerStepId> =
T extends AutomationTriggerStepId.APP
? AppActionTriggerOutputs
: T extends AutomationTriggerStepId.CRON
? CronTriggerOutputs
: T extends AutomationTriggerStepId.ROW_ACTION
? Record<string, any>
: T extends AutomationTriggerStepId.ROW_DELETED
? RowDeletedTriggerOutputs
: T extends AutomationTriggerStepId.ROW_SAVED
? RowCreatedTriggerOutputs
: T extends AutomationTriggerStepId.ROW_UPDATED
? RowUpdatedTriggerOutputs
: T extends AutomationTriggerStepId.WEBHOOK
? WebhookTriggerOutputs
: never
export interface AutomationTriggerSchema<
TTrigger extends AutomationTriggerStepId
> extends AutomationStepSchemaBase {