Add more automation tests (#14369)
* Add more automation tests * remove comment * update assertion * unused type * split out query creation * remove map
This commit is contained in:
parent
7c3593c929
commit
37f749019d
|
@ -1,55 +1,36 @@
|
||||||
import { Datasource, Query } from "@budibase/types"
|
import { Datasource, Query } from "@budibase/types"
|
||||||
import * as setup from "./utilities"
|
import * as setup from "./utilities"
|
||||||
import {
|
import { DatabaseName } from "../../integrations/tests/utils"
|
||||||
DatabaseName,
|
|
||||||
getDatasource,
|
|
||||||
knexClient,
|
|
||||||
} from "../../integrations/tests/utils"
|
|
||||||
import { Knex } from "knex"
|
import { Knex } from "knex"
|
||||||
import { generator } from "@budibase/backend-core/tests"
|
|
||||||
|
|
||||||
describe.each(
|
describe.each([
|
||||||
[
|
|
||||||
DatabaseName.POSTGRES,
|
DatabaseName.POSTGRES,
|
||||||
DatabaseName.MYSQL,
|
DatabaseName.MYSQL,
|
||||||
DatabaseName.SQL_SERVER,
|
DatabaseName.SQL_SERVER,
|
||||||
DatabaseName.MARIADB,
|
DatabaseName.MARIADB,
|
||||||
DatabaseName.ORACLE,
|
DatabaseName.ORACLE,
|
||||||
].map(name => [name, getDatasource(name)])
|
])("execute query action (%s)", name => {
|
||||||
)("execute query action (%s)", (_, dsProvider) => {
|
|
||||||
let tableName: string
|
let tableName: string
|
||||||
let client: Knex
|
let client: Knex
|
||||||
let datasource: Datasource
|
let datasource: Datasource
|
||||||
let query: Query
|
let query: Query
|
||||||
let config = setup.getConfig()
|
const config = setup.getConfig()
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
|
|
||||||
const ds = await dsProvider
|
const testSetup = await setup.setupTestDatasource(config, name)
|
||||||
datasource = await config.api.datasource.create(ds)
|
datasource = testSetup.datasource
|
||||||
client = await knexClient(ds)
|
client = testSetup.client
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
tableName = generator.guid()
|
tableName = await setup.createTestTable(client, {
|
||||||
await client.schema.createTable(tableName, table => {
|
a: { type: "string" },
|
||||||
table.string("a")
|
b: { type: "number" },
|
||||||
table.integer("b")
|
|
||||||
})
|
|
||||||
await client(tableName).insert({ a: "string", b: 1 })
|
|
||||||
query = await config.api.query.save({
|
|
||||||
name: "test query",
|
|
||||||
datasourceId: datasource._id!,
|
|
||||||
parameters: [],
|
|
||||||
fields: {
|
|
||||||
sql: client(tableName).select("*").toSQL().toNative().sql,
|
|
||||||
},
|
|
||||||
transformer: "",
|
|
||||||
schema: {},
|
|
||||||
readable: true,
|
|
||||||
queryVerb: "read",
|
|
||||||
})
|
})
|
||||||
|
await setup.insertTestData(client, tableName, [{ a: "string", b: 1 }])
|
||||||
|
query = await setup.saveTestQuery(config, client, tableName, datasource)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
import * as automation from "../../index"
|
import * as automation from "../../index"
|
||||||
import * as setup from "../utilities"
|
import * as setup from "../utilities"
|
||||||
import { Table, LoopStepType } from "@budibase/types"
|
import {
|
||||||
|
Table,
|
||||||
|
LoopStepType,
|
||||||
|
CreateRowStepOutputs,
|
||||||
|
ServerLogStepOutputs,
|
||||||
|
FieldType,
|
||||||
|
} from "@budibase/types"
|
||||||
import { createAutomationBuilder } from "../utilities/AutomationBuilder"
|
import { createAutomationBuilder } from "../utilities/AutomationBuilder"
|
||||||
|
import { DatabaseName } from "../../../integrations/tests/utils"
|
||||||
|
|
||||||
describe("Automation Scenarios", () => {
|
describe("Automation Scenarios", () => {
|
||||||
let config = setup.getConfig(),
|
let config = setup.getConfig(),
|
||||||
|
@ -63,6 +70,72 @@ describe("Automation Scenarios", () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should run an automation where a loop is successfully run twice", async () => {
|
||||||
|
const builder = createAutomationBuilder({
|
||||||
|
name: "Test Trigger with Loop and Create Row",
|
||||||
|
})
|
||||||
|
|
||||||
|
const results = await builder
|
||||||
|
.rowSaved(
|
||||||
|
{ tableId: table._id! },
|
||||||
|
{
|
||||||
|
row: {
|
||||||
|
name: "Trigger Row",
|
||||||
|
description: "This row triggers the automation",
|
||||||
|
},
|
||||||
|
id: "1234",
|
||||||
|
revision: "1",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.loop({
|
||||||
|
option: LoopStepType.ARRAY,
|
||||||
|
binding: [1, 2, 3],
|
||||||
|
})
|
||||||
|
.createRow({
|
||||||
|
row: {
|
||||||
|
name: "Item {{ loop.currentItem }}",
|
||||||
|
description: "Created from loop",
|
||||||
|
tableId: table._id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.loop({
|
||||||
|
option: LoopStepType.STRING,
|
||||||
|
binding: "Message 1,Message 2,Message 3",
|
||||||
|
})
|
||||||
|
.serverLog({ text: "{{loop.currentItem}}" })
|
||||||
|
.run()
|
||||||
|
|
||||||
|
expect(results.trigger).toBeDefined()
|
||||||
|
expect(results.steps).toHaveLength(2)
|
||||||
|
|
||||||
|
expect(results.steps[0].outputs.iterations).toBe(3)
|
||||||
|
expect(results.steps[0].outputs.items).toHaveLength(3)
|
||||||
|
|
||||||
|
results.steps[0].outputs.items.forEach(
|
||||||
|
(output: CreateRowStepOutputs, index: number) => {
|
||||||
|
expect(output).toMatchObject({
|
||||||
|
success: true,
|
||||||
|
row: {
|
||||||
|
name: `Item ${index + 1}`,
|
||||||
|
description: "Created from loop",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(results.steps[1].outputs.iterations).toBe(3)
|
||||||
|
expect(results.steps[1].outputs.items).toHaveLength(3)
|
||||||
|
|
||||||
|
results.steps[1].outputs.items.forEach(
|
||||||
|
(output: ServerLogStepOutputs, index: number) => {
|
||||||
|
expect(output).toMatchObject({
|
||||||
|
success: true,
|
||||||
|
})
|
||||||
|
expect(output.message).toContain(`Message ${index + 1}`)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("Row Automations", () => {
|
describe("Row Automations", () => {
|
||||||
|
@ -157,4 +230,94 @@ describe("Automation Scenarios", () => {
|
||||||
expect(results.steps[1].outputs.success).toBeTruthy()
|
expect(results.steps[1].outputs.success).toBeTruthy()
|
||||||
expect(results.steps[2].outputs.rows).toHaveLength(1)
|
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)])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -28,6 +28,7 @@ import {
|
||||||
SmtpEmailStepInputs,
|
SmtpEmailStepInputs,
|
||||||
ExecuteQueryStepInputs,
|
ExecuteQueryStepInputs,
|
||||||
QueryRowsStepInputs,
|
QueryRowsStepInputs,
|
||||||
|
ServerLogStepInputs,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import {} from "../../steps/loop"
|
import {} from "../../steps/loop"
|
||||||
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
|
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
|
||||||
|
@ -119,6 +120,10 @@ class AutomationBuilder {
|
||||||
return this.step(BUILTIN_ACTION_DEFINITIONS.LOOP, inputs)
|
return this.step(BUILTIN_ACTION_DEFINITIONS.LOOP, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serverLog(input: ServerLogStepInputs): this {
|
||||||
|
return this.step(BUILTIN_ACTION_DEFINITIONS.SERVER_LOG, input)
|
||||||
|
}
|
||||||
|
|
||||||
private trigger<T extends { [key: string]: any }>(
|
private trigger<T extends { [key: string]: any }>(
|
||||||
triggerSchema: AutomationTriggerSchema,
|
triggerSchema: AutomationTriggerSchema,
|
||||||
inputs?: T,
|
inputs?: T,
|
||||||
|
|
|
@ -3,7 +3,14 @@ import { context } from "@budibase/backend-core"
|
||||||
import { BUILTIN_ACTION_DEFINITIONS, getAction } from "../../actions"
|
import { BUILTIN_ACTION_DEFINITIONS, getAction } from "../../actions"
|
||||||
import emitter from "../../../events/index"
|
import emitter from "../../../events/index"
|
||||||
import env from "../../../environment"
|
import env from "../../../environment"
|
||||||
import { AutomationActionStepId } from "@budibase/types"
|
import { AutomationActionStepId, Datasource } from "@budibase/types"
|
||||||
|
import { Knex } from "knex"
|
||||||
|
import { generator } from "@budibase/backend-core/tests"
|
||||||
|
import {
|
||||||
|
getDatasource,
|
||||||
|
knexClient,
|
||||||
|
DatabaseName,
|
||||||
|
} from "../../../integrations/tests/utils"
|
||||||
|
|
||||||
let config: TestConfig
|
let config: TestConfig
|
||||||
|
|
||||||
|
@ -57,5 +64,58 @@ export async function runStep(stepId: string, inputs: any, stepContext?: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function createTestTable(client: Knex, schema: any) {
|
||||||
|
const tableName = generator.guid()
|
||||||
|
await client.schema.createTable(tableName, table => {
|
||||||
|
for (const fieldName in schema) {
|
||||||
|
const field = schema[fieldName]
|
||||||
|
if (field.type === "string") {
|
||||||
|
table.string(fieldName)
|
||||||
|
} else if (field.type === "number") {
|
||||||
|
table.integer(fieldName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return tableName
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function insertTestData(
|
||||||
|
client: Knex,
|
||||||
|
tableName: string,
|
||||||
|
rows: any[]
|
||||||
|
) {
|
||||||
|
await client(tableName).insert(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveTestQuery(
|
||||||
|
config: TestConfig,
|
||||||
|
client: Knex,
|
||||||
|
tableName: string,
|
||||||
|
datasource: Datasource
|
||||||
|
) {
|
||||||
|
return await config.api.query.save({
|
||||||
|
name: "test query",
|
||||||
|
datasourceId: datasource._id!,
|
||||||
|
parameters: [],
|
||||||
|
fields: {
|
||||||
|
sql: client(tableName).select("*").toSQL().toNative().sql,
|
||||||
|
},
|
||||||
|
transformer: "",
|
||||||
|
schema: {},
|
||||||
|
readable: true,
|
||||||
|
queryVerb: "read",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setupTestDatasource(
|
||||||
|
config: TestConfig,
|
||||||
|
dbName: DatabaseName
|
||||||
|
) {
|
||||||
|
const db = await getDatasource(dbName)
|
||||||
|
const datasource = await config.api.datasource.create(db)
|
||||||
|
const client = await knexClient(db)
|
||||||
|
return { datasource, client }
|
||||||
|
}
|
||||||
|
|
||||||
export const apiKey = "test"
|
export const apiKey = "test"
|
||||||
export const actions = BUILTIN_ACTION_DEFINITIONS
|
export const actions = BUILTIN_ACTION_DEFINITIONS
|
||||||
|
|
|
@ -98,6 +98,24 @@ export type ActionImplementations<T extends Hosting> = {
|
||||||
}
|
}
|
||||||
: {})
|
: {})
|
||||||
|
|
||||||
|
export type AutomationStepOutputs =
|
||||||
|
| CollectStepOutputs
|
||||||
|
| CreateRowStepOutputs
|
||||||
|
| DelayStepOutputs
|
||||||
|
| DeleteRowStepOutputs
|
||||||
|
| ExecuteQueryStepOutputs
|
||||||
|
| ExecuteScriptStepOutputs
|
||||||
|
| FilterStepOutputs
|
||||||
|
| QueryRowsStepOutputs
|
||||||
|
| BaseAutomationOutputs
|
||||||
|
| BashStepOutputs
|
||||||
|
| ExternalAppStepOutputs
|
||||||
|
| OpenAIStepOutputs
|
||||||
|
| ServerLogStepOutputs
|
||||||
|
| TriggerAutomationStepOutputs
|
||||||
|
| UpdateRowStepOutputs
|
||||||
|
| ZapierStepOutputs
|
||||||
|
|
||||||
export type BaseAutomationOutputs = {
|
export type BaseAutomationOutputs = {
|
||||||
success?: boolean
|
success?: boolean
|
||||||
response?: {
|
response?: {
|
||||||
|
@ -199,7 +217,7 @@ export type LoopStepInputs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LoopStepOutputs = {
|
export type LoopStepOutputs = {
|
||||||
items: string
|
items: AutomationStepOutputs[]
|
||||||
success: boolean
|
success: boolean
|
||||||
iterations: number
|
iterations: number
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue