Merge pull request #9478 from Budibase/api-tests-generate-tenants

Api Tests generate new tenants and users
This commit is contained in:
Pedro Silva 2023-02-02 17:40:25 +00:00 committed by GitHub
commit b63bc49176
23 changed files with 1117 additions and 806 deletions

View File

@ -17,6 +17,6 @@
] ]
}, },
"[typescript]": { "[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
} }

View File

@ -4,4 +4,7 @@ ENCRYPTED_TEST_PUBLIC_API_KEY=a65722f06bee5caeadc5d7ca2f543a43-d610e627344210c64
COUCH_DB_URL=http://budibase:budibase@localhost:4567 COUCH_DB_URL=http://budibase:budibase@localhost:4567
COUCH_DB_USER=budibase COUCH_DB_USER=budibase
COUCH_DB_PASSWORD=budibase COUCH_DB_PASSWORD=budibase
JWT_SECRET=test JWT_SECRET=test
BUDIBASE_SERVER_URL=http://localhost:4100
BUDIBASE_HOST= budirelease.live
BUDIBASE_ACCOUNTS_URL=https://account.budirelease.live

View File

@ -16,4 +16,4 @@ if (!process.env.DEBUG) {
global.console.log = jest.fn() // console.log are ignored in tests global.console.log = jest.fn() // console.log are ignored in tests
} }
jest.setTimeout(10000) jest.setTimeout(60000)

View File

@ -11,17 +11,22 @@ interface ApiOptions {
class InternalAPIClient { class InternalAPIClient {
host: string host: string
tenantName?: string
appId?: string appId?: string
cookie?: string cookie?: string
constructor(appId?: string) { constructor(appId?: string) {
if (!env.BUDIBASE_SERVER_URL) { if (!env.BUDIBASE_HOST) {
throw new Error("Must set BUDIBASE_SERVER_URL env var") throw new Error("Must set BUDIBASE_SERVER_URL env var")
} }
this.host = `${env.BUDIBASE_SERVER_URL}/api` this.host = `${env.BUDIBASE_HOST}/api`
this.appId = appId this.appId = appId
} }
setTenantName(tenantName: string) {
this.tenantName = tenantName
}
apiCall = apiCall =
(method: APIMethod) => (method: APIMethod) =>
async (url = "", options: ApiOptions = {}) => { async (url = "", options: ApiOptions = {}) => {
@ -33,15 +38,25 @@ class InternalAPIClient {
"Content-Type": "application/json", "Content-Type": "application/json",
Accept: "application/json", Accept: "application/json",
cookie: this.cookie, cookie: this.cookie,
redirect: "follow",
follow: 20,
...options.headers, ...options.headers,
}, },
credentials: "include", credentials: "include",
} }
// prettier-ignore
// @ts-ignore // @ts-ignore
const response = await fetch(`${this.host}${url}`, requestOptions) const response = await fetch(`https://${process.env.TENANT_ID}.${this.host}${url}`, requestOptions)
if (response.status !== 200) {
if (response.status == 404 || response.status == 500) {
console.error("Error in apiCall")
console.error("Response:")
console.error(response) console.error(response)
console.error("Response body:")
console.error(response.body)
console.error("Request body:")
console.error(requestOptions.body)
} }
return response return response
} }

View File

@ -0,0 +1,38 @@
import { Response } from "node-fetch"
import { Account } from "@budibase/types"
import AccountsAPIClient from "./accountsAPIClient"
import { NewAccount } from "../fixtures/types/newAccount"
export default class AccountsApi {
api: AccountsAPIClient
constructor(AccountsAPIClient: AccountsAPIClient) {
this.api = AccountsAPIClient
}
async validateEmail(email: string): Promise<Response> {
const response = await this.api.post(`/accounts/validate/email`, {
body: { email },
})
expect(response).toHaveStatusCode(200)
return response
}
async validateTenantId(tenantId: string): Promise<Response> {
const response = await this.api.post(`/accounts/validate/tenantId`, {
body: { tenantId },
})
expect(response).toHaveStatusCode(200)
return response
}
async create(body: Partial<NewAccount>): Promise<[Response, Account]> {
const headers = {
"no-verify": "1",
}
const response = await this.api.post(`/accounts`, { body, headers })
const json = await response.json()
expect(response).toHaveStatusCode(201)
return [response, json]
}
}

View File

