Adding more test cases for the controllers, tables and views weren't as well covered as required.

This commit is contained in:
mike12345567 2021-03-15 16:36:38 +00:00
parent 3406138f34
commit 794372987e
11 changed files with 241 additions and 107 deletions

View File

@ -65,12 +65,14 @@ exports.save = async function(ctx) {
// Don't rename if the name is the same
let { _rename } = tableToSave
/* istanbul ignore next */
if (_rename && _rename.old === _rename.updated) {
_rename = null
delete tableToSave._rename
}
// rename row fields when table column is renamed
/* istanbul ignore next */
if (_rename && tableToSave.schema[_rename.updated].type === FieldTypes.LINK) {
ctx.throw(400, "Cannot rename a linked column.")
} else if (_rename && tableToSave.primaryDisplay === _rename.old) {
@ -159,7 +161,7 @@ exports.destroy = async function(ctx) {
ctx.eventEmitter &&
ctx.eventEmitter.emitTable(`table:delete`, appId, tableToDelete)
ctx.status = 200
ctx.message = `Table ${ctx.params.tableId} deleted.`
ctx.body = { message: `Table ${ctx.params.tableId} deleted.` }
}
exports.validateCSVSchema = async function(ctx) {

View File

@ -90,7 +90,8 @@ exports.handleDataImport = async (user, table, dataImport) => {
return table
}
exports.handleSearchIndexes = async (db, table) => {
exports.handleSearchIndexes = async (appId, table) => {
const db = new CouchDB(appId)
// create relevant search indexes
if (table.indexes && table.indexes.length > 0) {
const currentIndexes = await db.getIndexes()
@ -150,6 +151,9 @@ class TableSaveFunctions {
constructor({ db, ctx, oldTable, dataImport }) {
this.db = db
this.ctx = ctx
if (this.ctx && this.ctx.user) {
this.appId = this.ctx.user.appId
}
this.oldTable = oldTable
this.dataImport = dataImport
// any rows that need updated
@ -178,7 +182,7 @@ class TableSaveFunctions {
// after saving
async after(table) {
table = await exports.handleSearchIndexes(this.db, table)
table = await exports.handleSearchIndexes(this.appId, table)
table = await exports.handleDataImport(
this.ctx.user,
table,

View File

@ -29,11 +29,13 @@ const controller = {
save: async ctx => {
const db = new CouchDB(ctx.user.appId)
const { originalName, ...viewToSave } = ctx.request.body
const designDoc = await db.get("_design/database")
const view = viewTemplate(viewToSave)
if (!viewToSave.name) {
ctx.throw(400, "Cannot create view without a name")
}
designDoc.views = {
...designDoc.views,
[viewToSave.name]: view,
@ -60,17 +62,16 @@ const controller = {
await db.put(table)
ctx.body = table.views[viewToSave.name]
ctx.message = `View ${viewToSave.name} saved successfully.`
ctx.body = {
...table.views[viewToSave.name],
name: viewToSave.name,
}
},
destroy: async ctx => {
const db = new CouchDB(ctx.user.appId)
const designDoc = await db.get("_design/database")
const viewName = decodeURI(ctx.params.viewName)
const view = designDoc.views[viewName]
delete designDoc.views[viewName]
await db.put(designDoc)
@ -80,16 +81,17 @@ const controller = {
await db.put(table)
ctx.body = view
ctx.message = `View ${ctx.params.viewName} saved successfully.`
},
exportView: async ctx => {
const db = new CouchDB(ctx.user.appId)
const designDoc = await db.get("_design/database")
const viewName = decodeURI(ctx.query.view)
const view = designDoc.views[viewName]
const format = ctx.query.format
if (!format) {
ctx.throw(400, "Format must be specified, either csv or json")
}
if (view) {
ctx.params.viewName = viewName
@ -102,6 +104,7 @@ const controller = {
}
} else {
// table all_ view
/* istanbul ignore next */
ctx.params.viewName = viewName
}

View File

@ -1,6 +1,7 @@
const setup = require("./utilities")
const tableUtils = require("../../controllers/table/utils")
describe("/analytics", () => {
describe("run misc tests", () => {
let request = setup.getRequest()
let config = setup.getConfig()
@ -10,29 +11,44 @@ describe("/analytics", () => {
await config.init()
})
describe("isEnabled", () => {
it("check if analytics enabled", async () => {
const res = await request
.get(`/api/analytics`)
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(typeof res.body.enabled).toEqual("boolean")
describe("/analytics", () => {
it("check if analytics enabled", async () => {
const res = await request
.get(`/api/analytics`)
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(typeof res.body.enabled).toEqual("boolean")
})
})
describe("/health", () => {
it("should confirm healthy", async () => {
await request.get("/health").expect(200)
})
})
describe("/version", () => {
it("should confirm version", async () => {
const res = await request.get("/version").expect(200)
expect(res.text.split(".").length).toEqual(3)
})
})
describe("test table utilities", () => {
it("should be able to import a CSV", async () => {
const table = await config.createTable()
const dataImport = {
csvString: "a,b,c,d\n1,2,3,4"
}
await tableUtils.handleDataImport({
appId: config.getAppId(),
userId: "test",
}, table, dataImport)
const rows = await config.getRows()
expect(rows[0].a).toEqual("1")
expect(rows[0].b).toEqual("2")
expect(rows[0].c).toEqual("3")
})
})
})
describe("/health", () => {
it("should confirm healthy", async () => {
let config = setup.getConfig()
await config.getRequest().get("/health").expect(200)
})
})
describe("/version", () => {
it("should confirm version", async () => {
const config = setup.getConfig()
const res = await config.getRequest().get("/version").expect(200)
expect(res.text.split(".").length).toEqual(3)
})
})

View File

@ -348,7 +348,7 @@ describe("/rows", () => {
const view = await config.createView()
const row = await config.createRow()
const res = await request
.get(`/api/views/${view._id}`)
.get(`/api/views/${view.name}`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)

View File

@ -1,5 +1,6 @@
const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
const { checkBuilderEndpoint, getDB } = require("./utilities/TestFunctions")
const setup = require("./utilities")
const { basicTable } = setup.structures
describe("/tables", () => {
let request = setup.getRequest()
@ -12,25 +13,22 @@ describe("/tables", () => {
})
describe("create", () => {
it("returns a success message when the table is successfully created", done => {
request
it("returns a success message when the table is successfully created", async () => {
const res = await request
.post(`/api/tables`)
.send({
name: "TestTable",
key: "name",
schema: {
name: { type: "string" }
name: {type: "string"}
}
})
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
.end(async (err, res) => {
expect(res.res.statusMessage).toEqual("Table TestTable saved successfully.")
expect(res.body.name).toEqual("TestTable")
done()
})
})
expect(res.res.statusMessage).toEqual("Table TestTable saved successfully.")
expect(res.body.name).toEqual("TestTable")
})
it("renames all the row fields for a table when a schema key is renamed", async () => {
const testTable = await config.createTable()
@ -56,41 +54,40 @@ describe("/tables", () => {
updated: "updatedName"
},
schema: {
updatedName: { type: "string" }
updatedName: {type: "string"}
}
})
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(updatedTable.res.statusMessage).toEqual("Table TestTable saved successfully.")
expect(updatedTable.body.name).toEqual("TestTable")
expect(updatedTable.res.statusMessage).toEqual("Table TestTable saved successfully.")
expect(updatedTable.body.name).toEqual("TestTable")
const res = await request
.get(`/api/${testTable._id}/rows/${testRow.body._id}`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
const res = await request
.get(`/api/${testTable._id}/rows/${testRow.body._id}`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(res.body.updatedName).toEqual("test")
expect(res.body.name).toBeUndefined()
})
expect(res.body.updatedName).toEqual("test")
expect(res.body.name).toBeUndefined()
})
it("should apply authorization to endpoint", async () => {
await checkBuilderEndpoint({
config,
method: "POST",
url: `/api/tables`,
body: {
name: "TestTable",
key: "name",
schema: {
name: { type: "string" }
}
it("should apply authorization to endpoint", async () => {
await checkBuilderEndpoint({
config,
method: "POST",
url: `/api/tables`,
body: {
name: "TestTable",
key: "name",
schema: {
name: {type: "string"}
}
})
}
})
})
})
describe("fetch", () => {
let testTable
@ -103,28 +100,91 @@ describe("/tables", () => {
delete testTable._rev
})
it("returns all the tables for that instance in the response body", done => {
request
it("returns all the tables for that instance in the response body", async () => {
const res = await request
.get(`/api/tables`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
.end(async (_, res) => {
const fetchedTable = res.body[0]
expect(fetchedTable.name).toEqual(testTable.name)
expect(fetchedTable.type).toEqual("table")
done()
})
const fetchedTable = res.body[0]
expect(fetchedTable.name).toEqual(testTable.name)
expect(fetchedTable.type).toEqual("table")
})
it("should apply authorization to endpoint", async () => {
await checkBuilderEndpoint({
config,
method: "GET",
url: `/api/tables`,
})
await checkBuilderEndpoint({
config,
method: "GET",
url: `/api/tables`,
})
})
})
describe("indexing", () => {
it("should be able to create a table with indexes", async () => {
const db = getDB(config)
const indexCount = (await db.getIndexes()).total_rows
const table = basicTable()
table.indexes = ["name"]
const res = await request
.post(`/api/tables`)
.send(table)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(res.body._id).toBeDefined()
expect(res.body._rev).toBeDefined()
expect((await db.getIndexes()).total_rows).toEqual(indexCount + 1)
// update index to see what happens
table.indexes = ["name", "description"]
await request
.post(`/api/tables`)
.send({
...table,
_id: res.body._id,
_rev: res.body._rev,
})
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
// shouldn't have created a new index
expect((await db.getIndexes()).total_rows).toEqual(indexCount + 1)
})
})
describe("updating user table", () => {
it("should add roleId and email field when adjusting user table schema", async () => {
const res = await request
.post(`/api/tables`)
.send({
...basicTable(),
_id: "ta_users",
})
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(res.body.schema.email).toBeDefined()
expect(res.body.schema.roleId).toBeDefined()
})
})
describe("validate csv", () => {
it("should be able to validate a CSV layout", async () => {
const res = await request
.post(`/api/tables/csv/validate`)
.send({
csvString: "a,b,c,d\n1,2,3,4"
})
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(res.body.schema).toBeDefined()
expect(res.body.schema.a).toEqual({
type: "string",
success: true,
})
})
})
describe("destroy", () => {
let testTable
@ -137,19 +197,16 @@ describe("/tables", () => {
delete testTable._rev
})
it("returns a success response when a table is deleted.", async done => {
request
it("returns a success response when a table is deleted.", async () => {
const res = await request
.delete(`/api/tables/${testTable._id}/${testTable._rev}`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
.end(async (_, res) => {
expect(res.res.statusMessage).toEqual(`Table ${testTable._id} deleted.`)
done()
})
})
expect(res.body.message).toEqual(`Table ${testTable._id} deleted.`)
})
it("deletes linked references to the table after deletion", async done => {
it("deletes linked references to the table after deletion", async () => {
const linkedTable = await config.createTable({
name: "LinkedTable",
type: "table",
@ -171,18 +228,15 @@ describe("/tables", () => {
},
})
request
const res = await request
.delete(`/api/tables/${testTable._id}/${testTable._rev}`)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
.end(async (_, res) => {
expect(res.res.statusMessage).toEqual(`Table ${testTable._id} deleted.`)
const dependentTable = await config.getTable(linkedTable._id)
expect(dependentTable.schema.TestTable).not.toBeDefined()
done()
})
})
expect(res.body.message).toEqual(`Table ${testTable._id} deleted.`)
const dependentTable = await config.getTable(linkedTable._id)
expect(dependentTable.schema.TestTable).not.toBeDefined()
})
it("should apply authorization to endpoint", async () => {
await checkBuilderEndpoint({
@ -191,6 +245,5 @@ describe("/tables", () => {
url: `/api/tables/${testTable._id}/${testTable._rev}`,
})
})
})
})

View File

@ -1,5 +1,6 @@
const rowController = require("../../../controllers/row")
const appController = require("../../../controllers/application")
const CouchDB = require("../../../../db")
function Request(appId, params) {
this.user = { appId }
@ -77,3 +78,7 @@ exports.checkPermissionsEndpoint = async ({
.set(failHeader)
.expect(403)
}
exports.getDB = config => {
return new CouchDB(config.getAppId())
}

View File

@ -29,9 +29,7 @@ describe("/views", () => {
.expect("Content-Type", /json/)
.expect(200)
expect(res.res.statusMessage).toEqual(
"View TestView saved successfully."
)
expect(res.body.tableId).toBe(table._id)
})
it("updates the table row with the new view metadata", async () => {
@ -46,10 +44,8 @@ describe("/views", () => {
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body.tableId).toBe(table._id)
expect(res.res.statusMessage).toEqual(
"View TestView saved successfully."
)
const updatedTable = await config.getTable(table._id)
expect(updatedTable.views).toEqual({
TestView: {
@ -173,4 +169,49 @@ describe("/views", () => {
expect(res.body).toMatchSnapshot()
})
})
describe("destroy", () => {
it("should be able to delete a view", async () => {
const table = await config.createTable()
const view = await config.createView()
const res = await request
.delete(`/api/views/${view.name}`)
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body.map).toBeDefined()
expect(res.body.meta.tableId).toEqual(table._id)
})
})
describe("exportView", () => {
it("should be able to delete a view", async () => {
await config.createTable()
await config.createRow()
const view = await config.createView()
let res = await request
.get(`/api/views/export?view=${view.name}&format=json`)
.set(config.defaultHeaders())
.expect(200)
let error
try {
const obj = JSON.parse(res.text)
expect(obj.length).toBe(1)
} catch (err) {
error = err
}
expect(error).toBeUndefined()
res = await request
.get(`/api/views/export?view=${view.name}&format=csv`)
.set(config.defaultHeaders())
.expect(200)
// this shouldn't be JSON
try {
JSON.parse(res.text)
} catch (err) {
error = err
}
expect(error).toBeDefined()
})
})
})

View File

@ -3,11 +3,11 @@ const usageQuota = require("../../utilities/usageQuota")
const thread = require("../thread")
const triggers = require("../triggers")
const { basicAutomation, basicTable } = require("../../tests/utilities/structures")
const TestConfig = require("../../tests/utilities/TestConfiguration")
const { wait } = require("../../utilities")
const env = require("../../environment")
const { makePartial } = require("../../tests/utilities")
const { cleanInputValues } = require("../automationUtils")
const setup = require("./utilities")
let workerJob
@ -31,13 +31,14 @@ jest.mock("worker-farm", () => {
})
describe("Run through some parts of the automations system", () => {
let config = new TestConfig(false)
let config = setup.getConfig()
beforeEach(async () => {
await automation.init()
await config.init()
})
afterAll(setup.afterAll)
it("should be able to init in builder", async () => {
await triggers.externalTrigger(basicAutomation(), { a: 1 })

View File

@ -30,6 +30,7 @@ const Pouch = PouchDB.defaults(POUCH_DB_DEFAULTS)
allDbs(Pouch)
// replicate your local levelDB pouch to a running HTTP compliant couch or pouchdb server.
/* istanbul ignore next */
// eslint-disable-next-line no-unused-vars
function replicateLocal() {
Pouch.allDbs().then(dbs => {

View File

@ -171,6 +171,13 @@ class TestConfiguration {
return this._req(null, { tableId, rowId }, controllers.row.find)
}
async getRows(tableId) {
if (!tableId && this.table) {
tableId = this.table._id
}
return this._req(null, { tableId }, controllers.row.fetchTableRows)
}
async createRole(config = null) {
config = config || basicRole()
return this._req(config, null, controllers.role.save)
@ -195,6 +202,7 @@ class TestConfiguration {
const view = config || {
map: "function(doc) { emit(doc[doc.key], doc._id); } ",
tableId: this.table._id,
name: "ViewTest",
}
return this._req(view, null, controllers.view.save)
}