tests to cover automation naming

This commit is contained in:
Peter Clement 2024-09-12 14:58:53 +01:00
parent 2cdbf4190b
commit a831a4bf07
4 changed files with 233 additions and 155 deletions

View File

@ -242,4 +242,28 @@ describe("Loop automations", () => {
expect(results.steps[1].outputs.message).toContain("- 3") expect(results.steps[1].outputs.message).toContain("- 3")
expect(results.steps[3].outputs.message).toContain("- 3") expect(results.steps[3].outputs.message).toContain("- 3")
}) })
it("should use automation names to loop with", async () => {
const builder = createAutomationBuilder({
name: "Test Trigger with Loop and Create Row",
})
const results = await builder
.appAction({ fields: {} })
.loop(
{
option: LoopStepType.ARRAY,
binding: [1, 2, 3],
},
"FirstLoopStep"
)
.serverLog({ text: "Message {{loop.currentItem}}" }, "FirstLoopLog")
.serverLog(
{ text: "{{steps.FirstLoopLog.iterations}}" },
"FirstLoopIterationLog"
)
.run()
expect(results.steps[1].outputs.message).toContain("- 3")
})
}) })

View File

@ -49,151 +49,188 @@ describe("Automation Scenarios", () => {
}, },
}) })
}) })
})
it("should trigger an automation which querys the database", async () => { it("should trigger an automation which querys the database", async () => {
const table = await config.createTable() const table = await config.createTable()
const row = { const row = {
name: "Test Row", name: "Test Row",
description: "original description", description: "original description",
tableId: table._id, tableId: table._id,
} }
await config.createRow(row) await config.createRow(row)
await config.createRow(row) await config.createRow(row)
const builder = createAutomationBuilder({ const builder = createAutomationBuilder({
name: "Test Row Save and Create", name: "Test Row Save and Create",
})
const results = await builder
.appAction({ fields: {} })
.queryRows({
tableId: table._id!,
})
.run()
expect(results.steps).toHaveLength(1)
expect(results.steps[0].outputs.rows).toHaveLength(2)
}) })
const results = await builder it("should trigger an automation which querys the database then deletes a row", async () => {
.appAction({ fields: {} }) const table = await config.createTable()
.queryRows({ const row = {
tableId: table._id!, name: "DFN",
description: "original description",
tableId: table._id,
}
await config.createRow(row)
await config.createRow(row)
const builder = createAutomationBuilder({
name: "Test Row Save and Create",
}) })
.run()
expect(results.steps).toHaveLength(1) const results = await builder
expect(results.steps[0].outputs.rows).toHaveLength(2) .appAction({ fields: {} })
}) .queryRows({
tableId: table._id!,
})
.deleteRow({
tableId: table._id!,
id: "{{ steps.1.rows.0._id }}",
})
.queryRows({
tableId: table._id!,
})
.run()
it("should trigger an automation which querys the database then deletes a row", async () => { expect(results.steps).toHaveLength(3)
const table = await config.createTable() expect(results.steps[1].outputs.success).toBeTruthy()
const row = { expect(results.steps[2].outputs.rows).toHaveLength(1)
name: "DFN",
description: "original description",
tableId: table._id,
}
await config.createRow(row)
await config.createRow(row)
const builder = createAutomationBuilder({
name: "Test Row Save and Create",
}) })
const results = await builder it("should query an external database for some data then insert than into an internal table", async () => {
.appAction({ fields: {} }) const { datasource, client } = await setup.setupTestDatasource(
.queryRows({ config,
tableId: table._id!, DatabaseName.MYSQL
})
.deleteRow({
tableId: table._id!,
id: "{{ steps.1.rows.0._id }}",
})
.queryRows({
tableId: table._id!,
})
.run()
expect(results.steps).toHaveLength(3)
expect(results.steps[1].outputs.success).toBeTruthy()
expect(results.steps[2].outputs.rows).toHaveLength(1)
})
it("should query an external database for some data then insert than into an internal table", async () => {
const { datasource, client } = await setup.setupTestDatasource(
config,
DatabaseName.MYSQL
)
const newTable = await config.createTable({
name: "table",
type: "table",
schema: {
name: {
name: "name",
type: FieldType.STRING,
constraints: {
presence: true,
},
},
age: {
name: "age",
type: FieldType.NUMBER,
constraints: {
presence: true,
},
},
},
})
const tableName = await setup.createTestTable(client, {
name: { type: "string" },
age: { type: "number" },
})
const rows = [
{ name: "Joe", age: 20 },
{ name: "Bob", age: 25 },
{ name: "Paul", age: 30 },
]
await setup.insertTestData(client, tableName, rows)
const query = await setup.saveTestQuery(
config,
client,
tableName,
datasource
)
const builder = createAutomationBuilder({
name: "Test external query and save",
})
const results = await builder
.appAction({
fields: {},
})
.executeQuery({
query: {
queryId: query._id!,
},
})
.loop({
option: LoopStepType.ARRAY,
binding: "{{ steps.1.response }}",
})
.createRow({
row: {
name: "{{ loop.currentItem.name }}",
age: "{{ loop.currentItem.age }}",
tableId: newTable._id!,
},
})
.queryRows({
tableId: newTable._id!,
})
.run()
expect(results.steps).toHaveLength(3)
expect(results.steps[1].outputs.iterations).toBe(3)
expect(results.steps[1].outputs.items).toHaveLength(3)
expect(results.steps[2].outputs.rows).toHaveLength(3)
rows.forEach(expectedRow => {
expect(results.steps[2].outputs.rows).toEqual(
expect.arrayContaining([expect.objectContaining(expectedRow)])
) )
const newTable = await config.createTable({
name: "table",
type: "table",
schema: {
name: {
name: "name",
type: FieldType.STRING,
constraints: {
presence: true,
},
},
age: {
name: "age",
type: FieldType.NUMBER,
constraints: {
presence: true,
},
},
},
})
const tableName = await setup.createTestTable(client, {
name: { type: "string" },
age: { type: "number" },
})
const rows = [
{ name: "Joe", age: 20 },
{ name: "Bob", age: 25 },
{ name: "Paul", age: 30 },
]
await setup.insertTestData(client, tableName, rows)
const query = await setup.saveTestQuery(
config,
client,
tableName,
datasource
)
const builder = createAutomationBuilder({
name: "Test external query and save",
})
const results = await builder
.appAction({
fields: {},
})
.executeQuery({
query: {
queryId: query._id!,
},
})
.loop({
option: LoopStepType.ARRAY,
binding: "{{ steps.1.response }}",
})
.createRow({
row: {
name: "{{ loop.currentItem.name }}",
age: "{{ loop.currentItem.age }}",
tableId: newTable._id!,
},
})
.queryRows({
tableId: newTable._id!,
})
.run()
expect(results.steps).toHaveLength(3)
expect(results.steps[1].outputs.iterations).toBe(3)
expect(results.steps[1].outputs.items).toHaveLength(3)
expect(results.steps[2].outputs.rows).toHaveLength(3)
rows.forEach(expectedRow => {
expect(results.steps[2].outputs.rows).toEqual(
expect.arrayContaining([expect.objectContaining(expectedRow)])
)
})
})
})
describe("Name Based Automations", () => {
it("should fetch and delete a rpw using automation naming", async () => {
const table = await config.createTable()
const row = {
name: "DFN",
description: "original description",
tableId: table._id,
}
await config.createRow(row)
await config.createRow(row)
const builder = createAutomationBuilder({
name: "Test Query and Delete Row",
})
const results = await builder
.appAction({ fields: {} })
.queryRows(
{
tableId: table._id!,
},
"InitialQueryStep"
)
.deleteRow({
tableId: table._id!,
id: "{{ steps.InitialQueryStep.rows.0._id }}",
})
.queryRows({
tableId: table._id!,
})
.run()
expect(results.steps).toHaveLength(3)
expect(results.steps[1].outputs.success).toBeTruthy()
expect(results.steps[2].outputs.rows).toHaveLength(1)
}) })
}) })
}) })

View File

@ -57,21 +57,27 @@ type BranchConfig = {
class BaseStepBuilder { class BaseStepBuilder {
protected steps: AutomationStep[] = [] protected steps: AutomationStep[] = []
protected stepNames: { [key: string]: string } = {}
protected step<TStep extends AutomationActionStepId>( protected step<TStep extends AutomationActionStepId>(
stepId: TStep, stepId: TStep,
stepSchema: Omit<AutomationStep, "id" | "stepId" | "inputs">, stepSchema: Omit<AutomationStep, "id" | "stepId" | "inputs">,
inputs: AutomationStepInputs<TStep> inputs: AutomationStepInputs<TStep>,
stepName?: string
): this { ): this {
const id = uuidv4()
this.steps.push({ this.steps.push({
...stepSchema, ...stepSchema,
inputs: inputs as any, inputs: inputs as any,
id: uuidv4(), id,
stepId, stepId,
name: stepName || stepSchema.name,
}) })
if (stepName) {
this.stepNames[id] = stepName
}
return this return this
} }
protected addBranchStep(branchConfig: BranchConfig): void { protected addBranchStep(branchConfig: BranchConfig): void {
const branchStepInputs: BranchStepInputs = { const branchStepInputs: BranchStepInputs = {
branches: [] as Branch[], branches: [] as Branch[],
@ -99,66 +105,74 @@ class BaseStepBuilder {
} }
// STEPS // STEPS
createRow(inputs: CreateRowStepInputs): this { createRow(inputs: CreateRowStepInputs, stepName?: string): this {
return this.step( return this.step(
AutomationActionStepId.CREATE_ROW, AutomationActionStepId.CREATE_ROW,
BUILTIN_ACTION_DEFINITIONS.CREATE_ROW, BUILTIN_ACTION_DEFINITIONS.CREATE_ROW,
inputs inputs,
stepName
) )
} }
updateRow(inputs: UpdateRowStepInputs): this { updateRow(inputs: UpdateRowStepInputs, stepName?: string): this {
return this.step( return this.step(
AutomationActionStepId.UPDATE_ROW, AutomationActionStepId.UPDATE_ROW,
BUILTIN_ACTION_DEFINITIONS.UPDATE_ROW, BUILTIN_ACTION_DEFINITIONS.UPDATE_ROW,
inputs inputs,
stepName
) )
} }
deleteRow(inputs: DeleteRowStepInputs): this { deleteRow(inputs: DeleteRowStepInputs, stepName?: string): this {
return this.step( return this.step(
AutomationActionStepId.DELETE_ROW, AutomationActionStepId.DELETE_ROW,
BUILTIN_ACTION_DEFINITIONS.DELETE_ROW, BUILTIN_ACTION_DEFINITIONS.DELETE_ROW,
inputs inputs,
stepName
) )
} }
sendSmtpEmail(inputs: SmtpEmailStepInputs): this { sendSmtpEmail(inputs: SmtpEmailStepInputs, stepName?: string): this {
return this.step( return this.step(
AutomationActionStepId.SEND_EMAIL_SMTP, AutomationActionStepId.SEND_EMAIL_SMTP,
BUILTIN_ACTION_DEFINITIONS.SEND_EMAIL_SMTP, BUILTIN_ACTION_DEFINITIONS.SEND_EMAIL_SMTP,
inputs inputs,
stepName
) )
} }
executeQuery(inputs: ExecuteQueryStepInputs): this { executeQuery(inputs: ExecuteQueryStepInputs, stepName?: string): this {
return this.step( return this.step(
AutomationActionStepId.EXECUTE_QUERY, AutomationActionStepId.EXECUTE_QUERY,
BUILTIN_ACTION_DEFINITIONS.EXECUTE_QUERY, BUILTIN_ACTION_DEFINITIONS.EXECUTE_QUERY,
inputs inputs,
stepName
) )
} }
queryRows(inputs: QueryRowsStepInputs): this { queryRows(inputs: QueryRowsStepInputs, stepName?: string): this {
return this.step( return this.step(
AutomationActionStepId.QUERY_ROWS, AutomationActionStepId.QUERY_ROWS,
BUILTIN_ACTION_DEFINITIONS.QUERY_ROWS, BUILTIN_ACTION_DEFINITIONS.QUERY_ROWS,
inputs inputs,
stepName
) )
} }
loop(inputs: LoopStepInputs): this { loop(inputs: LoopStepInputs, stepName?: string): this {
return this.step( return this.step(
AutomationActionStepId.LOOP, AutomationActionStepId.LOOP,
BUILTIN_ACTION_DEFINITIONS.LOOP, BUILTIN_ACTION_DEFINITIONS.LOOP,
inputs inputs,
stepName
) )
} }
serverLog(input: ServerLogStepInputs): this { serverLog(input: ServerLogStepInputs, stepName?: string): this {
return this.step( return this.step(
AutomationActionStepId.SERVER_LOG, AutomationActionStepId.SERVER_LOG,
BUILTIN_ACTION_DEFINITIONS.SERVER_LOG, BUILTIN_ACTION_DEFINITIONS.SERVER_LOG,
input input,
stepName
) )
} }
} }
@ -186,6 +200,7 @@ class AutomationBuilder extends BaseStepBuilder {
definition: { definition: {
steps: [], steps: [],
trigger: {} as AutomationTrigger, trigger: {} as AutomationTrigger,
stepNames: {},
}, },
type: "automation", type: "automation",
appId: options.appId ?? setup.getConfig().getAppId(), appId: options.appId ?? setup.getConfig().getAppId(),
@ -268,6 +283,7 @@ class AutomationBuilder extends BaseStepBuilder {
build(): Automation { build(): Automation {
this.automationConfig.definition.steps = this.steps this.automationConfig.definition.steps = this.steps
this.automationConfig.definition.stepNames = this.stepNames
return this.automationConfig return this.automationConfig
} }

View File

@ -124,6 +124,7 @@ export interface Automation extends Document {
definition: { definition: {
steps: AutomationStep[] steps: AutomationStep[]
trigger: AutomationTrigger trigger: AutomationTrigger
stepNames?: Record<string, string>
} }
screenId?: string screenId?: string
uiTree?: any uiTree?: any