Finishing off automation test cases, above 90% coverage for automations codebase.
This commit is contained in:
parent
799168c6b8
commit
3406138f34
|
@ -33,7 +33,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"test": "jest --testPathIgnorePatterns=routes && npm run test:integration",
|
||||
"test:integration": "jest --runInBand --coverage",
|
||||
"test:integration": "jest --coverage --detectOpenHandles",
|
||||
"test:watch": "jest --watch",
|
||||
"run:docker": "node src/index",
|
||||
"dev:builder": "cross-env PORT=4001 nodemon src/index.js",
|
||||
|
|
|
@ -66,7 +66,7 @@ module.exports = server.listen(env.PORT || 0, async () => {
|
|||
console.log(`Budibase running on ${JSON.stringify(server.address())}`)
|
||||
env._set("PORT", server.address().port)
|
||||
eventEmitter.emitPort(env.PORT)
|
||||
automations.init()
|
||||
await automations.init()
|
||||
// only init the self hosting DB info in the Pouch, not needed in self hosting prod
|
||||
if (!env.CLOUD) {
|
||||
await selfhost.init()
|
||||
|
|
|
@ -37,12 +37,12 @@ let AUTOMATION_BUCKET = env.AUTOMATION_BUCKET
|
|||
let AUTOMATION_DIRECTORY = env.AUTOMATION_DIRECTORY
|
||||
let MANIFEST = null
|
||||
|
||||
/* instanbul ignore next */
|
||||
/* istanbul ignore next */
|
||||
function buildBundleName(pkgName, version) {
|
||||
return `${pkgName}@${version}.min.js`
|
||||
}
|
||||
|
||||
/* instanbul ignore next */
|
||||
/* istanbul ignore next */
|
||||
async function downloadPackage(name, version, bundleName) {
|
||||
await download(
|
||||
`${AUTOMATION_BUCKET}/${name}/${version}/${bundleName}`,
|
||||
|
@ -51,6 +51,7 @@ async function downloadPackage(name, version, bundleName) {
|
|||
return require(join(AUTOMATION_DIRECTORY, bundleName))
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
module.exports.getAction = async function(actionName) {
|
||||
if (BUILTIN_ACTIONS[actionName] != null) {
|
||||
return BUILTIN_ACTIONS[actionName]
|
||||
|
|
|
@ -30,23 +30,22 @@ async function updateQuota(automation) {
|
|||
/**
|
||||
* This module is built purely to kick off the worker farm and manage the inputs/outputs
|
||||
*/
|
||||
module.exports.init = function() {
|
||||
actions.init().then(() => {
|
||||
triggers.automationQueue.process(async job => {
|
||||
try {
|
||||
if (env.CLOUD && job.data.automation && !env.SELF_HOSTED) {
|
||||
job.data.automation.apiKey = await updateQuota(job.data.automation)
|
||||
}
|
||||
if (env.BUDIBASE_ENVIRONMENT === "PRODUCTION") {
|
||||
await runWorker(job)
|
||||
} else {
|
||||
await singleThread(job)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`${job.data.automation.appId} automation ${job.data.automation._id} was unable to run - ${err}`
|
||||
)
|
||||
module.exports.init = async function() {
|
||||
await actions.init()
|
||||
triggers.automationQueue.process(async job => {
|
||||
try {
|
||||
if (env.CLOUD && job.data.automation && !env.SELF_HOSTED) {
|
||||
job.data.automation.apiKey = await updateQuota(job.data.automation)
|
||||
}
|
||||
})
|
||||
if (env.BUDIBASE_ENVIRONMENT === "PRODUCTION") {
|
||||
await runWorker(job)
|
||||
} else {
|
||||
await singleThread(job)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`${job.data.automation.appId} automation ${job.data.automation._id} was unable to run - ${err}`
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,14 +1,151 @@
|
|||
const automation = require("../index")
|
||||
const usageQuota = require("../../utilities/usageQuota")
|
||||
const thread = require("../thread")
|
||||
const triggers = require("../triggers")
|
||||
const { basicAutomation, basicTable } = require("../../tests/utilities/structures")
|
||||
const TestConfig = require("../../tests/utilities/TestConfiguration")
|
||||
const { wait } = require("../../utilities")
|
||||
const env = require("../../environment")
|
||||
const { makePartial } = require("../../tests/utilities")
|
||||
const { cleanInputValues } = require("../automationUtils")
|
||||
|
||||
let workerJob
|
||||
|
||||
jest.mock("../../utilities/usageQuota")
|
||||
usageQuota.getAPIKey.mockReturnValue({ apiKey: "test" })
|
||||
jest.mock("../thread")
|
||||
jest.spyOn(global.console, "error")
|
||||
jest.mock("worker-farm", () => {
|
||||
return () => {
|
||||
const value = jest
|
||||
.fn()
|
||||
.mockReturnValueOnce(undefined)
|
||||
.mockReturnValueOnce("Error")
|
||||
return (input, callback) => {
|
||||
workerJob = input
|
||||
if (callback) {
|
||||
callback(value())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
describe("Run through some parts of the automations system", () => {
|
||||
let config = new TestConfig(false)
|
||||
|
||||
beforeEach(async () => {
|
||||
await automation.init()
|
||||
await config.init()
|
||||
})
|
||||
|
||||
|
||||
describe("Check the primary input functions to automations", () => {
|
||||
it("should be able to init in builder", async () => {
|
||||
|
||||
await triggers.externalTrigger(basicAutomation(), { a: 1 })
|
||||
await wait(100)
|
||||
expect(workerJob).toBeUndefined()
|
||||
expect(thread).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should be able to init in cloud", async () => {
|
||||
|
||||
env.CLOUD = true
|
||||
env.BUDIBASE_ENVIRONMENT = "PRODUCTION"
|
||||
await triggers.externalTrigger(basicAutomation(), { a: 1 })
|
||||
await wait(100)
|
||||
// haven't added a mock implementation so getAPIKey of usageQuota just returns undefined
|
||||
expect(usageQuota.update).toHaveBeenCalledWith("test", "automationRuns", 1)
|
||||
expect(workerJob).toBeDefined()
|
||||
env.BUDIBASE_ENVIRONMENT = "JEST"
|
||||
env.CLOUD = false
|
||||
})
|
||||
|
||||
it("try error scenario", async () => {
|
||||
env.CLOUD = true
|
||||
env.BUDIBASE_ENVIRONMENT = "PRODUCTION"
|
||||
// the second call will throw an error
|
||||
await triggers.externalTrigger(basicAutomation(), { a: 1 })
|
||||
await wait(100)
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
env.BUDIBASE_ENVIRONMENT = "JEST"
|
||||
env.CLOUD = false
|
||||
})
|
||||
|
||||
it("should be able to check triggering row filling", async () => {
|
||||
const automation = basicAutomation()
|
||||
let table = basicTable()
|
||||
table.schema.boolean = {
|
||||
type: "boolean",
|
||||
constraints: {
|
||||
type: "boolean",
|
||||
},
|
||||
}
|
||||
table.schema.number = {
|
||||
type: "number",
|
||||
constraints: {
|
||||
type: "number",
|
||||
},
|
||||
}
|
||||
table.schema.datetime = {
|
||||
type: "datetime",
|
||||
constraints: {
|
||||
type: "datetime",
|
||||
},
|
||||
}
|
||||
table = await config.createTable(table)
|
||||
automation.definition.trigger.inputs.tableId = table._id
|
||||
const params = await triggers.fillRowOutput(automation, { appId: config.getAppId() })
|
||||
expect(params.row).toBeDefined()
|
||||
const date = new Date(params.row.datetime)
|
||||
expect(typeof params.row.name).toBe("string")
|
||||
expect(typeof params.row.boolean).toBe("boolean")
|
||||
expect(typeof params.row.number).toBe("number")
|
||||
expect(date.getFullYear()).toBe(1970)
|
||||
})
|
||||
|
||||
it("should check coercion", async () => {
|
||||
const table = await config.createTable()
|
||||
const automation = basicAutomation()
|
||||
automation.definition.trigger.inputs.tableId = table._id
|
||||
automation.definition.trigger.stepId = "APP"
|
||||
automation.definition.trigger.inputs.fields = { a: "number" }
|
||||
await triggers.externalTrigger(automation, {
|
||||
appId: config.getAppId(),
|
||||
fields: {
|
||||
a: "1"
|
||||
}
|
||||
})
|
||||
await wait(100)
|
||||
expect(thread).toHaveBeenCalledWith(makePartial({
|
||||
data: {
|
||||
event: {
|
||||
fields: {
|
||||
a: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
it("should be able to clean inputs with the utilities", () => {
|
||||
// can't clean without a schema
|
||||
let output = cleanInputValues({a: "1"})
|
||||
expect(output.a).toBe("1")
|
||||
output = cleanInputValues({a: "1", b: "true", c: "false", d: 1, e: "help"}, {
|
||||
properties: {
|
||||
a: {
|
||||
type: "number",
|
||||
},
|
||||
b: {
|
||||
type: "boolean",
|
||||
},
|
||||
c: {
|
||||
type: "boolean",
|
||||
}
|
||||
}
|
||||
})
|
||||
expect(output.a).toBe(1)
|
||||
expect(output.b).toBe(true)
|
||||
expect(output.c).toBe(false)
|
||||
expect(output.d).toBe(1)
|
||||
expect(output.e).toBe("help")
|
||||
})
|
||||
})
|
|
@ -225,6 +225,7 @@ async function queueRelevantRowAutomations(event, eventType) {
|
|||
}
|
||||
|
||||
emitter.on("row:save", async function(event) {
|
||||
/* istanbul ignore next */
|
||||
if (!event || !event.row || !event.row.tableId) {
|
||||
return
|
||||
}
|
||||
|
@ -232,6 +233,7 @@ emitter.on("row:save", async function(event) {
|
|||
})
|
||||
|
||||
emitter.on("row:update", async function(event) {
|
||||
/* istanbul ignore next */
|
||||
if (!event || !event.row || !event.row.tableId) {
|
||||
return
|
||||
}
|
||||
|
@ -239,6 +241,7 @@ emitter.on("row:update", async function(event) {
|
|||
})
|
||||
|
||||
emitter.on("row:delete", async function(event) {
|
||||
/* istanbul ignore next */
|
||||
if (!event || !event.row || !event.row.tableId) {
|
||||
return
|
||||
}
|
||||
|
@ -272,6 +275,7 @@ async function fillRowOutput(automation, params) {
|
|||
}
|
||||
params.row = row
|
||||
} catch (err) {
|
||||
/* istanbul ignore next */
|
||||
throw "Failed to find table for trigger"
|
||||
}
|
||||
return params
|
||||
|
@ -297,6 +301,7 @@ module.exports.externalTrigger = async function(automation, params) {
|
|||
automationQueue.add({ automation, event: params })
|
||||
}
|
||||
|
||||
module.exports.fillRowOutput = fillRowOutput
|
||||
module.exports.automationQueue = automationQueue
|
||||
|
||||
module.exports.BUILTIN_DEFINITIONS = BUILTIN_DEFINITIONS
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
exports.makePartial = obj => {
|
||||
const newObj = {}
|
||||
for (let key of Object.keys(obj)) {
|
||||
if (typeof obj[key] === "object") {
|
||||
newObj[key] = exports.makePartial(obj[key])
|
||||
} else {
|
||||
newObj[key] = obj[key]
|
||||
}
|
||||
}
|
||||
return expect.objectContaining(newObj)
|
||||
}
|
Loading…
Reference in New Issue