@ -0,0 +1,64 @@
import env from "../../../environment"
import fetch, { HeadersInit } from "node-fetch"
type APIMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE"
interface ApiOptions {
method?: APIMethod
body?: object
headers?: HeadersInit | undefined
}
class AccountsAPIClient {
host: string
appId?: string
cookie?: string
constructor(appId?: string) {
if (!env.BUDIBASE_ACCOUNTS_URL) {
throw new Error("Must set BUDIBASE_SERVER_URL env var")
}
this.host = `${env.BUDIBASE_ACCOUNTS_URL}/api`
this.appId = appId
}
apiCall =
(method: APIMethod) =>
async (url = "", options: ApiOptions = {}) => {
const requestOptions = {
method,
body: JSON.stringify(options.body),
headers: {
"x-budibase-app-id": this.appId,
"Content-Type": "application/json",
Accept: "application/json",
cookie: this.cookie,
redirect: "follow",
follow: 20,
...options.headers,
},
credentials: "include",
}
// @ts-ignore
const response = await fetch(`${this.host}${url}`, requestOptions)
if (response.status == 404 || response.status == 500) {
console.error("Error in apiCall")
console.error("Response:")
console.error(response)
console.error("Response body:")
console.error(response.body)
console.error("Request body:")
console.error(requestOptions.body)
}
return response
}
post = this.apiCall("POST")
get = this.apiCall("GET")
patch = this.apiCall("PATCH")
del = this.apiCall("DELETE")
put = this.apiCall("PUT")
}
export default AccountsAPIClient

View File

