Table CRUD events + add timekeeper for tests

This commit is contained in:
Rory Powell 2022-04-11 14:39:31 +01:00
parent d41037a859
commit 5ab9f1a9c5
23 changed files with 1338 additions and 74 deletions

View File

@ -43,7 +43,8 @@
"jest": "^26.6.3",
"pouchdb": "^7.2.1",
"pouchdb-adapter-memory": "^7.2.2",
"pouchdb-all-dbs": "^1.0.2"
"pouchdb-all-dbs": "^1.0.2",
"timekeeper": "^2.2.0"
},
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc"
}

View File

@ -1,4 +1,10 @@
const env = require("../src/environment")
const { mocks } = require("../testUtils")
// mock all dates to 2020-01-01T00:00:00.000Z
// use tk.reset() to use real dates in individual tests
const tk = require("timekeeper")
tk.freeze(mocks.date.MOCK_DATE)
env._set("SELF_HOSTED", "1")
env._set("NODE_ENV", "jest")

View File

@ -1,6 +1,4 @@
require("../../tests/utilities/TestConfiguration")
const { mocks } = require("../../tests/utilities")
mocks.date.mock()
const { getDB, allDbs } = require("../")
describe("db", () => {

View File

@ -6,13 +6,11 @@ exports.created = () => {
events.processEvent(Events.TABLE_CREATED, properties)
}
// TODO
exports.updated = () => {
const properties = {}
events.processEvent(Events.TABLE_UPDATED, properties)
}
// TODO
exports.deleted = () => {
const properties = {}
events.processEvent(Events.TABLE_DELETED, properties)

View File

@ -1,6 +1,4 @@
require("../../tests/utilities/TestConfiguration")
const { mocks } = require("../../tests/utilities")
mocks.date.mock()
const { runMigrations, getMigrationsDoc } = require("../index")
const { getDB } = require("../../db")
const {

View File

@ -1,13 +1,2 @@
exports.MOCK_DATE = new Date("2020-01-01T00:00:00.000Z")
exports.MOCK_DATE_TIMESTAMP = 1577836800000
exports.mock = () => {
// eslint-disable-next-line no-global-assign
Date = jest.fn(() => exports.MOCK_DATE)
Date.now = jest.fn(() => exports.MOCK_DATE_TIMESTAMP)
return {
MOCK_DATE: exports.MOCK_DATE,
MOCK_DATE_TIMESTAMP: exports.MOCK_DATE_TIMESTAMP,
}
}

View File

@ -95,7 +95,14 @@ jest.mock("../../../events", () => {
servedApp: jest.fn(),
servedAppPreview: jest.fn(),
},
table: {},
table: {
created: jest.fn(),
updated: jest.fn(),
deleted: jest.fn(),
exported: jest.fn(),
imported: jest.fn(),
permissionUpdated: jest.fn(),
},
view: {},
}
})

View File

@ -5161,6 +5161,11 @@ through@~2.3.4:
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
timekeeper@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/timekeeper/-/timekeeper-2.2.0.tgz#9645731fce9e3280a18614a57a9d1b72af3ca368"
integrity sha512-W3AmPTJWZkRwu+iSNxPIsLZ2ByADsOLbbLxe46UJyWj3mlYLlwucKiq+/dPm0l9wTzqoF3/2PH0AGFCebjq23A==
tiny-queue@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046"

View File

@ -597,6 +597,16 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
htmlparser2@^6.0.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
dependencies:
domelementtype "^2.0.1"
domhandler "^4.0.0"
domutils "^2.5.2"
entities "^2.0.0"
icss-replace-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
@ -661,6 +671,11 @@ is-module@^1.0.0:
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-reference@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
@ -701,6 +716,11 @@ json5@^1.0.1:
dependencies:
minimist "^1.2.0"
leaflet@^1.7.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.7.1.tgz#10d684916edfe1bf41d688a3b97127c0322a2a19"
integrity sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==
lilconfig@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082"
@ -769,6 +789,11 @@ nanoid@^3.1.30, nanoid@^3.1.32:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c"
integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==
nanoid@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557"
integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==
node-releases@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
@ -822,6 +847,11 @@ p-timeout@^3.2.0:
dependencies:
p-finally "^1.0.0"
parse-srcset@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
integrity sha1-8r0iH2zJcKk42IVWq8WJyqqiveE=
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@ -1124,6 +1154,15 @@ postcss@^8.2.10:
picocolors "^1.0.0"
source-map-js "^1.0.1"
postcss@^8.3.11:
version "8.4.12"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905"
integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==
dependencies:
nanoid "^3.3.1"
picocolors "^1.0.0"
source-map-js "^1.0.2"
promise.series@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/promise.series/-/promise.series-0.2.0.tgz#2cc7ebe959fc3a6619c04ab4dbdc9e452d864bbd"
@ -1269,6 +1308,23 @@ safe-identifier@^0.4.2:
resolved "https://registry.yarnpkg.com/safe-identifier/-/safe-identifier-0.4.2.tgz#cf6bfca31c2897c588092d1750d30ef501d59fcb"
integrity sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==
sanitize-html@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.7.0.tgz#e106205b468aca932e2f9baf241f24660d34e279"
integrity sha512-jfQelabOn5voO7FAfnQF7v+jsA6z9zC/O4ec0z3E35XPEtHYJT/OdUziVWlKW4irCr2kXaQAyXTXDHWAibg1tA==
dependencies:
deepmerge "^4.2.2"
escape-string-regexp "^4.0.0"
htmlparser2 "^6.0.0"
is-plain-object "^5.0.0"
parse-srcset "^1.0.2"
postcss "^8.3.11"
screenfull@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-6.0.1.tgz#3b71e6f06b72d817a8d3be73c45ebe71fa8da1ce"
integrity sha512-yzQW+j4zMUBQC51xxWaoDYjxOtl8Kn+xvue3p6v/fv2pIi1jH4AldgVLU8TBfFVgH2x3VXlf3+YiA/AYIPlaew==
serialize-javascript@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
@ -1288,7 +1344,7 @@ slash@^3.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
source-map-js@^1.0.1:
source-map-js@^1.0.1, source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==

View File

@ -170,6 +170,7 @@
"rimraf": "^3.0.2",
"supertest": "^4.0.2",
"swagger-jsdoc": "^6.1.0",
"timekeeper": "^2.2.0",
"ts-jest": "^27.0.3",
"ts-node": "^10.0.0",
"typescript": "^4.5.5",

View File

@ -1,5 +1,11 @@
const { tmpdir } = require("os")
const env = require("../src/environment")
const { mocks } = require("@budibase/backend-core/testUtils")
// mock all dates to 2020-01-01T00:00:00.000Z
// use tk.reset() to use real dates in individual tests
const tk = require("timekeeper")
tk.freeze(mocks.date.MOCK_DATE)
env._set("SELF_HOSTED", "1")
env._set("NODE_ENV", "jest")

View File

@ -3,8 +3,6 @@ const { RestImporter } = require("../index")
const fs = require("fs")
const path = require('path')
const { events} = require("@budibase/backend-core")
const { mocks } = require("@budibase/backend-core/testUtils")
mocks.date.mock()
const getData = (file) => {
return fs.readFileSync(path.join(__dirname, `../sources/tests/${file}`), "utf8")

View File

@ -5,6 +5,7 @@ const { isExternalTable, isSQL } = require("../../../integrations/utils")
const { getDatasourceParams } = require("../../../db/utils")
const { getAppDB } = require("@budibase/backend-core/context")
const { getTable, getAllInternalTables } = require("./utils")
const { events } = require("@budibase/backend-core")
function pickApi({ tableId, table }) {
if (table && !tableId) {
@ -56,6 +57,11 @@ exports.save = async function (ctx) {
const appId = ctx.appId
const table = ctx.request.body
const savedTable = await pickApi({ table }).save(ctx)
if (!table._id) {
events.table.created(savedTable)
} else {
events.table.updated(savedTable)
}
ctx.status = 200
ctx.message = `Table ${table.name} saved successfully.`
ctx.eventEmitter &&
@ -67,6 +73,7 @@ exports.destroy = async function (ctx) {
const appId = ctx.appId
const tableId = ctx.params.tableId
const deletedTable = await pickApi({ tableId }).destroy(ctx)
events.table.deleted(deletedTable)
ctx.eventEmitter &&
ctx.eventEmitter.emitTable(`table:delete`, appId, deletedTable)
ctx.status = 200

View File

@ -11,7 +11,7 @@ const { getAppDB } = require("@budibase/backend-core/context")
import { isTest } from "../../../environment"
import { cleanupAttachments } from "../../../utilities/rowProcessor"
import { runStaticFormulaChecks } from "./bulkFormula"
import { quotas, QuotaUsageType, StaticQuotaName } from "@budibase/pro"
import { quotas } from "@budibase/pro"
export async function save(ctx: any) {
const db = getAppDB()

View File

@ -6,8 +6,6 @@ const {
} = require("./utilities/TestFunctions")
const setup = require("./utilities")
const { basicAutomation, newAutomation, automationTrigger, automationStep } = setup.structures
const { mocks } = require("@budibase/backend-core/testUtils")
mocks.date.mock()
const MAX_RETRIES = 4
const { TRIGGER_DEFINITIONS, ACTION_DEFINITIONS } = require("../../../automations")
const { events } = require("@budibase/backend-core")

View File

@ -6,8 +6,6 @@ let { checkBuilderEndpoint } = require("./utilities/TestFunctions")
const pg = require("pg")
const { checkCacheForDynamicVariable } = require("../../../threads/utils")
const { events } = require("@budibase/backend-core")
const { mocks } = require("@budibase/backend-core/testUtils")
mocks.date.mock()
describe("/datasources", () => {
let request = setup.getRequest()

View File

@ -13,8 +13,6 @@ const setup = require("./utilities")
const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
const { checkCacheForDynamicVariable } = require("../../../threads/utils")
const { basicQuery, basicDatasource } = setup.structures
const { mocks } = require("@budibase/backend-core/testUtils")
mocks.date.mock()
const { events } = require("@budibase/backend-core")
describe("/queries", () => {

View File

@ -1,6 +1,7 @@
const { checkBuilderEndpoint, getDB } = require("./utilities/TestFunctions")
const setup = require("./utilities")
const { checkBuilderEndpoint, getDB } = require("./utilities/TestFunctions")
const { basicTable } = setup.structures
const { events } = require("@budibase/backend-core")
describe("/tables", () => {
let request = setup.getRequest()
@ -28,9 +29,42 @@ describe("/tables", () => {
.expect(200)
expect(res.res.statusMessage).toEqual("Table TestTable saved successfully.")
expect(res.body.name).toEqual("TestTable")
expect(events.table.created).toBeCalledTimes(1)
expect(events.table.created).toBeCalledWith(res.body)
})
it("renames all the row fields for a table when a schema key is renamed", async () => {
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("update", () => {
it("updates a table", async () => {
const testTable = await config.createTable()
const res = await request
.post(`/api/tables`)
.send(testTable)
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
expect(events.table.updated).toBeCalledTimes(1)
expect(events.table.updated).toBeCalledWith(res.body)
})
it("updates all the row fields for a table when a schema key is renamed", async () => {
const testTable = await config.createTable()
const testRow = await request
@ -73,18 +107,19 @@ describe("/tables", () => {
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"}
}
}
describe("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()
})
})
})
@ -152,22 +187,6 @@ describe("/tables", () => {
})
})
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
@ -204,6 +223,8 @@ describe("/tables", () => {
.expect('Content-Type', /json/)
.expect(200)
expect(res.body.message).toEqual(`Table ${testTable._id} deleted.`)
expect(events.table.deleted).toBeCalledTimes(1)
expect(events.table.deleted).toBeCalledWith(testTable)
})
it("deletes linked references to the table after deletion", async () => {

View File

@ -1,5 +1,9 @@
const setup = require("./utilities")
// need real Date for this test
const tk = require('timekeeper');
tk.reset()
describe("test the delay logic", () => {
it("should be able to run the delay", async () => {
const time = 100

View File

@ -12105,6 +12105,11 @@ timed-out@^4.0.1:
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
timekeeper@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/timekeeper/-/timekeeper-2.2.0.tgz#9645731fce9e3280a18614a57a9d1b72af3ca368"
integrity sha512-W3AmPTJWZkRwu+iSNxPIsLZ2ByADsOLbbLxe46UJyWj3mlYLlwucKiq+/dPm0l9wTzqoF3/2PH0AGFCebjq23A==
timm@^1.6.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/timm/-/timm-1.7.1.tgz#96bab60c7d45b5a10a8a4d0f0117c6b7e5aff76f"

View File

@ -77,6 +77,7 @@
"prettier": "2.3.1",
"rimraf": "^3.0.2",
"supertest": "^6.1.3",
"timekeeper": "^2.2.0",
"ts-jest": "^27.0.3",
"ts-node": "^10.0.0",
"typescript": "4.5.5",

View File

@ -1,4 +1,10 @@
const env = require("../src/environment")
const { mocks } = require("@budibase/backend-core/testUtils")
// mock all dates to 2020-01-01T00:00:00.000Z
// use tk.reset() to use real dates in individual tests
const tk = require("timekeeper")
tk.freeze(mocks.date.MOCK_DATE)
env._set("SELF_HOSTED", "1")
env._set("NODE_ENV", "jest")

File diff suppressed because it is too large Load Diff