diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index 38302ee108..42614b4b3b 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -470,19 +470,12 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -<<<<<<< HEAD -"@budibase/types@2.1.14-alpha.2": - version "2.1.14-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.1.14-alpha.2.tgz#a537796012504e59afe06595f094c5ee2075de9b" - integrity sha512-6lrxQDBozX+yOWXBYN2K2Usg3liWXjmWtZ/F4Pky01dsFdD9M0GdYEUI0+Efhw78wEFaDeA2H9iXvuswKT/I6g== -======= "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: "@jridgewell/trace-mapping" "0.3.9" ->>>>>>> 32163fce702c09aa56597b2467d750d218406fc1 "@hapi/hoek@^9.0.0": version "9.3.0" @@ -1597,7 +1590,6 @@ axios@0.24.0: dependencies: follow-redirects "^1.14.4" -<<<<<<< HEAD axios@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35" @@ -1607,16 +1599,10 @@ axios@^1.1.3: form-data "^4.0.0" proxy-from-env "^1.1.0" -babel-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" - integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== -======= babel-jest@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" integrity sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q== ->>>>>>> 32163fce702c09aa56597b2467d750d218406fc1 dependencies: "@jest/transform" "^28.1.3" "@types/babel__core" "^7.1.14" @@ -5206,7 +5192,6 @@ shimmer@^1.2.0: resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== -<<<<<<< HEAD side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -5216,10 +5201,7 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: -======= signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: ->>>>>>> 32163fce702c09aa56597b2467d750d218406fc1 version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -5688,12 +5670,11 @@ universalify@^0.1.2: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== -<<<<<<< HEAD universalify@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== -======= + update-browserslist-db@^1.0.9: version "1.0.10" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" @@ -5701,7 +5682,6 @@ update-browserslist-db@^1.0.9: dependencies: escalade "^3.1.1" picocolors "^1.0.0" ->>>>>>> 32163fce702c09aa56597b2467d750d218406fc1 update-notifier@^5.1.0: version "5.1.0" diff --git a/packages/server/src/middleware/tests/currentapp.spec.js b/packages/server/src/middleware/tests/currentapp.spec.js index 12f68bedfc..16beb14f83 100644 --- a/packages/server/src/middleware/tests/currentapp.spec.js +++ b/packages/server/src/middleware/tests/currentapp.spec.js @@ -44,7 +44,7 @@ function mockAuthWithNoCookie() { }, cache: { user: { - getUser: () => { + getUser: async id => { return { _id: "us_uuid1", } @@ -78,6 +78,15 @@ function mockAuthWithCookie() { clearCookie: jest.fn(), getCookie: () => ({ appId: "app_different", roleId: "PUBLIC" }), }, + cache: { + user: { + getUser: async id => { + return { + _id: "us_uuid1", + } + }, + }, + }, } }) } @@ -183,6 +192,15 @@ describe("Current app middleware", () => { setCookie: jest.fn(), getCookie: jest.fn(), }, + cache: { + user: { + getUser: async id => { + return { + _id: "us_uuid1", + } + }, + }, + }, } }) await checkExpected(true) @@ -204,6 +222,15 @@ describe("Current app middleware", () => { setCookie: jest.fn(), getCookie: () => ({ appId: "app_test", roleId: "PUBLIC" }), }, + cache: { + user: { + getUser: async id => { + return { + _id: "us_uuid1", + } + }, + }, + }, } }) await checkExpected(false) diff --git a/packages/server/src/utilities/global.js b/packages/server/src/utilities/global.js deleted file mode 100644 index 6d82f79ce2..0000000000 --- a/packages/server/src/utilities/global.js +++ /dev/null @@ -1,127 +0,0 @@ -const { - getMultiIDParams, - getGlobalIDFromUserMetadataID, -} = require("../db/utils") -const { BUILTIN_ROLE_IDS } = require("@budibase/backend-core/roles") -const { getProdAppID } = require("@budibase/backend-core/db") -const { getGlobalUserParams } = require("@budibase/backend-core/db") -const { user: userCache } = require("@budibase/backend-core/cache") -const { - getGlobalDB, - isUserInAppTenant, -} = require("@budibase/backend-core/tenancy") -const env = require("../environment") -const { getAppId } = require("@budibase/backend-core/context") -const { groups } = require("@budibase/pro") - -exports.updateAppRole = (user, { appId } = {}) => { - appId = appId || getAppId() - - if (!user || !user.roles) { - return user - } - // if in an multi-tenancy environment make sure roles are never updated - if (env.MULTI_TENANCY && !isUserInAppTenant(appId, user)) { - delete user.builder - delete user.admin - user.roleId = BUILTIN_ROLE_IDS.PUBLIC - return user - } - // always use the deployed app - user.roleId = user.roles[getProdAppID(appId)] - // if a role wasn't found then either set as admin (builder) or public (everyone else) - if (!user.roleId && user.builder && user.builder.global) { - user.roleId = BUILTIN_ROLE_IDS.ADMIN - } else if (!user.roleId && !user?.userGroups?.length) { - user.roleId = BUILTIN_ROLE_IDS.PUBLIC - } else if (user?.userGroups?.length) { - user.roleId = null - } - - delete user.roles - return user -} - -async function checkGroupRoles(user, { appId } = {}) { - if (user.roleId && user.roleId !== BUILTIN_ROLE_IDS.PUBLIC) { - return user - } - user.roleId = await groups.getGroupRoleId(user, appId) - return user -} - -async function processUser(user, { appId } = {}) { - if (user) { - delete user.password - } - user = await exports.updateAppRole(user, { appId }) - if (!user.roleId && user?.userGroups?.length) { - user = await checkGroupRoles(user, { appId }) - } - - return user -} - -exports.getCachedSelf = async (ctx, appId) => { - // this has to be tenant aware, can't depend on the context to find it out - // running some middlewares before the tenancy causes context to break - const user = await userCache.getUser(ctx.user._id) - return processUser(user, { appId }) -} - -exports.getRawGlobalUser = async userId => { - const db = getGlobalDB() - return db.get(getGlobalIDFromUserMetadataID(userId)) -} - -exports.getGlobalUser = async userId => { - const appId = getAppId() - let user = await exports.getRawGlobalUser(userId) - return processUser(user, { appId }) -} - -exports.getGlobalUsers = async (users = null) => { - const appId = getAppId() - const db = getGlobalDB() - let globalUsers - if (users) { - const globalIds = users.map(user => getGlobalIDFromUserMetadataID(user._id)) - globalUsers = (await db.allDocs(getMultiIDParams(globalIds))).rows.map( - row => row.doc - ) - } else { - globalUsers = ( - await db.allDocs( - getGlobalUserParams(null, { - include_docs: true, - }) - ) - ).rows.map(row => row.doc) - } - globalUsers = globalUsers - .filter(user => user != null) - .map(user => { - delete user.password - delete user.forceResetPassword - return user - }) - if (!appId) { - return globalUsers - } - - return globalUsers.map(user => exports.updateAppRole(user)) -} - -exports.getGlobalUsersFromMetadata = async users => { - const globalUsers = await exports.getGlobalUsers(users) - return users.map(user => { - const globalUser = globalUsers.find( - globalUser => globalUser && user._id.includes(globalUser._id) - ) - return { - ...globalUser, - // doing user second overwrites the id and rev (always metadata) - ...user, - } - }) -} diff --git a/packages/server/src/utilities/global.ts b/packages/server/src/utilities/global.ts new file mode 100644 index 0000000000..f9f6b376ce --- /dev/null +++ b/packages/server/src/utilities/global.ts @@ -0,0 +1,136 @@ +import { getMultiIDParams, getGlobalIDFromUserMetadataID } from "../db/utils" +import { + roles, + db as dbCore, + cache, + tenancy, + context, +} from "@budibase/backend-core" +import env from "../environment" +import { groups } from "@budibase/pro" +import { BBContext, ContextUser, User } from "@budibase/types" + +export function updateAppRole( + user: ContextUser, + { appId }: { appId?: string } = {} +) { + appId = appId || context.getAppId() + + if (!user || !user.roles) { + return user + } + // if in an multi-tenancy environment make sure roles are never updated + if (env.MULTI_TENANCY && appId && !tenancy.isUserInAppTenant(appId, user)) { + delete user.builder + delete user.admin + user.roleId = roles.BUILTIN_ROLE_IDS.PUBLIC + return user + } + // always use the deployed app + if (appId) { + user.roleId = user.roles[dbCore.getProdAppID(appId)] + } + // if a role wasn't found then either set as admin (builder) or public (everyone else) + if (!user.roleId && user.builder && user.builder.global) { + user.roleId = roles.BUILTIN_ROLE_IDS.ADMIN + } else if (!user.roleId && !user?.userGroups?.length) { + user.roleId = roles.BUILTIN_ROLE_IDS.PUBLIC + } else if (user?.userGroups?.length) { + user.roleId = undefined + } + + delete user.roles + return user +} + +async function checkGroupRoles( + user: ContextUser, + { appId }: { appId?: string } = {} +) { + if (user.roleId && user.roleId !== roles.BUILTIN_ROLE_IDS.PUBLIC) { + return user + } + if (appId) { + user.roleId = await groups.getGroupRoleId(user as User, appId) + } + return user +} + +async function processUser( + user: ContextUser, + { appId }: { appId?: string } = {} +) { + if (user) { + delete user.password + } + user = await updateAppRole(user, { appId }) + if (!user.roleId && user?.userGroups?.length) { + user = await checkGroupRoles(user, { appId }) + } + + return user +} + +export async function getCachedSelf(ctx: BBContext, appId: string) { + // this has to be tenant aware, can't depend on the context to find it out + // running some middlewares before the tenancy causes context to break + const user = await cache.user.getUser(ctx.user?._id!) + return processUser(user, { appId }) +} + +export async function getRawGlobalUser(userId: string) { + const db = tenancy.getGlobalDB() + return db.get(getGlobalIDFromUserMetadataID(userId)) +} + +export async function getGlobalUser(userId: string) { + const appId = context.getAppId() + let user = await getRawGlobalUser(userId) + return processUser(user, { appId }) +} + +export async function getGlobalUsers(users?: ContextUser[]) { + const appId = context.getAppId() + const db = tenancy.getGlobalDB() + let globalUsers + if (users) { + const globalIds = users.map(user => getGlobalIDFromUserMetadataID(user._id)) + globalUsers = (await db.allDocs(getMultiIDParams(globalIds))).rows.map( + row => row.doc + ) + } else { + globalUsers = ( + await db.allDocs( + dbCore.getGlobalUserParams(null, { + include_docs: true, + }) + ) + ).rows.map(row => row.doc) + } + globalUsers = globalUsers + .filter(user => user != null) + .map(user => { + delete user.password + delete user.forceResetPassword + return user + }) + if (!appId) { + return globalUsers + } + + return globalUsers.map(user => updateAppRole(user)) +} + +export async function getGlobalUsersFromMetadata(users: ContextUser[]) { + const globalUsers = await getGlobalUsers(users) + return users.map(user => { + const globalUser = globalUsers.find( + globalUser => globalUser && user._id?.includes(globalUser._id) + ) + return { + ...globalUser, + // doing user second overwrites the id and rev (always metadata) + ...user, + } + }) +} diff --git a/packages/types/src/sdk/koa.ts b/packages/types/src/sdk/koa.ts index b8831dcbee..cd171bfe9e 100644 --- a/packages/types/src/sdk/koa.ts +++ b/packages/types/src/sdk/koa.ts @@ -6,7 +6,7 @@ export interface ContextUser extends Omit { globalId?: string license: License userId?: string - roleId?: string + roleId?: string | null role?: Role roles?: UserRoles } diff --git a/qa-core/src/config/internal-api/TestConfiguration/applications.ts b/qa-core/src/config/internal-api/TestConfiguration/applications.ts index cb0558222e..13d0969854 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/applications.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/applications.ts @@ -114,8 +114,6 @@ export default class AppApi { return [response, json] } - - async delete(appId: string): Promise<[Response, any]> { const response = await this.api.del(`/applications/${appId}`) const json = await response.json() @@ -123,7 +121,11 @@ export default class AppApi { return [response, json] } - async update(appId: string, oldName: string, body: any): Promise<[Response, Application]> { + async update( + appId: string, + oldName: string, + body: any + ): Promise<[Response, Application]> { const response = await this.api.put(`/applications/${appId}`, { body }) const json = await response.json() expect(response).toHaveStatusCode(200) @@ -142,7 +144,6 @@ export default class AppApi { const json = await response.json() expect(response).toHaveStatusCode(200) if (screenExists) { - expect(json.routes["/test"]).toBeTruthy() } else { expect(json.routes["/test"]).toBeUndefined() diff --git a/qa-core/src/config/internal-api/TestConfiguration/tables.ts b/qa-core/src/config/internal-api/TestConfiguration/tables.ts index ed0ab78cad..5b7e1648a0 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/tables.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/tables.ts @@ -46,9 +46,7 @@ export default class TablesApi { const response = await this.api.del(`/tables/${id}/${revId}`) const json = await response.json() expect(response).toHaveStatusCode(200) - expect(json.message).toEqual( - `Table ${id} deleted.` - ) + expect(json.message).toEqual(`Table ${id} deleted.`) return [response, json] } } diff --git a/qa-core/src/config/internal-api/fixtures/applications.ts b/qa-core/src/config/internal-api/fixtures/applications.ts index abdd674577..200aa9abff 100644 --- a/qa-core/src/config/internal-api/fixtures/applications.ts +++ b/qa-core/src/config/internal-api/fixtures/applications.ts @@ -1,7 +1,6 @@ import generator from "../../generator" import { Application } from "@budibase/server/api/controllers/public/mapping/types" - const generate = ( overrides: Partial = {} ): Partial => ({ diff --git a/qa-core/src/tests/internal-api/applications/applications.spec.ts b/qa-core/src/tests/internal-api/applications/applications.spec.ts index 4b9b66ec65..4b3208ee10 100644 --- a/qa-core/src/tests/internal-api/applications/applications.spec.ts +++ b/qa-core/src/tests/internal-api/applications/applications.spec.ts @@ -48,7 +48,8 @@ describe("Internal API - Application creation, update, publish and delete", () = }) config.applications.api.appId = app.appId - const [appPackageResponse, appPackageJson] = await config.applications.getAppPackage(app.appId) + const [appPackageResponse, appPackageJson] = + await config.applications.getAppPackage(app.appId) expect(appPackageJson.application.name).toEqual(app.name) expect(appPackageJson.application.version).toEqual(app.version) expect(appPackageJson.application.url).toEqual(app.url) @@ -72,7 +73,6 @@ describe("Internal API - Application creation, update, publish and delete", () = config.applications.api.appId = db.getProdAppID(app.appId) await config.applications.canRender() - // unpublish app await config.applications.unpublish(app.appId) }) @@ -109,22 +109,16 @@ describe("Internal API - Application creation, update, publish and delete", () = config.applications.api.appId = app.appId - await config.applications.update( - app.appId, - app.name, - { - name: generator.word(), - } - ) + await config.applications.update(app.appId, app.name, { + name: generator.word(), + }) }) it("POST - Revert Changes without changes", async () => { const app = await config.applications.create(generateApp()) config.applications.api.appId = app.appId - await config.applications.revertUnpublished( - app.appId - ) + await config.applications.revertUnpublished(app.appId) }) it("POST - Revert Changes", async () => { @@ -134,20 +128,14 @@ describe("Internal API - Application creation, update, publish and delete", () = // publish app await config.applications.publish(app.url) - // Change/add component to the app - await config.screen.create( - generateScreen("BASIC") - ) + await config.screen.create(generateScreen("BASIC")) // // Revert the app to published state - await config.applications.revertPublished( - app.appId - ) + await config.applications.revertPublished(app.appId) // Check screen is removed await config.applications.getRoutes() - }) it("DELETE - Delete an application", async () => { @@ -155,5 +143,4 @@ describe("Internal API - Application creation, update, publish and delete", () = await config.applications.delete(app.appId) }) - }) diff --git a/qa-core/src/tests/internal-api/screens/screens.spec.ts b/qa-core/src/tests/internal-api/screens/screens.spec.ts index 2dc7962914..218d71cb0d 100644 --- a/qa-core/src/tests/internal-api/screens/screens.spec.ts +++ b/qa-core/src/tests/internal-api/screens/screens.spec.ts @@ -38,9 +38,7 @@ describe("Internal API - /screens endpoints", () => { // Create Screen appConfig.applications.api.appId = app.appId - await config.screen.create( - generateScreen("BASIC") - ) + await config.screen.create(generateScreen("BASIC")) // Check screen exists await appConfig.applications.getRoutes(true) @@ -58,6 +56,5 @@ describe("Internal API - /screens endpoints", () => { // Delete Screen await config.screen.delete(screen._id!, screen._rev!) - }) }) diff --git a/qa-core/src/tests/internal-api/tables/tables.spec.ts b/qa-core/src/tests/internal-api/tables/tables.spec.ts index 69ad0fed7b..4f9e4299cf 100644 --- a/qa-core/src/tests/internal-api/tables/tables.spec.ts +++ b/qa-core/src/tests/internal-api/tables/tables.spec.ts @@ -3,93 +3,87 @@ import { Application } from "@budibase/server/api/controllers/public/mapping/typ import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient" import generator from "../../../config/generator" import { - generateTable, - generateNewColumnForTable, + generateTable, + generateNewColumnForTable, } from "../../../config/internal-api/fixtures/table" import { generateNewRowForTable } from "../../../config/internal-api/fixtures/rows" describe("Internal API - Application creation, update, publish and delete", () => { - const api = new InternalAPIClient() - const config = new TestConfiguration(api) + const api = new InternalAPIClient() + const config = new TestConfiguration(api) - beforeAll(async () => { - await config.beforeAll() + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + async function createAppFromTemplate() { + return config.applications.create({ + name: generator.word(), + url: `/${generator.word()}`, + useTemplate: "true", + templateName: "Near Miss Register", + templateKey: "app/near-miss-register", + templateFile: undefined, }) + } - afterAll(async () => { - await config.afterAll() - }) + it("Operations on Tables", async () => { + // create the app + const appName = generator.word() + const app = await createAppFromTemplate() + config.applications.api.appId = app.appId - async function createAppFromTemplate() { - return config.applications.create({ - name: generator.word(), - url: `/${generator.word()}`, - useTemplate: "true", - templateName: "Near Miss Register", - templateKey: "app/near-miss-register", - templateFile: undefined, - }) + // Get current tables: expect 2 in this template + await config.tables.getAll(2) + + // Add new table + const [createdTableResponse, createdTableData] = await config.tables.save( + generateTable() + ) + + //Table was added + await config.tables.getAll(3) + + //Get information about the table + await config.tables.getTableById(createdTableData._id) + + //Add Column to table + const newColumn = generateNewColumnForTable(createdTableData) + const [addColumnResponse, addColumnData] = await config.tables.save( + newColumn, + true + ) + + //Add Row to table + const newRow = generateNewRowForTable(addColumnData._id) + await config.rows.add(addColumnData._id, newRow) + + //Get Row from table + const [getRowResponse, getRowData] = await config.rows.getAll( + addColumnData._id + ) + + //Delete Row from table + const rowToDelete = { + rows: [getRowData[0]], } + const [deleteRowResponse, deleteRowData] = await config.rows.delete( + addColumnData._id, + rowToDelete + ) + expect(deleteRowData[0]._id).toEqual(getRowData[0]._id) - it("Operations on Tables", async () => { - // create the app - const appName = generator.word() - const app = await createAppFromTemplate() - config.applications.api.appId = app.appId + //Delete the table + const [deleteTableResponse, deleteTable] = await config.tables.delete( + addColumnData._id, + addColumnData._rev + ) - // Get current tables: expect 2 in this template - await config.tables.getAll(2) - - // Add new table - const [createdTableResponse, createdTableData] = await config.tables.save( - generateTable() - ) - - //Table was added - await config.tables.getAll(3) - - //Get information about the table - await config.tables.getTableById( - createdTableData._id - ) - - //Add Column to table - const newColumn = generateNewColumnForTable(createdTableData) - const [addColumnResponse, addColumnData] = await config.tables.save( - newColumn, - true - ) - - //Add Row to table - const newRow = generateNewRowForTable(addColumnData._id) - await config.rows.add( - addColumnData._id, - newRow - ) - - //Get Row from table - const [getRowResponse, getRowData] = await config.rows.getAll( - addColumnData._id - ) - - //Delete Row from table - const rowToDelete = { - rows: [getRowData[0]], - } - const [deleteRowResponse, deleteRowData] = await config.rows.delete( - addColumnData._id, - rowToDelete - ) - expect(deleteRowData[0]._id).toEqual(getRowData[0]._id) - - //Delete the table - const [deleteTableResponse, deleteTable] = await config.tables.delete( - addColumnData._id, - addColumnData._rev - ) - - - //Table was deleted - await config.tables.getAll(2) - }) + //Table was deleted + await config.tables.getAll(2) + }) })