@ -110,11 +110,10 @@ export default class AppApi {
return [response, json] return [response, json]
} }
async delete(appId: string): Promise<[Response, any]> { async delete(appId: string): Promise<Response> {
const response = await this.api.del(`/applications/${appId}`) const response = await this.api.del(`/applications/${appId}`)
const json = await response.json() expect(response).toHaveStatusCode(204)
expect(response).toHaveStatusCode(200) return response
return [response, json]
} }
async rename( async rename(

View File

@ -1,10 +1,13 @@
import ApplicationApi from "./applications" import ApplicationApi from "./applications"
import AuthApi from "./auth" import AuthApi from "./auth"
import InternalAPIClient from "./InternalAPIClient" import InternalAPIClient from "./InternalAPIClient"
import AccountsApiClient from "./accountsAPIClient"
import TablesApi from "./tables" import TablesApi from "./tables"
import RowApi from "./rows" import RowApi from "./rows"
import ScreenApi from "./screens" import ScreenApi from "./screens"
import UserManagementApi from "./userManagement" import UserManagementApi from "./userManagement"
import AccountsApi from "./accounts"
import { generateAccount } from "../fixtures/accounts"
export default class TestConfiguration<T> { export default class TestConfiguration<T> {
applications: ApplicationApi applications: ApplicationApi
@ -14,14 +17,24 @@ export default class TestConfiguration<T> {
tables: TablesApi tables: TablesApi
rows: RowApi rows: RowApi
users: UserManagementApi users: UserManagementApi
accounts: AccountsApi
apiClient: InternalAPIClient
accountsApiClient: AccountsApiClient
constructor(apiClient: InternalAPIClient) { constructor(
this.applications = new ApplicationApi(apiClient) apiClient: InternalAPIClient,
this.tables = new TablesApi(apiClient) accountsApiClient: AccountsApiClient
this.rows = new RowApi(apiClient) ) {
this.auth = new AuthApi(apiClient) this.apiClient = apiClient
this.screen = new ScreenApi(apiClient) this.accountsApiClient = accountsApiClient
this.users = new UserManagementApi(apiClient)
this.applications = new ApplicationApi(this.apiClient)
this.tables = new TablesApi(this.apiClient)
this.rows = new RowApi(this.apiClient)
this.auth = new AuthApi(this.apiClient)
this.screen = new ScreenApi(this.apiClient)
this.users = new UserManagementApi(this.apiClient)
this.accounts = new AccountsApi(this.accountsApiClient)
this.context = <T>{} this.context = <T>{}
} }
@ -31,8 +44,31 @@ export default class TestConfiguration<T> {
<string>process.env.BB_ADMIN_USER_PASSWORD <string>process.env.BB_ADMIN_USER_PASSWORD
) )
} }
// TODO: add logic to setup or login based in env variables
async setupAccountAndTenant() {
const account = generateAccount()
await this.accounts.validateEmail(<string>account.email)
await this.accounts.validateTenantId(<string>account.tenantId)
process.env.TENANT_ID = <string>account.tenantId
await this.accounts.create(account)
await this.updateApiClients(<string>account.tenantName)
await this.auth.login(<string>account.email, <string>account.password)
}
async updateApiClients(tenantName: string) {
this.apiClient.setTenantName(tenantName)
this.applications = new ApplicationApi(this.apiClient)
this.tables = new TablesApi(this.apiClient)
this.rows = new RowApi(this.apiClient)
this.auth = new AuthApi(this.apiClient)
this.screen = new ScreenApi(this.apiClient)
this.users = new UserManagementApi(this.apiClient)
this.context = <T>{}
}
async login(email: string, password: string) { async login(email: string, password: string) {
await this.auth.logout()
await this.auth.login(email, password) await this.auth.login(email, password)
} }

View File

@ -0,0 +1,21 @@
import { NewAccount } from "./types/newAccount"
import generator from "../../generator"
import { Hosting } from "@budibase/types"
export const generateAccount = (): Partial<NewAccount> => {
const randomGuid = generator.guid()
let tenant: string = "a" + randomGuid
tenant = tenant.replace(/-/g, "")
return {
email: `qa+${randomGuid}@budibase.com`,
hosting: Hosting.CLOUD,
name: `qa+${randomGuid}@budibase.com`,
password: `${randomGuid}`,
profession: "software_engineer",
size: "10+",
tenantId: `${tenant}`,
tenantName: `${tenant}`,
}
}

View File

@ -0,0 +1,5 @@
import { Account } from "@budibase/types"
export interface NewAccount extends Account {
password: string
}

View File

@ -1,6 +1,9 @@
const env = { const env = {
BUDIBASE_SERVER_URL: process.env.BUDIBASE_SERVER_URL, BUDIBASE_SERVER_URL: process.env.BUDIBASE_SERVER_URL,
BUDIBASE_ACCOUNT_URL: process.env.BUDIBASE_ACCOUNT_URL,
BUDIBASE_PUBLIC_API_KEY: process.env.BUDIBASE_PUBLIC_API_KEY, BUDIBASE_PUBLIC_API_KEY: process.env.BUDIBASE_PUBLIC_API_KEY,
BUDIBASE_ACCOUNTS_URL: process.env.BUDIBASE_ACCOUNTS_URL,
BUDIBASE_HOST: process.env.BUDIBASE_HOST,
_set(key: any, value: any) { _set(key: any, value: any) {
process.env[key] = value process.env[key] = value
module.exports[key] = value module.exports[key] = value

View File

@ -1,147 +0,0 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import { db } from "@budibase/backend-core"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import {
generateApp,
appFromTemplate,
} from "../../../config/internal-api/fixtures/applications"
import generator from "../../../config/generator"
import generateScreen from "../../../config/internal-api/fixtures/screens"
describe("Internal API - Application creation, update, publish and delete", () => {
const api = new InternalAPIClient()
const config = new TestConfiguration<Application>(api)
beforeAll(async () => {
await config.loginAsAdmin()
})
afterAll(async () => {
await config.afterAll()
})
it("Get applications without applications", async () => {
await config.applications.fetchEmptyAppList()
})
it("Get all Applications after creating an application", async () => {
await config.applications.create({
...generateApp(),
useTemplate: false,
})
await config.applications.fetchAllApplications()
})
it("Get application details", async () => {
const app = await config.applications.create({
...generateApp(),
useTemplate: false,
})
config.applications.api.appId = app.appId
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(appPackageJson.application.name).toEqual(app.name)
expect(appPackageJson.application.version).toEqual(app.version)
expect(appPackageJson.application.url).toEqual(app.url)
expect(appPackageJson.application.tenantId).toEqual(app.tenantId)
expect(appPackageJson.application.status).toEqual(app.status)
})
it("Publish app", async () => {
// create the app
const app = await config.applications.create(appFromTemplate())
config.applications.api.appId = app.appId
// check preview renders
await config.applications.canRender()
// publish app
await config.applications.publish(<string>app.appId)
// check published app renders
config.applications.api.appId = db.getProdAppID(app.appId!)
await config.applications.canRender()
// unpublish app
await config.applications.unpublish(<string>app.appId)
})
it("Sync application before deployment", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
const [syncResponse, sync] = await config.applications.sync(
<string>app.appId
)
expect(sync).toEqual({
message: "App sync not required, app not deployed.",
})
})
it("Sync application after deployment", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// publish app
await config.applications.publish(<string>app._id)
const [syncResponse, sync] = await config.applications.sync(
<string>app.appId
)
expect(sync).toEqual({
message: "App sync completed successfully.",
})
})
it("Rename an application", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
await config.applications.rename(<string>app.appId, <string>app.name, {
name: generator.word(),
})
})
it("Update the icon and color of an application", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
await config.applications.updateIcon(<string>app.appId)
})
it("Revert Changes without changes", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
await config.applications.revertUnpublished(<string>app.appId)
})
it("Revert Changes", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// publish app
await config.applications.publish(<string>app._id)
// Change/add component to the app
await config.screen.create(generateScreen("BASIC"))
// // Revert the app to published state
await config.applications.revertPublished(<string>app.appId)
await config.applications.unlock(<string>app.appId)
// Check screen is removed
await config.applications.getRoutes()
})
it("Delete an application", async () => {
const app = await config.applications.create(generateApp())
await config.applications.delete(<string>app.appId)
})
})

View File

