Update to improve test cases and get JOI to work as expected.
This commit is contained in:
parent
5997550fbb
commit
31939e3dc9
|
@ -23,6 +23,7 @@ const workflowActions = store => ({
|
||||||
create: async ({ name }) => {
|
create: async ({ name }) => {
|
||||||
const workflow = {
|
const workflow = {
|
||||||
name,
|
name,
|
||||||
|
type: "workflow",
|
||||||
definition: {
|
definition: {
|
||||||
steps: [],
|
steps: [],
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,6 +2,7 @@ const {
|
||||||
createClientDatabase,
|
createClientDatabase,
|
||||||
createApplication,
|
createApplication,
|
||||||
createInstance,
|
createInstance,
|
||||||
|
createModel,
|
||||||
defaultHeaders,
|
defaultHeaders,
|
||||||
supertest,
|
supertest,
|
||||||
insertDocument,
|
insertDocument,
|
||||||
|
@ -19,24 +20,24 @@ const TEST_WORKFLOW = {
|
||||||
|
|
||||||
},
|
},
|
||||||
definition: {
|
definition: {
|
||||||
triggers: [
|
trigger: {},
|
||||||
|
steps: [
|
||||||
],
|
],
|
||||||
next: {
|
},
|
||||||
stepId: "abc123",
|
type: "workflow",
|
||||||
type: "SERVER",
|
|
||||||
conditions: {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ACTION_DEFINITIONS = {}
|
||||||
|
let TRIGGER_DEFINITIONS = {}
|
||||||
|
let LOGIC_DEFINITIONS = {}
|
||||||
|
|
||||||
describe("/workflows", () => {
|
describe("/workflows", () => {
|
||||||
let request
|
let request
|
||||||
let server
|
let server
|
||||||
let app
|
let app
|
||||||
let instance
|
let instance
|
||||||
let workflow
|
let workflow
|
||||||
|
let model
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
({ request, server } = await supertest())
|
({ request, server } = await supertest())
|
||||||
|
@ -45,8 +46,9 @@ describe("/workflows", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
if (workflow) await destroyDocument(workflow.id)
|
||||||
instance = await createInstance(request, app._id)
|
instance = await createInstance(request, app._id)
|
||||||
if (workflow) await destroyDocument(workflow.id);
|
model = await createModel(request, app._id, instance._id)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
@ -58,9 +60,77 @@ describe("/workflows", () => {
|
||||||
type: "workflow",
|
type: "workflow",
|
||||||
...TEST_WORKFLOW
|
...TEST_WORKFLOW
|
||||||
});
|
});
|
||||||
|
workflow = { ...workflow, ...TEST_WORKFLOW }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe("get definitions", () => {
|
||||||
|
it("returns a list of definitions for actions", async () => {
|
||||||
|
const res = await request
|
||||||
|
.get(`/api/workflows/action/list`)
|
||||||
|
.set(defaultHeaders(app._id, instance._id))
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(Object.keys(res.body).length).not.toEqual(0)
|
||||||
|
ACTION_DEFINITIONS = res.body
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of definitions for triggers", async () => {
|
||||||
|
const res = await request
|
||||||
|
.get(`/api/workflows/trigger/list`)
|
||||||
|
.set(defaultHeaders(app._id, instance._id))
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(Object.keys(res.body).length).not.toEqual(0)
|
||||||
|
TRIGGER_DEFINITIONS = res.body
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of definitions for actions", async () => {
|
||||||
|
const res = await request
|
||||||
|
.get(`/api/workflows/logic/list`)
|
||||||
|
.set(defaultHeaders(app._id, instance._id))
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(Object.keys(res.body).length).not.toEqual(0)
|
||||||
|
LOGIC_DEFINITIONS = res.body
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns all of the definitions in one", async () => {
|
||||||
|
const res = await request
|
||||||
|
.get(`/api/workflows/definitions/list`)
|
||||||
|
.set(defaultHeaders(app._id, instance._id))
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(Object.keys(res.body.action).length).toEqual(Object.keys(ACTION_DEFINITIONS).length)
|
||||||
|
expect(Object.keys(res.body.trigger).length).toEqual(Object.keys(TRIGGER_DEFINITIONS).length)
|
||||||
|
expect(Object.keys(res.body.logic).length).toEqual(Object.keys(LOGIC_DEFINITIONS).length)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
|
it("should setup the workflow fully", () => {
|
||||||
|
let trigger = TRIGGER_DEFINITIONS["RECORD_SAVED"]
|
||||||
|
trigger.inputs.modelId = model._id
|
||||||
|
trigger.id = "wadiawdo34"
|
||||||
|
let saveAction = ACTION_DEFINITIONS["SAVE_RECORD"]
|
||||||
|
saveAction.inputs.record = {
|
||||||
|
modelId: model._id,
|
||||||
|
name: "Testing",
|
||||||
|
}
|
||||||
|
saveAction.id = "awde444wk"
|
||||||
|
let deleteAction = ACTION_DEFINITIONS["DELETE_RECORD"]
|
||||||
|
deleteAction.inputs.id = "{{blocks[1].id}}"
|
||||||
|
deleteAction.inputs.revision = "{{blocks[1].revision}}"
|
||||||
|
deleteAction.id = "78MOt8nQO"
|
||||||
|
|
||||||
|
TEST_WORKFLOW.definition.steps.push(saveAction)
|
||||||
|
TEST_WORKFLOW.definition.steps.push(deleteAction)
|
||||||
|
TEST_WORKFLOW.definition.trigger = trigger
|
||||||
|
})
|
||||||
|
|
||||||
it("returns a success message when the workflow is successfully created", async () => {
|
it("returns a success message when the workflow is successfully created", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api/workflows`)
|
.post(`/api/workflows`)
|
||||||
|
@ -91,6 +161,7 @@ describe("/workflows", () => {
|
||||||
workflow._id = workflow.id
|
workflow._id = workflow.id
|
||||||
workflow._rev = workflow.rev
|
workflow._rev = workflow.rev
|
||||||
workflow.name = "Updated Name";
|
workflow.name = "Updated Name";
|
||||||
|
workflow.type = "workflow"
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.put(`/api/workflows`)
|
.put(`/api/workflows`)
|
||||||
|
|
|
@ -23,18 +23,20 @@ function generateStepSchema(allowStepTypes) {
|
||||||
}).unknown(true)
|
}).unknown(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateValidator(existing = false) {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const workflowValidator = joiValidator.body(Joi.object({
|
return joiValidator.body(Joi.object({
|
||||||
live: Joi.bool(),
|
live: Joi.bool(),
|
||||||
id: Joi.string().required(),
|
id: existing ? Joi.string().required() : Joi.string(),
|
||||||
rev: Joi.string().required(),
|
rev: existing ? Joi.string().required() : Joi.string(),
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required(),
|
||||||
type: Joi.string().valid("workflow").required(),
|
type: Joi.string().valid("workflow").required(),
|
||||||
definition: Joi.object({
|
definition: Joi.object({
|
||||||
steps: Joi.array().required().items(generateStepSchema(["ACTION", "LOGIC"])),
|
steps: Joi.array().required().items(generateStepSchema(["ACTION", "LOGIC"])),
|
||||||
trigger: generateStepSchema(["TRIGGER"]).required(),
|
trigger: generateStepSchema(["TRIGGER"]),
|
||||||
}).required().unknown(true),
|
}).required().unknown(true),
|
||||||
}).unknown(true))
|
}).unknown(true))
|
||||||
|
}
|
||||||
|
|
||||||
router
|
router
|
||||||
.get(
|
.get(
|
||||||
|
@ -62,13 +64,13 @@ router
|
||||||
.put(
|
.put(
|
||||||
"/api/workflows",
|
"/api/workflows",
|
||||||
authorized(BUILDER),
|
authorized(BUILDER),
|
||||||
workflowValidator,
|
generateValidator(true),
|
||||||
controller.update
|
controller.update
|
||||||
)
|
)
|
||||||
.post(
|
.post(
|
||||||
"/api/workflows",
|
"/api/workflows",
|
||||||
authorized(BUILDER),
|
authorized(BUILDER),
|
||||||
workflowValidator,
|
generateValidator(false),
|
||||||
controller.create
|
controller.create
|
||||||
)
|
)
|
||||||
.post("/api/workflows/:id/trigger", controller.trigger)
|
.post("/api/workflows/:id/trigger", controller.trigger)
|
||||||
|
|
|
@ -2,9 +2,16 @@ function validate(schema, property) {
|
||||||
// Return a Koa middleware function
|
// Return a Koa middleware function
|
||||||
return (ctx, next) => {
|
return (ctx, next) => {
|
||||||
if (schema) {
|
if (schema) {
|
||||||
const { error } = schema.validate(ctx[property])
|
let params =
|
||||||
|
ctx[property] != null
|
||||||
|
? ctx[property]
|
||||||
|
: ctx.request[property] != null
|
||||||
|
? ctx.request[property]
|
||||||
|
: null
|
||||||
|
const { error } = schema.validate(params)
|
||||||
if (error) {
|
if (error) {
|
||||||
ctx.throw(400, `Invalid ${property} - ${error.message}`)
|
ctx.throw(400, `Invalid ${property} - ${error.message}`)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return next()
|
return next()
|
||||||
|
|
|
@ -7,6 +7,7 @@ module.exports.definition = {
|
||||||
icon: "ri-user-add-fill",
|
icon: "ri-user-add-fill",
|
||||||
name: "Create User",
|
name: "Create User",
|
||||||
type: "ACTION",
|
type: "ACTION",
|
||||||
|
stepId: "CREATE_USER",
|
||||||
inputs: {},
|
inputs: {},
|
||||||
schema: {
|
schema: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
|
@ -5,6 +5,7 @@ module.exports.definition = {
|
||||||
icon: "ri-time-fill",
|
icon: "ri-time-fill",
|
||||||
tagline: "Delay for {{inputs.time}} milliseconds",
|
tagline: "Delay for {{inputs.time}} milliseconds",
|
||||||
description: "Delay the workflow until an amount of time has passed",
|
description: "Delay the workflow until an amount of time has passed",
|
||||||
|
stepId: "DELAY",
|
||||||
inputs: {},
|
inputs: {},
|
||||||
schema: {
|
schema: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
|
@ -6,6 +6,7 @@ module.exports.definition = {
|
||||||
name: "Delete Record",
|
name: "Delete Record",
|
||||||
tagline: "Delete a {{inputs.enriched.model.name}} record",
|
tagline: "Delete a {{inputs.enriched.model.name}} record",
|
||||||
type: "ACTION",
|
type: "ACTION",
|
||||||
|
stepId: "DELETE_RECORD",
|
||||||
inputs: {},
|
inputs: {},
|
||||||
schema: {
|
schema: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
|
@ -11,6 +11,7 @@ module.exports.definition = {
|
||||||
icon: "ri-git-branch-line",
|
icon: "ri-git-branch-line",
|
||||||
description: "Filter any workflows which do not meet certain conditions",
|
description: "Filter any workflows which do not meet certain conditions",
|
||||||
type: "LOGIC",
|
type: "LOGIC",
|
||||||
|
stepId: "FILTER",
|
||||||
inputs: {},
|
inputs: {},
|
||||||
schema: {
|
schema: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
|
@ -6,6 +6,7 @@ module.exports.definition = {
|
||||||
icon: "ri-save-3-fill",
|
icon: "ri-save-3-fill",
|
||||||
description: "Save a record to your database",
|
description: "Save a record to your database",
|
||||||
type: "ACTION",
|
type: "ACTION",
|
||||||
|
stepId: "SAVE_RECORD",
|
||||||
inputs: {},
|
inputs: {},
|
||||||
schema: {
|
schema: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
|
@ -7,6 +7,7 @@ module.exports.definition = {
|
||||||
icon: "ri-mail-open-fill",
|
icon: "ri-mail-open-fill",
|
||||||
name: "Send Email",
|
name: "Send Email",
|
||||||
type: "ACTION",
|
type: "ACTION",
|
||||||
|
stepId: "SEND_EMAIL",
|
||||||
inputs: {},
|
inputs: {},
|
||||||
schema: {
|
schema: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Orchestrator {
|
||||||
constructor(workflow, triggerOutput) {
|
constructor(workflow, triggerOutput) {
|
||||||
this._instanceId = triggerOutput.instanceId
|
this._instanceId = triggerOutput.instanceId
|
||||||
// block zero is never used as the mustache is zero indexed for customer facing
|
// block zero is never used as the mustache is zero indexed for customer facing
|
||||||
this._context = { blocks: [{}, triggerOutput] }
|
this._context = { blocks: [{}], trigger: triggerOutput }
|
||||||
this._workflow = workflow
|
this._workflow = workflow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ const BUILTIN_DEFINITIONS = {
|
||||||
icon: "ri-save-line",
|
icon: "ri-save-line",
|
||||||
tagline: "Record is added to {{inputs.enriched.model.name}}",
|
tagline: "Record is added to {{inputs.enriched.model.name}}",
|
||||||
description: "Fired when a record is saved to your database",
|
description: "Fired when a record is saved to your database",
|
||||||
|
stepId: "RECORD_SAVED",
|
||||||
inputs: {},
|
inputs: {},
|
||||||
schema: {
|
schema: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
@ -42,6 +43,7 @@ const BUILTIN_DEFINITIONS = {
|
||||||
icon: "ri-delete-bin-line",
|
icon: "ri-delete-bin-line",
|
||||||
tagline: "Record is deleted from {{inputs.enriched.model.name}}",
|
tagline: "Record is deleted from {{inputs.enriched.model.name}}",
|
||||||
description: "Fired when a record is deleted from your database",
|
description: "Fired when a record is deleted from your database",
|
||||||
|
stepId: "RECORD_DELETED",
|
||||||
inputs: {},
|
inputs: {},
|
||||||
schema: {
|
schema: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|
Loading…
Reference in New Issue