Updating row tests, reducing console logging during tests for speed and clarity, testing some misc endpoints and updating search functionality to use a starts with operator when working with strings on rows.

This commit is contained in:
mike12345567 2021-03-10 17:55:42 +00:00
parent f69e06870b
commit 163d24a767
10 changed files with 204 additions and 61 deletions

View File

@ -33,7 +33,7 @@
}, },
"scripts": { "scripts": {
"test": "jest --testPathIgnorePatterns=routes && npm run test:integration", "test": "jest --testPathIgnorePatterns=routes && npm run test:integration",
"test:integration": "jest routes --runInBand --coverage", "test:integration": "jest --runInBand --coverage",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"run:docker": "node src/index", "run:docker": "node src/index",
"dev:builder": "cross-env PORT=4001 nodemon src/index.js", "dev:builder": "cross-env PORT=4001 nodemon src/index.js",

View File

@ -3,20 +3,13 @@ const { join } = require("../../utilities/centralPath")
const readline = require("readline") const readline = require("readline")
const { budibaseAppsDir } = require("../../utilities/budibaseDir") const { budibaseAppsDir } = require("../../utilities/budibaseDir")
const env = require("../../environment") const env = require("../../environment")
const selfhost = require("../../selfhost")
const ENV_FILE_PATH = "/.env" const ENV_FILE_PATH = "/.env"
exports.fetch = async function(ctx) { exports.fetch = async function(ctx) {
ctx.status = 200 ctx.status = 200
if (env.SELF_HOSTED) { ctx.body = {
ctx.body = { budibase: env.BUDIBASE_API_KEY,
selfhost: await selfhost.getSelfHostAPIKey(), userId: env.USERID_API_KEY,
}
} else {
ctx.body = {
budibase: env.BUDIBASE_API_KEY,
userId: env.USERID_API_KEY,
}
} }
} }

View File

@ -224,6 +224,7 @@ exports.fetchView = async function(ctx) {
try { try {
table = await db.get(viewInfo.meta.tableId) table = await db.get(viewInfo.meta.tableId)
} catch (err) { } catch (err) {
/* istanbul ignore next */
table = { table = {
schema: {}, schema: {},
} }
@ -255,16 +256,24 @@ exports.fetchView = async function(ctx) {
exports.search = async function(ctx) { exports.search = async function(ctx) {
const appId = ctx.user.appId const appId = ctx.user.appId
const db = new CouchDB(appId) const db = new CouchDB(appId)
const { const {
query, query,
pagination: { pageSize = 10, page }, pagination: { pageSize = 10, page },
} = ctx.request.body } = ctx.request.body
query.tableId = ctx.params.tableId // make all strings a starts with operation rather than pure equality
for (const [key, queryVal] of Object.entries(query)) {
if (typeof queryVal === "string") {
query[key] = {
$gt: queryVal,
$lt: `${queryVal}\uffff`,
}
}
}
// pure equality for table
query.tableId = ctx.params.tableId
const response = await db.find({ const response = await db.find({
selector: query, selector: query,
limit: pageSize, limit: pageSize,
@ -324,7 +333,6 @@ exports.destroy = async function(ctx) {
const row = await db.get(ctx.params.rowId) const row = await db.get(ctx.params.rowId)
if (row.tableId !== ctx.params.tableId) { if (row.tableId !== ctx.params.tableId) {
ctx.throw(400, "Supplied tableId doesn't match the row's tableId") ctx.throw(400, "Supplied tableId doesn't match the row's tableId")
return
} }
await linkRows.updateLinks({ await linkRows.updateLinks({
appId, appId,
@ -376,15 +384,6 @@ exports.fetchEnrichedRow = async function(ctx) {
const db = new CouchDB(appId) const db = new CouchDB(appId)
const tableId = ctx.params.tableId const tableId = ctx.params.tableId
const rowId = ctx.params.rowId const rowId = ctx.params.rowId
if (appId == null || tableId == null || rowId == null) {
ctx.status = 400
ctx.body = {
status: 400,
error:
"Cannot handle request, URI params have not been successfully prepared.",
}
return
}
// need table to work out where links go in row // need table to work out where links go in row
let [table, row] = await Promise.all([ let [table, row] = await Promise.all([
db.get(tableId), db.get(tableId),

View File

@ -41,13 +41,15 @@ router.use(async (ctx, next) => {
try { try {
await next() await next()
} catch (err) { } catch (err) {
ctx.log.error(err)
ctx.status = err.status || err.statusCode || 500 ctx.status = err.status || err.statusCode || 500
ctx.body = { ctx.body = {
message: err.message, message: err.message,
status: ctx.status, status: ctx.status,
} }
console.trace(err) if (env.NODE_ENV !== "jest") {
ctx.log.error(err)
console.trace(err)
}
} }
}) })

View File

@ -8,6 +8,7 @@ const usage = require("../../middleware/usageQuota")
const router = Router() const router = Router()
/* istanbul ignore next */
router.param("file", async (file, ctx, next) => { router.param("file", async (file, ctx, next) => {
ctx.file = file && file.includes(".") ? file : "index.html" ctx.file = file && file.includes(".") ? file : "index.html"

View File

@ -35,7 +35,7 @@ describe("/api/keys", () => {
describe("update", () => { describe("update", () => {
it("should allow updating a value", async () => { it("should allow updating a value", async () => {
fs.writeFileSync(path.join(budibaseAppsDir(), ".env"), "") fs.writeFileSync(path.join(budibaseAppsDir(), ".env"), "TEST_API_KEY=thing")
const res = await request const res = await request
.put(`/api/keys/TEST`) .put(`/api/keys/TEST`)
.send({ .send({

View File

@ -0,0 +1,16 @@
const setup = require("./utilities")
describe("test things in the Cloud/Self hosted", () => {
describe("test self hosted static page", () => {
it("should be able to load the static page", async () => {
await setup.switchToCloudForFunction(async () => {
let request = setup.getRequest()
let config = setup.getConfig()
await config.init()
const res = await request.get(`/`).expect(200)
expect(res.text.includes("<title>Budibase self hosting</title>")).toEqual(true)
setup.afterAll()
})
})
})
})

View File

@ -17,15 +17,15 @@ describe("/rows", () => {
row = basicRow(table._id) row = basicRow(table._id)
}) })
const loadRow = async id => const loadRow = async (id, status = 200) =>
await request await request
.get(`/api/${table._id}/rows/${id}`) .get(`/api/${table._id}/rows/${id}`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(status)
describe("save, load, update, delete", () => { describe("save, load, update", () => {
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 request const res = await request
.post(`/api/${row.tableId}/rows`) .post(`/api/${row.tableId}/rows`)
@ -217,38 +217,152 @@ describe("/rows", () => {
expect(savedRow.body.description).toEqual(existing.description) expect(savedRow.body.description).toEqual(existing.description)
expect(savedRow.body.name).toEqual("Updated Name") expect(savedRow.body.name).toEqual("Updated Name")
})
it("should throw an error when given improper types", async () => {
const existing = await config.createRow()
await request
.patch(`/api/${table._id}/rows/${existing._id}`)
.send({
_id: existing._id,
_rev: existing._rev,
tableId: table._id,
name: 1,
})
.set(config.defaultHeaders())
.expect(400)
})
})
describe("destroy", () => {
it("should be able to delete a row", async () => {
const createdRow = await config.createRow(row)
const res = await request
.delete(`/api/${table._id}/rows/${createdRow._id}/${createdRow._rev}`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(res.body.ok).toEqual(true)
})
it("shouldn't allow deleting a row in a table which is different to the one the row was created on", async () => {
const createdRow = await config.createRow(row)
await request
.delete(`/api/wrong_table/rows/${createdRow._id}/${createdRow._rev}`)
.set(config.defaultHeaders())
.expect(400)
}) })
}) })
describe("validate", () => { describe("validate", () => {
it("should return no errors on valid row", async () => { it("should return no errors on valid row", async () => {
const result = await request const res = await request
.post(`/api/${table._id}/rows/validate`) .post(`/api/${table._id}/rows/validate`)
.send({ name: "ivan" }) .send({ name: "ivan" })
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
expect(result.body.valid).toBe(true) expect(res.body.valid).toBe(true)
expect(Object.keys(result.body.errors)).toEqual([]) expect(Object.keys(res.body.errors)).toEqual([])
}) })
it("should errors on invalid row", async () => { it("should errors on invalid row", async () => {
const result = await request const res = await request
.post(`/api/${table._id}/rows/validate`) .post(`/api/${table._id}/rows/validate`)
.send({ name: 1 }) .send({ name: 1 })
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
expect(result.body.valid).toBe(false) expect(res.body.valid).toBe(false)
expect(Object.keys(result.body.errors)).toEqual(["name"]) expect(Object.keys(res.body.errors)).toEqual(["name"])
}) })
}) })
describe("enrich row unit test", () => { describe("bulkDelete", () => {
it("should be able to delete a bulk set of rows", async () => {
const row1 = await config.createRow()
const row2 = await config.createRow()
const res = await request
.post(`/api/${table._id}/rows`)
.send({
type: "delete",
rows: [
row1,
row2,
]
})
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(res.body.length).toEqual(2)
await loadRow(row1._id, 404)
})
})
describe("search", () => {
it("should run a search on the table", async () => {
const row = await config.createRow()
// add another row that shouldn't be found
await config.createRow({
...basicRow(),
name: "Other Contact",
})
const res = await request
.post(`/api/${table._id}/rows/search`)
.send({
query: {
name: "Test",
},
pagination: { pageSize: 25, page: 0 }
})
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(res.body.length).toEqual(1)
expect(res.body[0]._id).toEqual(row._id)
})
})
describe("fetchView", () => {
it("should be able to fetch tables contents via 'view'", async () => {
const row = await config.createRow()
const res = await request
.get(`/api/views/all_${table._id}`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(res.body.length).toEqual(1)
expect(res.body[0]._id).toEqual(row._id)
})
it("should throw an error if view doesn't exist", async () => {
await request
.get(`/api/views/derp`)
.set(config.defaultHeaders())
.expect(400)
})
it("should be able to run on a view", async () => {
const view = await config.createView()
const row = await config.createRow()
const res = await request
.get(`/api/views/${view._id}`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(res.body.length).toEqual(1)
expect(res.body[0]._id).toEqual(row._id)
})
})
describe("user testing", () => {
})
describe("fetchEnrichedRows", () => {
it("should allow enriching some linked rows", async () => { it("should allow enriching some linked rows", async () => {
const table = await config.createLinkedTable() const table = await config.createLinkedTable()
const firstRow = await config.createRow({ const firstRow = await config.createRow({
@ -262,30 +376,45 @@ describe("/rows", () => {
link: [{_id: firstRow._id}], link: [{_id: firstRow._id}],
tableId: table._id, tableId: table._id,
}) })
const enriched = await outputProcessing(config.getAppId(), table, [secondRow])
expect(enriched[0].link.length).toBe(1) // test basic enrichment
expect(enriched[0].link[0]._id).toBe(firstRow._id) const resBasic = await request
expect(enriched[0].link[0].primaryDisplay).toBe("Test Contact") .get(`/api/${table._id}/rows/${secondRow._id}`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(resBasic.body.link[0]._id).toBe(firstRow._id)
expect(resBasic.body.link[0].primaryDisplay).toBe("Test Contact")
// test full enrichment
const resEnriched = await request
.get(`/api/${table._id}/${secondRow._id}/enrich`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(resEnriched.body.link.length).toBe(1)
expect(resEnriched.body.link[0]._id).toBe(firstRow._id)
expect(resEnriched.body.link[0].name).toBe("Test Contact")
expect(resEnriched.body.link[0].description).toBe("original description")
}) })
}) })
it("should allow enriching attachment rows", async () => { describe("attachments", () => {
const table = await config.createAttachmentTable() it("should allow enriching attachment rows", async () => {
const row = await config.createRow({ const table = await config.createAttachmentTable()
name: "test", const row = await config.createRow({
description: "test", name: "test",
attachment: [{ description: "test",
url: "/test/thing", attachment: [{
}], url: "/test/thing",
tableId: table._id, }],
tableId: table._id,
})
// the environment needs configured for this
await setup.switchToCloudForFunction(async () => {
const enriched = await outputProcessing(config.getAppId(), table, [row])
expect(enriched[0].attachment[0].url).toBe(`/app-assets/assets/${config.getAppId()}/test/thing`)
})
}) })
// the environment needs configured for this
env.CLOUD = 1
env.SELF_HOSTED = 1
const enriched = await outputProcessing(config.getAppId(), table, [row])
expect(enriched[0].attachment[0].url).toBe(`/app-assets/assets/${config.getAppId()}/test/thing`)
// remove env config
env.CLOUD = undefined
env.SELF_HOSTED = undefined
}) })
}) })

View File

@ -56,7 +56,11 @@ if (electron.app && electron.app.isPackaged) {
const server = http.createServer(app.callback()) const server = http.createServer(app.callback())
destroyable(server) destroyable(server)
server.on("close", () => console.log("Server Closed")) server.on("close", () => {
if (env.NODE_ENV !== "jest") {
console.log("Server Closed")
}
})
module.exports = server.listen(env.PORT || 0, async () => { module.exports = server.listen(env.PORT || 0, async () => {
console.log(`Budibase running on ${JSON.stringify(server.address())}`) console.log(`Budibase running on ${JSON.stringify(server.address())}`)

View File

@ -9,7 +9,6 @@ class TestConfiguration {
this.ctx = { this.ctx = {
config: {}, config: {},
auth: {}, auth: {},
request: {},
cookies: { cookies: {
set: jest.fn(), set: jest.fn(),
get: jest.fn() get: jest.fn()