@ -0,0 +1,54 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import { db } from "@budibase/backend-core"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
import {
generateApp,
appFromTemplate,
} from "../../../config/internal-api/fixtures/applications"
import generator from "../../../config/generator"
import generateScreen from "../../../config/internal-api/fixtures/screens"
describe("Internal API - Application creation", () => {
const api = new InternalAPIClient()
const accountsAPI = new AccountsAPIClient()
const config = new TestConfiguration<Application>(api, accountsAPI)
beforeAll(async () => {
await config.setupAccountAndTenant()
})
afterAll(async () => {
await config.afterAll()
})
it("Get applications without applications", async () => {
await config.applications.fetchEmptyAppList()
})
it("Get all Applications after creating an application", async () => {
await config.applications.create({
...generateApp(),
useTemplate: false,
})
await config.applications.fetchAllApplications()
})
it("Get application details", async () => {
const app = await config.applications.create({
...generateApp(),
useTemplate: false,
})
config.applications.api.appId = app.appId
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(appPackageJson.application.name).toEqual(app.name)
expect(appPackageJson.application.version).toEqual(app.version)
expect(appPackageJson.application.url).toEqual(app.url)
expect(appPackageJson.application.tenantId).toEqual(app.tenantId)
expect(appPackageJson.application.status).toEqual(app.status)
})
})

View File

@ -0,0 +1,31 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import { db } from "@budibase/backend-core"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
import {
generateApp,
appFromTemplate,
} from "../../../config/internal-api/fixtures/applications"
import generator from "../../../config/generator"
import generateScreen from "../../../config/internal-api/fixtures/screens"
describe("Internal API - Application creation, update, publish and delete", () => {
const api = new InternalAPIClient()
const accountsAPI = new AccountsAPIClient()
const config = new TestConfiguration<Application>(api, accountsAPI)
beforeAll(async () => {
await config.setupAccountAndTenant()
})
afterAll(async () => {
await config.afterAll()
})
it("DELETE - Delete an application", async () => {
const app = await config.applications.create(generateApp())
await config.applications.delete(<string>app.appId)
})
})

View File

@ -0,0 +1,71 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import { db } from "@budibase/backend-core"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
import {
generateApp,
appFromTemplate,
} from "../../../config/internal-api/fixtures/applications"
import generator from "../../../config/generator"
import generateScreen from "../../../config/internal-api/fixtures/screens"
describe("Internal API - Application creation, update, publish and delete", () => {
const api = new InternalAPIClient()
const accountsAPI = new AccountsAPIClient()
const config = new TestConfiguration<Application>(api, accountsAPI)
beforeAll(async () => {
await config.setupAccountAndTenant()
})
afterAll(async () => {
await config.afterAll()
})
it("Publish app", async () => {
// create the app
const app = await config.applications.create(appFromTemplate())
config.applications.api.appId = app.appId
// check preview renders
await config.applications.canRender()
// publish app
await config.applications.publish(<string>app.appId)
// check published app renders
config.applications.api.appId = db.getProdAppID(app.appId!)
await config.applications.canRender()
// unpublish app
await config.applications.unpublish(<string>app.appId)
})
it("Sync application before deployment", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
const [syncResponse, sync] = await config.applications.sync(
<string>app.appId
)
expect(sync).toEqual({
message: "App sync not required, app not deployed.",
})
})
it("Sync application after deployment", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// publish app
await config.applications.publish(<string>app._id)
const [syncResponse, sync] = await config.applications.sync(
<string>app.appId
)
expect(sync).toEqual({
message: "App sync completed successfully.",
})
})
})

View File

@ -0,0 +1,59 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import { db } from "@budibase/backend-core"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
import {
generateApp,
appFromTemplate,
} from "../../../config/internal-api/fixtures/applications"
import generator from "../../../config/generator"
import generateScreen from "../../../config/internal-api/fixtures/screens"
describe("Internal API - Application creation, update, publish and delete", () => {
const api = new InternalAPIClient()
const accountsAPI = new AccountsAPIClient()
const config = new TestConfiguration<Application>(api, accountsAPI)
beforeAll(async () => {
await config.setupAccountAndTenant()
})
afterAll(async () => {
await config.afterAll()
})
it("Update an application", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
await config.applications.rename(<string>app.appId, <string>app.name, {
name: generator.word(),
})
})
it("Revert Changes without changes", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
await config.applications.revertUnpublished(<string>app.appId)
})
it("Revert Changes", async () => {
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// publish app
await config.applications.publish(<string>app._id)
// Change/add component to the app
await config.screen.create(generateScreen("BASIC"))
// // Revert the app to published state
await config.applications.revertPublished(<string>app.appId)
// Check screen is removed
await config.applications.getRoutes()
})
})

View File

