Merge pull request #1252 from Budibase/feature/test-refactor
Server test refactor
This commit is contained in:
commit
1f03851f0d
|
@ -52,7 +52,8 @@
|
||||||
"collectCoverageFrom": [
|
"collectCoverageFrom": [
|
||||||
"src/**/*.js",
|
"src/**/*.js",
|
||||||
"!**/node_modules/**",
|
"!**/node_modules/**",
|
||||||
"!src/db/views/*.js"
|
"!src/db/views/*.js",
|
||||||
|
"!src/api/routes/tests"
|
||||||
],
|
],
|
||||||
"coverageReporters": [
|
"coverageReporters": [
|
||||||
"lcov",
|
"lcov",
|
||||||
|
|
|
@ -8,14 +8,13 @@ const {
|
||||||
|
|
||||||
exports.fetch = async function(ctx) {
|
exports.fetch = async function(ctx) {
|
||||||
const database = new CouchDB(ctx.user.appId)
|
const database = new CouchDB(ctx.user.appId)
|
||||||
const datasources = (
|
ctx.body = (
|
||||||
await database.allDocs(
|
await database.allDocs(
|
||||||
getDatasourceParams(null, {
|
getDatasourceParams(null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
).rows.map(row => row.doc)
|
).rows.map(row => row.doc)
|
||||||
ctx.body = datasources
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.save = async function(ctx) {
|
exports.save = async function(ctx) {
|
||||||
|
|
|
@ -1,25 +1,15 @@
|
||||||
const {
|
const { clearAllApps, checkBuilderEndpoint } = require("./utilities/TestFunctions")
|
||||||
createApplication,
|
const setup = require("./utilities")
|
||||||
builderEndpointShouldBlockNormalUsers,
|
|
||||||
supertest,
|
|
||||||
clearApplications,
|
|
||||||
defaultHeaders,
|
|
||||||
} = require("./couchTestUtils")
|
|
||||||
|
|
||||||
describe("/applications", () => {
|
describe("/applications", () => {
|
||||||
let request
|
let request = setup.getRequest()
|
||||||
let server
|
let config = setup.getConfig()
|
||||||
|
|
||||||
beforeAll(async () => {
|
afterAll(setup.afterAll)
|
||||||
({ request, server } = await supertest())
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await clearApplications(request)
|
await clearAllApps()
|
||||||
})
|
await config.init()
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
server.close()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
|
@ -27,7 +17,7 @@ describe("/applications", () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.post("/api/applications")
|
.post("/api/applications")
|
||||||
.send({ name: "My App" })
|
.send({ name: "My App" })
|
||||||
.set(defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.res.statusMessage).toEqual("Application My App created successfully")
|
expect(res.res.statusMessage).toEqual("Application My App created successfully")
|
||||||
|
@ -35,41 +25,35 @@ describe("/applications", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
const otherApplication = await createApplication(request)
|
await checkBuilderEndpoint({
|
||||||
const appId = otherApplication.instance._id
|
config,
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
|
||||||
request,
|
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/applications`,
|
url: `/api/applications`,
|
||||||
appId: appId,
|
|
||||||
body: { name: "My App" }
|
body: { name: "My App" }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("fetch", () => {
|
describe("fetch", () => {
|
||||||
it("lists all applications", async () => {
|
it("lists all applications", async () => {
|
||||||
await createApplication(request, "app1")
|
await config.createApp(request, "app1")
|
||||||
await createApplication(request, "app2")
|
await config.createApp(request, "app2")
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.get("/api/applications")
|
.get("/api/applications")
|
||||||
.set(defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.length).toBe(2)
|
// two created apps + the inited app
|
||||||
|
expect(res.body.length).toBe(3)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
const otherApplication = await createApplication(request)
|
await checkBuilderEndpoint({
|
||||||
const appId = otherApplication.instance._id
|
config,
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
|
||||||
request,
|
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/applications`,
|
url: `/api/applications`,
|
||||||
appId: appId,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,74 +1,33 @@
|
||||||
const {
|
const {
|
||||||
createApplication,
|
checkBuilderEndpoint,
|
||||||
createTable,
|
getAllTableRows,
|
||||||
getAllFromTable,
|
clearAllAutomations,
|
||||||
defaultHeaders,
|
} = require("./utilities/TestFunctions")
|
||||||
supertest,
|
const { basicAutomation } = require("./utilities/structures")
|
||||||
insertDocument,
|
const setup = require("./utilities")
|
||||||
destroyDocument,
|
|
||||||
builderEndpointShouldBlockNormalUsers
|
|
||||||
} = require("./couchTestUtils")
|
|
||||||
let { generateAutomationID } = require("../../../db/utils")
|
|
||||||
|
|
||||||
const { delay } = require("./testUtils")
|
|
||||||
|
|
||||||
const MAX_RETRIES = 4
|
const MAX_RETRIES = 4
|
||||||
const AUTOMATION_ID = generateAutomationID()
|
|
||||||
const TEST_AUTOMATION = {
|
|
||||||
_id: AUTOMATION_ID,
|
|
||||||
name: "My Automation",
|
|
||||||
screenId: "kasdkfldsafkl",
|
|
||||||
live: true,
|
|
||||||
uiTree: {
|
|
||||||
|
|
||||||
},
|
|
||||||
definition: {
|
|
||||||
trigger: {},
|
|
||||||
steps: [
|
|
||||||
],
|
|
||||||
},
|
|
||||||
type: "automation",
|
|
||||||
}
|
|
||||||
|
|
||||||
let ACTION_DEFINITIONS = {}
|
let ACTION_DEFINITIONS = {}
|
||||||
let TRIGGER_DEFINITIONS = {}
|
let TRIGGER_DEFINITIONS = {}
|
||||||
let LOGIC_DEFINITIONS = {}
|
let LOGIC_DEFINITIONS = {}
|
||||||
|
|
||||||
describe("/automations", () => {
|
describe("/automations", () => {
|
||||||
let request
|
let request = setup.getRequest()
|
||||||
let server
|
let config = setup.getConfig()
|
||||||
let app
|
|
||||||
let appId
|
|
||||||
let automation
|
let automation
|
||||||
let automationId
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
afterAll(setup.afterAll)
|
||||||
({ request, server } = await supertest())
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = await createApplication(request)
|
await config.init()
|
||||||
appId = app.instance._id
|
|
||||||
if (automation) await destroyDocument(automation.id)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
const triggerWorkflow = async automation => {
|
||||||
server.close()
|
|
||||||
})
|
|
||||||
|
|
||||||
const createAutomation = async () => {
|
|
||||||
automation = await insertDocument(appId, {
|
|
||||||
type: "automation",
|
|
||||||
...TEST_AUTOMATION
|
|
||||||
})
|
|
||||||
automation = { ...automation, ...TEST_AUTOMATION }
|
|
||||||
}
|
|
||||||
|
|
||||||
const triggerWorkflow = async (automationId) => {
|
|
||||||
return await request
|
return await request
|
||||||
.post(`/api/automations/${automationId}/trigger`)
|
.post(`/api/automations/${automation._id}/trigger`)
|
||||||
.send({ name: "Test", description: "TEST" })
|
.send({ name: "Test", description: "TEST" })
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
}
|
}
|
||||||
|
@ -77,7 +36,7 @@ describe("/automations", () => {
|
||||||
it("returns a list of definitions for actions", async () => {
|
it("returns a list of definitions for actions", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/automations/action/list`)
|
.get(`/api/automations/action/list`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -88,7 +47,7 @@ describe("/automations", () => {
|
||||||
it("returns a list of definitions for triggers", async () => {
|
it("returns a list of definitions for triggers", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/automations/trigger/list`)
|
.get(`/api/automations/trigger/list`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -99,7 +58,7 @@ describe("/automations", () => {
|
||||||
it("returns a list of definitions for actions", async () => {
|
it("returns a list of definitions for actions", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/automations/logic/list`)
|
.get(`/api/automations/logic/list`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -110,7 +69,7 @@ describe("/automations", () => {
|
||||||
it("returns all of the definitions in one", async () => {
|
it("returns all of the definitions in one", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/automations/definitions/list`)
|
.get(`/api/automations/definitions/list`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -121,6 +80,7 @@ describe("/automations", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
|
const autoConfig = basicAutomation()
|
||||||
it("should setup the automation fully", () => {
|
it("should setup the automation fully", () => {
|
||||||
let trigger = TRIGGER_DEFINITIONS["ROW_SAVED"]
|
let trigger = TRIGGER_DEFINITIONS["ROW_SAVED"]
|
||||||
trigger.id = "wadiawdo34"
|
trigger.id = "wadiawdo34"
|
||||||
|
@ -131,52 +91,51 @@ describe("/automations", () => {
|
||||||
}
|
}
|
||||||
createAction.id = "awde444wk"
|
createAction.id = "awde444wk"
|
||||||
|
|
||||||
TEST_AUTOMATION.definition.steps.push(createAction)
|
autoConfig.definition.steps.push(createAction)
|
||||||
TEST_AUTOMATION.definition.trigger = trigger
|
autoConfig.definition.trigger = trigger
|
||||||
})
|
})
|
||||||
|
|
||||||
it("returns a success message when the automation is successfully created", async () => {
|
it("returns a success message when the automation is successfully created", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api/automations`)
|
.post(`/api/automations`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.send(TEST_AUTOMATION)
|
.send(autoConfig)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.message).toEqual("Automation created successfully")
|
expect(res.body.message).toEqual("Automation created successfully")
|
||||||
expect(res.body.automation.name).toEqual("My Automation")
|
expect(res.body.automation.name).toEqual("My Automation")
|
||||||
expect(res.body.automation._id).not.toEqual(null)
|
expect(res.body.automation._id).not.toEqual(null)
|
||||||
automationId = res.body.automation._id
|
automation = res.body.automation
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
await checkBuilderEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/automations`,
|
url: `/api/automations`,
|
||||||
appId: appId,
|
body: autoConfig
|
||||||
body: TEST_AUTOMATION
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("trigger", () => {
|
describe("trigger", () => {
|
||||||
it("trigger the automation successfully", async () => {
|
it("trigger the automation successfully", async () => {
|
||||||
let table = await createTable(request, appId)
|
let table = await config.createTable()
|
||||||
TEST_AUTOMATION.definition.trigger.inputs.tableId = table._id
|
automation.definition.trigger.inputs.tableId = table._id
|
||||||
TEST_AUTOMATION.definition.steps[0].inputs.row.tableId = table._id
|
automation.definition.steps[0].inputs.row.tableId = table._id
|
||||||
await createAutomation()
|
automation = await config.createAutomation(automation)
|
||||||
await delay(500)
|
await setup.delay(500)
|
||||||
const res = await triggerWorkflow(automation._id)
|
const res = await triggerWorkflow(automation)
|
||||||
// this looks a bit mad but we don't actually have a way to wait for a response from the automation to
|
// this looks a bit mad but we don't actually have a way to wait for a response from the automation to
|
||||||
// know that it has finished all of its actions - this is currently the best way
|
// know that it has finished all of its actions - this is currently the best way
|
||||||
// also when this runs in CI it is very temper-mental so for now trying to make run stable by repeating until it works
|
// also when this runs in CI it is very temper-mental so for now trying to make run stable by repeating until it works
|
||||||
// TODO: update when workflow logs are a thing
|
// TODO: update when workflow logs are a thing
|
||||||
for (let tries = 0; tries < MAX_RETRIES; tries++) {
|
for (let tries = 0; tries < MAX_RETRIES; tries++) {
|
||||||
expect(res.body.message).toEqual(`Automation ${automation._id} has been triggered.`)
|
expect(res.body.message).toEqual(`Automation ${automation._id} has been triggered.`)
|
||||||
expect(res.body.automation.name).toEqual(TEST_AUTOMATION.name)
|
expect(res.body.automation.name).toEqual(automation.name)
|
||||||
await delay(500)
|
await setup.delay(500)
|
||||||
let elements = await getAllFromTable(request, appId, table._id)
|
let elements = await getAllTableRows(config)
|
||||||
// don't test it unless there are values to test
|
// don't test it unless there are values to test
|
||||||
if (elements.length > 1) {
|
if (elements.length > 1) {
|
||||||
expect(elements.length).toEqual(5)
|
expect(elements.length).toEqual(5)
|
||||||
|
@ -191,65 +150,63 @@ describe("/automations", () => {
|
||||||
|
|
||||||
describe("update", () => {
|
describe("update", () => {
|
||||||
it("updates a automations data", async () => {
|
it("updates a automations data", async () => {
|
||||||
await createAutomation()
|
automation = await config.createAutomation(automation)
|
||||||
automation._id = automation.id
|
|
||||||
automation._rev = automation.rev
|
|
||||||
automation.name = "Updated Name"
|
automation.name = "Updated Name"
|
||||||
automation.type = "automation"
|
automation.type = "automation"
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.put(`/api/automations`)
|
.put(`/api/automations`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.send(automation)
|
.send(automation)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.message).toEqual(`Automation ${AUTOMATION_ID} updated successfully.`)
|
expect(res.body.message).toEqual(`Automation ${automation._id} updated successfully.`)
|
||||||
expect(res.body.automation.name).toEqual("Updated Name")
|
expect(res.body.automation.name).toEqual("Updated Name")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("fetch", () => {
|
describe("fetch", () => {
|
||||||
it("return all the automations for an instance", async () => {
|
it("return all the automations for an instance", async () => {
|
||||||
await createAutomation()
|
await clearAllAutomations(config)
|
||||||
|
const autoConfig = basicAutomation()
|
||||||
|
automation = await config.createAutomation(autoConfig)
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/automations`)
|
.get(`/api/automations`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body[0]).toEqual(expect.objectContaining(TEST_AUTOMATION))
|
expect(res.body[0]).toEqual(expect.objectContaining(autoConfig))
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
await checkBuilderEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/automations`,
|
url: `/api/automations`,
|
||||||
appId: appId,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("destroy", () => {
|
describe("destroy", () => {
|
||||||
it("deletes a automation by its ID", async () => {
|
it("deletes a automation by its ID", async () => {
|
||||||
await createAutomation()
|
const automation = await config.createAutomation()
|
||||||
const res = await request
|
const res = await request
|
||||||
.delete(`/api/automations/${automation.id}/${automation.rev}`)
|
.delete(`/api/automations/${automation.id}/${automation.rev}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.id).toEqual(TEST_AUTOMATION._id)
|
expect(res.body.id).toEqual(automation._id)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await createAutomation()
|
const automation = await config.createAutomation()
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
await checkBuilderEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: `/api/automations/${automation.id}/${automation._rev}`,
|
url: `/api/automations/${automation.id}/${automation._rev}`,
|
||||||
appId: appId,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,326 +0,0 @@
|
||||||
const CouchDB = require("../../../db")
|
|
||||||
const supertest = require("supertest")
|
|
||||||
const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
|
|
||||||
const packageJson = require("../../../../package")
|
|
||||||
const jwt = require("jsonwebtoken")
|
|
||||||
const env = require("../../../environment")
|
|
||||||
const {
|
|
||||||
BUILTIN_PERMISSION_IDS,
|
|
||||||
} = require("../../../utilities/security/permissions")
|
|
||||||
|
|
||||||
const TEST_CLIENT_ID = "test-client-id"
|
|
||||||
|
|
||||||
exports.TEST_CLIENT_ID = TEST_CLIENT_ID
|
|
||||||
exports.supertest = async () => {
|
|
||||||
let request
|
|
||||||
let server
|
|
||||||
env.PORT = 4002
|
|
||||||
server = require("../../../app")
|
|
||||||
|
|
||||||
request = supertest(server)
|
|
||||||
return { request, server }
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.defaultHeaders = appId => {
|
|
||||||
const builderUser = {
|
|
||||||
userId: "BUILDER",
|
|
||||||
roleId: BUILTIN_ROLE_IDS.BUILDER,
|
|
||||||
}
|
|
||||||
|
|
||||||
const builderToken = jwt.sign(builderUser, env.JWT_SECRET)
|
|
||||||
|
|
||||||
const headers = {
|
|
||||||
Accept: "application/json",
|
|
||||||
Cookie: [`budibase:builder:local=${builderToken}`],
|
|
||||||
}
|
|
||||||
if (appId) {
|
|
||||||
headers["x-budibase-app-id"] = appId
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.publicHeaders = appId => {
|
|
||||||
const headers = {
|
|
||||||
Accept: "application/json",
|
|
||||||
}
|
|
||||||
if (appId) {
|
|
||||||
headers["x-budibase-app-id"] = appId
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.BASE_TABLE = {
|
|
||||||
name: "TestTable",
|
|
||||||
type: "table",
|
|
||||||
key: "name",
|
|
||||||
schema: {
|
|
||||||
name: {
|
|
||||||
type: "string",
|
|
||||||
constraints: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: "string",
|
|
||||||
constraints: {
|
|
||||||
type: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.createTable = async (request, appId, table, removeId = true) => {
|
|
||||||
if (removeId && table != null && table._id) {
|
|
||||||
delete table._id
|
|
||||||
}
|
|
||||||
table = table || exports.BASE_TABLE
|
|
||||||
|
|
||||||
const res = await request
|
|
||||||
.post(`/api/tables`)
|
|
||||||
.set(exports.defaultHeaders(appId))
|
|
||||||
.send(table)
|
|
||||||
return res.body
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.makeBasicRow = tableId => {
|
|
||||||
return {
|
|
||||||
name: "Test Contact",
|
|
||||||
description: "original description",
|
|
||||||
status: "new",
|
|
||||||
tableId: tableId,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.createRow = async (request, appId, tableId, row = null) => {
|
|
||||||
row = row || exports.makeBasicRow(tableId)
|
|
||||||
const res = await request
|
|
||||||
.post(`/api/${tableId}/rows`)
|
|
||||||
.send(row)
|
|
||||||
.set(exports.defaultHeaders(appId))
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
return res.body
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.createRole = async (request, appId) => {
|
|
||||||
const roleBody = {
|
|
||||||
name: "NewRole",
|
|
||||||
inherits: BUILTIN_ROLE_IDS.BASIC,
|
|
||||||
permissionId: BUILTIN_PERMISSION_IDS.READ_ONLY,
|
|
||||||
}
|
|
||||||
const res = await request
|
|
||||||
.post(`/api/roles`)
|
|
||||||
.send(roleBody)
|
|
||||||
.set(exports.defaultHeaders(appId))
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
return res.body
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.addPermission = async (
|
|
||||||
request,
|
|
||||||
appId,
|
|
||||||
role,
|
|
||||||
resource,
|
|
||||||
level = "read"
|
|
||||||
) => {
|
|
||||||
const res = await request
|
|
||||||
.post(`/api/permission/${role}/${resource}/${level}`)
|
|
||||||
.set(exports.defaultHeaders(appId))
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
return res.body
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.createLinkedTable = async (request, appId) => {
|
|
||||||
// get the ID to link to
|
|
||||||
const table = await exports.createTable(request, appId)
|
|
||||||
table.primaryDisplay = "name"
|
|
||||||
table.schema.link = {
|
|
||||||
type: "link",
|
|
||||||
fieldName: "link",
|
|
||||||
tableId: table._id,
|
|
||||||
}
|
|
||||||
return exports.createTable(request, appId, table, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.createAttachmentTable = async (request, appId) => {
|
|
||||||
const table = await exports.createTable(request, appId)
|
|
||||||
table.schema.attachment = {
|
|
||||||
type: "attachment",
|
|
||||||
}
|
|
||||||
return exports.createTable(request, appId, table, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.getAllFromTable = async (request, appId, tableId) => {
|
|
||||||
const res = await request
|
|
||||||
.get(`/api/${tableId}/rows`)
|
|
||||||
.set(exports.defaultHeaders(appId))
|
|
||||||
return res.body
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.createView = async (request, appId, tableId, view) => {
|
|
||||||
view = view || {
|
|
||||||
map: "function(doc) { emit(doc[doc.key], doc._id); } ",
|
|
||||||
tableId: tableId,
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await request
|
|
||||||
.post(`/api/views`)
|
|
||||||
.set(exports.defaultHeaders(appId))
|
|
||||||
.send(view)
|
|
||||||
return res.body
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.createApplication = async (request, name = "test_application") => {
|
|
||||||
const res = await request
|
|
||||||
.post("/api/applications")
|
|
||||||
.send({
|
|
||||||
name,
|
|
||||||
})
|
|
||||||
.set(exports.defaultHeaders())
|
|
||||||
return res.body
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.clearApplications = async request => {
|
|
||||||
const res = await request
|
|
||||||
.get("/api/applications")
|
|
||||||
.set(exports.defaultHeaders())
|
|
||||||
for (let app of res.body) {
|
|
||||||
const appId = app._id
|
|
||||||
await request
|
|
||||||
.delete(`/api/applications/${appId}`)
|
|
||||||
.set(exports.defaultHeaders(appId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.createUser = async (
|
|
||||||
request,
|
|
||||||
appId,
|
|
||||||
email = "babs@babs.com",
|
|
||||||
password = "babs_password"
|
|
||||||
) => {
|
|
||||||
const res = await request
|
|
||||||
.post(`/api/users`)
|
|
||||||
.set(exports.defaultHeaders(appId))
|
|
||||||
.send({
|
|
||||||
name: "Bill",
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
roleId: BUILTIN_ROLE_IDS.POWER,
|
|
||||||
})
|
|
||||||
return res.body
|
|
||||||
}
|
|
||||||
|
|
||||||
const createUserWithRole = async (request, appId, roleId, email) => {
|
|
||||||
const password = `password_${email}`
|
|
||||||
await request
|
|
||||||
.post(`/api/users`)
|
|
||||||
.set(exports.defaultHeaders(appId))
|
|
||||||
.send({
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
roleId,
|
|
||||||
})
|
|
||||||
|
|
||||||
const anonUser = {
|
|
||||||
userId: "ANON",
|
|
||||||
roleId: BUILTIN_ROLE_IDS.PUBLIC,
|
|
||||||
appId: appId,
|
|
||||||
version: packageJson.version,
|
|
||||||
}
|
|
||||||
|
|
||||||
const anonToken = jwt.sign(anonUser, env.JWT_SECRET)
|
|
||||||
|
|
||||||
const loginResult = await request
|
|
||||||
.post(`/api/authenticate`)
|
|
||||||
.set({
|
|
||||||
Cookie: `budibase:${appId}:local=${anonToken}`,
|
|
||||||
"x-budibase-app-id": appId,
|
|
||||||
})
|
|
||||||
.send({ email, password })
|
|
||||||
|
|
||||||
// returning necessary request headers
|
|
||||||
return {
|
|
||||||
Accept: "application/json",
|
|
||||||
Cookie: loginResult.headers["set-cookie"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.testPermissionsForEndpoint = async ({
|
|
||||||
request,
|
|
||||||
method,
|
|
||||||
url,
|
|
||||||
body,
|
|
||||||
appId,
|
|
||||||
passRole,
|
|
||||||
failRole,
|
|
||||||
}) => {
|
|
||||||
const passHeader = await createUserWithRole(
|
|
||||||
request,
|
|
||||||
appId,
|
|
||||||
passRole,
|
|
||||||
"passUser@budibase.com"
|
|
||||||
)
|
|
||||||
|
|
||||||
await createRequest(request, method, url, body)
|
|
||||||
.set(passHeader)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
const failHeader = await createUserWithRole(
|
|
||||||
request,
|
|
||||||
appId,
|
|
||||||
failRole,
|
|
||||||
"failUser@budibase.com"
|
|
||||||
)
|
|
||||||
|
|
||||||
await createRequest(request, method, url, body)
|
|
||||||
.set(failHeader)
|
|
||||||
.expect(403)
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.builderEndpointShouldBlockNormalUsers = async ({
|
|
||||||
request,
|
|
||||||
method,
|
|
||||||
url,
|
|
||||||
body,
|
|
||||||
appId,
|
|
||||||
}) => {
|
|
||||||
const headers = await createUserWithRole(
|
|
||||||
request,
|
|
||||||
appId,
|
|
||||||
BUILTIN_ROLE_IDS.BASIC,
|
|
||||||
"basicUser@budibase.com"
|
|
||||||
)
|
|
||||||
|
|
||||||
await createRequest(request, method, url, body)
|
|
||||||
.set(headers)
|
|
||||||
.expect(403)
|
|
||||||
}
|
|
||||||
|
|
||||||
const createRequest = (request, method, url, body) => {
|
|
||||||
let req
|
|
||||||
|
|
||||||
if (method === "POST") req = request.post(url).send(body)
|
|
||||||
else if (method === "GET") req = request.get(url)
|
|
||||||
else if (method === "DELETE") req = request.delete(url)
|
|
||||||
else if (method === "PATCH") req = request.patch(url).send(body)
|
|
||||||
else if (method === "PUT") req = request.put(url).send(body)
|
|
||||||
|
|
||||||
return req
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.insertDocument = async (databaseId, document) => {
|
|
||||||
const { id, ...documentFields } = document
|
|
||||||
return await new CouchDB(databaseId).put({ _id: id, ...documentFields })
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.destroyDocument = async (databaseId, documentId) => {
|
|
||||||
return await new CouchDB(databaseId).destroy(documentId)
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.getDocument = async (databaseId, documentId) => {
|
|
||||||
return await new CouchDB(databaseId).get(documentId)
|
|
||||||
}
|
|
|
@ -1,67 +1,23 @@
|
||||||
const {
|
let { basicDatasource } = require("./utilities/structures")
|
||||||
supertest,
|
let { checkBuilderEndpoint } = require("./utilities/TestFunctions")
|
||||||
createApplication,
|
let setup = require("./utilities")
|
||||||
defaultHeaders,
|
|
||||||
builderEndpointShouldBlockNormalUsers,
|
|
||||||
getDocument,
|
|
||||||
insertDocument
|
|
||||||
} = require("./couchTestUtils")
|
|
||||||
let { generateDatasourceID, generateQueryID } = require("../../../db/utils")
|
|
||||||
|
|
||||||
const DATASOURCE_ID = generateDatasourceID()
|
|
||||||
const TEST_DATASOURCE = {
|
|
||||||
_id: DATASOURCE_ID,
|
|
||||||
type: "datasource",
|
|
||||||
name: "Test",
|
|
||||||
source: "POSTGRES",
|
|
||||||
config: {},
|
|
||||||
type: "datasource",
|
|
||||||
}
|
|
||||||
|
|
||||||
const TEST_QUERY = {
|
|
||||||
_id: generateQueryID(DATASOURCE_ID),
|
|
||||||
datasourceId: DATASOURCE_ID,
|
|
||||||
name:"New Query",
|
|
||||||
parameters:[],
|
|
||||||
fields:{},
|
|
||||||
schema:{},
|
|
||||||
queryVerb:"read",
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("/datasources", () => {
|
describe("/datasources", () => {
|
||||||
let request
|
let request = setup.getRequest()
|
||||||
let server
|
let config = setup.getConfig()
|
||||||
let app
|
|
||||||
let appId
|
|
||||||
let datasource
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
afterAll(setup.afterAll)
|
||||||
({ request, server } = await supertest())
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
server.close()
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = await createApplication(request)
|
await config.init()
|
||||||
appId = app.instance._id
|
})
|
||||||
});
|
|
||||||
|
|
||||||
async function createDatasource() {
|
|
||||||
return await insertDocument(appId, TEST_DATASOURCE)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createQuery() {
|
|
||||||
return await insertDocument(appId, TEST_QUERY)
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
it("should create a new datasource", async () => {
|
it("should create a new datasource", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api/datasources`)
|
.post(`/api/datasources`)
|
||||||
.send(TEST_DATASOURCE)
|
.send(basicDatasource())
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -74,7 +30,7 @@ describe("/datasources", () => {
|
||||||
let datasource
|
let datasource
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
datasource = await createDatasource()
|
datasource = await config.createDatasource()
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -84,34 +40,34 @@ describe("/datasources", () => {
|
||||||
it("returns all the datasources from the server", async () => {
|
it("returns all the datasources from the server", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/datasources`)
|
.get(`/api/datasources`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
const datasources = res.body;
|
const datasources = res.body
|
||||||
expect(datasources).toEqual([
|
expect(datasources).toEqual([
|
||||||
{
|
{
|
||||||
|
"_id": datasources[0]._id,
|
||||||
"_rev": datasources[0]._rev,
|
"_rev": datasources[0]._rev,
|
||||||
...TEST_DATASOURCE
|
...basicDatasource()
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
await checkBuilderEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/datasources`,
|
url: `/api/datasources`,
|
||||||
appId: appId,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("destroy", () => {
|
describe("destroy", () => {
|
||||||
let datasource;
|
let datasource
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
datasource = await createDatasource()
|
datasource = await config.createDatasource()
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -119,16 +75,16 @@ describe("/datasources", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("deletes queries for the datasource after deletion and returns a success message", async () => {
|
it("deletes queries for the datasource after deletion and returns a success message", async () => {
|
||||||
await createQuery(datasource.id)
|
await config.createQuery()
|
||||||
|
|
||||||
await request
|
await request
|
||||||
.delete(`/api/datasources/${datasource.id}/${datasource.rev}`)
|
.delete(`/api/datasources/${datasource._id}/${datasource._rev}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/datasources`)
|
.get(`/api/datasources`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -136,11 +92,10 @@ describe("/datasources", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
await checkBuilderEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: `/api/datasources/${datasource._id}/${datasource._rev}`,
|
url: `/api/datasources/${datasource._id}/${datasource._rev}`,
|
||||||
appId: appId,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,46 +1,30 @@
|
||||||
const {
|
|
||||||
createApplication,
|
|
||||||
createTable,
|
|
||||||
createRow,
|
|
||||||
supertest,
|
|
||||||
defaultHeaders,
|
|
||||||
addPermission,
|
|
||||||
publicHeaders,
|
|
||||||
makeBasicRow,
|
|
||||||
} = require("./couchTestUtils")
|
|
||||||
const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
|
const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
|
||||||
|
const setup = require("./utilities")
|
||||||
|
const { basicRow } = require("./utilities/structures")
|
||||||
|
|
||||||
const HIGHER_ROLE_ID = BUILTIN_ROLE_IDS.BASIC
|
const HIGHER_ROLE_ID = BUILTIN_ROLE_IDS.BASIC
|
||||||
const STD_ROLE_ID = BUILTIN_ROLE_IDS.PUBLIC
|
const STD_ROLE_ID = BUILTIN_ROLE_IDS.PUBLIC
|
||||||
|
|
||||||
describe("/permission", () => {
|
describe("/permission", () => {
|
||||||
let server
|
let request = setup.getRequest()
|
||||||
let request
|
let config = setup.getConfig()
|
||||||
let appId
|
|
||||||
let table
|
let table
|
||||||
let perms
|
let perms
|
||||||
let row
|
let row
|
||||||
|
|
||||||
beforeAll(async () => {
|
afterAll(setup.afterAll)
|
||||||
;({ request, server } = await supertest())
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
server.close()
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
let app = await createApplication(request)
|
await config.init()
|
||||||
appId = app.instance._id
|
table = await config.createTable()
|
||||||
table = await createTable(request, appId)
|
row = await config.createRow()
|
||||||
perms = await addPermission(request, appId, STD_ROLE_ID, table._id)
|
perms = await config.addPermission(STD_ROLE_ID, table._id)
|
||||||
row = await createRow(request, appId, table._id)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
async function getTablePermissions() {
|
async function getTablePermissions() {
|
||||||
return request
|
return request
|
||||||
.get(`/api/permission/${table._id}`)
|
.get(`/api/permission/${table._id}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +33,7 @@ describe("/permission", () => {
|
||||||
it("should be able to get levels", async () => {
|
it("should be able to get levels", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/permission/levels`)
|
.get(`/api/permission/levels`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body).toBeDefined()
|
expect(res.body).toBeDefined()
|
||||||
|
@ -68,7 +52,7 @@ describe("/permission", () => {
|
||||||
it("should get the resource permissions", async () => {
|
it("should get the resource permissions", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/permission/${table._id}`)
|
.get(`/api/permission/${table._id}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body["read"]).toEqual(STD_ROLE_ID)
|
expect(res.body["read"]).toEqual(STD_ROLE_ID)
|
||||||
|
@ -76,13 +60,13 @@ describe("/permission", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should get resource permissions with multiple roles", async () => {
|
it("should get resource permissions with multiple roles", async () => {
|
||||||
perms = await addPermission(request, appId, HIGHER_ROLE_ID, table._id, "write")
|
perms = await config.addPermission(HIGHER_ROLE_ID, table._id, "write")
|
||||||
const res = await getTablePermissions()
|
const res = await getTablePermissions()
|
||||||
expect(res.body["read"]).toEqual(STD_ROLE_ID)
|
expect(res.body["read"]).toEqual(STD_ROLE_ID)
|
||||||
expect(res.body["write"]).toEqual(HIGHER_ROLE_ID)
|
expect(res.body["write"]).toEqual(HIGHER_ROLE_ID)
|
||||||
const allRes = await request
|
const allRes = await request
|
||||||
.get(`/api/permission`)
|
.get(`/api/permission`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(allRes.body[table._id]["write"]).toEqual(HIGHER_ROLE_ID)
|
expect(allRes.body[table._id]["write"]).toEqual(HIGHER_ROLE_ID)
|
||||||
|
@ -94,7 +78,7 @@ describe("/permission", () => {
|
||||||
it("should be able to remove the permission", async () => {
|
it("should be able to remove the permission", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.delete(`/api/permission/${STD_ROLE_ID}/${table._id}/read`)
|
.delete(`/api/permission/${STD_ROLE_ID}/${table._id}/read`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body[0]._id).toEqual(STD_ROLE_ID)
|
expect(res.body[0]._id).toEqual(STD_ROLE_ID)
|
||||||
|
@ -107,7 +91,7 @@ describe("/permission", () => {
|
||||||
it("should be able to read the row", async () => {
|
it("should be able to read the row", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/${table._id}/rows`)
|
.get(`/api/${table._id}/rows`)
|
||||||
.set(publicHeaders(appId))
|
.set(config.publicHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body[0]._id).toEqual(row._id)
|
expect(res.body[0]._id).toEqual(row._id)
|
||||||
|
@ -116,8 +100,8 @@ describe("/permission", () => {
|
||||||
it("shouldn't allow writing from a public user", async () => {
|
it("shouldn't allow writing from a public user", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api/${table._id}/rows`)
|
.post(`/api/${table._id}/rows`)
|
||||||
.send(makeBasicRow(table._id))
|
.send(basicRow(table._id))
|
||||||
.set(publicHeaders(appId))
|
.set(config.publicHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(403)
|
.expect(403)
|
||||||
expect(res.status).toEqual(403)
|
expect(res.status).toEqual(403)
|
||||||
|
|
|
@ -1,77 +1,35 @@
|
||||||
const {
|
const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
|
||||||
supertest,
|
const { basicQuery } = require("./utilities/structures")
|
||||||
createApplication,
|
const setup = require("./utilities")
|
||||||
defaultHeaders,
|
|
||||||
builderEndpointShouldBlockNormalUsers,
|
|
||||||
getDocument,
|
|
||||||
insertDocument,
|
|
||||||
} = require("./couchTestUtils")
|
|
||||||
let { generateDatasourceID, generateQueryID } = require("../../../db/utils")
|
|
||||||
|
|
||||||
const DATASOURCE_ID = generateDatasourceID()
|
|
||||||
const TEST_DATASOURCE = {
|
|
||||||
_id: DATASOURCE_ID,
|
|
||||||
type: "datasource",
|
|
||||||
name: "Test",
|
|
||||||
source: "POSTGRES",
|
|
||||||
config: {},
|
|
||||||
type: "datasource",
|
|
||||||
}
|
|
||||||
|
|
||||||
const TEST_QUERY = {
|
|
||||||
_id: generateQueryID(DATASOURCE_ID),
|
|
||||||
datasourceId: DATASOURCE_ID,
|
|
||||||
name: "New Query",
|
|
||||||
parameters: [],
|
|
||||||
fields: {},
|
|
||||||
schema: {},
|
|
||||||
queryVerb: "read",
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("/queries", () => {
|
describe("/queries", () => {
|
||||||
let request
|
let request = setup.getRequest()
|
||||||
let server
|
let config = setup.getConfig()
|
||||||
let app
|
|
||||||
let appId
|
|
||||||
let datasource
|
|
||||||
let query
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
afterAll(setup.afterAll)
|
||||||
;({ request, server } = await supertest())
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
server.close()
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = await createApplication(request)
|
await config.init()
|
||||||
appId = app.instance._id
|
|
||||||
})
|
})
|
||||||
|
|
||||||
async function createDatasource() {
|
|
||||||
return await insertDocument(appId, TEST_DATASOURCE)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createQuery() {
|
|
||||||
return await insertDocument(appId, TEST_QUERY)
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
it("should create a new query", async () => {
|
it("should create a new query", async () => {
|
||||||
|
const { _id } = await config.createDatasource()
|
||||||
|
const query = basicQuery(_id)
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api/queries`)
|
.post(`/api/queries`)
|
||||||
.send(TEST_QUERY)
|
.send(query)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.res.statusMessage).toEqual(
|
expect(res.res.statusMessage).toEqual(
|
||||||
`Query ${TEST_QUERY.name} saved successfully.`
|
`Query ${query.name} saved successfully.`
|
||||||
)
|
)
|
||||||
expect(res.body).toEqual({
|
expect(res.body).toEqual({
|
||||||
_rev: res.body._rev,
|
_rev: res.body._rev,
|
||||||
...TEST_QUERY,
|
_id: res.body._id,
|
||||||
|
...query,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -80,7 +38,7 @@ describe("/queries", () => {
|
||||||
let datasource
|
let datasource
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
datasource = await createDatasource()
|
datasource = await config.createDatasource()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -88,29 +46,29 @@ describe("/queries", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("returns all the queries from the server", async () => {
|
it("returns all the queries from the server", async () => {
|
||||||
const query = await createQuery()
|
const query = await config.createQuery()
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/queries`)
|
.get(`/api/queries`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
const queries = res.body
|
const queries = res.body
|
||||||
expect(queries).toEqual([
|
expect(queries).toEqual([
|
||||||
{
|
{
|
||||||
_rev: query.rev,
|
_rev: query._rev,
|
||||||
...TEST_QUERY,
|
_id: query._id,
|
||||||
|
...basicQuery(datasource._id),
|
||||||
readable: true,
|
readable: true,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
await checkBuilderEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/datasources`,
|
url: `/api/datasources`,
|
||||||
appId: appId,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -119,7 +77,7 @@ describe("/queries", () => {
|
||||||
let datasource
|
let datasource
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
datasource = await createDatasource()
|
datasource = await config.createDatasource()
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -127,16 +85,16 @@ describe("/queries", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("deletes a query and returns a success message", async () => {
|
it("deletes a query and returns a success message", async () => {
|
||||||
const query = await createQuery()
|
const query = await config.createQuery()
|
||||||
|
|
||||||
await request
|
await request
|
||||||
.delete(`/api/queries/${query.id}/${query.rev}`)
|
.delete(`/api/queries/${query._id}/${query._rev}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/queries`)
|
.get(`/api/queries`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -144,11 +102,10 @@ describe("/queries", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
await checkBuilderEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: `/api/datasources/${datasource._id}/${datasource._rev}`,
|
url: `/api/datasources/${datasource._id}/${datasource._rev}`,
|
||||||
appId: appId,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,43 +1,26 @@
|
||||||
const {
|
|
||||||
createApplication,
|
|
||||||
supertest,
|
|
||||||
defaultHeaders,
|
|
||||||
} = require("./couchTestUtils")
|
|
||||||
const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
|
const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
|
||||||
const {
|
const {
|
||||||
BUILTIN_PERMISSION_IDS,
|
BUILTIN_PERMISSION_IDS,
|
||||||
} = require("../../../utilities/security/permissions")
|
} = require("../../../utilities/security/permissions")
|
||||||
|
const { basicRole } = require("./utilities/structures")
|
||||||
const roleBody = {
|
const setup = require("./utilities")
|
||||||
name: "NewRole",
|
|
||||||
inherits: BUILTIN_ROLE_IDS.BASIC,
|
|
||||||
permissionId: BUILTIN_PERMISSION_IDS.READ_ONLY,
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("/roles", () => {
|
describe("/roles", () => {
|
||||||
let server
|
let request = setup.getRequest()
|
||||||
let request
|
let config = setup.getConfig()
|
||||||
let appId
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
afterAll(setup.afterAll)
|
||||||
;({ request, server } = await supertest())
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
server.close()
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
let app = await createApplication(request)
|
await config.init()
|
||||||
appId = app.instance._id
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
it("returns a success message when role is successfully created", async () => {
|
it("returns a success message when role is successfully created", async () => {
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api/roles`)
|
.post(`/api/roles`)
|
||||||
.send(roleBody)
|
.send(basicRole())
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -53,8 +36,8 @@ describe("/roles", () => {
|
||||||
it("should list custom roles, plus 2 default roles", async () => {
|
it("should list custom roles, plus 2 default roles", async () => {
|
||||||
const createRes = await request
|
const createRes = await request
|
||||||
.post(`/api/roles`)
|
.post(`/api/roles`)
|
||||||
.send(roleBody)
|
.send(basicRole())
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -62,7 +45,7 @@ describe("/roles", () => {
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/roles`)
|
.get(`/api/roles`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -92,7 +75,7 @@ describe("/roles", () => {
|
||||||
const createRes = await request
|
const createRes = await request
|
||||||
.post(`/api/roles`)
|
.post(`/api/roles`)
|
||||||
.send({ name: "user", permissionId: BUILTIN_PERMISSION_IDS.READ_ONLY })
|
.send({ name: "user", permissionId: BUILTIN_PERMISSION_IDS.READ_ONLY })
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -100,12 +83,12 @@ describe("/roles", () => {
|
||||||
|
|
||||||
await request
|
await request
|
||||||
.delete(`/api/roles/${customRole._id}/${customRole._rev}`)
|
.delete(`/api/roles/${customRole._id}/${customRole._rev}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
await request
|
await request
|
||||||
.get(`/api/roles/${customRole._id}`)
|
.get(`/api/roles/${customRole._id}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect(404)
|
.expect(404)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,66 +1,45 @@
|
||||||
const {
|
|
||||||
createApplication,
|
|
||||||
createTable,
|
|
||||||
supertest,
|
|
||||||
defaultHeaders,
|
|
||||||
createLinkedTable,
|
|
||||||
createAttachmentTable,
|
|
||||||
makeBasicRow,
|
|
||||||
} = require("./couchTestUtils");
|
|
||||||
const { outputProcessing } = require("../../../utilities/rowProcessor")
|
const { outputProcessing } = require("../../../utilities/rowProcessor")
|
||||||
const env = require("../../../environment")
|
const env = require("../../../environment")
|
||||||
|
const { basicRow } = require("./utilities/structures")
|
||||||
|
const setup = require("./utilities")
|
||||||
|
|
||||||
describe("/rows", () => {
|
describe("/rows", () => {
|
||||||
let request
|
let request = setup.getRequest()
|
||||||
let server
|
let config = setup.getConfig()
|
||||||
let appId
|
|
||||||
let table
|
let table
|
||||||
let row
|
let row
|
||||||
let app
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
afterAll(setup.afterAll)
|
||||||
({ request, server } = await supertest())
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
server.close()
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = await createApplication(request)
|
await config.init()
|
||||||
appId = app.instance._id
|
table = await config.createTable()
|
||||||
table = await createTable(request, appId)
|
row = basicRow(table._id)
|
||||||
row = makeBasicRow(table._id)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const createRow = async r =>
|
|
||||||
await request
|
|
||||||
.post(`/api/${r ? r.tableId : row.tableId}/rows`)
|
|
||||||
.send(r || row)
|
|
||||||
.set(defaultHeaders(appId))
|
|
||||||
.expect('Content-Type', /json/)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
const loadRow = async id =>
|
const loadRow = async id =>
|
||||||
await request
|
await request
|
||||||
.get(`/api/${table._id}/rows/${id}`)
|
.get(`/api/${table._id}/rows/${id}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
|
||||||
describe("save, load, update, delete", () => {
|
describe("save, load, update, delete", () => {
|
||||||
it("returns a success message when the row is created", async () => {
|
it("returns a success message when the row is created", async () => {
|
||||||
const res = await createRow()
|
const res = await request
|
||||||
|
.post(`/api/${row.tableId}/rows`)
|
||||||
|
.send(row)
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
expect(res.res.statusMessage).toEqual(`${table.name} saved successfully`)
|
expect(res.res.statusMessage).toEqual(`${table.name} saved successfully`)
|
||||||
expect(res.body.name).toEqual("Test Contact")
|
expect(res.body.name).toEqual("Test Contact")
|
||||||
expect(res.body._rev).toBeDefined()
|
expect(res.body._rev).toBeDefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("updates a row successfully", async () => {
|
it("updates a row successfully", async () => {
|
||||||
const rec = await createRow()
|
const existing = await config.createRow()
|
||||||
const existing = rec.body
|
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api/${table._id}/rows`)
|
.post(`/api/${table._id}/rows`)
|
||||||
|
@ -70,7 +49,7 @@ describe("/rows", () => {
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
name: "Updated Name",
|
name: "Updated Name",
|
||||||
})
|
})
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -79,12 +58,11 @@ describe("/rows", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should load a row", async () => {
|
it("should load a row", async () => {
|
||||||
const rec = await createRow()
|
const existing = await config.createRow()
|
||||||
const existing = rec.body
|
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/${table._id}/rows/${existing._id}`)
|
.get(`/api/${table._id}/rows/${existing._id}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -102,12 +80,12 @@ describe("/rows", () => {
|
||||||
name: "Second Contact",
|
name: "Second Contact",
|
||||||
status: "new"
|
status: "new"
|
||||||
}
|
}
|
||||||
await createRow()
|
await config.createRow()
|
||||||
await createRow(newRow)
|
await config.createRow(newRow)
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/${table._id}/rows`)
|
.get(`/api/${table._id}/rows`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -117,10 +95,10 @@ describe("/rows", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("load should return 404 when row does not exist", async () => {
|
it("load should return 404 when row does not exist", async () => {
|
||||||
await createRow()
|
await config.createRow()
|
||||||
await request
|
await request
|
||||||
.get(`/api/${table._id}/rows/not-a-valid-id`)
|
.get(`/api/${table._id}/rows/not-a-valid-id`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(404)
|
.expect(404)
|
||||||
})
|
})
|
||||||
|
@ -132,7 +110,7 @@ describe("/rows", () => {
|
||||||
const number = {type:"number", constraints: { type: "number", presence: false }}
|
const number = {type:"number", constraints: { type: "number", presence: false }}
|
||||||
const datetime = {type:"datetime", constraints: { type: "string", presence: false, datetime: {earliest:"", latest: ""} }}
|
const datetime = {type:"datetime", constraints: { type: "string", presence: false, datetime: {earliest:"", latest: ""} }}
|
||||||
|
|
||||||
table = await createTable(request, appId, {
|
table = await config.createTable({
|
||||||
name: "TestTable2",
|
name: "TestTable2",
|
||||||
type: "table",
|
type: "table",
|
||||||
key: "name",
|
key: "name",
|
||||||
|
@ -187,7 +165,7 @@ describe("/rows", () => {
|
||||||
attachmentEmpty : "",
|
attachmentEmpty : "",
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = (await createRow(row)).body._id
|
const id = (await config.createRow(row))._id
|
||||||
|
|
||||||
const saved = (await loadRow(id)).body
|
const saved = (await loadRow(id)).body
|
||||||
|
|
||||||
|
@ -217,8 +195,7 @@ describe("/rows", () => {
|
||||||
|
|
||||||
describe("patch", () => {
|
describe("patch", () => {
|
||||||
it("should update only the fields that are supplied", async () => {
|
it("should update only the fields that are supplied", async () => {
|
||||||
const rec = await createRow()
|
const existing = await config.createRow()
|
||||||
const existing = rec.body
|
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.patch(`/api/${table._id}/rows/${existing._id}`)
|
.patch(`/api/${table._id}/rows/${existing._id}`)
|
||||||
|
@ -228,7 +205,7 @@ describe("/rows", () => {
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
name: "Updated Name",
|
name: "Updated Name",
|
||||||
})
|
})
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -249,7 +226,7 @@ describe("/rows", () => {
|
||||||
const result = await request
|
const result = await request
|
||||||
.post(`/api/${table._id}/rows/validate`)
|
.post(`/api/${table._id}/rows/validate`)
|
||||||
.send({ name: "ivan" })
|
.send({ name: "ivan" })
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -261,7 +238,7 @@ describe("/rows", () => {
|
||||||
const result = await request
|
const result = await request
|
||||||
.post(`/api/${table._id}/rows/validate`)
|
.post(`/api/${table._id}/rows/validate`)
|
||||||
.send({ name: 1 })
|
.send({ name: 1 })
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -273,19 +250,19 @@ describe("/rows", () => {
|
||||||
|
|
||||||
describe("enrich row unit test", () => {
|
describe("enrich row unit test", () => {
|
||||||
it("should allow enriching some linked rows", async () => {
|
it("should allow enriching some linked rows", async () => {
|
||||||
const table = await createLinkedTable(request, appId)
|
const table = await config.createLinkedTable()
|
||||||
const firstRow = (await createRow({
|
const firstRow = await config.createRow({
|
||||||
name: "Test Contact",
|
name: "Test Contact",
|
||||||
description: "original description",
|
description: "original description",
|
||||||
tableId: table._id
|
tableId: table._id
|
||||||
})).body
|
})
|
||||||
const secondRow = (await createRow({
|
const secondRow = await config.createRow({
|
||||||
name: "Test 2",
|
name: "Test 2",
|
||||||
description: "og desc",
|
description: "og desc",
|
||||||
link: [{_id: firstRow._id}],
|
link: [{_id: firstRow._id}],
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
})).body
|
})
|
||||||
const enriched = await outputProcessing(appId, table, [secondRow])
|
const enriched = await outputProcessing(config.getAppId(), table, [secondRow])
|
||||||
expect(enriched[0].link.length).toBe(1)
|
expect(enriched[0].link.length).toBe(1)
|
||||||
expect(enriched[0].link[0]._id).toBe(firstRow._id)
|
expect(enriched[0].link[0]._id).toBe(firstRow._id)
|
||||||
expect(enriched[0].link[0].primaryDisplay).toBe("Test Contact")
|
expect(enriched[0].link[0].primaryDisplay).toBe("Test Contact")
|
||||||
|
@ -293,20 +270,20 @@ describe("/rows", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should allow enriching attachment rows", async () => {
|
it("should allow enriching attachment rows", async () => {
|
||||||
const table = await createAttachmentTable(request, appId)
|
const table = await config.createAttachmentTable()
|
||||||
const row = (await createRow({
|
const row = await config.createRow({
|
||||||
name: "test",
|
name: "test",
|
||||||
description: "test",
|
description: "test",
|
||||||
attachment: [{
|
attachment: [{
|
||||||
url: "/test/thing",
|
url: "/test/thing",
|
||||||
}],
|
}],
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
})).body
|
})
|
||||||
// the environment needs configured for this
|
// the environment needs configured for this
|
||||||
env.CLOUD = 1
|
env.CLOUD = 1
|
||||||
env.SELF_HOSTED = 1
|
env.SELF_HOSTED = 1
|
||||||
const enriched = await outputProcessing(appId, table, [row])
|
const enriched = await outputProcessing(config.getAppId(), table, [row])
|
||||||
expect(enriched[0].attachment[0].url).toBe(`/app-assets/assets/${appId}/test/thing`)
|
expect(enriched[0].attachment[0].url).toBe(`/app-assets/assets/${config.getAppId()}/test/thing`)
|
||||||
// remove env config
|
// remove env config
|
||||||
env.CLOUD = undefined
|
env.CLOUD = undefined
|
||||||
env.SELF_HOSTED = undefined
|
env.SELF_HOSTED = undefined
|
||||||
|
|
|
@ -1,30 +1,15 @@
|
||||||
const {
|
const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
|
||||||
createTable,
|
const setup = require("./utilities")
|
||||||
supertest,
|
|
||||||
createApplication,
|
|
||||||
defaultHeaders,
|
|
||||||
builderEndpointShouldBlockNormalUsers,
|
|
||||||
getDocument
|
|
||||||
} = require("./couchTestUtils")
|
|
||||||
|
|
||||||
describe("/tables", () => {
|
describe("/tables", () => {
|
||||||
let request
|
let request = setup.getRequest()
|
||||||
let server
|
let config = setup.getConfig()
|
||||||
let app
|
|
||||||
let appId
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
afterAll(setup.afterAll)
|
||||||
({ request, server } = await supertest())
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
server.close()
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = await createApplication(request)
|
await config.init()
|
||||||
appId = app.instance._id
|
})
|
||||||
});
|
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
it("returns a success message when the table is successfully created", done => {
|
it("returns a success message when the table is successfully created", done => {
|
||||||
|
@ -37,25 +22,25 @@ describe("/tables", () => {
|
||||||
name: { type: "string" }
|
name: { type: "string" }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.end(async (err, res) => {
|
.end(async (err, res) => {
|
||||||
expect(res.res.statusMessage).toEqual("Table TestTable saved successfully.");
|
expect(res.res.statusMessage).toEqual("Table TestTable saved successfully.")
|
||||||
expect(res.body.name).toEqual("TestTable");
|
expect(res.body.name).toEqual("TestTable")
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("renames all the row fields for a table when a schema key is renamed", async () => {
|
it("renames all the row fields for a table when a schema key is renamed", async () => {
|
||||||
const testTable = await createTable(request, appId);
|
const testTable = await config.createTable()
|
||||||
|
|
||||||
const testRow = await request
|
const testRow = await request
|
||||||
.post(`/api/${testTable._id}/rows`)
|
.post(`/api/${testTable._id}/rows`)
|
||||||
.send({
|
.send({
|
||||||
name: "test"
|
name: "test"
|
||||||
})
|
})
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -74,29 +59,28 @@ describe("/tables", () => {
|
||||||
updatedName: { type: "string" }
|
updatedName: { type: "string" }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(updatedTable.res.statusMessage).toEqual("Table TestTable saved successfully.");
|
expect(updatedTable.res.statusMessage).toEqual("Table TestTable saved successfully.")
|
||||||
expect(updatedTable.body.name).toEqual("TestTable");
|
expect(updatedTable.body.name).toEqual("TestTable")
|
||||||
|
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/${testTable._id}/rows/${testRow.body._id}`)
|
.get(`/api/${testTable._id}/rows/${testRow.body._id}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.updatedName).toEqual("test");
|
expect(res.body.updatedName).toEqual("test")
|
||||||
expect(res.body.name).toBeUndefined();
|
expect(res.body.name).toBeUndefined()
|
||||||
});
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
await checkBuilderEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/tables`,
|
url: `/api/tables`,
|
||||||
appId: appId,
|
|
||||||
body: {
|
body: {
|
||||||
name: "TestTable",
|
name: "TestTable",
|
||||||
key: "name",
|
key: "name",
|
||||||
|
@ -106,68 +90,67 @@ describe("/tables", () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
describe("fetch", () => {
|
describe("fetch", () => {
|
||||||
let testTable
|
let testTable
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
testTable = await createTable(request, appId, testTable)
|
testTable = await config.createTable(testTable)
|
||||||
});
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
delete testTable._rev
|
delete testTable._rev
|
||||||
});
|
})
|
||||||
|
|
||||||
it("returns all the tables for that instance in the response body", done => {
|
it("returns all the tables for that instance in the response body", done => {
|
||||||
request
|
request
|
||||||
.get(`/api/tables`)
|
.get(`/api/tables`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.end(async (_, res) => {
|
.end(async (_, res) => {
|
||||||
const fetchedTable = res.body[0];
|
const fetchedTable = res.body[0]
|
||||||
expect(fetchedTable.name).toEqual(testTable.name);
|
expect(fetchedTable.name).toEqual(testTable.name)
|
||||||
expect(fetchedTable.type).toEqual("table");
|
expect(fetchedTable.type).toEqual("table")
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
await checkBuilderEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/tables`,
|
url: `/api/tables`,
|
||||||
appId: appId,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
describe("destroy", () => {
|
describe("destroy", () => {
|
||||||
let testTable;
|
let testTable
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
testTable = await createTable(request, appId, testTable)
|
testTable = await config.createTable(testTable)
|
||||||
});
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
delete testTable._rev
|
delete testTable._rev
|
||||||
});
|
})
|
||||||
|
|
||||||
it("returns a success response when a table is deleted.", async done => {
|
it("returns a success response when a table is deleted.", async done => {
|
||||||
request
|
request
|
||||||
.delete(`/api/tables/${testTable._id}/${testTable._rev}`)
|
.delete(`/api/tables/${testTable._id}/${testTable._rev}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.end(async (_, res) => {
|
.end(async (_, res) => {
|
||||||
expect(res.res.statusMessage).toEqual(`Table ${testTable._id} deleted.`);
|
expect(res.res.statusMessage).toEqual(`Table ${testTable._id} deleted.`)
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("deletes linked references to the table after deletion", async done => {
|
it("deletes linked references to the table after deletion", async done => {
|
||||||
const linkedTable = await createTable(request, appId, {
|
const linkedTable = await config.createTable({
|
||||||
name: "LinkedTable",
|
name: "LinkedTable",
|
||||||
type: "table",
|
type: "table",
|
||||||
key: "name",
|
key: "name",
|
||||||
|
@ -190,25 +173,24 @@ describe("/tables", () => {
|
||||||
|
|
||||||
request
|
request
|
||||||
.delete(`/api/tables/${testTable._id}/${testTable._rev}`)
|
.delete(`/api/tables/${testTable._id}/${testTable._rev}`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.end(async (_, res) => {
|
.end(async (_, res) => {
|
||||||
expect(res.res.statusMessage).toEqual(`Table ${testTable._id} deleted.`);
|
expect(res.res.statusMessage).toEqual(`Table ${testTable._id} deleted.`)
|
||||||
const dependentTable = await getDocument(appId, linkedTable._id)
|
const dependentTable = await config.getTable(linkedTable._id)
|
||||||
expect(dependentTable.schema.TestTable).not.toBeDefined();
|
expect(dependentTable.schema.TestTable).not.toBeDefined()
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await builderEndpointShouldBlockNormalUsers({
|
await checkBuilderEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: `/api/tables/${testTable._id}/${testTable._rev}`,
|
url: `/api/tables/${testTable._id}/${testTable._rev}`,
|
||||||
appId: appId,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
module.exports.delay = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
|
@ -1,46 +1,25 @@
|
||||||
const {
|
|
||||||
createApplication,
|
|
||||||
supertest,
|
|
||||||
defaultHeaders,
|
|
||||||
createUser,
|
|
||||||
testPermissionsForEndpoint,
|
|
||||||
} = require("./couchTestUtils")
|
|
||||||
const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
|
const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
|
||||||
const { cloneDeep } = require("lodash/fp")
|
const { checkPermissionsEndpoint } = require("./utilities/TestFunctions")
|
||||||
|
const { basicUser } = require("./utilities/structures")
|
||||||
const baseBody = {
|
const setup = require("./utilities")
|
||||||
email: "bill@bill.com",
|
|
||||||
password: "yeeooo",
|
|
||||||
roleId: BUILTIN_ROLE_IDS.POWER,
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("/users", () => {
|
describe("/users", () => {
|
||||||
let request
|
let request = setup.getRequest()
|
||||||
let server
|
let config = setup.getConfig()
|
||||||
let app
|
|
||||||
let appId
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
afterAll(setup.afterAll)
|
||||||
;({ request, server } = await supertest(server))
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = await createApplication(request)
|
await config.init()
|
||||||
appId = app.instance._id
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
server.close()
|
|
||||||
server.destroy()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("fetch", () => {
|
describe("fetch", () => {
|
||||||
it("returns a list of users from an instance db", async () => {
|
it("returns a list of users from an instance db", async () => {
|
||||||
await createUser(request, appId, "brenda@brenda.com", "brendas_password")
|
await config.createUser("brenda@brenda.com", "brendas_password")
|
||||||
await createUser(request, appId, "pam@pam.com", "pam_password")
|
await config.createUser("pam@pam.com", "pam_password")
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/users`)
|
.get(`/api/users`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
@ -50,12 +29,12 @@ describe("/users", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await createUser(request, appId, "brenda@brenda.com", "brendas_password")
|
await config.createUser("brenda@brenda.com", "brendas_password")
|
||||||
await testPermissionsForEndpoint({
|
await checkPermissionsEndpoint({
|
||||||
|
config,
|
||||||
request,
|
request,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `/api/users`,
|
url: `/api/users`,
|
||||||
appId: appId,
|
|
||||||
passRole: BUILTIN_ROLE_IDS.ADMIN,
|
passRole: BUILTIN_ROLE_IDS.ADMIN,
|
||||||
failRole: BUILTIN_ROLE_IDS.PUBLIC,
|
failRole: BUILTIN_ROLE_IDS.PUBLIC,
|
||||||
})
|
})
|
||||||
|
@ -64,11 +43,11 @@ describe("/users", () => {
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
it("returns a success message when a user is successfully created", async () => {
|
it("returns a success message when a user is successfully created", async () => {
|
||||||
const body = cloneDeep(baseBody)
|
const body = basicUser(BUILTIN_ROLE_IDS.POWER)
|
||||||
body.email = "bill@budibase.com"
|
body.email = "bill@budibase.com"
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api/users`)
|
.post(`/api/users`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.send(body)
|
.send(body)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
|
@ -78,14 +57,13 @@ describe("/users", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should apply authorization to endpoint", async () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
const body = cloneDeep(baseBody)
|
const body = basicUser(BUILTIN_ROLE_IDS.POWER)
|
||||||
body.email = "brandNewUser@user.com"
|
body.email = "brandNewUser@user.com"
|
||||||
await testPermissionsForEndpoint({
|
await checkPermissionsEndpoint({
|
||||||
request,
|
config,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body,
|
body,
|
||||||
url: `/api/users`,
|
url: `/api/users`,
|
||||||
appId: appId,
|
|
||||||
passRole: BUILTIN_ROLE_IDS.ADMIN,
|
passRole: BUILTIN_ROLE_IDS.ADMIN,
|
||||||
failRole: BUILTIN_ROLE_IDS.PUBLIC,
|
failRole: BUILTIN_ROLE_IDS.PUBLIC,
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,248 @@
|
||||||
|
const { BUILTIN_ROLE_IDS } = require("../../../../utilities/security/roles")
|
||||||
|
const jwt = require("jsonwebtoken")
|
||||||
|
const env = require("../../../../environment")
|
||||||
|
const {
|
||||||
|
basicTable,
|
||||||
|
basicRow,
|
||||||
|
basicRole,
|
||||||
|
basicAutomation,
|
||||||
|
basicDatasource,
|
||||||
|
basicQuery,
|
||||||
|
} = require("./structures")
|
||||||
|
const controllers = require("./controllers")
|
||||||
|
const supertest = require("supertest")
|
||||||
|
|
||||||
|
const EMAIL = "babs@babs.com"
|
||||||
|
const PASSWORD = "babs_password"
|
||||||
|
|
||||||
|
class TestConfiguration {
|
||||||
|
constructor() {
|
||||||
|
env.PORT = 4002
|
||||||
|
this.server = require("../../../../app")
|
||||||
|
// we need the request for logging in, involves cookies, hard to fake
|
||||||
|
this.request = supertest(this.server)
|
||||||
|
this.appId = null
|
||||||
|
}
|
||||||
|
|
||||||
|
getRequest() {
|
||||||
|
return this.request
|
||||||
|
}
|
||||||
|
|
||||||
|
getAppId() {
|
||||||
|
return this.appId
|
||||||
|
}
|
||||||
|
|
||||||
|
async _req(config, params, controlFunc) {
|
||||||
|
const request = {}
|
||||||
|
// fake cookies, we don't need them
|
||||||
|
request.cookies = { set: () => {}, get: () => {} }
|
||||||
|
request.config = { jwtSecret: env.JWT_SECRET }
|
||||||
|
request.appId = this.appId
|
||||||
|
request.user = { appId: this.appId }
|
||||||
|
request.request = {
|
||||||
|
body: config,
|
||||||
|
}
|
||||||
|
if (params) {
|
||||||
|
request.params = params
|
||||||
|
}
|
||||||
|
await controlFunc(request)
|
||||||
|
return request.body
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(appName = "test_application") {
|
||||||
|
return this.createApp(appName)
|
||||||
|
}
|
||||||
|
|
||||||
|
end() {
|
||||||
|
this.server.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultHeaders() {
|
||||||
|
const builderUser = {
|
||||||
|
userId: "BUILDER",
|
||||||
|
roleId: BUILTIN_ROLE_IDS.BUILDER,
|
||||||
|
}
|
||||||
|
const builderToken = jwt.sign(builderUser, env.JWT_SECRET)
|
||||||
|
const headers = {
|
||||||
|
Accept: "application/json",
|
||||||
|
Cookie: [`budibase:builder:local=${builderToken}`],
|
||||||
|
}
|
||||||
|
if (this.appId) {
|
||||||
|
headers["x-budibase-app-id"] = this.appId
|
||||||
|
}
|
||||||
|
return headers
|
||||||
|
}
|
||||||
|
|
||||||
|
publicHeaders() {
|
||||||
|
const headers = {
|
||||||
|
Accept: "application/json",
|
||||||
|
}
|
||||||
|
if (this.appId) {
|
||||||
|
headers["x-budibase-app-id"] = this.appId
|
||||||
|
}
|
||||||
|
return headers
|
||||||
|
}
|
||||||
|
|
||||||
|
async createApp(appName) {
|
||||||
|
this.app = await this._req({ name: appName }, null, controllers.app.create)
|
||||||
|
this.appId = this.app._id
|
||||||
|
return this.app
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateTable(config = null) {
|
||||||
|
config = config || basicTable()
|
||||||
|
this.table = await this._req(config, null, controllers.table.save)
|
||||||
|
return this.table
|
||||||
|
}
|
||||||
|
|
||||||
|
async createTable(config = null) {
|
||||||
|
if (config != null && config._id) {
|
||||||
|
delete config._id
|
||||||
|
}
|
||||||
|
return this.updateTable(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getTable(tableId = null) {
|
||||||
|
tableId = tableId || this.table._id
|
||||||
|
return this._req(null, { id: tableId }, controllers.table.find)
|
||||||
|
}
|
||||||
|
|
||||||
|
async createLinkedTable() {
|
||||||
|
if (!this.table) {
|
||||||
|
throw "Must have created a table first."
|
||||||
|
}
|
||||||
|
const tableConfig = basicTable()
|
||||||
|
tableConfig.primaryDisplay = "name"
|
||||||
|
tableConfig.schema.link = {
|
||||||
|
type: "link",
|
||||||
|
fieldName: "link",
|
||||||
|
tableId: this.table._id,
|
||||||
|
}
|
||||||
|
const linkedTable = await this.createTable(tableConfig)
|
||||||
|
this.linkedTable = linkedTable
|
||||||
|
return linkedTable
|
||||||
|
}
|
||||||
|
|
||||||
|
async createAttachmentTable() {
|
||||||
|
const table = basicTable()
|
||||||
|
table.schema.attachment = {
|
||||||
|
type: "attachment",
|
||||||
|
}
|
||||||
|
return this.createTable(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
async createRow(config = null) {
|
||||||
|
if (!this.table) {
|
||||||
|
throw "Test requires table to be configured."
|
||||||
|
}
|
||||||
|
config = config || basicRow(this.table._id)
|
||||||
|
return this._req(config, { tableId: this.table._id }, controllers.row.save)
|
||||||
|
}
|
||||||
|
|
||||||
|
async createRole(config = null) {
|
||||||
|
config = config || basicRole()
|
||||||
|
return this._req(config, null, controllers.role.save)
|
||||||
|
}
|
||||||
|
|
||||||
|
async addPermission(roleId, resourceId, level = "read") {
|
||||||
|
return this._req(
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
roleId,
|
||||||
|
resourceId,
|
||||||
|
level,
|
||||||
|
},
|
||||||
|
controllers.perms.addPermission
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async createView(config) {
|
||||||
|
if (!this.table) {
|
||||||
|
throw "Test requires table to be configured."
|
||||||
|
}
|
||||||
|
const view = config || {
|
||||||
|
map: "function(doc) { emit(doc[doc.key], doc._id); } ",
|
||||||
|
tableId: this.table._id,
|
||||||
|
}
|
||||||
|
return this._req(view, null, controllers.view.save)
|
||||||
|
}
|
||||||
|
|
||||||
|
async createAutomation(config) {
|
||||||
|
config = config || basicAutomation()
|
||||||
|
if (config._rev) {
|
||||||
|
delete config._rev
|
||||||
|
}
|
||||||
|
this.automation = (
|
||||||
|
await this._req(config, null, controllers.automation.create)
|
||||||
|
).automation
|
||||||
|
return this.automation
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllAutomations() {
|
||||||
|
return this._req(null, null, controllers.automation.fetch)
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAutomation(automation = null) {
|
||||||
|
automation = automation || this.automation
|
||||||
|
if (!automation) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return this._req(
|
||||||
|
null,
|
||||||
|
{ id: automation._id, rev: automation._rev },
|
||||||
|
controllers.automation.destroy
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async createDatasource(config = null) {
|
||||||
|
config = config || basicDatasource()
|
||||||
|
this.datasource = await this._req(config, null, controllers.datasource.save)
|
||||||
|
return this.datasource
|
||||||
|
}
|
||||||
|
|
||||||
|
async createQuery(config = null) {
|
||||||
|
if (!this.datasource && !config) {
|
||||||
|
throw "No data source created for query."
|
||||||
|
}
|
||||||
|
config = config || basicQuery(this.datasource._id)
|
||||||
|
return this._req(config, null, controllers.query.save)
|
||||||
|
}
|
||||||
|
|
||||||
|
async createUser(
|
||||||
|
email = EMAIL,
|
||||||
|
password = PASSWORD,
|
||||||
|
roleId = BUILTIN_ROLE_IDS.POWER
|
||||||
|
) {
|
||||||
|
return this._req(
|
||||||
|
{
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
roleId,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
controllers.user.create
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async login(email, password) {
|
||||||
|
if (!email || !password) {
|
||||||
|
await this.createUser()
|
||||||
|
email = EMAIL
|
||||||
|
password = PASSWORD
|
||||||
|
}
|
||||||
|
const result = await this.request
|
||||||
|
.post(`/api/authenticate`)
|
||||||
|
.set({
|
||||||
|
"x-budibase-app-id": this.appId,
|
||||||
|
})
|
||||||
|
.send({ email, password })
|
||||||
|
|
||||||
|
// returning necessary request headers
|
||||||
|
return {
|
||||||
|
Accept: "application/json",
|
||||||
|
Cookie: result.headers["set-cookie"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TestConfiguration
|
|
@ -0,0 +1,79 @@
|
||||||
|
const rowController = require("../../../controllers/row")
|
||||||
|
const appController = require("../../../controllers/application")
|
||||||
|
|
||||||
|
function Request(appId, params) {
|
||||||
|
this.user = { appId }
|
||||||
|
this.params = params
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getAllTableRows = async config => {
|
||||||
|
const req = new Request(config.appId, { tableId: config.table._id })
|
||||||
|
await rowController.fetchTableRows(req)
|
||||||
|
return req.body
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.clearAllApps = async () => {
|
||||||
|
const req = {}
|
||||||
|
await appController.fetch(req)
|
||||||
|
const apps = req.body
|
||||||
|
if (!apps || apps.length <= 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (let app of apps) {
|
||||||
|
const appId = app._id
|
||||||
|
await appController.delete(new Request(null, { appId }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.clearAllAutomations = async config => {
|
||||||
|
const automations = await config.getAllAutomations()
|
||||||
|
for (let auto of automations) {
|
||||||
|
await config.deleteAutomation(auto)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createRequest = (request, method, url, body) => {
|
||||||
|
let req
|
||||||
|
|
||||||
|
if (method === "POST") req = request.post(url).send(body)
|
||||||
|
else if (method === "GET") req = request.get(url)
|
||||||
|
else if (method === "DELETE") req = request.delete(url)
|
||||||
|
else if (method === "PATCH") req = request.patch(url).send(body)
|
||||||
|
else if (method === "PUT") req = request.put(url).send(body)
|
||||||
|
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.checkBuilderEndpoint = async ({ config, method, url, body }) => {
|
||||||
|
const headers = await config.login()
|
||||||
|
await exports
|
||||||
|
.createRequest(config.request, method, url, body)
|
||||||
|
.set(headers)
|
||||||
|
.expect(403)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.checkPermissionsEndpoint = async ({
|
||||||
|
config,
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
body,
|
||||||
|
passRole,
|
||||||
|
failRole,
|
||||||
|
}) => {
|
||||||
|
const password = "PASSWORD"
|
||||||
|
await config.createUser("passUser@budibase.com", password, passRole)
|
||||||
|
const passHeader = await config.login("passUser@budibase.com", password)
|
||||||
|
|
||||||
|
await exports
|
||||||
|
.createRequest(config.request, method, url, body)
|
||||||
|
.set(passHeader)
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
await config.createUser("failUser@budibase.com", password, failRole)
|
||||||
|
const failHeader = await config.login("failUser@budibase.com", password)
|
||||||
|
|
||||||
|
await exports
|
||||||
|
.createRequest(config.request, method, url, body)
|
||||||
|
.set(failHeader)
|
||||||
|
.expect(403)
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
module.exports = {
|
||||||
|
table: require("../../../controllers/table"),
|
||||||
|
row: require("../../../controllers/row"),
|
||||||
|
role: require("../../../controllers/role"),
|
||||||
|
perms: require("../../../controllers/permission"),
|
||||||
|
view: require("../../../controllers/view"),
|
||||||
|
app: require("../../../controllers/application"),
|
||||||
|
user: require("../../../controllers/user"),
|
||||||
|
automation: require("../../../controllers/automation"),
|
||||||
|
datasource: require("../../../controllers/datasource"),
|
||||||
|
query: require("../../../controllers/query"),
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
const TestConfig = require("./TestConfiguration")
|
||||||
|
|
||||||
|
exports.delay = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
|
||||||
|
let request, config
|
||||||
|
|
||||||
|
exports.beforeAll = () => {
|
||||||
|
config = new TestConfig()
|
||||||
|
request = config.getRequest()
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.afterAll = () => {
|
||||||
|
if (config) {
|
||||||
|
config.end()
|
||||||
|
}
|
||||||
|
request = null
|
||||||
|
config = null
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getRequest = () => {
|
||||||
|
if (!request) {
|
||||||
|
exports.beforeAll()
|
||||||
|
}
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getConfig = () => {
|
||||||
|
if (!config) {
|
||||||
|
exports.beforeAll()
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
const { BUILTIN_ROLE_IDS } = require("../../../../utilities/security/roles")
|
||||||
|
const {
|
||||||
|
BUILTIN_PERMISSION_IDS,
|
||||||
|
} = require("../../../../utilities/security/permissions")
|
||||||
|
|
||||||
|
exports.basicTable = () => {
|
||||||
|
return {
|
||||||
|
name: "TestTable",
|
||||||
|
type: "table",
|
||||||
|
key: "name",
|
||||||
|
schema: {
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: "string",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.basicAutomation = () => {
|
||||||
|
return {
|
||||||
|
name: "My Automation",
|
||||||
|
screenId: "kasdkfldsafkl",
|
||||||
|
live: true,
|
||||||
|
uiTree: {},
|
||||||
|
definition: {
|
||||||
|
trigger: {
|
||||||
|
inputs: {},
|
||||||
|
},
|
||||||
|
steps: [],
|
||||||
|
},
|
||||||
|
type: "automation",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.basicRow = tableId => {
|
||||||
|
return {
|
||||||
|
name: "Test Contact",
|
||||||
|
description: "original description",
|
||||||
|
status: "new",
|
||||||
|
tableId: tableId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.basicRole = () => {
|
||||||
|
return {
|
||||||
|
name: "NewRole",
|
||||||
|
inherits: BUILTIN_ROLE_IDS.BASIC,
|
||||||
|
permissionId: BUILTIN_PERMISSION_IDS.READ_ONLY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.basicDatasource = () => {
|
||||||
|
return {
|
||||||
|
type: "datasource",
|
||||||
|
name: "Test",
|
||||||
|
source: "POSTGRES",
|
||||||
|
config: {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.basicQuery = datasourceId => {
|
||||||
|
return {
|
||||||
|
datasourceId: datasourceId,
|
||||||
|
name: "New Query",
|
||||||
|
parameters: [],
|
||||||
|
fields: {},
|
||||||
|
schema: {},
|
||||||
|
queryVerb: "read",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.basicUser = role => {
|
||||||
|
return {
|
||||||
|
email: "bill@bill.com",
|
||||||
|
password: "yeeooo",
|
||||||
|
roleId: role,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,65 +1,56 @@
|
||||||
const {
|
const setup = require("./utilities")
|
||||||
createApplication,
|
|
||||||
createTable,
|
|
||||||
supertest,
|
|
||||||
defaultHeaders,
|
|
||||||
getDocument
|
|
||||||
} = require("./couchTestUtils")
|
|
||||||
|
|
||||||
describe("/views", () => {
|
describe("/views", () => {
|
||||||
let request
|
let request = setup.getRequest()
|
||||||
let server
|
let config = setup.getConfig()
|
||||||
let app
|
|
||||||
let appId
|
|
||||||
let table
|
let table
|
||||||
|
|
||||||
const createView = async (config = {
|
afterAll(setup.afterAll)
|
||||||
name: "TestView",
|
|
||||||
field: "Price",
|
|
||||||
calculation: "stats",
|
|
||||||
tableId: table._id
|
|
||||||
}) =>
|
|
||||||
await request
|
|
||||||
.post(`/api/views`)
|
|
||||||
.send(config)
|
|
||||||
.set(defaultHeaders(appId))
|
|
||||||
.expect('Content-Type', /json/)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
const createRow = async row => request
|
|
||||||
.post(`/api/${table._id}/rows`)
|
|
||||||
.send(row)
|
|
||||||
.set(defaultHeaders(appId))
|
|
||||||
.expect('Content-Type', /json/)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
({ request, server } = await supertest())
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = await createApplication(request)
|
await config.init()
|
||||||
appId = app.instance._id
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
server.close()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
table = await createTable(request, appId);
|
table = await config.createTable()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("returns a success message when the view is successfully created", async () => {
|
it("returns a success message when the view is successfully created", async () => {
|
||||||
const res = await createView()
|
const res = await request
|
||||||
expect(res.res.statusMessage).toEqual("View TestView saved successfully.");
|
.post(`/api/views`)
|
||||||
|
.send({
|
||||||
|
name: "TestView",
|
||||||
|
field: "Price",
|
||||||
|
calculation: "stats",
|
||||||
|
tableId: table._id,
|
||||||
|
})
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.res.statusMessage).toEqual(
|
||||||
|
"View TestView saved successfully."
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("updates the table row with the new view metadata", async () => {
|
it("updates the table row with the new view metadata", async () => {
|
||||||
const res = await createView()
|
const res = await request
|
||||||
expect(res.res.statusMessage).toEqual("View TestView saved successfully.");
|
.post(`/api/views`)
|
||||||
const updatedTable = await getDocument(appId, table._id)
|
.send({
|
||||||
|
name: "TestView",
|
||||||
|
field: "Price",
|
||||||
|
calculation: "stats",
|
||||||
|
tableId: table._id,
|
||||||
|
})
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.res.statusMessage).toEqual(
|
||||||
|
"View TestView saved successfully."
|
||||||
|
)
|
||||||
|
const updatedTable = await config.getTable(table._id)
|
||||||
expect(updatedTable.views).toEqual({
|
expect(updatedTable.views).toEqual({
|
||||||
TestView: {
|
TestView: {
|
||||||
field: "Price",
|
field: "Price",
|
||||||
|
@ -88,88 +79,98 @@ describe("/views", () => {
|
||||||
field: {
|
field: {
|
||||||
type: "string",
|
type: "string",
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
});
|
|
||||||
|
|
||||||
describe("fetch", () => {
|
describe("fetch", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
table = await createTable(request, appId);
|
table = await config.createTable()
|
||||||
});
|
})
|
||||||
|
|
||||||
it("returns only custom views", async () => {
|
it("returns only custom views", async () => {
|
||||||
await createView()
|
await config.createView({
|
||||||
|
name: "TestView",
|
||||||
|
field: "Price",
|
||||||
|
calculation: "stats",
|
||||||
|
tableId: table._id,
|
||||||
|
})
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/views`)
|
.get(`/api/views`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body.length).toBe(1)
|
expect(res.body.length).toBe(1)
|
||||||
expect(res.body.find(({ name }) => name === "TestView")).toBeDefined()
|
expect(res.body.find(({ name }) => name === "TestView")).toBeDefined()
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
describe("query", () => {
|
describe("query", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
table = await createTable(request, appId);
|
table = await config.createTable()
|
||||||
});
|
})
|
||||||
|
|
||||||
it("returns data for the created view", async () => {
|
it("returns data for the created view", async () => {
|
||||||
await createView()
|
await config.createView({
|
||||||
await createRow({
|
name: "TestView",
|
||||||
|
field: "Price",
|
||||||
|
calculation: "stats",
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
Price: 1000
|
|
||||||
})
|
})
|
||||||
await createRow({
|
await config.createRow({
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
Price: 2000
|
Price: 1000,
|
||||||
})
|
})
|
||||||
await createRow({
|
await config.createRow({
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
Price: 4000
|
Price: 2000,
|
||||||
|
})
|
||||||
|
await config.createRow({
|
||||||
|
tableId: table._id,
|
||||||
|
Price: 4000,
|
||||||
})
|
})
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/views/TestView?calculation=stats`)
|
.get(`/api/views/TestView?calculation=stats`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body.length).toBe(1)
|
expect(res.body.length).toBe(1)
|
||||||
expect(res.body).toMatchSnapshot()
|
expect(res.body).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("returns data for the created view using a group by", async () => {
|
it("returns data for the created view using a group by", async () => {
|
||||||
await createView({
|
await config.createView({
|
||||||
calculation: "stats",
|
calculation: "stats",
|
||||||
name: "TestView",
|
name: "TestView",
|
||||||
field: "Price",
|
field: "Price",
|
||||||
groupBy: "Category",
|
groupBy: "Category",
|
||||||
tableId: table._id
|
tableId: table._id,
|
||||||
})
|
})
|
||||||
await createRow({
|
await config.createRow({
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
Price: 1000,
|
Price: 1000,
|
||||||
Category: "One"
|
Category: "One",
|
||||||
})
|
})
|
||||||
await createRow({
|
await config.createRow({
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
Price: 2000,
|
Price: 2000,
|
||||||
Category: "One"
|
Category: "One",
|
||||||
})
|
})
|
||||||
await createRow({
|
await config.createRow({
|
||||||
tableId: table._id,
|
tableId: table._id,
|
||||||
Price: 4000,
|
Price: 4000,
|
||||||
Category: "Two"
|
Category: "Two",
|
||||||
})
|
})
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/views/TestView?calculation=stats&group=Category`)
|
.get(`/api/views/TestView?calculation=stats&group=Category`)
|
||||||
.set(defaultHeaders(appId))
|
.set(config.defaultHeaders())
|
||||||
.expect('Content-Type', /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
expect(res.body.length).toBe(2)
|
expect(res.body.length).toBe(2)
|
||||||
expect(res.body).toMatchSnapshot()
|
expect(res.body).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
|
@ -49,6 +49,12 @@ const TYPE_TRANSFORM_MAP = {
|
||||||
"": null,
|
"": null,
|
||||||
[undefined]: undefined,
|
[undefined]: undefined,
|
||||||
[null]: null,
|
[null]: null,
|
||||||
|
parse: date => {
|
||||||
|
if (date instanceof Date) {
|
||||||
|
return date.toISOString()
|
||||||
|
}
|
||||||
|
return date
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[FieldTypes.ATTACHMENT]: {
|
[FieldTypes.ATTACHMENT]: {
|
||||||
"": [],
|
"": [],
|
||||||
|
|
Loading…
Reference in New Issue