Introduce test error propagation to public API endpoints.

This commit is contained in:
Sam Rose 2025-02-26 12:02:35 +00:00
parent 433c20d80c
commit 5b285940f1
No known key found for this signature in database
5 changed files with 58 additions and 18 deletions

View File

@ -48,7 +48,7 @@ function getUser(ctx: UserCtx, userId?: string) {
if (userId) {
ctx.params = { userId }
} else if (!ctx.params?.userId) {
throw "No user ID provided for getting"
throw new Error("No user ID provided for getting")
}
return readGlobalUser(ctx)
}

View File

@ -12,6 +12,7 @@ import { paramResource, paramSubResource } from "../../../middleware/resourceId"
import { PermissionLevel, PermissionType } from "@budibase/types"
import { CtxFn } from "./utils/Endpoint"
import mapperMiddleware from "./middleware/mapper"
import testErrorHandling from "./middleware/testErrorHandling"
import env from "../../../environment"
import { middleware, redis } from "@budibase/backend-core"
import { SelectableDatabase } from "@budibase/backend-core/src/redis/utils"
@ -144,6 +145,10 @@ function applyRoutes(
// add the output mapper middleware
addMiddleware(endpoints.read, mapperMiddleware, { output: true })
addMiddleware(endpoints.write, mapperMiddleware, { output: true })
if (env.isTest()) {
addMiddleware(endpoints.read, testErrorHandling)
addMiddleware(endpoints.write, testErrorHandling)
}
addToRouter(endpoints.read)
addToRouter(endpoints.write)
}

View File

@ -0,0 +1,24 @@
import { Ctx } from "@budibase/types"
import environment from "../../../../environment"
export default async (ctx: Ctx, next: any) => {
try {
await next()
} catch (err: any) {
if (
!(environment.isTest() && ctx.headers["x-budibase-include-stacktrace"])
) {
throw err
}
const status = err.status || err.statusCode || 500
let error = err
while (error.cause) {
error = error.cause
}
ctx.status = status
ctx.body = { status, message: error.message, stack: error.stack }
}
}

View File

@ -1,12 +1,13 @@
import * as setup from "../../tests/utilities"
import { User } from "@budibase/types"
import { mocks } from "@budibase/backend-core/tests"
import { generator, mocks } from "@budibase/backend-core/tests"
import nock from "nock"
import environment from "../../../../environment"
import TestConfiguration from "../../../../tests/utilities/TestConfiguration"
const config = new TestConfiguration()
let globalUser: User
let users: Record<string, User> = {}
beforeAll(async () => {
await config.init()
@ -16,25 +17,26 @@ afterAll(setup.afterAll)
beforeEach(async () => {
globalUser = await config.globalUser()
users[globalUser._id!] = globalUser
nock.cleanAll()
nock(environment.WORKER_URL!)
.get(`/api/global/users/${globalUser._id}`)
.get(new RegExp(`/api/global/users/.*`))
.reply(200, (uri, body) => {
return globalUser
const id = uri.split("/").pop()
return users[id!]
})
.persist()
nock(environment.WORKER_URL!)
.post(`/api/global/users`)
.reply(200, (uri, body) => {
const updatedUser = body as User
if (updatedUser._id === globalUser._id) {
globalUser = updatedUser
return globalUser
} else {
throw new Error("User not found")
const newUser = body as User
if (!newUser._id) {
newUser._id = `us_${generator.guid()}`
}
users[newUser._id!] = newUser
return newUser
})
.persist()
})
@ -47,7 +49,7 @@ function base() {
}
}
describe.only("check user endpoints", () => {
describe("check user endpoints", () => {
it("should not allow a user to update their own roles", async () => {
await config.withUser(globalUser, () =>
config.api.public.user.update({
@ -67,14 +69,12 @@ describe.only("check user endpoints", () => {
})
describe("no user role update in free", () => {
it("should not allow 'roles' to be updated", async () => {
const res = await makeRequest("post", "/users", {
...base(),
it.only("should not allow 'roles' to be updated", async () => {
const newUser = await config.api.public.user.create({
email: generator.email({ domain: "example.com" }),
roles: { app_a: "BASIC" },
})
expect(res.status).toBe(200)
expect(res.body.data.roles["app_a"]).toBeUndefined()
expect(res.body.message).toBeDefined()
expect(newUser.roles["app_a"]).toBeUndefined()
})
it("should not allow 'admin' to be updated", async () => {

View File

@ -1,4 +1,4 @@
import { User } from "@budibase/types"
import { UnsavedUser, User } from "@budibase/types"
import { Expectations, PublicAPI } from "../base"
export class UserPublicAPI extends PublicAPI {
@ -16,4 +16,15 @@ export class UserPublicAPI extends PublicAPI {
destroy = async (id: string, expectations?: Expectations): Promise<void> => {
return await this._delete(`/users/${id}`, { expectations })
}
create = async (
user: UnsavedUser,
expectations?: Expectations
): Promise<User> => {
const response = await this._post<{ data: User }>("/users", {
body: user,
expectations,
})
return response.data
}
}