@ -1,20 +1,19 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration" import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { App } from "@budibase/types" import { App } from "@budibase/types"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient" import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import { import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
generateApp, import { generateApp } from "../../../config/internal-api/fixtures/applications"
appFromTemplate,
} from "../../../config/internal-api/fixtures/applications"
import { Screen } from "@budibase/types" import { Screen } from "@budibase/types"
import generateScreen from "../../../config/internal-api/fixtures/screens" import generateScreen from "../../../config/internal-api/fixtures/screens"
describe("Internal API - /screens endpoints", () => { describe("Internal API - /screens endpoints", () => {
const api = new InternalAPIClient() const api = new InternalAPIClient()
const config = new TestConfiguration<Screen>(api) const accountsAPI = new AccountsAPIClient()
const appConfig = new TestConfiguration<App>(api) const config = new TestConfiguration<Screen>(api, accountsAPI)
const appConfig = new TestConfiguration<App>(api, accountsAPI)
beforeAll(async () => { beforeAll(async () => {
await config.loginAsAdmin() await config.setupAccountAndTenant()
}) })
afterAll(async () => { afterAll(async () => {

View File

@ -1,6 +1,7 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration" import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types" import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient" import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
import generator from "../../../config/generator" import generator from "../../../config/generator"
import { import {
generateTable, generateTable,
@ -13,10 +14,11 @@ import {
describe("Internal API - Table Operations", () => { describe("Internal API - Table Operations", () => {
const api = new InternalAPIClient() const api = new InternalAPIClient()
const config = new TestConfiguration<Application>(api) const accountsAPI = new AccountsAPIClient()
const config = new TestConfiguration<Application>(api, accountsAPI)
beforeAll(async () => { beforeAll(async () => {
await config.loginAsAdmin() await config.setupAccountAndTenant()
}) })
afterAll(async () => { afterAll(async () => {

View File

@ -1,39 +1,39 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration" import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types" import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient" import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
import { import {
generateApp, generateApp,
appFromTemplate, appFromTemplate,
} from "../../../config/internal-api/fixtures/applications" } from "../../../config/internal-api/fixtures/applications"
import { generateUser } from "../../../config/internal-api/fixtures/userManagement" import { generateUser } from "../../../config/internal-api/fixtures/userManagement"
import { User } from "@budibase/types" import { User } from "@budibase/types"
import {
generateNewColumnForTable,
generateTable,
} from "../../../config/internal-api/fixtures/table"
import generateScreen from "../../../config/internal-api/fixtures/screens"
import { db } from "@budibase/backend-core" import { db } from "@budibase/backend-core"
describe("Internal API - App Specific Roles & Permissions", () => { describe("Internal API - App Specific Roles & Permissions", () => {
const api = new InternalAPIClient() let api: InternalAPIClient
const config = new TestConfiguration<Application>(api) let accountsAPI: AccountsAPIClient
let config: TestConfiguration<Application>
// Before each test, login as admin. Some tests will require login as a different user // Before each test, login as admin. Some tests will require login as a different user
beforeEach(async () => { beforeAll(async () => {
await config.loginAsAdmin() api = new InternalAPIClient()
accountsAPI = new AccountsAPIClient()
config = new TestConfiguration<Application>(api, accountsAPI)
await config.setupAccountAndTenant()
}) })
afterAll(async () => {
await config.afterAll()
})
afterAll(async () => { afterAll(async () => {
await config.afterAll() await config.afterAll()
}) })
it("Add BASIC user to app", async () => { it("Add BASIC user to app", async () => {
// Create a user with BASIC role and check if it was created successfully
const appUser = generateUser() const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false) expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false) expect(appUser[0].admin?.global).toEqual(false)
// Add the user to the tenant.
const [createUserResponse, createUserJson] = await config.users.addMultiple( const [createUserResponse, createUserJson] = await config.users.addMultiple(
appUser appUser
) )
@ -41,12 +41,9 @@ describe("Internal API - App Specific Roles & Permissions", () => {
const app = await config.applications.create(appFromTemplate()) const app = await config.applications.create(appFromTemplate())
config.applications.api.appId = app.appId config.applications.api.appId = app.appId
// Get all the information from the create user
const [userInfoResponse, userInfoJson] = await config.users.getInfo( const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id createUserJson.created.successful[0]._id
) )
// Create the body with the information from the user and add the role to the app
const body: User = { const body: User = {
...userInfoJson, ...userInfoJson,
roles: { roles: {
@ -55,7 +52,6 @@ describe("Internal API - App Specific Roles & Permissions", () => {
} }
await config.users.updateInfo(body) await config.users.updateInfo(body)
// Get the user information again and check if the role was added
const [changedUserInfoResponse, changedUserInfoJson] = const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id) await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined() expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
@ -74,12 +70,9 @@ describe("Internal API - App Specific Roles & Permissions", () => {
const app = await config.applications.create(appFromTemplate()) const app = await config.applications.create(appFromTemplate())
config.applications.api.appId = app.appId config.applications.api.appId = app.appId
// Get all the information from the create user
const [userInfoResponse, userInfoJson] = await config.users.getInfo( const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id createUserJson.created.successful[0]._id
) )
// Create the body with the information from the user and add the role to the app
const body: User = { const body: User = {
...userInfoJson, ...userInfoJson,
roles: { roles: {
@ -88,7 +81,6 @@ describe("Internal API - App Specific Roles & Permissions", () => {
} }
await config.users.updateInfo(body) await config.users.updateInfo(body)
// Get the user information again and check if the role was added
const [changedUserInfoResponse, changedUserInfoJson] = const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id) await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined() expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
@ -102,9 +94,9 @@ describe("Internal API - App Specific Roles & Permissions", () => {
}) })
it("Add POWER user to app", async () => { it("Add POWER user to app", async () => {
// Create a user with POWER role and check if it was created successfully
const powerUser = generateUser(1, "developer") const powerUser = generateUser(1, "developer")
expect(powerUser[0].builder?.global).toEqual(true) expect(powerUser[0].builder?.global).toEqual(true)
const [createUserResponse, createUserJson] = await config.users.addMultiple( const [createUserResponse, createUserJson] = await config.users.addMultiple(
powerUser powerUser
) )
@ -112,12 +104,9 @@ describe("Internal API - App Specific Roles & Permissions", () => {
const app = await config.applications.create(generateApp()) const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId config.applications.api.appId = app.appId
// Get all the information from the create user
const [userInfoResponse, userInfoJson] = await config.users.getInfo( const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id createUserJson.created.successful[0]._id
) )
// Create the body with the information from the user and add the role to the app
const body: User = { const body: User = {
...userInfoJson, ...userInfoJson,
roles: { roles: {
@ -132,609 +121,4 @@ describe("Internal API - App Specific Roles & Permissions", () => {
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined() expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("POWER") expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("POWER")
}) })
describe("Check Access for default roles", () => {
it("Check Table access for app user", async () => {
// Create a user with BASIC role and check if it was created successfully
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(appUser)
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Get all the information from the create user
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
// Create the body with the information from the user and add the role to the app
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "BASIC",
},
}
await config.users.updateInfo(body)
// Get the user information again and check if the role was added
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("BASIC")
// Create a table
const [createdTableResponse, createdTableData] = await config.tables.save(
generateTable()
)
// Login with the user created and try to create a column
await config.login(<string>appUser[0].email, <string>appUser[0].password)
const newColumn = generateNewColumnForTable(createdTableData)
await config.tables.forbiddenSave(newColumn)
await config.tables.forbiddenSave(generateTable())
})
it("Check Table access for developer", async () => {
// Create a user with POWER role and check if it was created successfully
const developer = generateUser(1, "developer")
expect(developer[0].builder?.global).toEqual(true)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(developer)
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Get all the information from the create user
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
// Create the body with the information from the user and add the role to the app
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "POWER",
},
}
await config.users.updateInfo(body)
// Get the user information again and check if the role was added
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("POWER")
// Create a table
const [createdTableResponse, createdTableData] = await config.tables.save(
generateTable()
)
// Login with the user created and try to create a column
await config.login(
<string>developer[0].email,
<string>developer[0].password
)
const newColumn = generateNewColumnForTable(createdTableData)
const [addColumnResponse, addColumnData] = await config.tables.save(
newColumn,
true
)
})
it("Check Table access for admin", async () => {
// Create a user with ADMIN role and check if it was created successfully
const adminUser = generateUser(1, "admin")
expect(adminUser[0].builder?.global).toEqual(true)
expect(adminUser[0].admin?.global).toEqual(true)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(adminUser)
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Get all the information from the create user
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
// Create the body with the information from the user and add the role to the app
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "ADMIN",
},
}
await config.users.updateInfo(body)
// Get the user information again and check if the role was added
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("ADMIN")
// Login with the created user and create a table
await config.login(
<string>adminUser[0].email,
<string>adminUser[0].password
)
const [createdTableResponse, createdTableData] = await config.tables.save(
generateTable()
)
const newColumn = generateNewColumnForTable(createdTableData)
const [addColumnResponse, addColumnData] = await config.tables.save(
newColumn,
true
)
})
})
describe("Screen Access for App specific roles", () => {
it("Check Screen access for BASIC Role", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: "BASIC",
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual("BASIC")
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with BASIC user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
expect(appPackageJson.screens[0].routing.roleId).toEqual("BASIC")
})
it("Check Screen access for POWER role", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: "POWER",
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual("POWER")
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with POWER user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(2)
})
it("Check Screen access for ADMIN role", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: "ADMIN",
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual("ADMIN")
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with ADMIN user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(3)
})
})
describe("Screen Access for custom roles", () => {
it("Custom role access for level 1 permissions", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "public",
name: "level 1",
}
const [createRoleResponse, createRoleJson] =
await config.users.createRole(role)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 2 permissions", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "read_only",
name: "level 2",
}
const [createRoleResponse, createRoleJson] =
await config.users.createRole(role)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 3 permissions", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "write",
name: "level 3",
}
const [createRoleResponse, createRoleJson] =
await config.users.createRole(role)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 4 permissions", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "power",
name: "level 4",
}
const [createRoleResponse, createRoleJson] =
await config.users.createRole(role)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 5 permissions", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] =
await config.users.addMultiple(appUser)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "admin",
name: "level 5",
}
const [createRoleResponse, createRoleJson] =
await config.users.createRole(role)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
})
}) })

View File

@ -0,0 +1,332 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
import { generateApp } from "../../../config/internal-api/fixtures/applications"
import { generateUser } from "../../../config/internal-api/fixtures/userManagement"
import { App, User } from "@budibase/types"
import generateScreen from "../../../config/internal-api/fixtures/screens"
import { db } from "@budibase/backend-core"
describe.skip("Internal API - App Specific Roles & Permissions", () => {
let api: InternalAPIClient
let accountsAPI: AccountsAPIClient
let config: TestConfiguration<Application>
let app: Partial<App>
// Before each test, login as admin. Some tests will require login as a different user
beforeEach(async () => {
api = new InternalAPIClient()
accountsAPI = new AccountsAPIClient()
config = new TestConfiguration<Application>(api, accountsAPI)
await config.setupAccountAndTenant()
app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
})
afterAll(async () => {
await config.afterAll()
})
it("Custom role access for level 1 permissions", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
appUser
)
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "public",
name: "level 1",
}
const [createRoleResponse, createRoleJson] = await config.users.createRole(
role
)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 2 permissions", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
appUser
)
// Create App
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "read_only",
name: "level 2",
}
const [createRoleResponse, createRoleJson] = await config.users.createRole(
role
)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 3 permissions", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
appUser
)
// Create App
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "write",
name: "level 3",
}
const [createRoleResponse, createRoleJson] = await config.users.createRole(
role
)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 4 permissions", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
appUser
)
// Create App
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "power",
name: "level 4",
}
const [createRoleResponse, createRoleJson] = await config.users.createRole(
role
)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
it("Custom role access for level 5 permissions", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
appUser
)
// Create App
//Create level 1 role
const role = {
inherits: "BASIC",
permissionId: "admin",
name: "level 5",
}
const [createRoleResponse, createRoleJson] = await config.users.createRole(
role
)
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: createRoleJson._id,
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id)
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with level 1 user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
})
})

View File

@ -0,0 +1,191 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
import { generateApp } from "../../../config/internal-api/fixtures/applications"
import { generateUser } from "../../../config/internal-api/fixtures/userManagement"
import { User } from "@budibase/types"
import generateScreen from "../../../config/internal-api/fixtures/screens"
import { db } from "@budibase/backend-core"
describe.skip("Internal API - Role screen access", () => {
let api: InternalAPIClient
let accountsAPI: AccountsAPIClient
let config: TestConfiguration<Application>
// Before each test, login as admin. Some tests will require login as a different user
beforeEach(async () => {
api = new InternalAPIClient()
accountsAPI = new AccountsAPIClient()
config = new TestConfiguration<Application>(api, accountsAPI)
await config.setupAccountAndTenant()
})
afterAll(async () => {
await config.afterAll()
})
it("Check Screen access for BASIC Role", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
appUser
)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: "BASIC",
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual("BASIC")
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with BASIC user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(1)
expect(appPackageJson.screens[0].routing.roleId).toEqual("BASIC")
})
it("Check Screen access for POWER role", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
appUser
)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: "POWER",
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual("POWER")
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with POWER user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(2)
})
it("Check Screen access for ADMIN role", async () => {
// Set up user
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
appUser
)
// Create App
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
// Update user roles
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const prodAppId = db.getProdAppID(app.appId!)
// Roles must always be set with prod appID
const body: User = {
...userInfoJson,
roles: {
[prodAppId]: "ADMIN",
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[prodAppId]).toBeDefined()
expect(changedUserInfoJson.roles[prodAppId]).toEqual("ADMIN")
await config.screen.create(generateScreen("BASIC"))
await config.screen.create(generateScreen("POWER"))
await config.screen.create(generateScreen("ADMIN"))
await config.applications.publish(<string>app.appId)
const [firstappPackageResponse, firstappPackageJson] =
await config.applications.getAppPackage(<string>app.appId)
expect(firstappPackageJson.screens).toBeDefined()
expect(firstappPackageJson.screens.length).toEqual(3)
// login with ADMIN user
await config.login(appUser[0].email!, appUser[0].password!)
const [selfInfoResponse, selfInfoJson] = await config.users.getSelf()
// fetch app package
const [appPackageResponse, appPackageJson] =
await config.applications.getAppPackage(app.appId!)
expect(appPackageJson.screens).toBeDefined()
expect(appPackageJson.screens.length).toEqual(3)
})
})

View File

@ -0,0 +1,149 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
import { generateApp } from "../../../config/internal-api/fixtures/applications"
import { generateUser } from "../../../config/internal-api/fixtures/userManagement"
import { User } from "@budibase/types"
import {
generateNewColumnForTable,
generateTable,
} from "../../../config/internal-api/fixtures/table"
describe.skip("Internal API - Role table access", () => {
let api: InternalAPIClient
let accountsAPI: AccountsAPIClient
let config: TestConfiguration<Application>
// Before each test, login as admin. Some tests will require login as a different user
beforeEach(async () => {
api = new InternalAPIClient()
accountsAPI = new AccountsAPIClient()
config = new TestConfiguration<Application>(api, accountsAPI)
await config.setupAccountAndTenant()
})
afterAll(async () => {
await config.afterAll()
})
it("Check Table access for app user", async () => {
const appUser = generateUser()
expect(appUser[0].builder?.global).toEqual(false)
expect(appUser[0].admin?.global).toEqual(false)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
appUser
)
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "BASIC",
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("BASIC")
const [createdTableResponse, createdTableData] = await config.tables.save(
generateTable()
)
await config.login(<string>appUser[0].email, <string>appUser[0].password)
const newColumn = generateNewColumnForTable(createdTableData)
await config.tables.forbiddenSave(newColumn)
await config.tables.forbiddenSave(generateTable())
})
it.skip("Check Table access for developer", async () => {
const developer = generateUser(1, "developer")
expect(developer[0].builder?.global).toEqual(true)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
developer
)
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "POWER",
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("POWER")
const [createdTableResponse, createdTableData] = await config.tables.save(
generateTable()
)
await config.login(
<string>developer[0].email,
<string>developer[0].password
)
const newColumn = generateNewColumnForTable(createdTableData)
const [addColumnResponse, addColumnData] = await config.tables.save(
newColumn,
true
)
})
it.skip("Check Table access for admin", async () => {
const adminUser = generateUser(1, "admin")
expect(adminUser[0].builder?.global).toEqual(true)
expect(adminUser[0].admin?.global).toEqual(true)
const [createUserResponse, createUserJson] = await config.users.addMultiple(
adminUser
)
const app = await config.applications.create(generateApp())
config.applications.api.appId = app.appId
const [userInfoResponse, userInfoJson] = await config.users.getInfo(
createUserJson.created.successful[0]._id
)
const body: User = {
...userInfoJson,
roles: {
[<string>app.appId]: "ADMIN",
},
}
await config.users.updateInfo(body)
const [changedUserInfoResponse, changedUserInfoJson] =
await config.users.getInfo(createUserJson.created.successful[0]._id)
expect(changedUserInfoJson.roles[<string>app.appId]).toBeDefined()
expect(changedUserInfoJson.roles[<string>app.appId]).toEqual("ADMIN")
await config.login(
<string>adminUser[0].email,
<string>adminUser[0].password
)
const [createdTableResponse, createdTableData] = await config.tables.save(
generateTable()
)
const newColumn = generateNewColumnForTable(createdTableData)
const [addColumnResponse, addColumnData] = await config.tables.save(
newColumn,
true
)
})
})

View File

@ -1,16 +1,18 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration" import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types" import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient" import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import AccountsAPIClient from "../../../config/internal-api/TestConfiguration/accountsAPIClient"
import { generateUser } from "../../../config/internal-api/fixtures/userManagement" import { generateUser } from "../../../config/internal-api/fixtures/userManagement"
import { User } from "@budibase/types" import { User } from "@budibase/types"
describe("Internal API - User Management & Permissions", () => { describe("Internal API - User Management & Permissions", () => {
const api = new InternalAPIClient() const api = new InternalAPIClient()
const config = new TestConfiguration<Application>(api) const accountsAPI = new AccountsAPIClient()
const config = new TestConfiguration<Application>(api, accountsAPI)
// Before each test, login as admin. Some tests will require login as a different user // Before each test, login as admin. Some tests will require login as a different user
beforeEach(async () => { beforeAll(async () => {
await config.loginAsAdmin() await config.setupAccountAndTenant()
}) })
afterAll(async () => { afterAll(async () => {