Merge pull request #13157 from Budibase/test-api-unification
Unifying how we send requests to the server in packages/server tests.
This commit is contained in:
commit
7bbda49c69
|
@ -1,5 +1,6 @@
|
||||||
import { APIError } from "@budibase/types"
|
import { APIError } from "@budibase/types"
|
||||||
import * as errors from "../errors"
|
import * as errors from "../errors"
|
||||||
|
import environment from "../environment"
|
||||||
|
|
||||||
export async function errorHandling(ctx: any, next: any) {
|
export async function errorHandling(ctx: any, next: any) {
|
||||||
try {
|
try {
|
||||||
|
@ -14,15 +15,19 @@ export async function errorHandling(ctx: any, next: any) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
const error = errors.getPublicError(err)
|
let error: APIError = {
|
||||||
const body: APIError = {
|
|
||||||
message: err.message,
|
message: err.message,
|
||||||
status: status,
|
status: status,
|
||||||
validationErrors: err.validation,
|
validationErrors: err.validation,
|
||||||
error,
|
error: errors.getPublicError(err),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = body
|
if (environment.isTest() && ctx.headers["x-budibase-include-stacktrace"]) {
|
||||||
|
// @ts-ignore
|
||||||
|
error.stack = err.stack
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ import {
|
||||||
GetResourcePermsResponse,
|
GetResourcePermsResponse,
|
||||||
ResourcePermissionInfo,
|
ResourcePermissionInfo,
|
||||||
GetDependantResourcesResponse,
|
GetDependantResourcesResponse,
|
||||||
|
AddPermissionResponse,
|
||||||
|
AddPermissionRequest,
|
||||||
|
RemovePermissionRequest,
|
||||||
|
RemovePermissionResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { getRoleParams } from "../../db/utils"
|
import { getRoleParams } from "../../db/utils"
|
||||||
import {
|
import {
|
||||||
|
@ -16,9 +20,9 @@ import {
|
||||||
import { removeFromArray } from "../../utilities"
|
import { removeFromArray } from "../../utilities"
|
||||||
import sdk from "../../sdk"
|
import sdk from "../../sdk"
|
||||||
|
|
||||||
const PermissionUpdateType = {
|
const enum PermissionUpdateType {
|
||||||
REMOVE: "remove",
|
REMOVE = "remove",
|
||||||
ADD: "add",
|
ADD = "add",
|
||||||
}
|
}
|
||||||
|
|
||||||
const SUPPORTED_LEVELS = CURRENTLY_SUPPORTED_LEVELS
|
const SUPPORTED_LEVELS = CURRENTLY_SUPPORTED_LEVELS
|
||||||
|
@ -39,7 +43,7 @@ async function updatePermissionOnRole(
|
||||||
resourceId,
|
resourceId,
|
||||||
level,
|
level,
|
||||||
}: { roleId: string; resourceId: string; level: PermissionLevel },
|
}: { roleId: string; resourceId: string; level: PermissionLevel },
|
||||||
updateType: string
|
updateType: PermissionUpdateType
|
||||||
) {
|
) {
|
||||||
const allowedAction = await sdk.permissions.resourceActionAllowed({
|
const allowedAction = await sdk.permissions.resourceActionAllowed({
|
||||||
resourceId,
|
resourceId,
|
||||||
|
@ -107,11 +111,15 @@ async function updatePermissionOnRole(
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await db.bulkDocs(docUpdates)
|
const response = await db.bulkDocs(docUpdates)
|
||||||
return response.map((resp: any) => {
|
return response.map(resp => {
|
||||||
const version = docUpdates.find(role => role._id === resp.id)?.version
|
const version = docUpdates.find(role => role._id === resp.id)?.version
|
||||||
resp._id = roles.getExternalRoleID(resp.id, version)
|
const _id = roles.getExternalRoleID(resp.id, version)
|
||||||
delete resp.id
|
return {
|
||||||
return resp
|
_id,
|
||||||
|
rev: resp.rev,
|
||||||
|
error: resp.error,
|
||||||
|
reason: resp.reason,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,13 +197,14 @@ export async function getDependantResources(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addPermission(ctx: UserCtx) {
|
export async function addPermission(ctx: UserCtx<void, AddPermissionResponse>) {
|
||||||
ctx.body = await updatePermissionOnRole(ctx.params, PermissionUpdateType.ADD)
|
const params: AddPermissionRequest = ctx.params
|
||||||
|
ctx.body = await updatePermissionOnRole(params, PermissionUpdateType.ADD)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removePermission(ctx: UserCtx) {
|
export async function removePermission(
|
||||||
ctx.body = await updatePermissionOnRole(
|
ctx: UserCtx<void, RemovePermissionResponse>
|
||||||
ctx.params,
|
) {
|
||||||
PermissionUpdateType.REMOVE
|
const params: RemovePermissionRequest = ctx.params
|
||||||
)
|
ctx.body = await updatePermissionOnRole(params, PermissionUpdateType.REMOVE)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,12 @@ import {
|
||||||
QueryPreview,
|
QueryPreview,
|
||||||
QuerySchema,
|
QuerySchema,
|
||||||
FieldType,
|
FieldType,
|
||||||
type ExecuteQueryRequest,
|
ExecuteQueryRequest,
|
||||||
type ExecuteQueryResponse,
|
ExecuteQueryResponse,
|
||||||
type Row,
|
Row,
|
||||||
QueryParameter,
|
QueryParameter,
|
||||||
|
PreviewQueryRequest,
|
||||||
|
PreviewQueryResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { ValidQueryNameRegex, utils as JsonUtils } from "@budibase/shared-core"
|
import { ValidQueryNameRegex, utils as JsonUtils } from "@budibase/shared-core"
|
||||||
|
|
||||||
|
@ -134,14 +136,16 @@ function enrichParameters(
|
||||||
return requestParameters
|
return requestParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function preview(ctx: UserCtx) {
|
export async function preview(
|
||||||
|
ctx: UserCtx<PreviewQueryRequest, PreviewQueryResponse>
|
||||||
|
) {
|
||||||
const { datasource, envVars } = await sdk.datasources.getWithEnvVars(
|
const { datasource, envVars } = await sdk.datasources.getWithEnvVars(
|
||||||
ctx.request.body.datasourceId
|
ctx.request.body.datasourceId
|
||||||
)
|
)
|
||||||
const query: QueryPreview = ctx.request.body
|
|
||||||
// preview may not have a queryId as it hasn't been saved, but if it does
|
// preview may not have a queryId as it hasn't been saved, but if it does
|
||||||
// this stops dynamic variables from calling the same query
|
// this stops dynamic variables from calling the same query
|
||||||
const { fields, parameters, queryVerb, transformer, queryId, schema } = query
|
const { fields, parameters, queryVerb, transformer, queryId, schema } =
|
||||||
|
ctx.request.body
|
||||||
|
|
||||||
let existingSchema = schema
|
let existingSchema = schema
|
||||||
if (queryId && !existingSchema) {
|
if (queryId && !existingSchema) {
|
||||||
|
@ -266,9 +270,7 @@ export async function preview(ctx: UserCtx) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const { rows, keys, info, extra } = (await Runner.run(
|
const { rows, keys, info, extra } = await Runner.run<QueryResponse>(inputs)
|
||||||
inputs
|
|
||||||
)) as QueryResponse
|
|
||||||
const { previewSchema, nestedSchemaFields } = getSchemaFields(rows, keys)
|
const { previewSchema, nestedSchemaFields } = getSchemaFields(rows, keys)
|
||||||
|
|
||||||
// if existing schema, update to include any previous schema keys
|
// if existing schema, update to include any previous schema keys
|
||||||
|
@ -281,7 +283,7 @@ export async function preview(ctx: UserCtx) {
|
||||||
}
|
}
|
||||||
// remove configuration before sending event
|
// remove configuration before sending event
|
||||||
delete datasource.config
|
delete datasource.config
|
||||||
await events.query.previewed(datasource, query)
|
await events.query.previewed(datasource, ctx.request.body)
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
rows,
|
rows,
|
||||||
nestedSchemaFields,
|
nestedSchemaFields,
|
||||||
|
@ -295,7 +297,10 @@ export async function preview(ctx: UserCtx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function execute(
|
async function execute(
|
||||||
ctx: UserCtx<ExecuteQueryRequest, ExecuteQueryResponse | Row[]>,
|
ctx: UserCtx<
|
||||||
|
ExecuteQueryRequest,
|
||||||
|
ExecuteQueryResponse | Record<string, any>[]
|
||||||
|
>,
|
||||||
opts: any = { rowsOnly: false, isAutomation: false }
|
opts: any = { rowsOnly: false, isAutomation: false }
|
||||||
) {
|
) {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
|
@ -350,18 +355,23 @@ async function execute(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function executeV1(ctx: UserCtx) {
|
export async function executeV1(
|
||||||
|
ctx: UserCtx<ExecuteQueryRequest, Record<string, any>[]>
|
||||||
|
) {
|
||||||
return execute(ctx, { rowsOnly: true, isAutomation: false })
|
return execute(ctx, { rowsOnly: true, isAutomation: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function executeV2(
|
export async function executeV2(
|
||||||
ctx: UserCtx,
|
ctx: UserCtx<
|
||||||
|
ExecuteQueryRequest,
|
||||||
|
ExecuteQueryResponse | Record<string, any>[]
|
||||||
|
>,
|
||||||
{ isAutomation }: { isAutomation?: boolean } = {}
|
{ isAutomation }: { isAutomation?: boolean } = {}
|
||||||
) {
|
) {
|
||||||
return execute(ctx, { rowsOnly: false, isAutomation })
|
return execute(ctx, { rowsOnly: false, isAutomation })
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeDynamicVariables = async (queryId: any) => {
|
const removeDynamicVariables = async (queryId: string) => {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
const query = await db.get<Query>(queryId)
|
const query = await db.get<Query>(queryId)
|
||||||
const datasource = await sdk.datasources.get(query.datasourceId)
|
const datasource = await sdk.datasources.get(query.datasourceId)
|
||||||
|
@ -384,7 +394,7 @@ const removeDynamicVariables = async (queryId: any) => {
|
||||||
|
|
||||||
export async function destroy(ctx: UserCtx) {
|
export async function destroy(ctx: UserCtx) {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
const queryId = ctx.params.queryId
|
const queryId = ctx.params.queryId as string
|
||||||
await removeDynamicVariables(queryId)
|
await removeDynamicVariables(queryId)
|
||||||
const query = await db.get<Query>(queryId)
|
const query = await db.get<Query>(queryId)
|
||||||
const datasource = await sdk.datasources.get(query.datasourceId)
|
const datasource = await sdk.datasources.get(query.datasourceId)
|
||||||
|
|
|
@ -211,7 +211,7 @@ export async function validate(ctx: Ctx<Row, ValidateResponse>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchEnrichedRow(ctx: any) {
|
export async function fetchEnrichedRow(ctx: UserCtx<void, Row>) {
|
||||||
const tableId = utils.getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
ctx.body = await pickApi(tableId).fetchEnrichedRow(ctx)
|
ctx.body = await pickApi(tableId).fetchEnrichedRow(ctx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,7 @@ describe("/applications", () => {
|
||||||
it("app should not sync if production", async () => {
|
it("app should not sync if production", async () => {
|
||||||
const { message } = await config.api.application.sync(
|
const { message } = await config.api.application.sync(
|
||||||
app.appId.replace("_dev", ""),
|
app.appId.replace("_dev", ""),
|
||||||
{ statusCode: 400 }
|
{ status: 400 }
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(message).toEqual(
|
expect(message).toEqual(
|
||||||
|
|
|
@ -29,7 +29,7 @@ describe("/api/applications/:appId/sync", () => {
|
||||||
let resp = (await config.api.attachment.process(
|
let resp = (await config.api.attachment.process(
|
||||||
"ohno.exe",
|
"ohno.exe",
|
||||||
Buffer.from([0]),
|
Buffer.from([0]),
|
||||||
{ expectStatus: 400 }
|
{ status: 400 }
|
||||||
)) as unknown as APIError
|
)) as unknown as APIError
|
||||||
expect(resp.message).toContain("invalid extension")
|
expect(resp.message).toContain("invalid extension")
|
||||||
})
|
})
|
||||||
|
@ -40,7 +40,7 @@ describe("/api/applications/:appId/sync", () => {
|
||||||
let resp = (await config.api.attachment.process(
|
let resp = (await config.api.attachment.process(
|
||||||
"OHNO.EXE",
|
"OHNO.EXE",
|
||||||
Buffer.from([0]),
|
Buffer.from([0]),
|
||||||
{ expectStatus: 400 }
|
{ status: 400 }
|
||||||
)) as unknown as APIError
|
)) as unknown as APIError
|
||||||
expect(resp.message).toContain("invalid extension")
|
expect(resp.message).toContain("invalid extension")
|
||||||
})
|
})
|
||||||
|
@ -51,7 +51,7 @@ describe("/api/applications/:appId/sync", () => {
|
||||||
undefined as any,
|
undefined as any,
|
||||||
undefined as any,
|
undefined as any,
|
||||||
{
|
{
|
||||||
expectStatus: 400,
|
status: 400,
|
||||||
}
|
}
|
||||||
)) as unknown as APIError
|
)) as unknown as APIError
|
||||||
expect(resp.message).toContain("No file provided")
|
expect(resp.message).toContain("No file provided")
|
||||||
|
|
|
@ -19,11 +19,8 @@ describe("/backups", () => {
|
||||||
|
|
||||||
describe("/api/backups/export", () => {
|
describe("/api/backups/export", () => {
|
||||||
it("should be able to export app", async () => {
|
it("should be able to export app", async () => {
|
||||||
const { body, headers } = await config.api.backup.exportBasicBackup(
|
const body = await config.api.backup.exportBasicBackup(config.getAppId()!)
|
||||||
config.getAppId()!
|
|
||||||
)
|
|
||||||
expect(body instanceof Buffer).toBe(true)
|
expect(body instanceof Buffer).toBe(true)
|
||||||
expect(headers["content-type"]).toEqual("application/gzip")
|
|
||||||
expect(events.app.exported).toBeCalledTimes(1)
|
expect(events.app.exported).toBeCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -38,15 +35,13 @@ describe("/backups", () => {
|
||||||
it("should infer the app name from the app", async () => {
|
it("should infer the app name from the app", async () => {
|
||||||
tk.freeze(mocks.date.MOCK_DATE)
|
tk.freeze(mocks.date.MOCK_DATE)
|
||||||
|
|
||||||
const { headers } = await config.api.backup.exportBasicBackup(
|
await config.api.backup.exportBasicBackup(config.getAppId()!, {
|
||||||
config.getAppId()!
|
headers: {
|
||||||
)
|
"content-disposition": `attachment; filename="${
|
||||||
|
config.getApp().name
|
||||||
expect(headers["content-disposition"]).toEqual(
|
}-export-${mocks.date.MOCK_DATE.getTime()}.tar.gz"`,
|
||||||
`attachment; filename="${
|
},
|
||||||
config.getApp().name
|
})
|
||||||
}-export-${mocks.date.MOCK_DATE.getTime()}.tar.gz"`
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ describe("/permission", () => {
|
||||||
table = (await config.createTable()) as typeof table
|
table = (await config.createTable()) as typeof table
|
||||||
row = await config.createRow()
|
row = await config.createRow()
|
||||||
view = await config.api.viewV2.create({ tableId: table._id })
|
view = await config.api.viewV2.create({ tableId: table._id })
|
||||||
perms = await config.api.permission.set({
|
perms = await config.api.permission.add({
|
||||||
roleId: STD_ROLE_ID,
|
roleId: STD_ROLE_ID,
|
||||||
resourceId: table._id,
|
resourceId: table._id,
|
||||||
level: PermissionLevel.READ,
|
level: PermissionLevel.READ,
|
||||||
|
@ -88,13 +88,13 @@ describe("/permission", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should get resource permissions with multiple roles", async () => {
|
it("should get resource permissions with multiple roles", async () => {
|
||||||
perms = await config.api.permission.set({
|
perms = await config.api.permission.add({
|
||||||
roleId: HIGHER_ROLE_ID,
|
roleId: HIGHER_ROLE_ID,
|
||||||
resourceId: table._id,
|
resourceId: table._id,
|
||||||
level: PermissionLevel.WRITE,
|
level: PermissionLevel.WRITE,
|
||||||
})
|
})
|
||||||
const res = await config.api.permission.get(table._id)
|
const res = await config.api.permission.get(table._id)
|
||||||
expect(res.body).toEqual({
|
expect(res).toEqual({
|
||||||
permissions: {
|
permissions: {
|
||||||
read: { permissionType: "EXPLICIT", role: STD_ROLE_ID },
|
read: { permissionType: "EXPLICIT", role: STD_ROLE_ID },
|
||||||
write: { permissionType: "EXPLICIT", role: HIGHER_ROLE_ID },
|
write: { permissionType: "EXPLICIT", role: HIGHER_ROLE_ID },
|
||||||
|
@ -117,16 +117,19 @@ describe("/permission", () => {
|
||||||
level: PermissionLevel.READ,
|
level: PermissionLevel.READ,
|
||||||
})
|
})
|
||||||
|
|
||||||
const response = await config.api.permission.set(
|
await config.api.permission.add(
|
||||||
{
|
{
|
||||||
roleId: STD_ROLE_ID,
|
roleId: STD_ROLE_ID,
|
||||||
resourceId: table._id,
|
resourceId: table._id,
|
||||||
level: PermissionLevel.EXECUTE,
|
level: PermissionLevel.EXECUTE,
|
||||||
},
|
},
|
||||||
{ expectStatus: 403 }
|
{
|
||||||
)
|
status: 403,
|
||||||
expect(response.message).toEqual(
|
body: {
|
||||||
"You are not allowed to 'read' the resource type 'datasource'"
|
message:
|
||||||
|
"You are not allowed to 'read' the resource type 'datasource'",
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -138,9 +141,9 @@ describe("/permission", () => {
|
||||||
resourceId: table._id,
|
resourceId: table._id,
|
||||||
level: PermissionLevel.READ,
|
level: PermissionLevel.READ,
|
||||||
})
|
})
|
||||||
expect(res.body[0]._id).toEqual(STD_ROLE_ID)
|
expect(res[0]._id).toEqual(STD_ROLE_ID)
|
||||||
const permsRes = await config.api.permission.get(table._id)
|
const permsRes = await config.api.permission.get(table._id)
|
||||||
expect(permsRes.body[STD_ROLE_ID]).toBeUndefined()
|
expect(permsRes.permissions[STD_ROLE_ID]).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("throw forbidden if the action is not allowed for the resource", async () => {
|
it("throw forbidden if the action is not allowed for the resource", async () => {
|
||||||
|
@ -156,10 +159,13 @@ describe("/permission", () => {
|
||||||
resourceId: table._id,
|
resourceId: table._id,
|
||||||
level: PermissionLevel.EXECUTE,
|
level: PermissionLevel.EXECUTE,
|
||||||
},
|
},
|
||||||
{ expectStatus: 403 }
|
{
|
||||||
)
|
status: 403,
|
||||||
expect(response.body.message).toEqual(
|
body: {
|
||||||
"You are not allowed to 'read' the resource type 'datasource'"
|
message:
|
||||||
|
"You are not allowed to 'read' the resource type 'datasource'",
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -181,10 +187,8 @@ describe("/permission", () => {
|
||||||
// replicate changes before checking permissions
|
// replicate changes before checking permissions
|
||||||
await config.publish()
|
await config.publish()
|
||||||
|
|
||||||
const res = await config.api.viewV2.search(view.id, undefined, {
|
const res = await config.api.viewV2.publicSearch(view.id)
|
||||||
usePublicUser: true,
|
expect(res.rows[0]._id).toEqual(row._id)
|
||||||
})
|
|
||||||
expect(res.body.rows[0]._id).toEqual(row._id)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should not be able to access the view data when the table is not public and there are no view permissions overrides", async () => {
|
it("should not be able to access the view data when the table is not public and there are no view permissions overrides", async () => {
|
||||||
|
@ -196,14 +200,11 @@ describe("/permission", () => {
|
||||||
// replicate changes before checking permissions
|
// replicate changes before checking permissions
|
||||||
await config.publish()
|
await config.publish()
|
||||||
|
|
||||||
await config.api.viewV2.search(view.id, undefined, {
|
await config.api.viewV2.publicSearch(view.id, undefined, { status: 403 })
|
||||||
expectStatus: 403,
|
|
||||||
usePublicUser: true,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should ignore the view permissions if the flag is not on", async () => {
|
it("should ignore the view permissions if the flag is not on", async () => {
|
||||||
await config.api.permission.set({
|
await config.api.permission.add({
|
||||||
roleId: STD_ROLE_ID,
|
roleId: STD_ROLE_ID,
|
||||||
resourceId: view.id,
|
resourceId: view.id,
|
||||||
level: PermissionLevel.READ,
|
level: PermissionLevel.READ,
|
||||||
|
@ -216,15 +217,14 @@ describe("/permission", () => {
|
||||||
// replicate changes before checking permissions
|
// replicate changes before checking permissions
|
||||||
await config.publish()
|
await config.publish()
|
||||||
|
|
||||||
await config.api.viewV2.search(view.id, undefined, {
|
await config.api.viewV2.publicSearch(view.id, undefined, {
|
||||||
expectStatus: 403,
|
status: 403,
|
||||||
usePublicUser: true,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should use the view permissions if the flag is on", async () => {
|
it("should use the view permissions if the flag is on", async () => {
|
||||||
mocks.licenses.useViewPermissions()
|
mocks.licenses.useViewPermissions()
|
||||||
await config.api.permission.set({
|
await config.api.permission.add({
|
||||||
roleId: STD_ROLE_ID,
|
roleId: STD_ROLE_ID,
|
||||||
resourceId: view.id,
|
resourceId: view.id,
|
||||||
level: PermissionLevel.READ,
|
level: PermissionLevel.READ,
|
||||||
|
@ -237,10 +237,8 @@ describe("/permission", () => {
|
||||||
// replicate changes before checking permissions
|
// replicate changes before checking permissions
|
||||||
await config.publish()
|
await config.publish()
|
||||||
|
|
||||||
const res = await config.api.viewV2.search(view.id, undefined, {
|
const res = await config.api.viewV2.publicSearch(view.id)
|
||||||
usePublicUser: true,
|
expect(res.rows[0]._id).toEqual(row._id)
|
||||||
})
|
|
||||||
expect(res.body.rows[0]._id).toEqual(row._id)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("shouldn't allow writing from a public user", async () => {
|
it("shouldn't allow writing from a public user", async () => {
|
||||||
|
@ -277,7 +275,7 @@ describe("/permission", () => {
|
||||||
|
|
||||||
const res = await config.api.permission.get(legacyView.name)
|
const res = await config.api.permission.get(legacyView.name)
|
||||||
|
|
||||||
expect(res.body).toEqual({
|
expect(res).toEqual({
|
||||||
permissions: {
|
permissions: {
|
||||||
read: {
|
read: {
|
||||||
permissionType: "BASE",
|
permissionType: "BASE",
|
||||||
|
|
|
@ -397,15 +397,16 @@ describe("/queries", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should fail with invalid integration type", async () => {
|
it("should fail with invalid integration type", async () => {
|
||||||
const response = await config.api.datasource.create(
|
const datasource: Datasource = {
|
||||||
{
|
...basicDatasource().datasource,
|
||||||
...basicDatasource().datasource,
|
source: "INVALID_INTEGRATION" as SourceName,
|
||||||
source: "INVALID_INTEGRATION" as SourceName,
|
}
|
||||||
|
await config.api.datasource.create(datasource, {
|
||||||
|
status: 500,
|
||||||
|
body: {
|
||||||
|
message: "No datasource implementation found.",
|
||||||
},
|
},
|
||||||
{ expectStatus: 500, rawResponse: true }
|
})
|
||||||
)
|
|
||||||
|
|
||||||
expect(response.body.message).toBe("No datasource implementation found.")
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ describe("/roles", () => {
|
||||||
|
|
||||||
it("should be able to get the role with a permission added", async () => {
|
it("should be able to get the role with a permission added", async () => {
|
||||||
const table = await config.createTable()
|
const table = await config.createTable()
|
||||||
await config.api.permission.set({
|
await config.api.permission.add({
|
||||||
roleId: BUILTIN_ROLE_IDS.POWER,
|
roleId: BUILTIN_ROLE_IDS.POWER,
|
||||||
resourceId: table._id,
|
resourceId: table._id,
|
||||||
level: PermissionLevel.READ,
|
level: PermissionLevel.READ,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { context, InternalTable, roles, tenancy } from "@budibase/backend-core"
|
||||||
import { quotas } from "@budibase/pro"
|
import { quotas } from "@budibase/pro"
|
||||||
import {
|
import {
|
||||||
AutoFieldSubType,
|
AutoFieldSubType,
|
||||||
|
DeleteRow,
|
||||||
FieldSchema,
|
FieldSchema,
|
||||||
FieldType,
|
FieldType,
|
||||||
FieldTypeSubtypes,
|
FieldTypeSubtypes,
|
||||||
|
@ -106,9 +107,6 @@ describe.each([
|
||||||
mocks.licenses.useCloudFree()
|
mocks.licenses.useCloudFree()
|
||||||
})
|
})
|
||||||
|
|
||||||
const loadRow = (id: string, tbl_Id: string, status = 200) =>
|
|
||||||
config.api.row.get(tbl_Id, id, { expectStatus: status })
|
|
||||||
|
|
||||||
const getRowUsage = async () => {
|
const getRowUsage = async () => {
|
||||||
const { total } = await config.doInContext(undefined, () =>
|
const { total } = await config.doInContext(undefined, () =>
|
||||||
quotas.getCurrentUsageValues(QuotaUsageType.STATIC, StaticQuotaName.ROWS)
|
quotas.getCurrentUsageValues(QuotaUsageType.STATIC, StaticQuotaName.ROWS)
|
||||||
|
@ -235,7 +233,7 @@ describe.each([
|
||||||
|
|
||||||
const res = await config.api.row.get(tableId, existing._id!)
|
const res = await config.api.row.get(tableId, existing._id!)
|
||||||
|
|
||||||
expect(res.body).toEqual({
|
expect(res).toEqual({
|
||||||
...existing,
|
...existing,
|
||||||
...defaultRowFields,
|
...defaultRowFields,
|
||||||
})
|
})
|
||||||
|
@ -265,7 +263,7 @@ describe.each([
|
||||||
await config.createRow()
|
await config.createRow()
|
||||||
|
|
||||||
await config.api.row.get(tableId, "1234567", {
|
await config.api.row.get(tableId, "1234567", {
|
||||||
expectStatus: 404,
|
status: 404,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -395,7 +393,7 @@ describe.each([
|
||||||
const createdRow = await config.createRow(row)
|
const createdRow = await config.createRow(row)
|
||||||
const id = createdRow._id!
|
const id = createdRow._id!
|
||||||
|
|
||||||
const saved = (await loadRow(id, table._id!)).body
|
const saved = await config.api.row.get(table._id!, id)
|
||||||
|
|
||||||
expect(saved.stringUndefined).toBe(undefined)
|
expect(saved.stringUndefined).toBe(undefined)
|
||||||
expect(saved.stringNull).toBe(null)
|
expect(saved.stringNull).toBe(null)
|
||||||
|
@ -476,8 +474,8 @@ describe.each([
|
||||||
)
|
)
|
||||||
|
|
||||||
const row = await config.api.row.get(table._id!, createRowResponse._id!)
|
const row = await config.api.row.get(table._id!, createRowResponse._id!)
|
||||||
expect(row.body.Story).toBeUndefined()
|
expect(row.Story).toBeUndefined()
|
||||||
expect(row.body).toEqual({
|
expect(row).toEqual({
|
||||||
...defaultRowFields,
|
...defaultRowFields,
|
||||||
OrderID: 1111,
|
OrderID: 1111,
|
||||||
Country: "Aussy",
|
Country: "Aussy",
|
||||||
|
@ -524,10 +522,10 @@ describe.each([
|
||||||
expect(row.name).toEqual("Updated Name")
|
expect(row.name).toEqual("Updated Name")
|
||||||
expect(row.description).toEqual(existing.description)
|
expect(row.description).toEqual(existing.description)
|
||||||
|
|
||||||
const savedRow = await loadRow(row._id!, table._id!)
|
const savedRow = await config.api.row.get(table._id!, row._id!)
|
||||||
|
|
||||||
expect(savedRow.body.description).toEqual(existing.description)
|
expect(savedRow.description).toEqual(existing.description)
|
||||||
expect(savedRow.body.name).toEqual("Updated Name")
|
expect(savedRow.name).toEqual("Updated Name")
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -543,7 +541,7 @@ describe.each([
|
||||||
tableId: table._id!,
|
tableId: table._id!,
|
||||||
name: 1,
|
name: 1,
|
||||||
},
|
},
|
||||||
{ expectStatus: 400 }
|
{ status: 400 }
|
||||||
)
|
)
|
||||||
|
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
|
@ -582,8 +580,8 @@ describe.each([
|
||||||
})
|
})
|
||||||
|
|
||||||
let getResp = await config.api.row.get(table._id!, row._id!)
|
let getResp = await config.api.row.get(table._id!, row._id!)
|
||||||
expect(getResp.body.user1[0]._id).toEqual(user1._id)
|
expect(getResp.user1[0]._id).toEqual(user1._id)
|
||||||
expect(getResp.body.user2[0]._id).toEqual(user2._id)
|
expect(getResp.user2[0]._id).toEqual(user2._id)
|
||||||
|
|
||||||
let patchResp = await config.api.row.patch(table._id!, {
|
let patchResp = await config.api.row.patch(table._id!, {
|
||||||
_id: row._id!,
|
_id: row._id!,
|
||||||
|
@ -595,8 +593,8 @@ describe.each([
|
||||||
expect(patchResp.user2[0]._id).toEqual(user2._id)
|
expect(patchResp.user2[0]._id).toEqual(user2._id)
|
||||||
|
|
||||||
getResp = await config.api.row.get(table._id!, row._id!)
|
getResp = await config.api.row.get(table._id!, row._id!)
|
||||||
expect(getResp.body.user1[0]._id).toEqual(user2._id)
|
expect(getResp.user1[0]._id).toEqual(user2._id)
|
||||||
expect(getResp.body.user2[0]._id).toEqual(user2._id)
|
expect(getResp.user2[0]._id).toEqual(user2._id)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should be able to update relationships when both columns are same name", async () => {
|
it("should be able to update relationships when both columns are same name", async () => {
|
||||||
|
@ -609,7 +607,7 @@ describe.each([
|
||||||
description: "test",
|
description: "test",
|
||||||
relationship: [row._id],
|
relationship: [row._id],
|
||||||
})
|
})
|
||||||
row = (await config.api.row.get(table._id!, row._id!)).body
|
row = await config.api.row.get(table._id!, row._id!)
|
||||||
expect(row.relationship.length).toBe(1)
|
expect(row.relationship.length).toBe(1)
|
||||||
const resp = await config.api.row.patch(table._id!, {
|
const resp = await config.api.row.patch(table._id!, {
|
||||||
_id: row._id!,
|
_id: row._id!,
|
||||||
|
@ -632,8 +630,10 @@ describe.each([
|
||||||
const createdRow = await config.createRow()
|
const createdRow = await config.createRow()
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
|
|
||||||
const res = await config.api.row.delete(table._id!, [createdRow])
|
const res = await config.api.row.bulkDelete(table._id!, {
|
||||||
expect(res.body[0]._id).toEqual(createdRow._id)
|
rows: [createdRow],
|
||||||
|
})
|
||||||
|
expect(res[0]._id).toEqual(createdRow._id)
|
||||||
await assertRowUsage(rowUsage - 1)
|
await assertRowUsage(rowUsage - 1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -682,10 +682,12 @@ describe.each([
|
||||||
const row2 = await config.createRow()
|
const row2 = await config.createRow()
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
|
|
||||||
const res = await config.api.row.delete(table._id!, [row1, row2])
|
const res = await config.api.row.bulkDelete(table._id!, {
|
||||||
|
rows: [row1, row2],
|
||||||
|
})
|
||||||
|
|
||||||
expect(res.body.length).toEqual(2)
|
expect(res.length).toEqual(2)
|
||||||
await loadRow(row1._id!, table._id!, 404)
|
await config.api.row.get(table._id!, row1._id!, { status: 404 })
|
||||||
await assertRowUsage(rowUsage - 2)
|
await assertRowUsage(rowUsage - 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -697,14 +699,12 @@ describe.each([
|
||||||
])
|
])
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
|
|
||||||
const res = await config.api.row.delete(table._id!, [
|
const res = await config.api.row.bulkDelete(table._id!, {
|
||||||
row1,
|
rows: [row1, row2._id!, { _id: row3._id }],
|
||||||
row2._id,
|
})
|
||||||
{ _id: row3._id },
|
|
||||||
])
|
|
||||||
|
|
||||||
expect(res.body.length).toEqual(3)
|
expect(res.length).toEqual(3)
|
||||||
await loadRow(row1._id!, table._id!, 404)
|
await config.api.row.get(table._id!, row1._id!, { status: 404 })
|
||||||
await assertRowUsage(rowUsage - 3)
|
await assertRowUsage(rowUsage - 3)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -712,34 +712,36 @@ describe.each([
|
||||||
const row1 = await config.createRow()
|
const row1 = await config.createRow()
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
|
|
||||||
const res = await config.api.row.delete(table._id!, row1)
|
const res = await config.api.row.delete(table._id!, row1 as DeleteRow)
|
||||||
|
|
||||||
expect(res.body.id).toEqual(row1._id)
|
expect(res.id).toEqual(row1._id)
|
||||||
await loadRow(row1._id!, table._id!, 404)
|
await config.api.row.get(table._id!, row1._id!, { status: 404 })
|
||||||
await assertRowUsage(rowUsage - 1)
|
await assertRowUsage(rowUsage - 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("Should ignore malformed/invalid delete requests", async () => {
|
it("Should ignore malformed/invalid delete requests", async () => {
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
|
|
||||||
const res = await config.api.row.delete(
|
await config.api.row.delete(table._id!, { not: "valid" } as any, {
|
||||||
table._id!,
|
status: 400,
|
||||||
{ not: "valid" },
|
body: {
|
||||||
{ expectStatus: 400 }
|
message: "Invalid delete rows request",
|
||||||
)
|
},
|
||||||
expect(res.body.message).toEqual("Invalid delete rows request")
|
})
|
||||||
|
|
||||||
const res2 = await config.api.row.delete(
|
await config.api.row.delete(table._id!, { rows: 123 } as any, {
|
||||||
table._id!,
|
status: 400,
|
||||||
{ rows: 123 },
|
body: {
|
||||||
{ expectStatus: 400 }
|
message: "Invalid delete rows request",
|
||||||
)
|
},
|
||||||
expect(res2.body.message).toEqual("Invalid delete rows request")
|
})
|
||||||
|
|
||||||
const res3 = await config.api.row.delete(table._id!, "invalid", {
|
await config.api.row.delete(table._id!, "invalid" as any, {
|
||||||
expectStatus: 400,
|
status: 400,
|
||||||
|
body: {
|
||||||
|
message: "Invalid delete rows request",
|
||||||
|
},
|
||||||
})
|
})
|
||||||
expect(res3.body.message).toEqual("Invalid delete rows request")
|
|
||||||
|
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
})
|
})
|
||||||
|
@ -757,16 +759,16 @@ describe.each([
|
||||||
const row = await config.createRow()
|
const row = await config.createRow()
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
|
|
||||||
const res = await config.api.legacyView.get(table._id!)
|
const rows = await config.api.legacyView.get(table._id!)
|
||||||
expect(res.body.length).toEqual(1)
|
expect(rows.length).toEqual(1)
|
||||||
expect(res.body[0]._id).toEqual(row._id)
|
expect(rows[0]._id).toEqual(row._id)
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should throw an error if view doesn't exist", async () => {
|
it("should throw an error if view doesn't exist", async () => {
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
|
|
||||||
await config.api.legacyView.get("derp", { expectStatus: 404 })
|
await config.api.legacyView.get("derp", { status: 404 })
|
||||||
|
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
})
|
})
|
||||||
|
@ -781,9 +783,9 @@ describe.each([
|
||||||
const row = await config.createRow()
|
const row = await config.createRow()
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
|
|
||||||
const res = await config.api.legacyView.get(view.name)
|
const rows = await config.api.legacyView.get(view.name)
|
||||||
expect(res.body.length).toEqual(1)
|
expect(rows.length).toEqual(1)
|
||||||
expect(res.body[0]._id).toEqual(row._id)
|
expect(rows[0]._id).toEqual(row._id)
|
||||||
|
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
})
|
})
|
||||||
|
@ -841,8 +843,8 @@ describe.each([
|
||||||
linkedTable._id!,
|
linkedTable._id!,
|
||||||
secondRow._id!
|
secondRow._id!
|
||||||
)
|
)
|
||||||
expect(resBasic.body.link.length).toBe(1)
|
expect(resBasic.link.length).toBe(1)
|
||||||
expect(resBasic.body.link[0]).toEqual({
|
expect(resBasic.link[0]).toEqual({
|
||||||
_id: firstRow._id,
|
_id: firstRow._id,
|
||||||
primaryDisplay: firstRow.name,
|
primaryDisplay: firstRow.name,
|
||||||
})
|
})
|
||||||
|
@ -852,10 +854,10 @@ describe.each([
|
||||||
linkedTable._id!,
|
linkedTable._id!,
|
||||||
secondRow._id!
|
secondRow._id!
|
||||||
)
|
)
|
||||||
expect(resEnriched.body.link.length).toBe(1)
|
expect(resEnriched.link.length).toBe(1)
|
||||||
expect(resEnriched.body.link[0]._id).toBe(firstRow._id)
|
expect(resEnriched.link[0]._id).toBe(firstRow._id)
|
||||||
expect(resEnriched.body.link[0].name).toBe("Test Contact")
|
expect(resEnriched.link[0].name).toBe("Test Contact")
|
||||||
expect(resEnriched.body.link[0].description).toBe("original description")
|
expect(resEnriched.link[0].description).toBe("original description")
|
||||||
await assertRowUsage(rowUsage)
|
await assertRowUsage(rowUsage)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -903,7 +905,7 @@ describe.each([
|
||||||
const res = await config.api.row.exportRows(table._id!, {
|
const res = await config.api.row.exportRows(table._id!, {
|
||||||
rows: [existing._id!],
|
rows: [existing._id!],
|
||||||
})
|
})
|
||||||
const results = JSON.parse(res.text)
|
const results = JSON.parse(res)
|
||||||
expect(results.length).toEqual(1)
|
expect(results.length).toEqual(1)
|
||||||
const row = results[0]
|
const row = results[0]
|
||||||
|
|
||||||
|
@ -922,7 +924,7 @@ describe.each([
|
||||||
rows: [existing._id!],
|
rows: [existing._id!],
|
||||||
columns: ["_id"],
|
columns: ["_id"],
|
||||||
})
|
})
|
||||||
const results = JSON.parse(res.text)
|
const results = JSON.parse(res)
|
||||||
expect(results.length).toEqual(1)
|
expect(results.length).toEqual(1)
|
||||||
const row = results[0]
|
const row = results[0]
|
||||||
|
|
||||||
|
@ -1000,7 +1002,7 @@ describe.each([
|
||||||
})
|
})
|
||||||
|
|
||||||
const row = await config.api.row.get(table._id!, newRow._id!)
|
const row = await config.api.row.get(table._id!, newRow._id!)
|
||||||
expect(row.body).toEqual({
|
expect(row).toEqual({
|
||||||
name: data.name,
|
name: data.name,
|
||||||
surname: data.surname,
|
surname: data.surname,
|
||||||
address: data.address,
|
address: data.address,
|
||||||
|
@ -1010,9 +1012,9 @@ describe.each([
|
||||||
id: newRow.id,
|
id: newRow.id,
|
||||||
...defaultRowFields,
|
...defaultRowFields,
|
||||||
})
|
})
|
||||||
expect(row.body._viewId).toBeUndefined()
|
expect(row._viewId).toBeUndefined()
|
||||||
expect(row.body.age).toBeUndefined()
|
expect(row.age).toBeUndefined()
|
||||||
expect(row.body.jobTitle).toBeUndefined()
|
expect(row.jobTitle).toBeUndefined()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1042,7 +1044,7 @@ describe.each([
|
||||||
})
|
})
|
||||||
|
|
||||||
const row = await config.api.row.get(tableId, newRow._id!)
|
const row = await config.api.row.get(tableId, newRow._id!)
|
||||||
expect(row.body).toEqual({
|
expect(row).toEqual({
|
||||||
...newRow,
|
...newRow,
|
||||||
name: newData.name,
|
name: newData.name,
|
||||||
address: newData.address,
|
address: newData.address,
|
||||||
|
@ -1051,9 +1053,9 @@ describe.each([
|
||||||
id: newRow.id,
|
id: newRow.id,
|
||||||
...defaultRowFields,
|
...defaultRowFields,
|
||||||
})
|
})
|
||||||
expect(row.body._viewId).toBeUndefined()
|
expect(row._viewId).toBeUndefined()
|
||||||
expect(row.body.age).toBeUndefined()
|
expect(row.age).toBeUndefined()
|
||||||
expect(row.body.jobTitle).toBeUndefined()
|
expect(row.jobTitle).toBeUndefined()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1071,12 +1073,12 @@ describe.each([
|
||||||
const createdRow = await config.createRow()
|
const createdRow = await config.createRow()
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
|
|
||||||
await config.api.row.delete(view.id, [createdRow])
|
await config.api.row.bulkDelete(view.id, { rows: [createdRow] })
|
||||||
|
|
||||||
await assertRowUsage(rowUsage - 1)
|
await assertRowUsage(rowUsage - 1)
|
||||||
|
|
||||||
await config.api.row.get(tableId, createdRow._id!, {
|
await config.api.row.get(tableId, createdRow._id!, {
|
||||||
expectStatus: 404,
|
status: 404,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1097,17 +1099,17 @@ describe.each([
|
||||||
])
|
])
|
||||||
const rowUsage = await getRowUsage()
|
const rowUsage = await getRowUsage()
|
||||||
|
|
||||||
await config.api.row.delete(view.id, [rows[0], rows[2]])
|
await config.api.row.bulkDelete(view.id, { rows: [rows[0], rows[2]] })
|
||||||
|
|
||||||
await assertRowUsage(rowUsage - 2)
|
await assertRowUsage(rowUsage - 2)
|
||||||
|
|
||||||
await config.api.row.get(tableId, rows[0]._id!, {
|
await config.api.row.get(tableId, rows[0]._id!, {
|
||||||
expectStatus: 404,
|
status: 404,
|
||||||
})
|
})
|
||||||
await config.api.row.get(tableId, rows[2]._id!, {
|
await config.api.row.get(tableId, rows[2]._id!, {
|
||||||
expectStatus: 404,
|
status: 404,
|
||||||
})
|
})
|
||||||
await config.api.row.get(tableId, rows[1]._id!, { expectStatus: 200 })
|
await config.api.row.get(tableId, rows[1]._id!, { status: 200 })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1154,8 +1156,8 @@ describe.each([
|
||||||
const createViewResponse = await config.createView()
|
const createViewResponse = await config.createView()
|
||||||
const response = await config.api.viewV2.search(createViewResponse.id)
|
const response = await config.api.viewV2.search(createViewResponse.id)
|
||||||
|
|
||||||
expect(response.body.rows).toHaveLength(10)
|
expect(response.rows).toHaveLength(10)
|
||||||
expect(response.body).toEqual({
|
expect(response).toEqual({
|
||||||
rows: expect.arrayContaining(
|
rows: expect.arrayContaining(
|
||||||
rows.map(r => ({
|
rows.map(r => ({
|
||||||
_viewId: createViewResponse.id,
|
_viewId: createViewResponse.id,
|
||||||
|
@ -1206,8 +1208,8 @@ describe.each([
|
||||||
|
|
||||||
const response = await config.api.viewV2.search(createViewResponse.id)
|
const response = await config.api.viewV2.search(createViewResponse.id)
|
||||||
|
|
||||||
expect(response.body.rows).toHaveLength(5)
|
expect(response.rows).toHaveLength(5)
|
||||||
expect(response.body).toEqual({
|
expect(response).toEqual({
|
||||||
rows: expect.arrayContaining(
|
rows: expect.arrayContaining(
|
||||||
expectedRows.map(r => ({
|
expectedRows.map(r => ({
|
||||||
_viewId: createViewResponse.id,
|
_viewId: createViewResponse.id,
|
||||||
|
@ -1328,8 +1330,8 @@ describe.each([
|
||||||
createViewResponse.id
|
createViewResponse.id
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.body.rows).toHaveLength(4)
|
expect(response.rows).toHaveLength(4)
|
||||||
expect(response.body.rows).toEqual(
|
expect(response.rows).toEqual(
|
||||||
expected.map(name => expect.objectContaining({ name }))
|
expected.map(name => expect.objectContaining({ name }))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1357,8 +1359,8 @@ describe.each([
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.body.rows).toHaveLength(4)
|
expect(response.rows).toHaveLength(4)
|
||||||
expect(response.body.rows).toEqual(
|
expect(response.rows).toEqual(
|
||||||
expected.map(name => expect.objectContaining({ name }))
|
expected.map(name => expect.objectContaining({ name }))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1382,8 +1384,8 @@ describe.each([
|
||||||
})
|
})
|
||||||
const response = await config.api.viewV2.search(view.id)
|
const response = await config.api.viewV2.search(view.id)
|
||||||
|
|
||||||
expect(response.body.rows).toHaveLength(10)
|
expect(response.rows).toHaveLength(10)
|
||||||
expect(response.body.rows).toEqual(
|
expect(response.rows).toEqual(
|
||||||
expect.arrayContaining(
|
expect.arrayContaining(
|
||||||
rows.map(r => ({
|
rows.map(r => ({
|
||||||
...(isInternal
|
...(isInternal
|
||||||
|
@ -1402,7 +1404,7 @@ describe.each([
|
||||||
const createViewResponse = await config.createView()
|
const createViewResponse = await config.createView()
|
||||||
const response = await config.api.viewV2.search(createViewResponse.id)
|
const response = await config.api.viewV2.search(createViewResponse.id)
|
||||||
|
|
||||||
expect(response.body.rows).toHaveLength(0)
|
expect(response.rows).toHaveLength(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("respects the limit parameter", async () => {
|
it("respects the limit parameter", async () => {
|
||||||
|
@ -1417,7 +1419,7 @@ describe.each([
|
||||||
query: {},
|
query: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(response.body.rows).toHaveLength(limit)
|
expect(response.rows).toHaveLength(limit)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("can handle pagination", async () => {
|
it("can handle pagination", async () => {
|
||||||
|
@ -1426,7 +1428,7 @@ describe.each([
|
||||||
|
|
||||||
const createViewResponse = await config.createView()
|
const createViewResponse = await config.createView()
|
||||||
const allRows = (await config.api.viewV2.search(createViewResponse.id))
|
const allRows = (await config.api.viewV2.search(createViewResponse.id))
|
||||||
.body.rows
|
.rows
|
||||||
|
|
||||||
const firstPageResponse = await config.api.viewV2.search(
|
const firstPageResponse = await config.api.viewV2.search(
|
||||||
createViewResponse.id,
|
createViewResponse.id,
|
||||||
|
@ -1436,7 +1438,7 @@ describe.each([
|
||||||
query: {},
|
query: {},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(firstPageResponse.body).toEqual({
|
expect(firstPageResponse).toEqual({
|
||||||
rows: expect.arrayContaining(allRows.slice(0, 4)),
|
rows: expect.arrayContaining(allRows.slice(0, 4)),
|
||||||
totalRows: isInternal ? 10 : undefined,
|
totalRows: isInternal ? 10 : undefined,
|
||||||
hasNextPage: true,
|
hasNextPage: true,
|
||||||
|
@ -1448,12 +1450,12 @@ describe.each([
|
||||||
{
|
{
|
||||||
paginate: true,
|
paginate: true,
|
||||||
limit: 4,
|
limit: 4,
|
||||||
bookmark: firstPageResponse.body.bookmark,
|
bookmark: firstPageResponse.bookmark,
|
||||||
|
|
||||||
query: {},
|
query: {},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(secondPageResponse.body).toEqual({
|
expect(secondPageResponse).toEqual({
|
||||||
rows: expect.arrayContaining(allRows.slice(4, 8)),
|
rows: expect.arrayContaining(allRows.slice(4, 8)),
|
||||||
totalRows: isInternal ? 10 : undefined,
|
totalRows: isInternal ? 10 : undefined,
|
||||||
hasNextPage: true,
|
hasNextPage: true,
|
||||||
|
@ -1465,11 +1467,11 @@ describe.each([
|
||||||
{
|
{
|
||||||
paginate: true,
|
paginate: true,
|
||||||
limit: 4,
|
limit: 4,
|
||||||
bookmark: secondPageResponse.body.bookmark,
|
bookmark: secondPageResponse.bookmark,
|
||||||
query: {},
|
query: {},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(lastPageResponse.body).toEqual({
|
expect(lastPageResponse).toEqual({
|
||||||
rows: expect.arrayContaining(allRows.slice(8)),
|
rows: expect.arrayContaining(allRows.slice(8)),
|
||||||
totalRows: isInternal ? 10 : undefined,
|
totalRows: isInternal ? 10 : undefined,
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
|
@ -1489,7 +1491,7 @@ describe.each([
|
||||||
email: "joe@joe.com",
|
email: "joe@joe.com",
|
||||||
roles: {},
|
roles: {},
|
||||||
},
|
},
|
||||||
{ expectStatus: 400 }
|
{ status: 400 }
|
||||||
)
|
)
|
||||||
expect(response.message).toBe("Cannot create new user entry.")
|
expect(response.message).toBe("Cannot create new user entry.")
|
||||||
})
|
})
|
||||||
|
@ -1516,58 +1518,52 @@ describe.each([
|
||||||
|
|
||||||
it("does not allow public users to fetch by default", async () => {
|
it("does not allow public users to fetch by default", async () => {
|
||||||
await config.publish()
|
await config.publish()
|
||||||
await config.api.viewV2.search(viewId, undefined, {
|
await config.api.viewV2.publicSearch(viewId, undefined, {
|
||||||
expectStatus: 403,
|
status: 403,
|
||||||
usePublicUser: true,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("allow public users to fetch when permissions are explicit", async () => {
|
it("allow public users to fetch when permissions are explicit", async () => {
|
||||||
await config.api.permission.set({
|
await config.api.permission.add({
|
||||||
roleId: roles.BUILTIN_ROLE_IDS.PUBLIC,
|
roleId: roles.BUILTIN_ROLE_IDS.PUBLIC,
|
||||||
level: PermissionLevel.READ,
|
level: PermissionLevel.READ,
|
||||||
resourceId: viewId,
|
resourceId: viewId,
|
||||||
})
|
})
|
||||||
await config.publish()
|
await config.publish()
|
||||||
|
|
||||||
const response = await config.api.viewV2.search(viewId, undefined, {
|
const response = await config.api.viewV2.publicSearch(viewId)
|
||||||
usePublicUser: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response.body.rows).toHaveLength(10)
|
expect(response.rows).toHaveLength(10)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("allow public users to fetch when permissions are inherited", async () => {
|
it("allow public users to fetch when permissions are inherited", async () => {
|
||||||
await config.api.permission.set({
|
await config.api.permission.add({
|
||||||
roleId: roles.BUILTIN_ROLE_IDS.PUBLIC,
|
roleId: roles.BUILTIN_ROLE_IDS.PUBLIC,
|
||||||
level: PermissionLevel.READ,
|
level: PermissionLevel.READ,
|
||||||
resourceId: tableId,
|
resourceId: tableId,
|
||||||
})
|
})
|
||||||
await config.publish()
|
await config.publish()
|
||||||
|
|
||||||
const response = await config.api.viewV2.search(viewId, undefined, {
|
const response = await config.api.viewV2.publicSearch(viewId)
|
||||||
usePublicUser: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response.body.rows).toHaveLength(10)
|
expect(response.rows).toHaveLength(10)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("respects inherited permissions, not allowing not public views from public tables", async () => {
|
it("respects inherited permissions, not allowing not public views from public tables", async () => {
|
||||||
await config.api.permission.set({
|
await config.api.permission.add({
|
||||||
roleId: roles.BUILTIN_ROLE_IDS.PUBLIC,
|
roleId: roles.BUILTIN_ROLE_IDS.PUBLIC,
|
||||||
level: PermissionLevel.READ,
|
level: PermissionLevel.READ,
|
||||||
resourceId: tableId,
|
resourceId: tableId,
|
||||||
})
|
})
|
||||||
await config.api.permission.set({
|
await config.api.permission.add({
|
||||||
roleId: roles.BUILTIN_ROLE_IDS.POWER,
|
roleId: roles.BUILTIN_ROLE_IDS.POWER,
|
||||||
level: PermissionLevel.READ,
|
level: PermissionLevel.READ,
|
||||||
resourceId: viewId,
|
resourceId: viewId,
|
||||||
})
|
})
|
||||||
await config.publish()
|
await config.publish()
|
||||||
|
|
||||||
await config.api.viewV2.search(viewId, undefined, {
|
await config.api.viewV2.publicSearch(viewId, undefined, {
|
||||||
usePublicUser: true,
|
status: 403,
|
||||||
expectStatus: 403,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1754,7 +1750,7 @@ describe.each([
|
||||||
}
|
}
|
||||||
const row = await config.api.row.save(tableId, rowData)
|
const row = await config.api.row.save(tableId, rowData)
|
||||||
|
|
||||||
const { body: retrieved } = await config.api.row.get(tableId, row._id!)
|
const retrieved = await config.api.row.get(tableId, row._id!)
|
||||||
expect(retrieved).toEqual({
|
expect(retrieved).toEqual({
|
||||||
name: rowData.name,
|
name: rowData.name,
|
||||||
description: rowData.description,
|
description: rowData.description,
|
||||||
|
@ -1781,7 +1777,7 @@ describe.each([
|
||||||
}
|
}
|
||||||
const row = await config.api.row.save(tableId, rowData)
|
const row = await config.api.row.save(tableId, rowData)
|
||||||
|
|
||||||
const { body: retrieved } = await config.api.row.get(tableId, row._id!)
|
const retrieved = await config.api.row.get(tableId, row._id!)
|
||||||
expect(retrieved).toEqual({
|
expect(retrieved).toEqual({
|
||||||
name: rowData.name,
|
name: rowData.name,
|
||||||
description: rowData.description,
|
description: rowData.description,
|
||||||
|
|
|
@ -663,8 +663,7 @@ describe("/tables", () => {
|
||||||
expect(migratedTable.schema["user column"]).toBeDefined()
|
expect(migratedTable.schema["user column"]).toBeDefined()
|
||||||
expect(migratedTable.schema["user relationship"]).not.toBeDefined()
|
expect(migratedTable.schema["user relationship"]).not.toBeDefined()
|
||||||
|
|
||||||
const resp = await config.api.row.get(table._id!, testRow._id!)
|
const migratedRow = await config.api.row.get(table._id!, testRow._id!)
|
||||||
const migratedRow = resp.body as Row
|
|
||||||
|
|
||||||
expect(migratedRow["user column"]).toBeDefined()
|
expect(migratedRow["user column"]).toBeDefined()
|
||||||
expect(migratedRow["user relationship"]).not.toBeDefined()
|
expect(migratedRow["user relationship"]).not.toBeDefined()
|
||||||
|
@ -716,15 +715,13 @@ describe("/tables", () => {
|
||||||
expect(migratedTable.schema["user column"]).toBeDefined()
|
expect(migratedTable.schema["user column"]).toBeDefined()
|
||||||
expect(migratedTable.schema["user relationship"]).not.toBeDefined()
|
expect(migratedTable.schema["user relationship"]).not.toBeDefined()
|
||||||
|
|
||||||
const row1Migrated = (await config.api.row.get(table._id!, row1._id!))
|
const row1Migrated = await config.api.row.get(table._id!, row1._id!)
|
||||||
.body as Row
|
|
||||||
expect(row1Migrated["user relationship"]).not.toBeDefined()
|
expect(row1Migrated["user relationship"]).not.toBeDefined()
|
||||||
expect(row1Migrated["user column"].map((r: Row) => r._id)).toEqual(
|
expect(row1Migrated["user column"].map((r: Row) => r._id)).toEqual(
|
||||||
expect.arrayContaining([users[0]._id, users[1]._id])
|
expect.arrayContaining([users[0]._id, users[1]._id])
|
||||||
)
|
)
|
||||||
|
|
||||||
const row2Migrated = (await config.api.row.get(table._id!, row2._id!))
|
const row2Migrated = await config.api.row.get(table._id!, row2._id!)
|
||||||
.body as Row
|
|
||||||
expect(row2Migrated["user relationship"]).not.toBeDefined()
|
expect(row2Migrated["user relationship"]).not.toBeDefined()
|
||||||
expect(row2Migrated["user column"].map((r: Row) => r._id)).toEqual(
|
expect(row2Migrated["user column"].map((r: Row) => r._id)).toEqual(
|
||||||
expect.arrayContaining([users[1]._id, users[2]._id])
|
expect.arrayContaining([users[1]._id, users[2]._id])
|
||||||
|
@ -773,15 +770,13 @@ describe("/tables", () => {
|
||||||
expect(migratedTable.schema["user column"]).toBeDefined()
|
expect(migratedTable.schema["user column"]).toBeDefined()
|
||||||
expect(migratedTable.schema["user relationship"]).not.toBeDefined()
|
expect(migratedTable.schema["user relationship"]).not.toBeDefined()
|
||||||
|
|
||||||
const row1Migrated = (await config.api.row.get(table._id!, row1._id!))
|
const row1Migrated = await config.api.row.get(table._id!, row1._id!)
|
||||||
.body as Row
|
|
||||||
expect(row1Migrated["user relationship"]).not.toBeDefined()
|
expect(row1Migrated["user relationship"]).not.toBeDefined()
|
||||||
expect(row1Migrated["user column"].map((r: Row) => r._id)).toEqual(
|
expect(row1Migrated["user column"].map((r: Row) => r._id)).toEqual(
|
||||||
expect.arrayContaining([users[0]._id, users[1]._id])
|
expect.arrayContaining([users[0]._id, users[1]._id])
|
||||||
)
|
)
|
||||||
|
|
||||||
const row2Migrated = (await config.api.row.get(table._id!, row2._id!))
|
const row2Migrated = await config.api.row.get(table._id!, row2._id!)
|
||||||
.body as Row
|
|
||||||
expect(row2Migrated["user relationship"]).not.toBeDefined()
|
expect(row2Migrated["user relationship"]).not.toBeDefined()
|
||||||
expect(row2Migrated["user column"].map((r: Row) => r._id)).toEqual([
|
expect(row2Migrated["user column"].map((r: Row) => r._id)).toEqual([
|
||||||
users[2]._id,
|
users[2]._id,
|
||||||
|
@ -831,7 +826,7 @@ describe("/tables", () => {
|
||||||
subtype: FieldSubtype.USERS,
|
subtype: FieldSubtype.USERS,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ expectStatus: 400 }
|
{ status: 400 }
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -846,7 +841,7 @@ describe("/tables", () => {
|
||||||
subtype: FieldSubtype.USERS,
|
subtype: FieldSubtype.USERS,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ expectStatus: 400 }
|
{ status: 400 }
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -861,7 +856,7 @@ describe("/tables", () => {
|
||||||
subtype: FieldSubtype.USERS,
|
subtype: FieldSubtype.USERS,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ expectStatus: 400 }
|
{ status: 400 }
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -880,7 +875,7 @@ describe("/tables", () => {
|
||||||
subtype: FieldSubtype.USERS,
|
subtype: FieldSubtype.USERS,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ expectStatus: 400 }
|
{ status: 400 }
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -90,7 +90,7 @@ describe("/users", () => {
|
||||||
})
|
})
|
||||||
await config.api.user.update(
|
await config.api.user.update(
|
||||||
{ ...user, roleId: roles.BUILTIN_ROLE_IDS.POWER },
|
{ ...user, roleId: roles.BUILTIN_ROLE_IDS.POWER },
|
||||||
{ expectStatus: 409 }
|
{ status: 409 }
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -177,7 +177,7 @@ describe.each([
|
||||||
}
|
}
|
||||||
|
|
||||||
await config.api.viewV2.create(newView, {
|
await config.api.viewV2.create(newView, {
|
||||||
expectStatus: 201,
|
status: 201,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -275,7 +275,7 @@ describe.each([
|
||||||
const tableId = table._id!
|
const tableId = table._id!
|
||||||
await config.api.viewV2.update(
|
await config.api.viewV2.update(
|
||||||
{ ...view, id: generator.guid() },
|
{ ...view, id: generator.guid() },
|
||||||
{ expectStatus: 404 }
|
{ status: 404 }
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(await config.api.table.get(tableId)).toEqual(
|
expect(await config.api.table.get(tableId)).toEqual(
|
||||||
|
@ -304,7 +304,7 @@ describe.each([
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ expectStatus: 404 }
|
{ status: 404 }
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(await config.api.table.get(tableId)).toEqual(
|
expect(await config.api.table.get(tableId)).toEqual(
|
||||||
|
@ -326,12 +326,10 @@ describe.each([
|
||||||
...viewV1,
|
...viewV1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectStatus: 400,
|
status: 400,
|
||||||
handleResponse: r => {
|
body: {
|
||||||
expect(r.body).toEqual({
|
message: "Only views V2 can be updated",
|
||||||
message: "Only views V2 can be updated",
|
status: 400,
|
||||||
status: 400,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -403,7 +401,7 @@ describe.each([
|
||||||
} as Record<string, FieldSchema>,
|
} as Record<string, FieldSchema>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectStatus: 200,
|
status: 200,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -30,9 +30,9 @@ describe("migrations", () => {
|
||||||
|
|
||||||
const appId = config.getAppId()
|
const appId = config.getAppId()
|
||||||
|
|
||||||
const response = await config.api.application.getRaw(appId)
|
await config.api.application.get(appId, {
|
||||||
|
headersNotPresent: [Header.MIGRATING_APP],
|
||||||
expect(response.headers[Header.MIGRATING_APP]).toBeUndefined()
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("accessing an app that has pending migrations will attach the migrating header", async () => {
|
it("accessing an app that has pending migrations will attach the migrating header", async () => {
|
||||||
|
@ -46,8 +46,10 @@ describe("migrations", () => {
|
||||||
func: async () => {},
|
func: async () => {},
|
||||||
})
|
})
|
||||||
|
|
||||||
const response = await config.api.application.getRaw(appId)
|
await config.api.application.get(appId, {
|
||||||
|
headers: {
|
||||||
expect(response.headers[Header.MIGRATING_APP]).toEqual(appId)
|
[Header.MIGRATING_APP]: appId,
|
||||||
|
},
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -24,7 +24,7 @@ describe("test the create row action", () => {
|
||||||
expect(res.id).toBeDefined()
|
expect(res.id).toBeDefined()
|
||||||
expect(res.revision).toBeDefined()
|
expect(res.revision).toBeDefined()
|
||||||
expect(res.success).toEqual(true)
|
expect(res.success).toEqual(true)
|
||||||
const gottenRow = await config.getRow(table._id, res.id)
|
const gottenRow = await config.api.row.get(table._id, res.id)
|
||||||
expect(gottenRow.name).toEqual("test")
|
expect(gottenRow.name).toEqual("test")
|
||||||
expect(gottenRow.description).toEqual("test")
|
expect(gottenRow.description).toEqual("test")
|
||||||
})
|
})
|
||||||
|
|
|
@ -36,7 +36,7 @@ describe("test the update row action", () => {
|
||||||
it("should be able to run the action", async () => {
|
it("should be able to run the action", async () => {
|
||||||
const res = await setup.runStep(setup.actions.UPDATE_ROW.stepId, inputs)
|
const res = await setup.runStep(setup.actions.UPDATE_ROW.stepId, inputs)
|
||||||
expect(res.success).toEqual(true)
|
expect(res.success).toEqual(true)
|
||||||
const updatedRow = await config.getRow(table._id!, res.id)
|
const updatedRow = await config.api.row.get(table._id!, res.id)
|
||||||
expect(updatedRow.name).toEqual("Updated name")
|
expect(updatedRow.name).toEqual("Updated name")
|
||||||
expect(updatedRow.description).not.toEqual("")
|
expect(updatedRow.description).not.toEqual("")
|
||||||
})
|
})
|
||||||
|
@ -87,8 +87,8 @@ describe("test the update row action", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
let getResp = await config.api.row.get(table._id!, row._id!)
|
let getResp = await config.api.row.get(table._id!, row._id!)
|
||||||
expect(getResp.body.user1[0]._id).toEqual(user1._id)
|
expect(getResp.user1[0]._id).toEqual(user1._id)
|
||||||
expect(getResp.body.user2[0]._id).toEqual(user2._id)
|
expect(getResp.user2[0]._id).toEqual(user2._id)
|
||||||
|
|
||||||
let stepResp = await setup.runStep(setup.actions.UPDATE_ROW.stepId, {
|
let stepResp = await setup.runStep(setup.actions.UPDATE_ROW.stepId, {
|
||||||
rowId: row._id,
|
rowId: row._id,
|
||||||
|
@ -103,8 +103,8 @@ describe("test the update row action", () => {
|
||||||
expect(stepResp.success).toEqual(true)
|
expect(stepResp.success).toEqual(true)
|
||||||
|
|
||||||
getResp = await config.api.row.get(table._id!, row._id!)
|
getResp = await config.api.row.get(table._id!, row._id!)
|
||||||
expect(getResp.body.user1[0]._id).toEqual(user2._id)
|
expect(getResp.user1[0]._id).toEqual(user2._id)
|
||||||
expect(getResp.body.user2[0]._id).toEqual(user2._id)
|
expect(getResp.user2[0]._id).toEqual(user2._id)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should overwrite links if those links are not set and we ask it do", async () => {
|
it("should overwrite links if those links are not set and we ask it do", async () => {
|
||||||
|
@ -140,8 +140,8 @@ describe("test the update row action", () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
let getResp = await config.api.row.get(table._id!, row._id!)
|
let getResp = await config.api.row.get(table._id!, row._id!)
|
||||||
expect(getResp.body.user1[0]._id).toEqual(user1._id)
|
expect(getResp.user1[0]._id).toEqual(user1._id)
|
||||||
expect(getResp.body.user2[0]._id).toEqual(user2._id)
|
expect(getResp.user2[0]._id).toEqual(user2._id)
|
||||||
|
|
||||||
let stepResp = await setup.runStep(setup.actions.UPDATE_ROW.stepId, {
|
let stepResp = await setup.runStep(setup.actions.UPDATE_ROW.stepId, {
|
||||||
rowId: row._id,
|
rowId: row._id,
|
||||||
|
@ -163,7 +163,7 @@ describe("test the update row action", () => {
|
||||||
expect(stepResp.success).toEqual(true)
|
expect(stepResp.success).toEqual(true)
|
||||||
|
|
||||||
getResp = await config.api.row.get(table._id!, row._id!)
|
getResp = await config.api.row.get(table._id!, row._id!)
|
||||||
expect(getResp.body.user1[0]._id).toEqual(user2._id)
|
expect(getResp.user1[0]._id).toEqual(user2._id)
|
||||||
expect(getResp.body.user2).toBeUndefined()
|
expect(getResp.user2).toBeUndefined()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -100,7 +100,7 @@ describe("test the link controller", () => {
|
||||||
const { _id } = await config.createRow(
|
const { _id } = await config.createRow(
|
||||||
basicLinkedRow(t1._id!, row._id!, linkField)
|
basicLinkedRow(t1._id!, row._id!, linkField)
|
||||||
)
|
)
|
||||||
return config.getRow(t1._id!, _id!)
|
return config.api.row.get(t1._id!, _id!)
|
||||||
}
|
}
|
||||||
|
|
||||||
it("should be able to confirm if two table schemas are equal", async () => {
|
it("should be able to confirm if two table schemas are equal", async () => {
|
||||||
|
|
|
@ -398,7 +398,7 @@ describe("postgres integrations", () => {
|
||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
expect(res.body).toEqual(updatedRow)
|
expect(res.body).toEqual(updatedRow)
|
||||||
|
|
||||||
const persistedRow = await config.getRow(
|
const persistedRow = await config.api.row.get(
|
||||||
primaryPostgresTable._id!,
|
primaryPostgresTable._id!,
|
||||||
row.id
|
row.id
|
||||||
)
|
)
|
||||||
|
@ -1040,28 +1040,37 @@ describe("postgres integrations", () => {
|
||||||
|
|
||||||
describe("POST /api/datasources/verify", () => {
|
describe("POST /api/datasources/verify", () => {
|
||||||
it("should be able to verify the connection", async () => {
|
it("should be able to verify the connection", async () => {
|
||||||
const response = await config.api.datasource.verify({
|
await config.api.datasource.verify(
|
||||||
datasource: await databaseTestProviders.postgres.datasource(),
|
{
|
||||||
})
|
datasource: await databaseTestProviders.postgres.datasource(),
|
||||||
expect(response.status).toBe(200)
|
},
|
||||||
expect(response.body.connected).toBe(true)
|
{
|
||||||
|
body: {
|
||||||
|
connected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should state an invalid datasource cannot connect", async () => {
|
it("should state an invalid datasource cannot connect", async () => {
|
||||||
const dbConfig = await databaseTestProviders.postgres.datasource()
|
const dbConfig = await databaseTestProviders.postgres.datasource()
|
||||||
const response = await config.api.datasource.verify({
|
await config.api.datasource.verify(
|
||||||
datasource: {
|
{
|
||||||
...dbConfig,
|
datasource: {
|
||||||
config: {
|
...dbConfig,
|
||||||
...dbConfig.config,
|
config: {
|
||||||
password: "wrongpassword",
|
...dbConfig.config,
|
||||||
|
password: "wrongpassword",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
{
|
||||||
|
body: {
|
||||||
expect(response.status).toBe(200)
|
connected: false,
|
||||||
expect(response.body.connected).toBe(false)
|
error: 'password authentication failed for user "postgres"',
|
||||||
expect(response.body.error).toBeDefined()
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,10 @@ describe("sdk >> rows >> internal", () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const persistedRow = await config.getRow(table._id!, response.row._id!)
|
const persistedRow = await config.api.row.get(
|
||||||
|
table._id!,
|
||||||
|
response.row._id!
|
||||||
|
)
|
||||||
expect(persistedRow).toEqual({
|
expect(persistedRow).toEqual({
|
||||||
...row,
|
...row,
|
||||||
type: "row",
|
type: "row",
|
||||||
|
@ -157,7 +160,10 @@ describe("sdk >> rows >> internal", () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const persistedRow = await config.getRow(table._id!, response.row._id!)
|
const persistedRow = await config.api.row.get(
|
||||||
|
table._id!,
|
||||||
|
response.row._id!
|
||||||
|
)
|
||||||
expect(persistedRow).toEqual({
|
expect(persistedRow).toEqual({
|
||||||
...row,
|
...row,
|
||||||
type: "row",
|
type: "row",
|
||||||
|
|
|
@ -712,11 +712,6 @@ export default class TestConfiguration {
|
||||||
return this.api.row.save(tableId, config)
|
return this.api.row.save(tableId, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRow(tableId: string, rowId: string): Promise<Row> {
|
|
||||||
const res = await this.api.row.get(tableId, rowId)
|
|
||||||
return res.body
|
|
||||||
}
|
|
||||||
|
|
||||||
async getRows(tableId: string) {
|
async getRows(tableId: string) {
|
||||||
if (!tableId && this.table) {
|
if (!tableId && this.table) {
|
||||||
tableId = this.table._id!
|
tableId = this.table._id!
|
||||||
|
|
|
@ -1,193 +1,133 @@
|
||||||
import { Response } from "supertest"
|
|
||||||
import {
|
import {
|
||||||
App,
|
App,
|
||||||
|
PublishResponse,
|
||||||
type CreateAppRequest,
|
type CreateAppRequest,
|
||||||
type FetchAppDefinitionResponse,
|
type FetchAppDefinitionResponse,
|
||||||
type FetchAppPackageResponse,
|
type FetchAppPackageResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import TestConfiguration from "../TestConfiguration"
|
import { Expectations, TestAPI } from "./base"
|
||||||
import { TestAPI } from "./base"
|
|
||||||
import { AppStatus } from "../../../db/utils"
|
import { AppStatus } from "../../../db/utils"
|
||||||
import { constants } from "@budibase/backend-core"
|
import { constants } from "@budibase/backend-core"
|
||||||
|
|
||||||
export class ApplicationAPI extends TestAPI {
|
export class ApplicationAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
create = async (
|
||||||
super(config)
|
app: CreateAppRequest,
|
||||||
|
expectations?: Expectations
|
||||||
|
): Promise<App> => {
|
||||||
|
const files = app.templateFile ? { templateFile: app.templateFile } : {}
|
||||||
|
delete app.templateFile
|
||||||
|
return await this._post<App>("/api/applications", {
|
||||||
|
fields: app,
|
||||||
|
files,
|
||||||
|
expectations,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
create = async (app: CreateAppRequest): Promise<App> => {
|
delete = async (
|
||||||
const request = this.request
|
appId: string,
|
||||||
.post("/api/applications")
|
expectations?: Expectations
|
||||||
.set(this.config.defaultHeaders())
|
): Promise<void> => {
|
||||||
.expect("Content-Type", /json/)
|
await this._delete(`/api/applications/${appId}`, { expectations })
|
||||||
|
|
||||||
for (const key of Object.keys(app)) {
|
|
||||||
request.field(key, (app as any)[key])
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app.templateFile) {
|
|
||||||
request.attach("templateFile", app.templateFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await request
|
|
||||||
|
|
||||||
if (result.statusCode !== 200) {
|
|
||||||
throw new Error(JSON.stringify(result.body))
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.body as App
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete = async (appId: string): Promise<void> => {
|
publish = async (appId: string): Promise<PublishResponse> => {
|
||||||
await this.request
|
return await this._post<PublishResponse>(
|
||||||
.delete(`/api/applications/${appId}`)
|
`/api/applications/${appId}/publish`,
|
||||||
.set(this.config.defaultHeaders())
|
{
|
||||||
.expect(200)
|
// While the publish endpoint does take an :appId parameter, it doesn't
|
||||||
}
|
// use it. It uses the appId from the context.
|
||||||
|
headers: {
|
||||||
publish = async (
|
[constants.Header.APP_ID]: appId,
|
||||||
appId: string
|
},
|
||||||
): Promise<{ _id: string; status: string; appUrl: string }> => {
|
}
|
||||||
// While the publish endpoint does take an :appId parameter, it doesn't
|
)
|
||||||
// use it. It uses the appId from the context.
|
|
||||||
let headers = {
|
|
||||||
...this.config.defaultHeaders(),
|
|
||||||
[constants.Header.APP_ID]: appId,
|
|
||||||
}
|
|
||||||
const result = await this.request
|
|
||||||
.post(`/api/applications/${appId}/publish`)
|
|
||||||
.set(headers)
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
return result.body as { _id: string; status: string; appUrl: string }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unpublish = async (appId: string): Promise<void> => {
|
unpublish = async (appId: string): Promise<void> => {
|
||||||
await this.request
|
await this._post(`/api/applications/${appId}/unpublish`, {
|
||||||
.post(`/api/applications/${appId}/unpublish`)
|
expectations: { status: 204 },
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect(204)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sync = async (
|
sync = async (
|
||||||
appId: string,
|
appId: string,
|
||||||
{ statusCode }: { statusCode: number } = { statusCode: 200 }
|
expectations?: Expectations
|
||||||
): Promise<{ message: string }> => {
|
): Promise<{ message: string }> => {
|
||||||
const result = await this.request
|
return await this._post<{ message: string }>(
|
||||||
.post(`/api/applications/${appId}/sync`)
|
`/api/applications/${appId}/sync`,
|
||||||
.set(this.config.defaultHeaders())
|
{ expectations }
|
||||||
.expect("Content-Type", /json/)
|
)
|
||||||
.expect(statusCode)
|
|
||||||
return result.body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getRaw = async (appId: string): Promise<Response> => {
|
get = async (appId: string, expectations?: Expectations): Promise<App> => {
|
||||||
// While the appPackage endpoint does take an :appId parameter, it doesn't
|
return await this._get<App>(`/api/applications/${appId}`, {
|
||||||
// use it. It uses the appId from the context.
|
// While the get endpoint does take an :appId parameter, it doesn't use
|
||||||
let headers = {
|
// it. It uses the appId from the context.
|
||||||
...this.config.defaultHeaders(),
|
headers: {
|
||||||
[constants.Header.APP_ID]: appId,
|
[constants.Header.APP_ID]: appId,
|
||||||
}
|
},
|
||||||
const result = await this.request
|
expectations,
|
||||||
.get(`/api/applications/${appId}/appPackage`)
|
})
|
||||||
.set(headers)
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
get = async (appId: string): Promise<App> => {
|
|
||||||
const result = await this.getRaw(appId)
|
|
||||||
return result.body.application as App
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefinition = async (
|
getDefinition = async (
|
||||||
appId: string
|
appId: string,
|
||||||
|
expectations?: Expectations
|
||||||
): Promise<FetchAppDefinitionResponse> => {
|
): Promise<FetchAppDefinitionResponse> => {
|
||||||
const result = await this.request
|
return await this._get<FetchAppDefinitionResponse>(
|
||||||
.get(`/api/applications/${appId}/definition`)
|
`/api/applications/${appId}/definition`,
|
||||||
.set(this.config.defaultHeaders())
|
{ expectations }
|
||||||
.expect("Content-Type", /json/)
|
)
|
||||||
.expect(200)
|
|
||||||
return result.body as FetchAppDefinitionResponse
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAppPackage = async (appId: string): Promise<FetchAppPackageResponse> => {
|
getAppPackage = async (
|
||||||
const result = await this.request
|
appId: string,
|
||||||
.get(`/api/applications/${appId}/appPackage`)
|
expectations?: Expectations
|
||||||
.set(this.config.defaultHeaders())
|
): Promise<FetchAppPackageResponse> => {
|
||||||
.expect("Content-Type", /json/)
|
return await this._get<FetchAppPackageResponse>(
|
||||||
.expect(200)
|
`/api/applications/${appId}/appPackage`,
|
||||||
return result.body
|
{ expectations }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
update = async (
|
update = async (
|
||||||
appId: string,
|
appId: string,
|
||||||
app: { name?: string; url?: string }
|
app: { name?: string; url?: string },
|
||||||
|
expectations?: Expectations
|
||||||
): Promise<App> => {
|
): Promise<App> => {
|
||||||
const request = this.request
|
return await this._put<App>(`/api/applications/${appId}`, {
|
||||||
.put(`/api/applications/${appId}`)
|
fields: app,
|
||||||
.set(this.config.defaultHeaders())
|
expectations,
|
||||||
.expect("Content-Type", /json/)
|
})
|
||||||
|
|
||||||
for (const key of Object.keys(app)) {
|
|
||||||
request.field(key, (app as any)[key])
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await request
|
|
||||||
|
|
||||||
if (result.statusCode !== 200) {
|
|
||||||
throw new Error(JSON.stringify(result.body))
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.body as App
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateClient = async (appId: string): Promise<void> => {
|
updateClient = async (
|
||||||
// While the updateClient endpoint does take an :appId parameter, it doesn't
|
appId: string,
|
||||||
// use it. It uses the appId from the context.
|
expectations?: Expectations
|
||||||
let headers = {
|
): Promise<void> => {
|
||||||
...this.config.defaultHeaders(),
|
await this._post(`/api/applications/${appId}/client/update`, {
|
||||||
[constants.Header.APP_ID]: appId,
|
// While the updateClient endpoint does take an :appId parameter, it doesn't
|
||||||
}
|
// use it. It uses the appId from the context.
|
||||||
const response = await this.request
|
headers: {
|
||||||
.post(`/api/applications/${appId}/client/update`)
|
[constants.Header.APP_ID]: appId,
|
||||||
.set(headers)
|
},
|
||||||
.expect("Content-Type", /json/)
|
expectations,
|
||||||
|
})
|
||||||
if (response.statusCode !== 200) {
|
|
||||||
throw new Error(JSON.stringify(response.body))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
revertClient = async (appId: string): Promise<void> => {
|
revertClient = async (appId: string): Promise<void> => {
|
||||||
// While the revertClient endpoint does take an :appId parameter, it doesn't
|
await this._post(`/api/applications/${appId}/client/revert`, {
|
||||||
// use it. It uses the appId from the context.
|
// While the revertClient endpoint does take an :appId parameter, it doesn't
|
||||||
let headers = {
|
// use it. It uses the appId from the context.
|
||||||
...this.config.defaultHeaders(),
|
headers: {
|
||||||
[constants.Header.APP_ID]: appId,
|
[constants.Header.APP_ID]: appId,
|
||||||
}
|
},
|
||||||
const response = await this.request
|
})
|
||||||
.post(`/api/applications/${appId}/client/revert`)
|
|
||||||
.set(headers)
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
|
|
||||||
if (response.statusCode !== 200) {
|
|
||||||
throw new Error(JSON.stringify(response.body))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch = async ({ status }: { status?: AppStatus } = {}): Promise<App[]> => {
|
fetch = async ({ status }: { status?: AppStatus } = {}): Promise<App[]> => {
|
||||||
let query = []
|
return await this._get<App[]>("/api/applications", {
|
||||||
if (status) {
|
query: { status },
|
||||||
query.push(`status=${status}`)
|
})
|
||||||
}
|
|
||||||
|
|
||||||
const result = await this.request
|
|
||||||
.get(`/api/applications${query.length ? `?${query.join("&")}` : ""}`)
|
|
||||||
.set(this.config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
return result.body as App[]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,16 @@
|
||||||
import {
|
import { ProcessAttachmentResponse } from "@budibase/types"
|
||||||
APIError,
|
import { Expectations, TestAPI } from "./base"
|
||||||
Datasource,
|
|
||||||
ProcessAttachmentResponse,
|
|
||||||
} from "@budibase/types"
|
|
||||||
import TestConfiguration from "../TestConfiguration"
|
|
||||||
import { TestAPI } from "./base"
|
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
|
|
||||||
export class AttachmentAPI extends TestAPI {
|
export class AttachmentAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
|
||||||
super(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
process = async (
|
process = async (
|
||||||
name: string,
|
name: string,
|
||||||
file: Buffer | fs.ReadStream | string,
|
file: Buffer | fs.ReadStream | string,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<ProcessAttachmentResponse> => {
|
): Promise<ProcessAttachmentResponse> => {
|
||||||
const result = await this.request
|
return await this._post(`/api/attachments/process`, {
|
||||||
.post(`/api/attachments/process`)
|
files: { file: { name, file } },
|
||||||
.attach("file", file, name)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
|
|
||||||
if (result.statusCode !== expectStatus) {
|
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
result.statusCode
|
|
||||||
}, body: ${JSON.stringify(result.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.body
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,42 +2,38 @@ import {
|
||||||
CreateAppBackupResponse,
|
CreateAppBackupResponse,
|
||||||
ImportAppBackupResponse,
|
ImportAppBackupResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import TestConfiguration from "../TestConfiguration"
|
import { Expectations, TestAPI } from "./base"
|
||||||
import { TestAPI } from "./base"
|
|
||||||
|
|
||||||
export class BackupAPI extends TestAPI {
|
export class BackupAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
exportBasicBackup = async (appId: string, expectations?: Expectations) => {
|
||||||
super(config)
|
const exp = {
|
||||||
}
|
...expectations,
|
||||||
|
headers: {
|
||||||
exportBasicBackup = async (appId: string) => {
|
...expectations?.headers,
|
||||||
const result = await this.request
|
"Content-Type": "application/gzip",
|
||||||
.post(`/api/backups/export?appId=${appId}`)
|
},
|
||||||
.set(this.config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /application\/gzip/)
|
|
||||||
.expect(200)
|
|
||||||
return {
|
|
||||||
body: result.body as Buffer,
|
|
||||||
headers: result.headers,
|
|
||||||
}
|
}
|
||||||
|
return await this._post<Buffer>(`/api/backups/export`, {
|
||||||
|
query: { appId },
|
||||||
|
expectations: exp,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
createBackup = async (appId: string) => {
|
createBackup = async (appId: string, expectations?: Expectations) => {
|
||||||
const result = await this.request
|
return await this._post<CreateAppBackupResponse>(
|
||||||
.post(`/api/apps/${appId}/backups`)
|
`/api/apps/${appId}/backups`,
|
||||||
.set(this.config.defaultHeaders())
|
{ expectations }
|
||||||
.expect("Content-Type", /json/)
|
)
|
||||||
.expect(200)
|
|
||||||
return result.body as CreateAppBackupResponse
|
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForBackupToComplete = async (appId: string, backupId: string) => {
|
waitForBackupToComplete = async (appId: string, backupId: string) => {
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||||
const result = await this.request
|
const response = await this._requestRaw(
|
||||||
.get(`/api/apps/${appId}/backups/${backupId}/file`)
|
"get",
|
||||||
.set(this.config.defaultHeaders())
|
`/api/apps/${appId}/backups/${backupId}/file`
|
||||||
if (result.status === 200) {
|
)
|
||||||
|
if (response.status === 200) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,13 +42,12 @@ export class BackupAPI extends TestAPI {
|
||||||
|
|
||||||
importBackup = async (
|
importBackup = async (
|
||||||
appId: string,
|
appId: string,
|
||||||
backupId: string
|
backupId: string,
|
||||||
|
expectations?: Expectations
|
||||||
): Promise<ImportAppBackupResponse> => {
|
): Promise<ImportAppBackupResponse> => {
|
||||||
const result = await this.request
|
return await this._post<ImportAppBackupResponse>(
|
||||||
.post(`/api/apps/${appId}/backups/${backupId}/import`)
|
`/api/apps/${appId}/backups/${backupId}/import`,
|
||||||
.set(this.config.defaultHeaders())
|
{ expectations }
|
||||||
.expect("Content-Type", /json/)
|
)
|
||||||
.expect(200)
|
|
||||||
return result.body as ImportAppBackupResponse
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,196 @@
|
||||||
import TestConfiguration from "../TestConfiguration"
|
import TestConfiguration from "../TestConfiguration"
|
||||||
import { SuperTest, Test } from "supertest"
|
import { SuperTest, Test, Response } from "supertest"
|
||||||
|
import { ReadStream } from "fs"
|
||||||
|
|
||||||
export interface TestAPIOpts {
|
type Headers = Record<string, string | string[] | undefined>
|
||||||
headers?: any
|
type Method = "get" | "post" | "put" | "patch" | "delete"
|
||||||
|
|
||||||
|
export interface AttachedFile {
|
||||||
|
name: string
|
||||||
|
file: Buffer | ReadStream | string
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAttachedFile(file: any): file is AttachedFile {
|
||||||
|
if (file === undefined) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const attachedFile = file as AttachedFile
|
||||||
|
return (
|
||||||
|
Object.hasOwnProperty.call(attachedFile, "file") &&
|
||||||
|
Object.hasOwnProperty.call(attachedFile, "name")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Expectations {
|
||||||
status?: number
|
status?: number
|
||||||
|
headers?: Record<string, string | RegExp>
|
||||||
|
headersNotPresent?: string[]
|
||||||
|
body?: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RequestOpts {
|
||||||
|
headers?: Headers
|
||||||
|
query?: Record<string, string | undefined>
|
||||||
|
body?: Record<string, any>
|
||||||
|
fields?: Record<string, any>
|
||||||
|
files?: Record<
|
||||||
|
string,
|
||||||
|
Buffer | ReadStream | string | AttachedFile | undefined
|
||||||
|
>
|
||||||
|
expectations?: Expectations
|
||||||
|
publicUser?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class TestAPI {
|
export abstract class TestAPI {
|
||||||
config: TestConfiguration
|
config: TestConfiguration
|
||||||
request: SuperTest<Test>
|
request: SuperTest<Test>
|
||||||
|
|
||||||
protected constructor(config: TestConfiguration) {
|
constructor(config: TestConfiguration) {
|
||||||
this.config = config
|
this.config = config
|
||||||
this.request = config.request!
|
this.request = config.request!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected _get = async <T>(url: string, opts?: RequestOpts): Promise<T> => {
|
||||||
|
return await this._request<T>("get", url, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _post = async <T>(url: string, opts?: RequestOpts): Promise<T> => {
|
||||||
|
return await this._request<T>("post", url, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _put = async <T>(url: string, opts?: RequestOpts): Promise<T> => {
|
||||||
|
return await this._request<T>("put", url, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _patch = async <T>(url: string, opts?: RequestOpts): Promise<T> => {
|
||||||
|
return await this._request<T>("patch", url, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _delete = async <T>(
|
||||||
|
url: string,
|
||||||
|
opts?: RequestOpts
|
||||||
|
): Promise<T> => {
|
||||||
|
return await this._request<T>("delete", url, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _requestRaw = async (
|
||||||
|
method: "get" | "post" | "put" | "patch" | "delete",
|
||||||
|
url: string,
|
||||||
|
opts?: RequestOpts
|
||||||
|
): Promise<Response> => {
|
||||||
|
const {
|
||||||
|
headers = {},
|
||||||
|
query = {},
|
||||||
|
body,
|
||||||
|
fields = {},
|
||||||
|
files = {},
|
||||||
|
expectations,
|
||||||
|
publicUser = false,
|
||||||
|
} = opts || {}
|
||||||
|
const { status = 200 } = expectations || {}
|
||||||
|
const expectHeaders = expectations?.headers || {}
|
||||||
|
|
||||||
|
if (status !== 204 && !expectHeaders["Content-Type"]) {
|
||||||
|
expectHeaders["Content-Type"] = /^application\/json/
|
||||||
|
}
|
||||||
|
|
||||||
|
let queryParams = []
|
||||||
|
for (const [key, value] of Object.entries(query)) {
|
||||||
|
if (value) {
|
||||||
|
queryParams.push(`${key}=${value}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (queryParams.length) {
|
||||||
|
url += `?${queryParams.join("&")}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const headersFn = publicUser
|
||||||
|
? this.config.publicHeaders.bind(this.config)
|
||||||
|
: this.config.defaultHeaders.bind(this.config)
|
||||||
|
let request = this.request[method](url).set(
|
||||||
|
headersFn({
|
||||||
|
"x-budibase-include-stacktrace": "true",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
if (headers) {
|
||||||
|
request = request.set(headers)
|
||||||
|
}
|
||||||
|
if (body) {
|
||||||
|
request = request.send(body)
|
||||||
|
}
|
||||||
|
for (const [key, value] of Object.entries(fields)) {
|
||||||
|
request = request.field(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(files)) {
|
||||||
|
if (isAttachedFile(value)) {
|
||||||
|
request = request.attach(key, value.file, value.name)
|
||||||
|
} else {
|
||||||
|
request = request.attach(key, value as any)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expectations?.headers) {
|
||||||
|
for (const [key, value] of Object.entries(expectations.headers)) {
|
||||||
|
if (value === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
`Got an undefined expected value for header "${key}", if you want to check for the absence of a header, use headersNotPresent`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
request = request.expect(key, value as any)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return await request
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _request = async <T>(
|
||||||
|
method: Method,
|
||||||
|
url: string,
|
||||||
|
opts?: RequestOpts
|
||||||
|
): Promise<T> => {
|
||||||
|
const { expectations } = opts || {}
|
||||||
|
const { status = 200 } = expectations || {}
|
||||||
|
|
||||||
|
const response = await this._requestRaw(method, url, opts)
|
||||||
|
|
||||||
|
if (response.status !== status) {
|
||||||
|
let message = `Expected status ${status} but got ${response.status}`
|
||||||
|
|
||||||
|
const stack = response.body.stack
|
||||||
|
delete response.body.stack
|
||||||
|
|
||||||
|
if (response.body) {
|
||||||
|
message += `\n\nBody:`
|
||||||
|
const body = JSON.stringify(response.body, null, 2)
|
||||||
|
for (const line of body.split("\n")) {
|
||||||
|
message += `\n⏐ ${line}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack) {
|
||||||
|
message += `\n\nStack from request handler:`
|
||||||
|
for (const line of stack.split("\n")) {
|
||||||
|
message += `\n⏐ ${line}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectations?.headersNotPresent) {
|
||||||
|
for (const header of expectations.headersNotPresent) {
|
||||||
|
if (response.headers[header]) {
|
||||||
|
throw new Error(
|
||||||
|
`Expected header ${header} not to be present, found value "${response.headers[header]}"`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectations?.body) {
|
||||||
|
expect(response.body).toMatchObject(expectations.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.body
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +1,48 @@
|
||||||
import {
|
import {
|
||||||
CreateDatasourceRequest,
|
|
||||||
Datasource,
|
Datasource,
|
||||||
VerifyDatasourceRequest,
|
VerifyDatasourceRequest,
|
||||||
|
CreateDatasourceResponse,
|
||||||
|
UpdateDatasourceResponse,
|
||||||
|
UpdateDatasourceRequest,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import TestConfiguration from "../TestConfiguration"
|
import { Expectations, TestAPI } from "./base"
|
||||||
import { TestAPI } from "./base"
|
|
||||||
import supertest from "supertest"
|
|
||||||
|
|
||||||
export class DatasourceAPI extends TestAPI {
|
export class DatasourceAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
create = async (
|
||||||
super(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
create = async <B extends boolean = false>(
|
|
||||||
config: Datasource,
|
config: Datasource,
|
||||||
{
|
expectations?: Expectations
|
||||||
expectStatus,
|
): Promise<Datasource> => {
|
||||||
rawResponse,
|
const response = await this._post<CreateDatasourceResponse>(
|
||||||
}: { expectStatus?: number; rawResponse?: B } = {}
|
`/api/datasources`,
|
||||||
): Promise<B extends false ? Datasource : supertest.Response> => {
|
{
|
||||||
const body: CreateDatasourceRequest = {
|
body: {
|
||||||
datasource: config,
|
datasource: config,
|
||||||
tablesFilter: [],
|
tablesFilter: [],
|
||||||
}
|
},
|
||||||
const result = await this.request
|
expectations,
|
||||||
.post(`/api/datasources`)
|
}
|
||||||
.send(body)
|
)
|
||||||
.set(this.config.defaultHeaders())
|
return response.datasource
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(expectStatus || 200)
|
|
||||||
if (rawResponse) {
|
|
||||||
return result as any
|
|
||||||
}
|
|
||||||
return result.body.datasource
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update = async (
|
update = async (
|
||||||
datasource: Datasource,
|
datasource: UpdateDatasourceRequest,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<Datasource> => {
|
): Promise<Datasource> => {
|
||||||
const result = await this.request
|
const response = await this._put<UpdateDatasourceResponse>(
|
||||||
.put(`/api/datasources/${datasource._id}`)
|
`/api/datasources/${datasource._id}`,
|
||||||
.send(datasource)
|
{ body: datasource, expectations }
|
||||||
.set(this.config.defaultHeaders())
|
)
|
||||||
.expect("Content-Type", /json/)
|
return response.datasource
|
||||||
.expect(expectStatus)
|
|
||||||
return result.body.datasource as Datasource
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verify = async (
|
verify = async (
|
||||||
data: VerifyDatasourceRequest,
|
data: VerifyDatasourceRequest,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
) => {
|
) => {
|
||||||
const result = await this.request
|
return await this._post(`/api/datasources/verify`, {
|
||||||
.post(`/api/datasources/verify`)
|
body: data,
|
||||||
.send(data)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(expectStatus)
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,8 @@
|
||||||
import TestConfiguration from "../TestConfiguration"
|
import { Expectations, TestAPI } from "./base"
|
||||||
import { TestAPI } from "./base"
|
import { Row } from "@budibase/types"
|
||||||
|
|
||||||
export class LegacyViewAPI extends TestAPI {
|
export class LegacyViewAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
get = async (id: string, expectations?: Expectations) => {
|
||||||
super(config)
|
return await this._get<Row[]>(`/api/views/${id}`, { expectations })
|
||||||
}
|
|
||||||
|
|
||||||
get = async (id: string, { expectStatus } = { expectStatus: 200 }) => {
|
|
||||||
return await this.request
|
|
||||||
.get(`/api/views/${id}`)
|
|
||||||
.set(this.config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(expectStatus)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +1,39 @@
|
||||||
import { AnyDocument, PermissionLevel } from "@budibase/types"
|
import {
|
||||||
import TestConfiguration from "../TestConfiguration"
|
AddPermissionRequest,
|
||||||
import { TestAPI } from "./base"
|
AddPermissionResponse,
|
||||||
|
GetResourcePermsResponse,
|
||||||
|
RemovePermissionRequest,
|
||||||
|
RemovePermissionResponse,
|
||||||
|
} from "@budibase/types"
|
||||||
|
import { Expectations, TestAPI } from "./base"
|
||||||
|
|
||||||
export class PermissionAPI extends TestAPI {
|
export class PermissionAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
get = async (resourceId: string, expectations?: Expectations) => {
|
||||||
super(config)
|
return await this._get<GetResourcePermsResponse>(
|
||||||
|
`/api/permission/${resourceId}`,
|
||||||
|
{ expectations }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get = async (
|
add = async (
|
||||||
resourceId: string,
|
request: AddPermissionRequest,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
) => {
|
): Promise<AddPermissionResponse> => {
|
||||||
return this.request
|
const { roleId, resourceId, level } = request
|
||||||
.get(`/api/permission/${resourceId}`)
|
return await this._post<AddPermissionResponse>(
|
||||||
.set(this.config.defaultHeaders())
|
`/api/permission/${roleId}/${resourceId}/${level}`,
|
||||||
.expect("Content-Type", /json/)
|
{ expectations }
|
||||||
.expect(expectStatus)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
set = async (
|
|
||||||
{
|
|
||||||
roleId,
|
|
||||||
resourceId,
|
|
||||||
level,
|
|
||||||
}: { roleId: string; resourceId: string; level: PermissionLevel },
|
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
|
||||||
): Promise<any> => {
|
|
||||||
const res = await this.request
|
|
||||||
.post(`/api/permission/${roleId}/${resourceId}/${level}`)
|
|
||||||
.set(this.config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(expectStatus)
|
|
||||||
return res.body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
revoke = async (
|
revoke = async (
|
||||||
{
|
request: RemovePermissionRequest,
|
||||||
roleId,
|
expectations?: Expectations
|
||||||
resourceId,
|
|
||||||
level,
|
|
||||||
}: { roleId: string; resourceId: string; level: PermissionLevel },
|
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
|
||||||
) => {
|
) => {
|
||||||
const res = await this.request
|
const { roleId, resourceId, level } = request
|
||||||
.delete(`/api/permission/${roleId}/${resourceId}/${level}`)
|
return await this._delete<RemovePermissionResponse>(
|
||||||
.set(this.config.defaultHeaders())
|
`/api/permission/${roleId}/${resourceId}/${level}`,
|
||||||
.expect("Content-Type", /json/)
|
{ expectations }
|
||||||
.expect(expectStatus)
|
)
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +1,32 @@
|
||||||
import TestConfiguration from "../TestConfiguration"
|
|
||||||
import {
|
import {
|
||||||
Query,
|
Query,
|
||||||
QueryPreview,
|
ExecuteQueryRequest,
|
||||||
type ExecuteQueryRequest,
|
ExecuteQueryResponse,
|
||||||
type ExecuteQueryResponse,
|
PreviewQueryRequest,
|
||||||
|
PreviewQueryResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { TestAPI } from "./base"
|
import { TestAPI } from "./base"
|
||||||
|
|
||||||
export class QueryAPI extends TestAPI {
|
export class QueryAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
|
||||||
super(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
create = async (body: Query): Promise<Query> => {
|
create = async (body: Query): Promise<Query> => {
|
||||||
const res = await this.request
|
return await this._post<Query>(`/api/queries`, { body })
|
||||||
.post(`/api/queries`)
|
|
||||||
.set(this.config.defaultHeaders())
|
|
||||||
.send(body)
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
|
|
||||||
if (res.status !== 200) {
|
|
||||||
throw new Error(JSON.stringify(res.body))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body as Query
|
|
||||||
}
|
}
|
||||||
|
|
||||||
execute = async (
|
execute = async (
|
||||||
queryId: string,
|
queryId: string,
|
||||||
body?: ExecuteQueryRequest
|
body?: ExecuteQueryRequest
|
||||||
): Promise<ExecuteQueryResponse> => {
|
): Promise<ExecuteQueryResponse> => {
|
||||||
const res = await this.request
|
return await this._post<ExecuteQueryResponse>(
|
||||||
.post(`/api/v2/queries/${queryId}`)
|
`/api/v2/queries/${queryId}`,
|
||||||
.set(this.config.defaultHeaders())
|
{
|
||||||
.send(body)
|
body,
|
||||||
.expect("Content-Type", /json/)
|
}
|
||||||
|
)
|
||||||
if (res.status !== 200) {
|
|
||||||
throw new Error(JSON.stringify(res.body))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
previewQuery = async (queryPreview: QueryPreview) => {
|
previewQuery = async (queryPreview: PreviewQueryRequest) => {
|
||||||
const res = await this.request
|
return await this._post<PreviewQueryResponse>(`/api/queries/preview`, {
|
||||||
.post(`/api/queries/preview`)
|
body: queryPreview,
|
||||||
.send(queryPreview)
|
})
|
||||||
.set(this.config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
if (res.status !== 200) {
|
|
||||||
throw new Error(JSON.stringify(res.body))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,162 +8,140 @@ import {
|
||||||
BulkImportResponse,
|
BulkImportResponse,
|
||||||
SearchRowResponse,
|
SearchRowResponse,
|
||||||
SearchParams,
|
SearchParams,
|
||||||
|
DeleteRowRequest,
|
||||||
|
DeleteRows,
|
||||||
|
DeleteRow,
|
||||||
|
ExportRowsResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import TestConfiguration from "../TestConfiguration"
|
import { Expectations, TestAPI } from "./base"
|
||||||
import { TestAPI } from "./base"
|
|
||||||
|
|
||||||
export class RowAPI extends TestAPI {
|
export class RowAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
|
||||||
super(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
get = async (
|
get = async (
|
||||||
sourceId: string,
|
sourceId: string,
|
||||||
rowId: string,
|
rowId: string,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
) => {
|
) => {
|
||||||
const request = this.request
|
return await this._get<Row>(`/api/${sourceId}/rows/${rowId}`, {
|
||||||
.get(`/api/${sourceId}/rows/${rowId}`)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect(expectStatus)
|
|
||||||
if (expectStatus !== 404) {
|
|
||||||
request.expect("Content-Type", /json/)
|
|
||||||
}
|
|
||||||
return request
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getEnriched = async (
|
getEnriched = async (
|
||||||
sourceId: string,
|
sourceId: string,
|
||||||
rowId: string,
|
rowId: string,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
) => {
|
) => {
|
||||||
const request = this.request
|
return await this._get<Row>(`/api/${sourceId}/${rowId}/enrich`, {
|
||||||
.get(`/api/${sourceId}/${rowId}/enrich`)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect(expectStatus)
|
|
||||||
if (expectStatus !== 404) {
|
|
||||||
request.expect("Content-Type", /json/)
|
|
||||||
}
|
|
||||||
return request
|
|
||||||
}
|
}
|
||||||
|
|
||||||
save = async (
|
save = async (
|
||||||
tableId: string,
|
tableId: string,
|
||||||
row: SaveRowRequest,
|
row: SaveRowRequest,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<Row> => {
|
): Promise<Row> => {
|
||||||
const resp = await this.request
|
return await this._post<Row>(`/api/${tableId}/rows`, {
|
||||||
.post(`/api/${tableId}/rows`)
|
body: row,
|
||||||
.send(row)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
if (resp.status !== expectStatus) {
|
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
resp.status
|
|
||||||
}, body: ${JSON.stringify(resp.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return resp.body as Row
|
|
||||||
}
|
}
|
||||||
|
|
||||||
validate = async (
|
validate = async (
|
||||||
sourceId: string,
|
sourceId: string,
|
||||||
row: SaveRowRequest,
|
row: SaveRowRequest,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<ValidateResponse> => {
|
): Promise<ValidateResponse> => {
|
||||||
const resp = await this.request
|
return await this._post<ValidateResponse>(
|
||||||
.post(`/api/${sourceId}/rows/validate`)
|
`/api/${sourceId}/rows/validate`,
|
||||||
.send(row)
|
{
|
||||||
.set(this.config.defaultHeaders())
|
body: row,
|
||||||
.expect("Content-Type", /json/)
|
expectations,
|
||||||
.expect(expectStatus)
|
}
|
||||||
return resp.body as ValidateResponse
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
patch = async (
|
patch = async (
|
||||||
sourceId: string,
|
sourceId: string,
|
||||||
row: PatchRowRequest,
|
row: PatchRowRequest,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<Row> => {
|
): Promise<Row> => {
|
||||||
let resp = await this.request
|
return await this._patch<Row>(`/api/${sourceId}/rows`, {
|
||||||
.patch(`/api/${sourceId}/rows`)
|
body: row,
|
||||||
.send(row)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
if (resp.status !== expectStatus) {
|
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
resp.status
|
|
||||||
}, body: ${JSON.stringify(resp.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return resp.body as Row
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete = async (
|
delete = async (
|
||||||
sourceId: string,
|
sourceId: string,
|
||||||
rows: Row | string | (Row | string)[],
|
row: DeleteRow,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
) => {
|
) => {
|
||||||
return this.request
|
return await this._delete<Row>(`/api/${sourceId}/rows`, {
|
||||||
.delete(`/api/${sourceId}/rows`)
|
body: row,
|
||||||
.send(Array.isArray(rows) ? { rows } : rows)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect("Content-Type", /json/)
|
}
|
||||||
.expect(expectStatus)
|
|
||||||
|
bulkDelete = async (
|
||||||
|
sourceId: string,
|
||||||
|
body: DeleteRows,
|
||||||
|
expectations?: Expectations
|
||||||
|
) => {
|
||||||
|
return await this._delete<Row[]>(`/api/${sourceId}/rows`, {
|
||||||
|
body,
|
||||||
|
expectations,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch = async (
|
fetch = async (
|
||||||
sourceId: string,
|
sourceId: string,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<Row[]> => {
|
): Promise<Row[]> => {
|
||||||
const request = this.request
|
return await this._get<Row[]>(`/api/${sourceId}/rows`, {
|
||||||
.get(`/api/${sourceId}/rows`)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect(expectStatus)
|
|
||||||
|
|
||||||
return (await request).body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exportRows = async (
|
exportRows = async (
|
||||||
tableId: string,
|
tableId: string,
|
||||||
body: ExportRowsRequest,
|
body: ExportRowsRequest,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
) => {
|
) => {
|
||||||
const request = this.request
|
const response = await this._requestRaw(
|
||||||
.post(`/api/${tableId}/rows/exportRows?format=json`)
|
"post",
|
||||||
.set(this.config.defaultHeaders())
|
`/api/${tableId}/rows/exportRows`,
|
||||||
.send(body)
|
{
|
||||||
.expect("Content-Type", /json/)
|
body,
|
||||||
.expect(expectStatus)
|
query: { format: "json" },
|
||||||
return request
|
expectations,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return response.text
|
||||||
}
|
}
|
||||||
|
|
||||||
bulkImport = async (
|
bulkImport = async (
|
||||||
tableId: string,
|
tableId: string,
|
||||||
body: BulkImportRequest,
|
body: BulkImportRequest,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<BulkImportResponse> => {
|
): Promise<BulkImportResponse> => {
|
||||||
let request = this.request
|
return await this._post<BulkImportResponse>(
|
||||||
.post(`/api/tables/${tableId}/import`)
|
`/api/tables/${tableId}/import`,
|
||||||
.send(body)
|
{
|
||||||
.set(this.config.defaultHeaders())
|
body,
|
||||||
.expect(expectStatus)
|
expectations,
|
||||||
return (await request).body
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
search = async (
|
search = async (
|
||||||
sourceId: string,
|
sourceId: string,
|
||||||
params?: SearchParams,
|
params?: SearchParams,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<SearchRowResponse> => {
|
): Promise<SearchRowResponse> => {
|
||||||
const request = this.request
|
return await this._post<SearchRowResponse>(`/api/${sourceId}/search`, {
|
||||||
.post(`/api/${sourceId}/search`)
|
body: params,
|
||||||
.send(params)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect(expectStatus)
|
|
||||||
|
|
||||||
return (await request).body
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,8 @@
|
||||||
import TestConfiguration from "../TestConfiguration"
|
|
||||||
import { Screen } from "@budibase/types"
|
import { Screen } from "@budibase/types"
|
||||||
import { TestAPI } from "./base"
|
import { Expectations, TestAPI } from "./base"
|
||||||
|
|
||||||
export class ScreenAPI extends TestAPI {
|
export class ScreenAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
list = async (expectations?: Expectations): Promise<Screen[]> => {
|
||||||
super(config)
|
return await this._get<Screen[]>(`/api/screens`, { expectations })
|
||||||
}
|
|
||||||
|
|
||||||
list = async (): Promise<Screen[]> => {
|
|
||||||
const res = await this.request
|
|
||||||
.get(`/api/screens`)
|
|
||||||
.set(this.config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
return res.body as Screen[]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,74 +5,38 @@ import {
|
||||||
SaveTableResponse,
|
SaveTableResponse,
|
||||||
Table,
|
Table,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import TestConfiguration from "../TestConfiguration"
|
import { Expectations, TestAPI } from "./base"
|
||||||
import { TestAPI } from "./base"
|
|
||||||
|
|
||||||
export class TableAPI extends TestAPI {
|
export class TableAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
|
||||||
super(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
save = async (
|
save = async (
|
||||||
data: SaveTableRequest,
|
data: SaveTableRequest,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<SaveTableResponse> => {
|
): Promise<SaveTableResponse> => {
|
||||||
const res = await this.request
|
return await this._post<SaveTableResponse>("/api/tables", {
|
||||||
.post(`/api/tables`)
|
body: data,
|
||||||
.send(data)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
|
|
||||||
if (res.status !== expectStatus) {
|
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
res.status
|
|
||||||
} with body ${JSON.stringify(res.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch = async (
|
fetch = async (expectations?: Expectations): Promise<Table[]> => {
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
return await this._get<Table[]>("/api/tables", { expectations })
|
||||||
): Promise<Table[]> => {
|
|
||||||
const res = await this.request
|
|
||||||
.get(`/api/tables`)
|
|
||||||
.set(this.config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(expectStatus)
|
|
||||||
return res.body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get = async (
|
get = async (
|
||||||
tableId: string,
|
tableId: string,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<Table> => {
|
): Promise<Table> => {
|
||||||
const res = await this.request
|
return await this._get<Table>(`/api/tables/${tableId}`, { expectations })
|
||||||
.get(`/api/tables/${tableId}`)
|
|
||||||
.set(this.config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(expectStatus)
|
|
||||||
return res.body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
migrate = async (
|
migrate = async (
|
||||||
tableId: string,
|
tableId: string,
|
||||||
data: MigrateRequest,
|
data: MigrateRequest,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<MigrateResponse> => {
|
): Promise<MigrateResponse> => {
|
||||||
const res = await this.request
|
return await this._post<MigrateResponse>(`/api/tables/${tableId}/migrate`, {
|
||||||
.post(`/api/tables/${tableId}/migrate`)
|
body: data,
|
||||||
.send(data)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
if (res.status !== expectStatus) {
|
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
res.status
|
|
||||||
} with body ${JSON.stringify(res.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return res.body
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,154 +4,79 @@ import {
|
||||||
Flags,
|
Flags,
|
||||||
UserMetadata,
|
UserMetadata,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import TestConfiguration from "../TestConfiguration"
|
import { Expectations, TestAPI } from "./base"
|
||||||
import { TestAPI } from "./base"
|
|
||||||
import { DocumentInsertResponse } from "@budibase/nano"
|
import { DocumentInsertResponse } from "@budibase/nano"
|
||||||
|
|
||||||
export class UserAPI extends TestAPI {
|
export class UserAPI extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
|
||||||
super(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch = async (
|
fetch = async (
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<FetchUserMetadataResponse> => {
|
): Promise<FetchUserMetadataResponse> => {
|
||||||
const res = await this.request
|
return await this._get<FetchUserMetadataResponse>("/api/users/metadata", {
|
||||||
.get(`/api/users/metadata`)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
|
|
||||||
if (res.status !== expectStatus) {
|
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
res.status
|
|
||||||
} with body ${JSON.stringify(res.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
find = async (
|
find = async (
|
||||||
id: string,
|
id: string,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<FindUserMetadataResponse> => {
|
): Promise<FindUserMetadataResponse> => {
|
||||||
const res = await this.request
|
return await this._get<FindUserMetadataResponse>(
|
||||||
.get(`/api/users/metadata/${id}`)
|
`/api/users/metadata/${id}`,
|
||||||
.set(this.config.defaultHeaders())
|
{
|
||||||
.expect("Content-Type", /json/)
|
expectations,
|
||||||
|
}
|
||||||
if (res.status !== expectStatus) {
|
)
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
res.status
|
|
||||||
} with body ${JSON.stringify(res.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update = async (
|
update = async (
|
||||||
user: UserMetadata,
|
user: UserMetadata,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<DocumentInsertResponse> => {
|
): Promise<DocumentInsertResponse> => {
|
||||||
const res = await this.request
|
return await this._put<DocumentInsertResponse>("/api/users/metadata", {
|
||||||
.put(`/api/users/metadata`)
|
body: user,
|
||||||
.set(this.config.defaultHeaders())
|
expectations,
|
||||||
.send(user)
|
})
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
|
|
||||||
if (res.status !== expectStatus) {
|
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
res.status
|
|
||||||
} with body ${JSON.stringify(res.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body as DocumentInsertResponse
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSelf = async (
|
updateSelf = async (
|
||||||
user: UserMetadata,
|
user: UserMetadata,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<DocumentInsertResponse> => {
|
): Promise<DocumentInsertResponse> => {
|
||||||
const res = await this.request
|
return await this._post<DocumentInsertResponse>(
|
||||||
.post(`/api/users/metadata/self`)
|
"/api/users/metadata/self",
|
||||||
.set(this.config.defaultHeaders())
|
{
|
||||||
.send(user)
|
body: user,
|
||||||
.expect("Content-Type", /json/)
|
expectations,
|
||||||
|
}
|
||||||
if (res.status !== expectStatus) {
|
)
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
res.status
|
|
||||||
} with body ${JSON.stringify(res.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body as DocumentInsertResponse
|
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy = async (
|
destroy = async (
|
||||||
id: string,
|
id: string,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<{ message: string }> => {
|
): Promise<{ message: string }> => {
|
||||||
const res = await this.request
|
return await this._delete<{ message: string }>(
|
||||||
.delete(`/api/users/metadata/${id}`)
|
`/api/users/metadata/${id}`,
|
||||||
.set(this.config.defaultHeaders())
|
{
|
||||||
.expect("Content-Type", /json/)
|
expectations,
|
||||||
|
}
|
||||||
if (res.status !== expectStatus) {
|
)
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
res.status
|
|
||||||
} with body ${JSON.stringify(res.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body as { message: string }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setFlag = async (
|
setFlag = async (
|
||||||
flag: string,
|
flag: string,
|
||||||
value: any,
|
value: any,
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
expectations?: Expectations
|
||||||
): Promise<{ message: string }> => {
|
): Promise<{ message: string }> => {
|
||||||
const res = await this.request
|
return await this._post<{ message: string }>(`/api/users/flags`, {
|
||||||
.post(`/api/users/flags`)
|
body: { flag, value },
|
||||||
.set(this.config.defaultHeaders())
|
expectations,
|
||||||
.send({ flag, value })
|
})
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
|
|
||||||
if (res.status !== expectStatus) {
|
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
res.status
|
|
||||||
} with body ${JSON.stringify(res.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body as { message: string }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getFlags = async (
|
getFlags = async (expectations?: Expectations): Promise<Flags> => {
|
||||||
{ expectStatus } = { expectStatus: 200 }
|
return await this._get<Flags>(`/api/users/flags`, {
|
||||||
): Promise<Flags> => {
|
expectations,
|
||||||
const res = await this.request
|
})
|
||||||
.get(`/api/users/flags`)
|
|
||||||
.set(this.config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
|
|
||||||
if (res.status !== expectStatus) {
|
|
||||||
throw new Error(
|
|
||||||
`Expected status ${expectStatus} but got ${
|
|
||||||
res.status
|
|
||||||
} with body ${JSON.stringify(res.body)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.body as Flags
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,21 +3,16 @@ import {
|
||||||
UpdateViewRequest,
|
UpdateViewRequest,
|
||||||
ViewV2,
|
ViewV2,
|
||||||
SearchViewRowRequest,
|
SearchViewRowRequest,
|
||||||
|
PaginatedSearchRowResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import TestConfiguration from "../TestConfiguration"
|
import { Expectations, TestAPI } from "./base"
|
||||||
import { TestAPI } from "./base"
|
|
||||||
import { generator } from "@budibase/backend-core/tests"
|
import { generator } from "@budibase/backend-core/tests"
|
||||||
import { Response } from "superagent"
|
|
||||||
import sdk from "../../../sdk"
|
import sdk from "../../../sdk"
|
||||||
|
|
||||||
export class ViewV2API extends TestAPI {
|
export class ViewV2API extends TestAPI {
|
||||||
constructor(config: TestConfiguration) {
|
|
||||||
super(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
create = async (
|
create = async (
|
||||||
viewData?: Partial<CreateViewRequest>,
|
viewData?: Partial<CreateViewRequest>,
|
||||||
{ expectStatus } = { expectStatus: 201 }
|
expectations?: Expectations
|
||||||
): Promise<ViewV2> => {
|
): Promise<ViewV2> => {
|
||||||
let tableId = viewData?.tableId
|
let tableId = viewData?.tableId
|
||||||
if (!tableId && !this.config.table) {
|
if (!tableId && !this.config.table) {
|
||||||
|
@ -30,43 +25,36 @@ export class ViewV2API extends TestAPI {
|
||||||
name: generator.guid(),
|
name: generator.guid(),
|
||||||
...viewData,
|
...viewData,
|
||||||
}
|
}
|
||||||
const result = await this.request
|
|
||||||
.post(`/api/v2/views`)
|
const exp: Expectations = {
|
||||||
.send(view)
|
status: 201,
|
||||||
.set(this.config.defaultHeaders())
|
...expectations,
|
||||||
.expect("Content-Type", /json/)
|
}
|
||||||
.expect(expectStatus)
|
|
||||||
return result.body.data as ViewV2
|
const resp = await this._post<{ data: ViewV2 }>("/api/v2/views", {
|
||||||
|
body: view,
|
||||||
|
expectations: exp,
|
||||||
|
})
|
||||||
|
return resp.data
|
||||||
}
|
}
|
||||||
|
|
||||||
update = async (
|
update = async (
|
||||||
view: UpdateViewRequest,
|
view: UpdateViewRequest,
|
||||||
{
|
expectations?: Expectations
|
||||||
expectStatus,
|
|
||||||
handleResponse,
|
|
||||||
}: {
|
|
||||||
expectStatus: number
|
|
||||||
handleResponse?: (response: Response) => void
|
|
||||||
} = { expectStatus: 200 }
|
|
||||||
): Promise<ViewV2> => {
|
): Promise<ViewV2> => {
|
||||||
const result = await this.request
|
const resp = await this._put<{ data: ViewV2 }>(`/api/v2/views/${view.id}`, {
|
||||||
.put(`/api/v2/views/${view.id}`)
|
body: view,
|
||||||
.send(view)
|
expectations,
|
||||||
.set(this.config.defaultHeaders())
|
})
|
||||||
.expect("Content-Type", /json/)
|
return resp.data
|
||||||
.expect(expectStatus)
|
|
||||||
|
|
||||||
if (handleResponse) {
|
|
||||||
handleResponse(result)
|
|
||||||
}
|
|
||||||
return result.body.data as ViewV2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete = async (viewId: string, { expectStatus } = { expectStatus: 204 }) => {
|
delete = async (viewId: string, expectations?: Expectations) => {
|
||||||
return this.request
|
const exp = {
|
||||||
.delete(`/api/v2/views/${viewId}`)
|
status: 204,
|
||||||
.set(this.config.defaultHeaders())
|
...expectations,
|
||||||
.expect(expectStatus)
|
}
|
||||||
|
return await this._delete(`/api/v2/views/${viewId}`, { expectations: exp })
|
||||||
}
|
}
|
||||||
|
|
||||||
get = async (viewId: string) => {
|
get = async (viewId: string) => {
|
||||||
|
@ -78,17 +66,29 @@ export class ViewV2API extends TestAPI {
|
||||||
search = async (
|
search = async (
|
||||||
viewId: string,
|
viewId: string,
|
||||||
params?: SearchViewRowRequest,
|
params?: SearchViewRowRequest,
|
||||||
{ expectStatus = 200, usePublicUser = false } = {}
|
expectations?: Expectations
|
||||||
) => {
|
) => {
|
||||||
return this.request
|
return await this._post<PaginatedSearchRowResponse>(
|
||||||
.post(`/api/v2/views/${viewId}/search`)
|
`/api/v2/views/${viewId}/search`,
|
||||||
.send(params)
|
{
|
||||||
.set(
|
body: params,
|
||||||
usePublicUser
|
expectations,
|
||||||
? this.config.publicHeaders()
|
}
|
||||||
: this.config.defaultHeaders()
|
)
|
||||||
)
|
}
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(expectStatus)
|
publicSearch = async (
|
||||||
|
viewId: string,
|
||||||
|
params?: SearchViewRowRequest,
|
||||||
|
expectations?: Expectations
|
||||||
|
) => {
|
||||||
|
return await this._post<PaginatedSearchRowResponse>(
|
||||||
|
`/api/v2/views/${viewId}/search`,
|
||||||
|
{
|
||||||
|
body: params,
|
||||||
|
expectations,
|
||||||
|
publicUser: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PlanType } from "../../../sdk"
|
import { PermissionLevel, PlanType } from "../../../sdk"
|
||||||
|
|
||||||
export interface ResourcePermissionInfo {
|
export interface ResourcePermissionInfo {
|
||||||
role: string
|
role: string
|
||||||
|
@ -14,3 +14,21 @@ export interface GetResourcePermsResponse {
|
||||||
export interface GetDependantResourcesResponse {
|
export interface GetDependantResourcesResponse {
|
||||||
resourceByType?: Record<string, number>
|
resourceByType?: Record<string, number>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AddedPermission {
|
||||||
|
_id?: string
|
||||||
|
rev?: string
|
||||||
|
error?: string
|
||||||
|
reason?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AddPermissionResponse = AddedPermission[]
|
||||||
|
|
||||||
|
export interface AddPermissionRequest {
|
||||||
|
roleId: string
|
||||||
|
resourceId: string
|
||||||
|
level: PermissionLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RemovePermissionRequest extends AddPermissionRequest {}
|
||||||
|
export interface RemovePermissionResponse extends AddPermissionResponse {}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { SearchFilters, SearchParams } from "../../../sdk"
|
import { SearchFilters, SearchParams } from "../../../sdk"
|
||||||
import { Row } from "../../../documents"
|
import { Row } from "../../../documents"
|
||||||
import { SortOrder } from "../../../api"
|
import { PaginationResponse, SortOrder } from "../../../api"
|
||||||
import { ReadStream } from "fs"
|
import { ReadStream } from "fs"
|
||||||
|
|
||||||
export interface SaveRowRequest extends Row {}
|
export interface SaveRowRequest extends Row {}
|
||||||
|
@ -31,6 +31,10 @@ export interface SearchRowResponse {
|
||||||
rows: any[]
|
rows: any[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PaginatedSearchRowResponse
|
||||||
|
extends SearchRowResponse,
|
||||||
|
PaginationResponse {}
|
||||||
|
|
||||||
export interface ExportRowsRequest {
|
export interface ExportRowsRequest {
|
||||||
rows: string[]
|
rows: string[]
|
||||||
columns?: string[]
|
columns?: string[]
|
||||||
|
|
|
@ -27,3 +27,9 @@ export interface FetchAppPackageResponse {
|
||||||
clientLibPath: string
|
clientLibPath: string
|
||||||
hasLock: boolean
|
hasLock: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PublishResponse {
|
||||||
|
_id: string
|
||||||
|
status: string
|
||||||
|
appUrl: string
|
||||||
|
}
|
||||||
|
|
|
@ -13,3 +13,4 @@ export * from "./searchFilter"
|
||||||
export * from "./cookies"
|
export * from "./cookies"
|
||||||
export * from "./automation"
|
export * from "./automation"
|
||||||
export * from "./layout"
|
export * from "./layout"
|
||||||
|
export * from "./query"
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { QueryPreview, QuerySchema } from "../../documents"
|
||||||
|
|
||||||
|
export interface PreviewQueryRequest extends QueryPreview {}
|
||||||
|
|
||||||
|
export interface PreviewQueryResponse {
|
||||||
|
rows: any[]
|
||||||
|
nestedSchemaFields: { [key: string]: { [key: string]: string | QuerySchema } }
|
||||||
|
schema: { [key: string]: string | QuerySchema }
|
||||||
|
info: any
|
||||||
|
extra: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExecuteQueryRequest {
|
||||||
|
parameters?: { [key: string]: string }
|
||||||
|
pagination?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExecuteQueryResponse {
|
||||||
|
data: Record<string, any>[]
|
||||||
|
}
|
|
@ -62,22 +62,6 @@ export interface PaginationValues {
|
||||||
limit: number | null
|
limit: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PreviewQueryRequest extends Omit<Query, "parameters"> {
|
|
||||||
parameters: {}
|
|
||||||
flags?: {
|
|
||||||
urlName?: boolean
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExecuteQueryRequest {
|
|
||||||
parameters?: { [key: string]: string }
|
|
||||||
pagination?: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExecuteQueryResponse {
|
|
||||||
data: Row[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum HttpMethod {
|
export enum HttpMethod {
|
||||||
GET = "GET",
|
GET = "GET",
|
||||||
POST = "POST",
|
POST = "POST",
|
||||||
|
|
Loading…
Reference in New Issue