Initial work on test refactoring, laying the utilities down which will be the basis of new testing framework, interacting directly with the controllers.

This commit is contained in:
mike12345567 2021-03-03 17:52:41 +00:00
parent 2beba28700
commit 6d9b8a6678
6 changed files with 341 additions and 18 deletions

View File

@ -52,7 +52,8 @@
"collectCoverageFrom": [
"src/**/*.js",
"!**/node_modules/**",
"!src/db/views/*.js"
"!src/db/views/*.js",
"!src/api/routes/tests"
],
"coverageReporters": [
"lcov",

View File

@ -1,21 +1,23 @@
const {
createApplication,
builderEndpointShouldBlockNormalUsers,
supertest,
clearApplications,
defaultHeaders,
} = require("./couchTestUtils")
} = require("./utilities")
const TestConfig = require("./utilities/TestConfiguration")
const { clearAllApps, checkBuilderEndpoint } = require("./utilities/TestFunctions")
describe("/applications", () => {
let request
let server
let config
beforeAll(async () => {
({ request, server } = await supertest())
});
beforeEach(async () => {
await clearApplications(request)
await clearAllApps()
config = new TestConfig(request)
await config.init()
})
afterAll(() => {
@ -35,23 +37,20 @@ describe("/applications", () => {
})
it("should apply authorization to endpoint", async () => {
const otherApplication = await createApplication(request)
const appId = otherApplication.instance._id
await builderEndpointShouldBlockNormalUsers({
await checkBuilderEndpoint({
config,
request,
method: "POST",
url: `/api/applications`,
appId: appId,
body: { name: "My App" }
})
})
})
describe("fetch", () => {
it("lists all applications", async () => {
await createApplication(request, "app1")
await createApplication(request, "app2")
await config.createApp(request, "app1")
await config.createApp(request, "app2")
const res = await request
.get("/api/applications")
@ -59,17 +58,16 @@ describe("/applications", () => {
.expect('Content-Type', /json/)
.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 () => {
const otherApplication = await createApplication(request)
const appId = otherApplication.instance._id
await builderEndpointShouldBlockNormalUsers({
await checkBuilderEndpoint({
config,
request,
method: "GET",
url: `/api/applications`,
appId: appId,
})
})
})

View File

@ -0,0 +1,159 @@
const { BUILTIN_ROLE_IDS } = require("../../../../utilities/security/roles")
const env = require("../../../../environment")
const { basicTable, basicRow, basicRole } = require("./structures")
const tableController = require("../../../controllers/table")
const rowController = require("../../../controllers/row")
const roleController = require("../../../controllers/role")
const permsController = require("../../../controllers/permission")
const viewController = require("../../../controllers/view")
const appController = require("../../../controllers/application")
const userController = require("../../../controllers/user")
const EMAIL = "babs@babs.com"
const PASSWORD = "babs_password"
class TestConfiguration {
constructor(request) {
// we need the request for logging in, involves cookies, hard to fake
this.request = request
this.appId = null
this.table = null
this.linkedTable = null
}
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)
}
async createApp(appName) {
this.app = await this._req({ name: appName }, null, appController.create)
this.appId = this.app._id
return this.app
}
async updateTable(config = null) {
config = config || basicTable()
this.table = await this._req(config, null, tableController.save)
return this.table
}
async createTable(config = null) {
if (config != null && config._id) {
delete config._id
}
return this.updateTable(config)
}
async createLinkedTables() {
const table = await this.createTable()
table.primaryDisplay = "name"
table.schema.link = {
type: "link",
fieldName: "link",
tableId: table._id,
}
const linkedTable = await this.createTable(table)
this.table = table
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 }, rowController.save)
}
async createRole(config = null) {
config = config || basicRole()
return this._req(config, null, roleController.save)
}
async addPermission(roleId, resourceId, level = "read") {
return this._req(
null,
{
roleId,
resourceId,
level,
},
permsController.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, viewController.save)
}
async createUser(
email = EMAIL,
password = PASSWORD,
roleId = BUILTIN_ROLE_IDS.POWER
) {
return this._req(
{
email,
password,
roleId,
},
null,
userController.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

View File

@ -0,0 +1,75 @@
const rowController = require("../../../controllers/row")
const appController = require("../../../controllers/application")
const CouchDB = require("../../../../db")
function Request(appId, params) {
this.user = { appId }
this.params = params
}
exports.getAllTableRows = async (appId, tableId) => {
const req = new Request(appId, { tableId })
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.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,
request,
method,
url,
body,
}) => {
const headers = await config.login()
await exports
.createRequest(request, method, url, body)
.set(headers)
.expect(403)
}
/**
* Raw DB insert utility.
*/
exports.insertDocument = async (databaseId, document) => {
const { id, ...documentFields } = document
return await new CouchDB(databaseId).put({ _id: id, ...documentFields })
}
/**
* Raw DB delete utility.
*/
exports.destroyDocument = async (databaseId, documentId) => {
return await new CouchDB(databaseId).destroy(documentId)
}
/**
* Raw DB get utility.
*/
exports.getDocument = async (databaseId, documentId) => {
return await new CouchDB(databaseId).get(documentId)
}

View File

@ -0,0 +1,47 @@
const supertest = require("supertest")
const { BUILTIN_ROLE_IDS } = require("../../../../utilities/security/roles")
const jwt = require("jsonwebtoken")
const env = require("../../../../environment")
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
}

View File

@ -0,0 +1,43 @@
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.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,
}
}