Move trigger output to the run function so it's easier to understand its purpose.
This commit is contained in:
parent
3139fccf2f
commit
ac2f40e955
|
@ -108,7 +108,7 @@ describe("/automations", () => {
|
|||
|
||||
it("Should ensure you can't have a branch as not a last step", async () => {
|
||||
const automation = createAutomationBuilder(config)
|
||||
.appAction({ fields: { status: "active" } })
|
||||
.appAction()
|
||||
.branch({
|
||||
activeBranch: {
|
||||
steps: stepBuilder =>
|
||||
|
@ -132,7 +132,7 @@ describe("/automations", () => {
|
|||
|
||||
it("Should check validation on an automation that has a branch step with no children", async () => {
|
||||
const automation = createAutomationBuilder(config)
|
||||
.appAction({ fields: { status: "active" } })
|
||||
.appAction()
|
||||
.branch({})
|
||||
.serverLog({ text: "Inactive user" })
|
||||
.build()
|
||||
|
@ -148,7 +148,7 @@ describe("/automations", () => {
|
|||
|
||||
it("Should check validation on a branch step with empty conditions", async () => {
|
||||
const automation = createAutomationBuilder(config)
|
||||
.appAction({ fields: { status: "active" } })
|
||||
.appAction()
|
||||
.branch({
|
||||
activeBranch: {
|
||||
steps: stepBuilder =>
|
||||
|
@ -169,7 +169,7 @@ describe("/automations", () => {
|
|||
|
||||
it("Should check validation on an branch that has a condition that is not valid", async () => {
|
||||
const automation = createAutomationBuilder(config)
|
||||
.appAction({ fields: { status: "active" } })
|
||||
.appAction()
|
||||
.branch({
|
||||
activeBranch: {
|
||||
steps: stepBuilder =>
|
||||
|
@ -241,6 +241,7 @@ describe("/automations", () => {
|
|||
|
||||
it("should be able to access platformUrl, logoUrl and company in the automation", async () => {
|
||||
const result = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.serverLog({
|
||||
text: "{{ settings.url }}",
|
||||
})
|
||||
|
@ -250,7 +251,7 @@ describe("/automations", () => {
|
|||
.serverLog({
|
||||
text: "{{ settings.company }}",
|
||||
})
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(result.steps[0].outputs.message).toEndWith("https://example.com")
|
||||
expect(result.steps[1].outputs.message).toEndWith(
|
||||
|
|
|
@ -25,6 +25,7 @@ describe("Branching automations", () => {
|
|||
const branch2Id = "44444444-4444-4444-4444-444444444444"
|
||||
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.serverLog(
|
||||
{ text: "Starting automation" },
|
||||
{ stepName: "FirstLog", stepId: firstLogId }
|
||||
|
@ -75,7 +76,7 @@ describe("Branching automations", () => {
|
|||
},
|
||||
},
|
||||
})
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps[3].outputs.status).toContain("branch1 branch taken")
|
||||
expect(results.steps[4].outputs.message).toContain("Branch 1.1")
|
||||
|
@ -83,7 +84,7 @@ describe("Branching automations", () => {
|
|||
|
||||
it("should execute correct branch based on string equality", async () => {
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction({ fields: { status: "active" } })
|
||||
.appAction()
|
||||
.branch({
|
||||
activeBranch: {
|
||||
steps: stepBuilder => stepBuilder.serverLog({ text: "Active user" }),
|
||||
|
@ -99,7 +100,7 @@ describe("Branching automations", () => {
|
|||
},
|
||||
},
|
||||
})
|
||||
.run()
|
||||
.run({ fields: { status: "active" } })
|
||||
expect(results.steps[0].outputs.status).toContain(
|
||||
"activeBranch branch taken"
|
||||
)
|
||||
|
@ -108,7 +109,7 @@ describe("Branching automations", () => {
|
|||
|
||||
it("should handle multiple conditions with AND operator", async () => {
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction({ fields: { status: "active", role: "admin" } })
|
||||
.appAction()
|
||||
.branch({
|
||||
activeAdminBranch: {
|
||||
steps: stepBuilder =>
|
||||
|
@ -129,14 +130,14 @@ describe("Branching automations", () => {
|
|||
},
|
||||
},
|
||||
})
|
||||
.run()
|
||||
.run({ 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" } })
|
||||
.appAction()
|
||||
.branch({
|
||||
specialBranch: {
|
||||
steps: stepBuilder => stepBuilder.serverLog({ text: "Special user" }),
|
||||
|
@ -161,14 +162,14 @@ describe("Branching automations", () => {
|
|||
},
|
||||
},
|
||||
})
|
||||
.run()
|
||||
.run({ 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" } })
|
||||
.appAction()
|
||||
.createRow({ row: { name: "Test", tableId: table._id } })
|
||||
.branch({
|
||||
specialBranch: {
|
||||
|
@ -194,7 +195,7 @@ describe("Branching automations", () => {
|
|||
},
|
||||
},
|
||||
})
|
||||
.run()
|
||||
.run({ fields: { status: "test", role: "user" } })
|
||||
|
||||
expect(results.steps[1].outputs.status).toEqual(
|
||||
AutomationStatus.NO_CONDITION_MET
|
||||
|
@ -204,7 +205,7 @@ describe("Branching automations", () => {
|
|||
|
||||
it("evaluate multiple conditions", async () => {
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction({ fields: { test_trigger: true } })
|
||||
.appAction()
|
||||
.serverLog({ text: "Starting automation" }, { stepId: "aN6znRYHG" })
|
||||
.branch({
|
||||
specialBranch: {
|
||||
|
@ -238,14 +239,14 @@ describe("Branching automations", () => {
|
|||
},
|
||||
},
|
||||
})
|
||||
.run()
|
||||
.run({ 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 } })
|
||||
.appAction()
|
||||
.serverLog({ text: "Starting automation" }, { stepId: "aN6znRYHG" })
|
||||
.branch({
|
||||
specialBranch: {
|
||||
|
@ -275,7 +276,7 @@ describe("Branching automations", () => {
|
|||
},
|
||||
},
|
||||
})
|
||||
.run()
|
||||
.run({ fields: { test_trigger: true } })
|
||||
|
||||
expect(results.steps[2].outputs.message).toContain("Special user")
|
||||
})
|
||||
|
|
|
@ -30,13 +30,7 @@ describe("Automation Scenarios", () => {
|
|||
const table = await config.api.table.save(basicTable())
|
||||
|
||||
const results = await createAutomationBuilder(config)
|
||||
.rowUpdated(
|
||||
{ tableId: table._id! },
|
||||
{
|
||||
row: { name: "Test", description: "TEST" },
|
||||
id: "1234",
|
||||
}
|
||||
)
|
||||
.rowUpdated({ tableId: table._id! })
|
||||
.createRow({
|
||||
row: {
|
||||
name: "{{trigger.row.name}}",
|
||||
|
@ -44,7 +38,10 @@ describe("Automation Scenarios", () => {
|
|||
tableId: table._id,
|
||||
},
|
||||
})
|
||||
.run()
|
||||
.run({
|
||||
row: { name: "Test", description: "TEST" },
|
||||
id: "1234",
|
||||
})
|
||||
|
||||
expect(results.steps).toHaveLength(1)
|
||||
|
||||
|
@ -66,10 +63,11 @@ 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()
|
||||
.queryRows({
|
||||
tableId: table._id!,
|
||||
})
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps).toHaveLength(1)
|
||||
expect(results.steps[0].outputs.rows).toHaveLength(2)
|
||||
|
@ -84,6 +82,7 @@ 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()
|
||||
.queryRows({
|
||||
tableId: table._id!,
|
||||
})
|
||||
|
@ -94,7 +93,7 @@ describe("Automation Scenarios", () => {
|
|||
.queryRows({
|
||||
tableId: table._id!,
|
||||
})
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps).toHaveLength(3)
|
||||
expect(results.steps[1].outputs.success).toBeTruthy()
|
||||
|
@ -125,6 +124,7 @@ describe("Automation Scenarios", () => {
|
|||
})
|
||||
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.createRow(
|
||||
{
|
||||
row: {
|
||||
|
@ -153,7 +153,7 @@ describe("Automation Scenarios", () => {
|
|||
},
|
||||
{ stepName: "QueryRowsStep" }
|
||||
)
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps).toHaveLength(3)
|
||||
|
||||
|
@ -193,6 +193,7 @@ 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()
|
||||
.queryRows(
|
||||
{
|
||||
tableId: table._id!,
|
||||
|
@ -206,7 +207,7 @@ describe("Automation Scenarios", () => {
|
|||
.queryRows({
|
||||
tableId: table._id!,
|
||||
})
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps).toHaveLength(3)
|
||||
expect(results.steps[1].outputs.success).toBeTruthy()
|
||||
|
@ -242,6 +243,7 @@ describe("Automation Scenarios", () => {
|
|||
|
||||
it("should stop an automation if the condition is not met", async () => {
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.createRow({
|
||||
row: {
|
||||
name: "Equal Test",
|
||||
|
@ -258,7 +260,7 @@ describe("Automation Scenarios", () => {
|
|||
value: 20,
|
||||
})
|
||||
.serverLog({ text: "Equal condition met" })
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps[2].outputs.success).toBeTrue()
|
||||
expect(results.steps[2].outputs.result).toBeFalse()
|
||||
|
@ -267,6 +269,7 @@ describe("Automation Scenarios", () => {
|
|||
|
||||
it("should continue the automation if the condition is met", async () => {
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.createRow({
|
||||
row: {
|
||||
name: "Not Equal Test",
|
||||
|
@ -283,7 +286,7 @@ describe("Automation Scenarios", () => {
|
|||
value: 20,
|
||||
})
|
||||
.serverLog({ text: "Not Equal condition met" })
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps[2].outputs.success).toBeTrue()
|
||||
expect(results.steps[2].outputs.result).toBeTrue()
|
||||
|
@ -333,6 +336,7 @@ describe("Automation Scenarios", () => {
|
|||
"should pass the filter when condition is $condition",
|
||||
async ({ condition, value, rowValue, expectPass }) => {
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.createRow({
|
||||
row: {
|
||||
name: `${condition} Test`,
|
||||
|
@ -351,7 +355,7 @@ describe("Automation Scenarios", () => {
|
|||
.serverLog({
|
||||
text: `${condition} condition ${expectPass ? "passed" : "failed"}`,
|
||||
})
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps[2].outputs.result).toBe(expectPass)
|
||||
if (expectPass) {
|
||||
|
@ -367,23 +371,21 @@ describe("Automation Scenarios", () => {
|
|||
const table = await config.api.table.save(basicTable())
|
||||
|
||||
const results = await createAutomationBuilder(config)
|
||||
.rowUpdated(
|
||||
{ tableId: table._id! },
|
||||
{
|
||||
row: { name: "Test", description: "TEST" },
|
||||
id: "1234",
|
||||
}
|
||||
)
|
||||
.rowUpdated({ tableId: table._id! })
|
||||
.serverLog({ text: "{{ [user].[email] }}" })
|
||||
.run()
|
||||
.run({
|
||||
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()
|
||||
.serverLog({ text: "{{ [user].[email] }}" })
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps[0].outputs.message).toContain("example.com")
|
||||
})
|
||||
|
@ -453,9 +455,7 @@ if (descriptions.length) {
|
|||
})
|
||||
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction({
|
||||
fields: {},
|
||||
})
|
||||
.appAction()
|
||||
.executeQuery({
|
||||
query: {
|
||||
queryId: query._id!,
|
||||
|
@ -475,7 +475,7 @@ if (descriptions.length) {
|
|||
.queryRows({
|
||||
tableId: newTable._id!,
|
||||
})
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps).toHaveLength(3)
|
||||
|
||||
|
|
|
@ -21,30 +21,32 @@ describe("Execute Script Automations", () => {
|
|||
|
||||
it("should execute a basic script and return the result", async () => {
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.executeScript({ code: "return 2 + 2" })
|
||||
.run()
|
||||
.run({ 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] } })
|
||||
.appAction()
|
||||
.executeScript(
|
||||
{
|
||||
code: "return trigger.fields.data.map(x => x * 2)",
|
||||
},
|
||||
{ stepId: "binding-script-step" }
|
||||
)
|
||||
.run()
|
||||
.run({ 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()
|
||||
.executeScript({ code: "return nonexistentVariable.map(x => x)" })
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps[0].outputs.response).toContain(
|
||||
"ReferenceError: nonexistentVariable is not defined"
|
||||
|
@ -54,7 +56,7 @@ describe("Execute Script Automations", () => {
|
|||
|
||||
it("should handle conditional logic in scripts", async () => {
|
||||
const results = await createAutomationBuilder(config)
|
||||
.appAction({ fields: { value: 10 } })
|
||||
.appAction()
|
||||
.executeScript({
|
||||
code: `
|
||||
if (trigger.fields.value > 5) {
|
||||
|
@ -64,14 +66,14 @@ describe("Execute Script Automations", () => {
|
|||
}
|
||||
`,
|
||||
})
|
||||
.run()
|
||||
.run({ 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: {} })
|
||||
.appAction()
|
||||
.serverLog(
|
||||
{ text: "Starting multi-step automation" },
|
||||
{ stepId: "start-log-step" }
|
||||
|
@ -92,7 +94,7 @@ describe("Execute Script Automations", () => {
|
|||
.serverLog({
|
||||
text: `Final result is {{ steps.ScriptingStep1.value }}`,
|
||||
})
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(results.steps[0].outputs.message).toContain(
|
||||
"Starting multi-step automation"
|
||||
|
|
|
@ -58,8 +58,9 @@ describe("test the openai action", () => {
|
|||
// own API key. We don't count this against your quota.
|
||||
const result = await expectAIUsage(0, () =>
|
||||
createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.openai({ prompt: "Hello, world", model: Model.GPT_4O_MINI })
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
)
|
||||
|
||||
expect(result.steps[0].outputs.response).toEqual("This is a test")
|
||||
|
@ -69,8 +70,9 @@ 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()
|
||||
.openai({ prompt: "", model: Model.GPT_4O_MINI })
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
)
|
||||
|
||||
expect(result.steps[0].outputs.response).toEqual(
|
||||
|
@ -84,8 +86,9 @@ describe("test the openai action", () => {
|
|||
|
||||
const result = await expectAIUsage(0, () =>
|
||||
createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.openai({ prompt: "Hello, world", model: Model.GPT_4O_MINI })
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
)
|
||||
|
||||
expect(result.steps[0].outputs.response).toEqual(
|
||||
|
@ -106,8 +109,9 @@ describe("test the openai action", () => {
|
|||
// key, so we charge users for it.
|
||||
const result = await expectAIUsage(14, () =>
|
||||
createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.openai({ model: Model.GPT_4O_MINI, prompt: "Hello, world" })
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
)
|
||||
|
||||
expect(result.steps[0].outputs.response).toEqual("This is a test")
|
||||
|
|
|
@ -29,6 +29,7 @@ describe("Test a query step automation", () => {
|
|||
|
||||
it("should be able to run the query step", async () => {
|
||||
const result = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.queryRows(
|
||||
{
|
||||
tableId: table._id!,
|
||||
|
@ -43,7 +44,7 @@ describe("Test a query step automation", () => {
|
|||
},
|
||||
{ stepName: "Query All Rows" }
|
||||
)
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(result.steps[0].outputs.success).toBe(true)
|
||||
expect(result.steps[0].outputs.rows).toBeDefined()
|
||||
|
@ -53,6 +54,7 @@ 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(config)
|
||||
.appAction()
|
||||
.queryRows(
|
||||
{
|
||||
tableId: table._id!,
|
||||
|
@ -63,7 +65,7 @@ describe("Test a query step automation", () => {
|
|||
},
|
||||
{ stepName: "Query With Empty Filter" }
|
||||
)
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(result.steps[0].outputs.success).toBe(true)
|
||||
expect(result.steps[0].outputs.rows).toBeDefined()
|
||||
|
@ -73,6 +75,7 @@ describe("Test a query step automation", () => {
|
|||
|
||||
it("Returns no rows when onEmptyFilter is RETURN_NONE and theres no filters", async () => {
|
||||
const result = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.queryRows(
|
||||
{
|
||||
tableId: table._id!,
|
||||
|
@ -85,7 +88,7 @@ describe("Test a query step automation", () => {
|
|||
},
|
||||
{ stepName: "Query With Return None" }
|
||||
)
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(result.steps[0].outputs.success).toBe(true)
|
||||
expect(result.steps[0].outputs.rows).toBeDefined()
|
||||
|
@ -94,6 +97,7 @@ 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(config)
|
||||
.appAction()
|
||||
.queryRows(
|
||||
{
|
||||
tableId: table._id!,
|
||||
|
@ -110,7 +114,7 @@ describe("Test a query step automation", () => {
|
|||
},
|
||||
{ stepName: "Query With Null Filter" }
|
||||
)
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(result.steps[0].outputs.success).toBe(true)
|
||||
expect(result.steps[0].outputs.rows).toBeDefined()
|
||||
|
@ -119,6 +123,7 @@ describe("Test a query step automation", () => {
|
|||
|
||||
it("Returns rows when onEmptyFilter is RETURN_ALL and no filter is passed", async () => {
|
||||
const result = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.queryRows(
|
||||
{
|
||||
tableId: table._id!,
|
||||
|
@ -130,7 +135,7 @@ describe("Test a query step automation", () => {
|
|||
},
|
||||
{ stepName: "Query With Return All" }
|
||||
)
|
||||
.run()
|
||||
.run({ fields: {} })
|
||||
|
||||
expect(result.steps[0].outputs.success).toBe(true)
|
||||
expect(result.steps[0].outputs.rows).toBeDefined()
|
||||
|
@ -146,6 +151,7 @@ describe("Test a query step automation", () => {
|
|||
name: NAME,
|
||||
})
|
||||
const result = await createAutomationBuilder(config)
|
||||
.appAction()
|
||||
.queryRows(
|
||||
{
|
||||
tableId: tableWithSpaces._id!,
|
||||
|
@ -154,7 +160,7 @@ describe("Test a query step automation", () => {
|
|||
},
|
||||
{ stepName: "Query table with spaces" }
|
||||
)
|
||||
.run()
|
||||
.run({ 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)
|
||||
|
|
|
@ -11,7 +11,7 @@ describe("Branching automations", () => {
|
|||
let webhook: Webhook
|
||||
|
||||
async function createWebhookAutomation() {
|
||||
const automation = await createAutomationBuilder(config)
|
||||
const { automation } = await createAutomationBuilder(config)
|
||||
.webhook({ fields: { parameter: "string" } })
|
||||
.createRow({
|
||||
row: { tableId: table._id!, name: "{{ trigger.parameter }}" },
|
||||
|
|
|
@ -2,38 +2,26 @@ import { v4 as uuidv4 } from "uuid"
|
|||
import { BUILTIN_ACTION_DEFINITIONS } from "../../actions"
|
||||
import { TRIGGER_DEFINITIONS } from "../../triggers"
|
||||
import {
|
||||
AppActionTriggerOutputs,
|
||||
Automation,
|
||||
AutomationActionStepId,
|
||||
AutomationStep,
|
||||
AutomationStepInputs,
|
||||
AutomationTrigger,
|
||||
AutomationTriggerDefinition,
|
||||
AutomationTriggerInputs,
|
||||
AutomationTriggerOutputs,
|
||||
AutomationTriggerStepId,
|
||||
BranchStepInputs,
|
||||
CronTriggerOutputs,
|
||||
isDidNotTriggerResponse,
|
||||
RowCreatedTriggerOutputs,
|
||||
RowDeletedTriggerOutputs,
|
||||
RowUpdatedTriggerOutputs,
|
||||
SearchFilters,
|
||||
TestAutomationRequest,
|
||||
WebhookTriggerOutputs,
|
||||
} from "@budibase/types"
|
||||
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
|
||||
import { automations } from "@budibase/shared-core"
|
||||
|
||||
type TriggerOutputs =
|
||||
| RowCreatedTriggerOutputs
|
||||
| RowUpdatedTriggerOutputs
|
||||
| RowDeletedTriggerOutputs
|
||||
| AppActionTriggerOutputs
|
||||
| WebhookTriggerOutputs
|
||||
| CronTriggerOutputs
|
||||
| undefined
|
||||
|
||||
type StepBuilderFunction = (stepBuilder: AutomationBuilder) => void
|
||||
type StepBuilderFunction = <TStep extends AutomationTriggerStepId>(
|
||||
stepBuilder: BranchStepBuilder<TStep>
|
||||
) => void
|
||||
|
||||
type BranchConfig = {
|
||||
[key: string]: {
|
||||
|
@ -42,38 +30,42 @@ type BranchConfig = {
|
|||
}
|
||||
}
|
||||
|
||||
class AutomationBuilder {
|
||||
private automationConfig: Automation
|
||||
private triggerOutputs: TriggerOutputs
|
||||
private triggerSet = false
|
||||
class TriggerBuilder {
|
||||
private config: TestConfiguration
|
||||
private steps: AutomationStep[] = []
|
||||
private stepNames: { [key: string]: string } = {}
|
||||
|
||||
constructor(config: TestConfiguration) {
|
||||
this.config = config
|
||||
this.triggerOutputs = { fields: {} }
|
||||
this.automationConfig = {
|
||||
name: `Test Automation ${uuidv4()}`,
|
||||
definition: {
|
||||
steps: [],
|
||||
trigger: {
|
||||
...TRIGGER_DEFINITIONS[AutomationTriggerStepId.APP],
|
||||
stepId: AutomationTriggerStepId.APP,
|
||||
inputs: this.triggerOutputs,
|
||||
id: uuidv4(),
|
||||
},
|
||||
stepNames: {},
|
||||
},
|
||||
type: "automation",
|
||||
appId: this.config.getAppId(),
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
name(n: string): this {
|
||||
this.automationConfig.name = n
|
||||
return this
|
||||
}
|
||||
appAction = this.trigger(AutomationTriggerStepId.APP)
|
||||
|
||||
rowSaved = this.trigger(AutomationTriggerStepId.ROW_SAVED)
|
||||
rowUpdated = this.trigger(AutomationTriggerStepId.ROW_UPDATED)
|
||||
rowDeleted = this.trigger(AutomationTriggerStepId.ROW_DELETED)
|
||||
webhook = this.trigger(AutomationTriggerStepId.WEBHOOK)
|
||||
cron = this.trigger(AutomationTriggerStepId.CRON)
|
||||
}
|
||||
|
||||
class BranchStepBuilder<TStep extends AutomationTriggerStepId> {
|
||||
protected steps: AutomationStep[] = []
|
||||
protected stepNames: { [key: string]: string } = {}
|
||||
|
||||
protected createStepFn<TStep extends AutomationActionStepId>(stepId: TStep) {
|
||||
return (
|
||||
|
@ -120,113 +112,103 @@ class AutomationBuilder {
|
|||
delay = this.createStepFn(AutomationActionStepId.DELAY)
|
||||
|
||||
protected addBranchStep(branchConfig: BranchConfig): void {
|
||||
const branchStepInputs: BranchStepInputs = {
|
||||
const inputs: BranchStepInputs = {
|
||||
branches: [],
|
||||
children: {},
|
||||
}
|
||||
|
||||
Object.entries(branchConfig).forEach(([key, branch]) => {
|
||||
const stepBuilder = new AutomationBuilder(this.config)
|
||||
branch.steps(stepBuilder)
|
||||
let branchId = uuidv4()
|
||||
branchStepInputs.branches.push({
|
||||
name: key,
|
||||
condition: branch.condition,
|
||||
id: branchId,
|
||||
})
|
||||
branchStepInputs.children![branchId] = stepBuilder.steps
|
||||
})
|
||||
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)
|
||||
inputs,
|
||||
})
|
||||
}
|
||||
|
||||
branch(branchConfig: BranchConfig): this {
|
||||
this.addBranchStep(branchConfig)
|
||||
return this
|
||||
}
|
||||
protected triggerInputOutput<
|
||||
TStep extends AutomationTriggerStepId,
|
||||
TInput = AutomationTriggerInputs<TStep>,
|
||||
TOutput = AutomationTriggerOutputs<TStep>
|
||||
>(stepId: TStep) {
|
||||
return (inputs: TInput, outputs?: TOutput) => {
|
||||
if (this.triggerSet) {
|
||||
throw new Error("Only one trigger can be set for an automation.")
|
||||
}
|
||||
this.triggerOutputs = outputs as TriggerOutputs | undefined
|
||||
this.automationConfig.definition.trigger = {
|
||||
...TRIGGER_DEFINITIONS[stepId],
|
||||
stepId,
|
||||
inputs,
|
||||
id: uuidv4(),
|
||||
} as AutomationTrigger
|
||||
this.triggerSet = true
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
class StepBuilder<
|
||||
TStep extends AutomationTriggerStepId
|
||||
> extends BranchStepBuilder<TStep> {
|
||||
private config: TestConfiguration
|
||||
private trigger: AutomationTrigger
|
||||
private _name: string | undefined = undefined
|
||||
|
||||
constructor(config: TestConfiguration, trigger: AutomationTrigger) {
|
||||
super()
|
||||
this.config = config
|
||||
this.trigger = trigger
|
||||
}
|
||||
|
||||
protected triggerOutputOnly<
|
||||
TStep extends AutomationTriggerStepId,
|
||||
TOutput = AutomationTriggerOutputs<TStep>
|
||||
>(stepId: TStep) {
|
||||
return (outputs: TOutput) => {
|
||||
this.triggerOutputs = outputs as TriggerOutputs
|
||||
this.automationConfig.definition.trigger = {
|
||||
...TRIGGER_DEFINITIONS[stepId],
|
||||
stepId,
|
||||
id: uuidv4(),
|
||||
} as AutomationTrigger
|
||||
this.triggerSet = true
|
||||
return this
|
||||
}
|
||||
name(n: string): this {
|
||||
this._name = n
|
||||
return this
|
||||
}
|
||||
|
||||
// The input and output for appAction is identical, and we only ever seem to
|
||||
// set the output, so we're ignoring the input for now.
|
||||
appAction = this.triggerOutputOnly(AutomationTriggerStepId.APP)
|
||||
|
||||
rowSaved = this.triggerInputOutput(AutomationTriggerStepId.ROW_SAVED)
|
||||
rowUpdated = this.triggerInputOutput(AutomationTriggerStepId.ROW_UPDATED)
|
||||
rowDeleted = this.triggerInputOutput(AutomationTriggerStepId.ROW_DELETED)
|
||||
webhook = this.triggerInputOutput(AutomationTriggerStepId.WEBHOOK)
|
||||
cron = this.triggerInputOutput(AutomationTriggerStepId.CRON)
|
||||
|
||||
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() {
|
||||
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 run(outputs: AutomationTriggerOutputs<TStep>) {
|
||||
const runner = await this.save()
|
||||
return await runner.run(outputs)
|
||||
}
|
||||
}
|
||||
|
||||
class AutomationRunner<TStep extends AutomationTriggerStepId> {
|
||||
private config: TestConfiguration
|
||||
automation: Automation
|
||||
|
||||
constructor(config: TestConfiguration, automation: Automation) {
|
||||
this.config = config
|
||||
this.automation = automation
|
||||
}
|
||||
|
||||
async run(outputs: 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.
|
||||
outputs as TestAutomationRequest
|
||||
)
|
||||
|
||||
if (isDidNotTriggerResponse(response)) {
|
||||
throw new Error(response.message)
|
||||
}
|
||||
|
||||
// Remove the trigger step from the response.
|
||||
response.steps.shift()
|
||||
return {
|
||||
trigger: response.trigger,
|
||||
steps: response.steps,
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
export function createAutomationBuilder(config: TestConfiguration) {
|
||||
return new AutomationBuilder(config)
|
||||
return new TriggerBuilder(config)
|
||||
}
|
||||
|
|
|
@ -253,10 +253,6 @@ export type OutgoingWebhookStepInputs = {
|
|||
headers: string | Record<string, string>
|
||||
}
|
||||
|
||||
export type AppActionTriggerInputs = {
|
||||
fields: object
|
||||
}
|
||||
|
||||
export type AppActionTriggerOutputs = {
|
||||
fields: object
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ import {
|
|||
OpenAIStepInputs,
|
||||
OpenAIStepOutputs,
|
||||
LoopStepInputs,
|
||||
AppActionTriggerInputs,
|
||||
CronTriggerInputs,
|
||||
RowUpdatedTriggerInputs,
|
||||
RowCreatedTriggerInputs,
|
||||
|
@ -332,7 +331,7 @@ export type AutomationTriggerDefinition = Omit<
|
|||
|
||||
export type AutomationTriggerInputs<T extends AutomationTriggerStepId> =
|
||||
T extends AutomationTriggerStepId.APP
|
||||
? AppActionTriggerInputs
|
||||
? void
|
||||
: T extends AutomationTriggerStepId.CRON
|
||||
? CronTriggerInputs
|
||||
: T extends AutomationTriggerStepId.ROW_ACTION
|
||||
|
|
Loading…
Reference in New Issue