From d9217b1148782ee85e918bb164515ae52443c836 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 10 Mar 2021 17:55:42 +0000 Subject: [PATCH] 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. --- packages/server/package.json | 2 +- .../server/src/api/controllers/apikeys.js | 13 +- packages/server/src/api/controllers/row.js | 25 ++- packages/server/src/api/index.js | 6 +- packages/server/src/api/routes/static.js | 1 + .../src/api/routes/tests/apikeys.spec.js | 2 +- .../server/src/api/routes/tests/cloud.spec.js | 16 ++ .../server/src/api/routes/tests/row.spec.js | 193 +++++++++++++++--- packages/server/src/app.js | 6 +- .../middleware/tests/authenticated.spec.js | 1 - 10 files changed, 204 insertions(+), 61 deletions(-) create mode 100644 packages/server/src/api/routes/tests/cloud.spec.js diff --git a/packages/server/package.json b/packages/server/package.json index 3fe0d68bf3..99763109f3 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -33,7 +33,7 @@ }, "scripts": { "test": "jest --testPathIgnorePatterns=routes && npm run test:integration", - "test:integration": "jest routes --runInBand --coverage", + "test:integration": "jest --runInBand --coverage", "test:watch": "jest --watch", "run:docker": "node src/index", "dev:builder": "cross-env PORT=4001 nodemon src/index.js", diff --git a/packages/server/src/api/controllers/apikeys.js b/packages/server/src/api/controllers/apikeys.js index 1cd69c54df..96754f17cc 100644 --- a/packages/server/src/api/controllers/apikeys.js +++ b/packages/server/src/api/controllers/apikeys.js @@ -3,20 +3,13 @@ const { join } = require("../../utilities/centralPath") const readline = require("readline") const { budibaseAppsDir } = require("../../utilities/budibaseDir") const env = require("../../environment") -const selfhost = require("../../selfhost") const ENV_FILE_PATH = "/.env" exports.fetch = async function(ctx) { ctx.status = 200 - if (env.SELF_HOSTED) { - ctx.body = { - selfhost: await selfhost.getSelfHostAPIKey(), - } - } else { - ctx.body = { - budibase: env.BUDIBASE_API_KEY, - userId: env.USERID_API_KEY, - } + ctx.body = { + budibase: env.BUDIBASE_API_KEY, + userId: env.USERID_API_KEY, } } diff --git a/packages/server/src/api/controllers/row.js b/packages/server/src/api/controllers/row.js index 5d783b7d18..bf985fe55d 100644 --- a/packages/server/src/api/controllers/row.js +++ b/packages/server/src/api/controllers/row.js @@ -224,6 +224,7 @@ exports.fetchView = async function(ctx) { try { table = await db.get(viewInfo.meta.tableId) } catch (err) { + /* istanbul ignore next */ table = { schema: {}, } @@ -255,16 +256,24 @@ exports.fetchView = async function(ctx) { exports.search = async function(ctx) { const appId = ctx.user.appId - const db = new CouchDB(appId) - const { query, pagination: { pageSize = 10, page }, } = 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({ selector: query, limit: pageSize, @@ -324,7 +333,6 @@ exports.destroy = async function(ctx) { const row = await db.get(ctx.params.rowId) if (row.tableId !== ctx.params.tableId) { ctx.throw(400, "Supplied tableId doesn't match the row's tableId") - return } await linkRows.updateLinks({ appId, @@ -376,15 +384,6 @@ exports.fetchEnrichedRow = async function(ctx) { const db = new CouchDB(appId) const tableId = ctx.params.tableId 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 let [table, row] = await Promise.all([ db.get(tableId), diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js index 7b063cb522..7628fa2077 100644 --- a/packages/server/src/api/index.js +++ b/packages/server/src/api/index.js @@ -41,13 +41,15 @@ router.use(async (ctx, next) => { try { await next() } catch (err) { - ctx.log.error(err) ctx.status = err.status || err.statusCode || 500 ctx.body = { message: err.message, status: ctx.status, } - console.trace(err) + if (env.NODE_ENV !== "jest") { + ctx.log.error(err) + console.trace(err) + } } }) diff --git a/packages/server/src/api/routes/static.js b/packages/server/src/api/routes/static.js index 2b0c9b36fc..c812c4d3b1 100644 --- a/packages/server/src/api/routes/static.js +++ b/packages/server/src/api/routes/static.js @@ -8,6 +8,7 @@ const usage = require("../../middleware/usageQuota") const router = Router() +/* istanbul ignore next */ router.param("file", async (file, ctx, next) => { ctx.file = file && file.includes(".") ? file : "index.html" diff --git a/packages/server/src/api/routes/tests/apikeys.spec.js b/packages/server/src/api/routes/tests/apikeys.spec.js index a8077a4492..dbee57c8b0 100644 --- a/packages/server/src/api/routes/tests/apikeys.spec.js +++ b/packages/server/src/api/routes/tests/apikeys.spec.js @@ -35,7 +35,7 @@ describe("/api/keys", () => { describe("update", () => { 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 .put(`/api/keys/TEST`) .send({ diff --git a/packages/server/src/api/routes/tests/cloud.spec.js b/packages/server/src/api/routes/tests/cloud.spec.js new file mode 100644 index 0000000000..3cb65ed819 --- /dev/null +++ b/packages/server/src/api/routes/tests/cloud.spec.js @@ -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("Budibase self hosting️")).toEqual(true) + setup.afterAll() + }) + }) + }) +}) diff --git a/packages/server/src/api/routes/tests/row.spec.js b/packages/server/src/api/routes/tests/row.spec.js index cc50520b77..1442e4eb75 100644 --- a/packages/server/src/api/routes/tests/row.spec.js +++ b/packages/server/src/api/routes/tests/row.spec.js @@ -17,15 +17,15 @@ describe("/rows", () => { row = basicRow(table._id) }) - const loadRow = async id => + const loadRow = async (id, status = 200) => await request .get(`/api/${table._id}/rows/${id}`) .set(config.defaultHeaders()) .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 () => { const res = await request .post(`/api/${row.tableId}/rows`) @@ -217,38 +217,152 @@ describe("/rows", () => { expect(savedRow.body.description).toEqual(existing.description) 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", () => { it("should return no errors on valid row", async () => { - const result = await request + const res = await request .post(`/api/${table._id}/rows/validate`) .send({ name: "ivan" }) .set(config.defaultHeaders()) .expect('Content-Type', /json/) .expect(200) - expect(result.body.valid).toBe(true) - expect(Object.keys(result.body.errors)).toEqual([]) + expect(res.body.valid).toBe(true) + expect(Object.keys(res.body.errors)).toEqual([]) }) it("should errors on invalid row", async () => { - const result = await request + const res = await request .post(`/api/${table._id}/rows/validate`) .send({ name: 1 }) .set(config.defaultHeaders()) .expect('Content-Type', /json/) .expect(200) - expect(result.body.valid).toBe(false) - expect(Object.keys(result.body.errors)).toEqual(["name"]) + expect(res.body.valid).toBe(false) + 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 () => { const table = await config.createLinkedTable() const firstRow = await config.createRow({ @@ -262,30 +376,45 @@ describe("/rows", () => { link: [{_id: firstRow._id}], tableId: table._id, }) - const enriched = await outputProcessing(config.getAppId(), table, [secondRow]) - expect(enriched[0].link.length).toBe(1) - expect(enriched[0].link[0]._id).toBe(firstRow._id) - expect(enriched[0].link[0].primaryDisplay).toBe("Test Contact") + + // test basic enrichment + const resBasic = await request + .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 () => { - const table = await config.createAttachmentTable() - const row = await config.createRow({ - name: "test", - description: "test", - attachment: [{ - url: "/test/thing", - }], - tableId: table._id, + describe("attachments", () => { + it("should allow enriching attachment rows", async () => { + const table = await config.createAttachmentTable() + const row = await config.createRow({ + name: "test", + description: "test", + attachment: [{ + url: "/test/thing", + }], + 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 }) }) \ No newline at end of file diff --git a/packages/server/src/app.js b/packages/server/src/app.js index 3779890c9d..15e996cfe6 100644 --- a/packages/server/src/app.js +++ b/packages/server/src/app.js @@ -56,7 +56,11 @@ if (electron.app && electron.app.isPackaged) { const server = http.createServer(app.callback()) 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 () => { console.log(`Budibase running on ${JSON.stringify(server.address())}`) diff --git a/packages/server/src/middleware/tests/authenticated.spec.js b/packages/server/src/middleware/tests/authenticated.spec.js index bb124d2f4a..fe7e592528 100644 --- a/packages/server/src/middleware/tests/authenticated.spec.js +++ b/packages/server/src/middleware/tests/authenticated.spec.js @@ -9,7 +9,6 @@ class TestConfiguration { this.ctx = { config: {}, auth: {}, - request: {}, cookies: { set: jest.fn(), get: jest.fn()