Merge pull request #15686 from Budibase/migrate-js-to-ts-1
Convert middleware tests to TS, remove mocks.
This commit is contained in:
commit
623effe27c
|
@ -1,11 +1,13 @@
|
|||
const setup = require("./utilities")
|
||||
const tableUtils = require("../../controllers/table/utils")
|
||||
import { handleDataImport } from "../../controllers/table/utils"
|
||||
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
|
||||
import { AutoFieldSubType, FieldType, JsonFieldSubType } from "@budibase/types"
|
||||
|
||||
describe("run misc tests", () => {
|
||||
let request = setup.getRequest()
|
||||
let config = setup.getConfig()
|
||||
const config = new TestConfiguration()
|
||||
|
||||
afterAll(setup.afterAll)
|
||||
afterAll(() => {
|
||||
config.end()
|
||||
})
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.init()
|
||||
|
@ -13,69 +15,67 @@ describe("run misc tests", () => {
|
|||
|
||||
describe("/bbtel", () => {
|
||||
it("check if analytics enabled", async () => {
|
||||
const res = await request
|
||||
.get(`/api/bbtel`)
|
||||
.set(config.defaultHeaders())
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200)
|
||||
expect(typeof res.body.enabled).toEqual("boolean")
|
||||
const { enabled } = await config.api.misc.bbtel()
|
||||
expect(enabled).toEqual(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("/health", () => {
|
||||
it("should confirm healthy", async () => {
|
||||
await request.get("/health").expect(200)
|
||||
await config.api.misc.health()
|
||||
})
|
||||
})
|
||||
|
||||
describe("/version", () => {
|
||||
it("should confirm version", async () => {
|
||||
const res = await request.get("/version").expect(200)
|
||||
const text = res.text
|
||||
if (text.includes("alpha")) {
|
||||
expect(text.split(".").length).toEqual(4)
|
||||
const version = await config.api.misc.version()
|
||||
if (version.includes("alpha")) {
|
||||
expect(version.split(".").length).toEqual(4)
|
||||
} else {
|
||||
expect(text.split(".").length).toEqual(3)
|
||||
expect(version.split(".").length).toEqual(3)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("test table utilities", () => {
|
||||
it("should be able to import data", async () => {
|
||||
return config.doInContext(null, async () => {
|
||||
return config.doInContext("", async () => {
|
||||
const table = await config.createTable({
|
||||
name: "table",
|
||||
type: "table",
|
||||
key: "name",
|
||||
schema: {
|
||||
a: {
|
||||
type: "string",
|
||||
type: FieldType.STRING,
|
||||
name: "a",
|
||||
constraints: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
b: {
|
||||
type: "string",
|
||||
name: "b",
|
||||
type: FieldType.STRING,
|
||||
constraints: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
c: {
|
||||
type: "string",
|
||||
name: "c",
|
||||
type: FieldType.STRING,
|
||||
constraints: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
d: {
|
||||
type: "string",
|
||||
name: "d",
|
||||
type: FieldType.STRING,
|
||||
constraints: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
e: {
|
||||
name: "Auto ID",
|
||||
type: "number",
|
||||
subtype: "autoID",
|
||||
type: FieldType.NUMBER,
|
||||
subtype: AutoFieldSubType.AUTO_ID,
|
||||
icon: "ri-magic-line",
|
||||
autocolumn: true,
|
||||
constraints: {
|
||||
|
@ -88,9 +88,9 @@ describe("run misc tests", () => {
|
|||
},
|
||||
},
|
||||
f: {
|
||||
type: "array",
|
||||
type: FieldType.ARRAY,
|
||||
constraints: {
|
||||
type: "array",
|
||||
type: JsonFieldSubType.ARRAY,
|
||||
presence: {
|
||||
allowEmpty: true,
|
||||
},
|
||||
|
@ -100,7 +100,7 @@ describe("run misc tests", () => {
|
|||
sortable: false,
|
||||
},
|
||||
g: {
|
||||
type: "options",
|
||||
type: FieldType.OPTIONS,
|
||||
constraints: {
|
||||
type: "string",
|
||||
presence: false,
|
||||
|
@ -118,16 +118,18 @@ describe("run misc tests", () => {
|
|||
{ a: "13", b: "14", c: "15", d: "16", g: "Omega" },
|
||||
]
|
||||
// Shift specific row tests to the row spec
|
||||
await tableUtils.handleDataImport(table, {
|
||||
importRows,
|
||||
user: { userId: "test" },
|
||||
})
|
||||
await handleDataImport(table, { importRows, userId: "test" })
|
||||
|
||||
// 4 rows imported, the auto ID starts at 1
|
||||
// We expect the handleDataImport function to update the lastID
|
||||
|
||||
// @ts-expect-error - fields have type FieldSchema, not specific
|
||||
// subtypes.
|
||||
expect(table.schema.e.lastID).toEqual(4)
|
||||
|
||||
// Array/Multi - should have added a new value to the inclusion.
|
||||
// @ts-expect-error - fields have type FieldSchema, not specific
|
||||
// subtypes.
|
||||
expect(table.schema.f.constraints.inclusion).toEqual([
|
||||
"Four",
|
||||
"One",
|
||||
|
@ -136,6 +138,8 @@ describe("run misc tests", () => {
|
|||
])
|
||||
|
||||
// Options - should have a new value in the inclusion
|
||||
// @ts-expect-error - fields have type FieldSchema, not specific
|
||||
// subtypes.
|
||||
expect(table.schema.g.constraints.inclusion).toEqual([
|
||||
"Alpha",
|
||||
"Beta",
|
||||
|
@ -143,25 +147,25 @@ describe("run misc tests", () => {
|
|||
"Omega",
|
||||
])
|
||||
|
||||
const rows = await config.getRows()
|
||||
const rows = await config.api.row.fetch(table._id!)
|
||||
expect(rows.length).toEqual(4)
|
||||
|
||||
const rowOne = rows.find(row => row.e === 1)
|
||||
const rowOne = rows.find(row => row.e === 1)!
|
||||
expect(rowOne.a).toEqual("1")
|
||||
expect(rowOne.f).toEqual(["One"])
|
||||
expect(rowOne.g).toEqual("Alpha")
|
||||
|
||||
const rowTwo = rows.find(row => row.e === 2)
|
||||
const rowTwo = rows.find(row => row.e === 2)!
|
||||
expect(rowTwo.a).toEqual("5")
|
||||
expect(rowTwo.f).toEqual([])
|
||||
expect(rowTwo.g).toEqual(undefined)
|
||||
|
||||
const rowThree = rows.find(row => row.e === 3)
|
||||
const rowThree = rows.find(row => row.e === 3)!
|
||||
expect(rowThree.a).toEqual("9")
|
||||
expect(rowThree.f).toEqual(["Two", "Four"])
|
||||
expect(rowThree.g).toEqual(undefined)
|
||||
|
||||
const rowFour = rows.find(row => row.e === 4)
|
||||
const rowFour = rows.find(row => row.e === 4)!
|
||||
expect(rowFour.a).toEqual("13")
|
||||
expect(rowFour.f).toEqual(undefined)
|
||||
expect(rowFour.g).toEqual("Omega")
|
|
@ -1,12 +0,0 @@
|
|||
import env from "../environment"
|
||||
import { Ctx } from "@budibase/types"
|
||||
|
||||
// if added as a middleware will stop requests unless builder is in self host mode
|
||||
// or cloud is in self host
|
||||
export default async (ctx: Ctx, next: any) => {
|
||||
if (env.SELF_HOSTED) {
|
||||
await next()
|
||||
return
|
||||
}
|
||||
ctx.throw(400, "Endpoint unavailable in cloud hosting.")
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
import ensureTenantAppOwnership from "../ensureTenantAppOwnership"
|
||||
import { tenancy, utils } from "@budibase/backend-core"
|
||||
|
||||
jest.mock("@budibase/backend-core", () => ({
|
||||
...jest.requireActual("@budibase/backend-core"),
|
||||
tenancy: {
|
||||
getTenantId: jest.fn(),
|
||||
},
|
||||
utils: {
|
||||
getAppIdFromCtx: jest.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
class TestConfiguration {
|
||||
constructor(appId = "tenant_1") {
|
||||
this.next = jest.fn()
|
||||
this.throw = jest.fn()
|
||||
this.middleware = ensureTenantAppOwnership
|
||||
|
||||
this.ctx = {
|
||||
next: this.next,
|
||||
throw: this.throw,
|
||||
}
|
||||
|
||||
utils.getAppIdFromCtx.mockResolvedValue(appId)
|
||||
}
|
||||
|
||||
async executeMiddleware() {
|
||||
return this.middleware(this.ctx, this.next)
|
||||
}
|
||||
|
||||
afterEach() {
|
||||
jest.clearAllMocks()
|
||||
}
|
||||
}
|
||||
|
||||
describe("Ensure Tenant Ownership Middleware", () => {
|
||||
let config
|
||||
|
||||
beforeEach(() => {
|
||||
config = new TestConfiguration()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
config.afterEach()
|
||||
})
|
||||
|
||||
it("calls next() when appId matches tenant ID", async () => {
|
||||
tenancy.getTenantId.mockReturnValue("tenant_1")
|
||||
|
||||
await config.executeMiddleware()
|
||||
|
||||
expect(utils.getAppIdFromCtx).toHaveBeenCalledWith(config.ctx)
|
||||
expect(config.next).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("throws when tenant appId does not match tenant ID", async () => {
|
||||
const appId = "app_dev_tenant3_fce449c4d75b4e4a9c7a6980d82a3e22"
|
||||
utils.getAppIdFromCtx.mockResolvedValue(appId)
|
||||
tenancy.getTenantId.mockReturnValue("tenant_2")
|
||||
|
||||
await config.executeMiddleware()
|
||||
|
||||
expect(utils.getAppIdFromCtx).toHaveBeenCalledWith(config.ctx)
|
||||
expect(config.throw).toHaveBeenCalledWith(403, "Unauthorized")
|
||||
})
|
||||
|
||||
it("throws 400 when appId is missing", async () => {
|
||||
utils.getAppIdFromCtx.mockResolvedValue(null)
|
||||
|
||||
await config.executeMiddleware()
|
||||
|
||||
expect(config.throw).toHaveBeenCalledWith(400, "appId must be provided")
|
||||
})
|
||||
})
|
|
@ -0,0 +1,52 @@
|
|||
import { UserCtx } from "@budibase/types"
|
||||
import ensureTenantAppOwnership from "../ensureTenantAppOwnership"
|
||||
import { context, Header, HTTPError } from "@budibase/backend-core"
|
||||
|
||||
function ctx(opts?: { appId: string }) {
|
||||
const ctx = {
|
||||
throw: (status: number, message: string) => {
|
||||
throw new HTTPError(message, status)
|
||||
},
|
||||
path: "",
|
||||
request: {
|
||||
headers: {},
|
||||
},
|
||||
} as unknown as UserCtx
|
||||
if (opts?.appId) {
|
||||
ctx.request.headers[Header.APP_ID] = opts.appId
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
describe("Ensure Tenant Ownership Middleware", () => {
|
||||
const tenantId = "tenant1"
|
||||
const appId = `app_dev_${tenantId}_fce449c4d75b4e4a9c7a6980d82a3e22`
|
||||
|
||||
it("calls next() when appId matches tenant ID", async () => {
|
||||
await context.doInTenant(tenantId, async () => {
|
||||
let called = false
|
||||
await ensureTenantAppOwnership(ctx({ appId }), () => {
|
||||
called = true
|
||||
})
|
||||
expect(called).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
it("throws when tenant appId does not match tenant ID", async () => {
|
||||
let called = false
|
||||
await expect(async () => {
|
||||
await context.doInTenant("tenant_2", async () => {
|
||||
await ensureTenantAppOwnership(ctx({ appId }), () => {
|
||||
called = true
|
||||
})
|
||||
})
|
||||
}).rejects.toThrow("Unauthorized")
|
||||
expect(called).toBe(false)
|
||||
})
|
||||
|
||||
it("throws 400 when appId is missing", async () => {
|
||||
await expect(ensureTenantAppOwnership(ctx(), () => {})).rejects.toThrow(
|
||||
"appId must be provided"
|
||||
)
|
||||
})
|
||||
})
|
|
@ -1,105 +0,0 @@
|
|||
const {
|
||||
paramResource,
|
||||
paramSubResource,
|
||||
bodyResource,
|
||||
bodySubResource,
|
||||
ResourceIdGetter,
|
||||
} = require("../resourceId")
|
||||
|
||||
class TestConfiguration {
|
||||
constructor(middleware) {
|
||||
this.middleware = middleware
|
||||
this.ctx = {
|
||||
request: {},
|
||||
}
|
||||
this.next = jest.fn()
|
||||
}
|
||||
|
||||
setParams(params) {
|
||||
this.ctx.params = params
|
||||
}
|
||||
|
||||
setBody(body) {
|
||||
this.ctx.body = body
|
||||
}
|
||||
|
||||
executeMiddleware() {
|
||||
return this.middleware(this.ctx, this.next)
|
||||
}
|
||||
}
|
||||
|
||||
describe("resourceId middleware", () => {
|
||||
it("calls next() when there is no request object to parse", () => {
|
||||
const config = new TestConfiguration(paramResource("main"))
|
||||
|
||||
config.executeMiddleware()
|
||||
|
||||
expect(config.next).toHaveBeenCalled()
|
||||
expect(config.ctx.resourceId).toBeUndefined()
|
||||
})
|
||||
|
||||
it("generates a resourceId middleware for context query parameters", () => {
|
||||
const config = new TestConfiguration(paramResource("main"))
|
||||
config.setParams({
|
||||
main: "test",
|
||||
})
|
||||
|
||||
config.executeMiddleware()
|
||||
|
||||
expect(config.ctx.resourceId).toEqual("test")
|
||||
})
|
||||
|
||||
it("generates a resourceId middleware for context query sub parameters", () => {
|
||||
const config = new TestConfiguration(paramSubResource("main", "sub"))
|
||||
config.setParams({
|
||||
main: "main",
|
||||
sub: "test",
|
||||
})
|
||||
|
||||
config.executeMiddleware()
|
||||
|
||||
expect(config.ctx.resourceId).toEqual("main")
|
||||
expect(config.ctx.subResourceId).toEqual("test")
|
||||
})
|
||||
|
||||
it("generates a resourceId middleware for context request body", () => {
|
||||
const config = new TestConfiguration(bodyResource("main"))
|
||||
config.setBody({
|
||||
main: "test",
|
||||
})
|
||||
|
||||
config.executeMiddleware()
|
||||
|
||||
expect(config.ctx.resourceId).toEqual("test")
|
||||
})
|
||||
|
||||
it("generates a resourceId middleware for context request body sub fields", () => {
|
||||
const config = new TestConfiguration(bodySubResource("main", "sub"))
|
||||
config.setBody({
|
||||
main: "main",
|
||||
sub: "test",
|
||||
})
|
||||
|
||||
config.executeMiddleware()
|
||||
|
||||
expect(config.ctx.resourceId).toEqual("main")
|
||||
expect(config.ctx.subResourceId).toEqual("test")
|
||||
})
|
||||
|
||||
it("parses resourceIds correctly for custom middlewares", () => {
|
||||
const middleware = new ResourceIdGetter("body")
|
||||
.mainResource("custom")
|
||||
.subResource("customSub")
|
||||
.build()
|
||||
let config = new TestConfiguration(middleware)
|
||||
config.setBody({
|
||||
custom: "test",
|
||||
customSub: "subtest",
|
||||
})
|
||||
|
||||
config.executeMiddleware()
|
||||
|
||||
expect(config.ctx.resourceId).toEqual("test")
|
||||
expect(config.ctx.subResourceId).toEqual("subtest")
|
||||
})
|
||||
})
|
|
@ -0,0 +1,93 @@
|
|||
import { Ctx } from "@budibase/types"
|
||||
import {
|
||||
paramResource,
|
||||
paramSubResource,
|
||||
bodyResource,
|
||||
bodySubResource,
|
||||
ResourceIdGetter,
|
||||
} from "../resourceId"
|
||||
|
||||
describe("resourceId middleware", () => {
|
||||
it("calls next() when there is no request object to parse", () => {
|
||||
const ctx = { request: {} } as Ctx
|
||||
let called = false
|
||||
paramResource("main")(ctx, () => {
|
||||
called = true
|
||||
})
|
||||
|
||||
expect(called).toBe(true)
|
||||
expect(ctx.resourceId).toBeUndefined()
|
||||
})
|
||||
|
||||
it("generates a resourceId middleware for context query parameters", () => {
|
||||
const ctx = { request: {}, params: { main: "test" } } as unknown as Ctx
|
||||
let called = false
|
||||
paramResource("main")(ctx, () => {
|
||||
called = true
|
||||
})
|
||||
|
||||
expect(called).toBe(true)
|
||||
expect(ctx.resourceId).toEqual("test")
|
||||
})
|
||||
|
||||
it("generates a resourceId middleware for context query sub parameters", () => {
|
||||
const ctx = {
|
||||
request: {},
|
||||
params: { main: "main", sub: "test" },
|
||||
} as unknown as Ctx
|
||||
let called = false
|
||||
paramSubResource("main", "sub")(ctx, () => {
|
||||
called = true
|
||||
})
|
||||
|
||||
expect(called).toBe(true)
|
||||
expect(ctx.resourceId).toEqual("main")
|
||||
expect(ctx.subResourceId).toEqual("test")
|
||||
})
|
||||
|
||||
it("generates a resourceId middleware for context request body", () => {
|
||||
const ctx = { request: {}, body: { main: "main" } } as unknown as Ctx
|
||||
let called = false
|
||||
bodyResource("main")(ctx, () => {
|
||||
called = true
|
||||
})
|
||||
|
||||
expect(called).toBe(true)
|
||||
expect(ctx.resourceId).toEqual("main")
|
||||
})
|
||||
|
||||
it("generates a resourceId middleware for context request body sub fields", () => {
|
||||
const ctx = {
|
||||
request: {},
|
||||
body: { main: "main", sub: "test" },
|
||||
} as unknown as Ctx
|
||||
let called = false
|
||||
bodySubResource("main", "sub")(ctx, () => {
|
||||
called = true
|
||||
})
|
||||
|
||||
expect(called).toBe(true)
|
||||
expect(ctx.resourceId).toEqual("main")
|
||||
expect(ctx.subResourceId).toEqual("test")
|
||||
})
|
||||
|
||||
it("parses resourceIds correctly for custom middlewares", () => {
|
||||
const middleware = new ResourceIdGetter("body")
|
||||
.mainResource("custom")
|
||||
.subResource("customSub")
|
||||
.build()
|
||||
|
||||
const ctx = {
|
||||
request: {},
|
||||
body: { custom: "test", customSub: "subTest" },
|
||||
} as unknown as Ctx
|
||||
let called = false
|
||||
middleware(ctx, () => {
|
||||
called = true
|
||||
})
|
||||
|
||||
expect(called).toBe(true)
|
||||
expect(ctx.resourceId).toEqual("test")
|
||||
expect(ctx.subResourceId).toEqual("subTest")
|
||||
})
|
||||
})
|
|
@ -1,43 +0,0 @@
|
|||
const selfHostMiddleware = require("../selfhost").default
|
||||
const env = require("../../environment")
|
||||
jest.mock("../../environment")
|
||||
|
||||
class TestConfiguration {
|
||||
constructor() {
|
||||
this.next = jest.fn()
|
||||
this.throw = jest.fn()
|
||||
this.middleware = selfHostMiddleware
|
||||
|
||||
this.ctx = {
|
||||
next: this.next,
|
||||
throw: this.throw,
|
||||
}
|
||||
}
|
||||
|
||||
executeMiddleware() {
|
||||
return this.middleware(this.ctx, this.next)
|
||||
}
|
||||
|
||||
afterEach() {
|
||||
jest.clearAllMocks()
|
||||
}
|
||||
}
|
||||
|
||||
describe("Self host middleware", () => {
|
||||
let config
|
||||
|
||||
beforeEach(() => {
|
||||
config = new TestConfiguration()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
config.afterEach()
|
||||
})
|
||||
|
||||
it("calls next() when SELF_HOSTED env var is set", async () => {
|
||||
env.SELF_HOSTED = 1
|
||||
|
||||
await config.executeMiddleware()
|
||||
expect(config.next).toHaveBeenCalled()
|
||||
})
|
||||
})
|
|
@ -19,6 +19,7 @@ import { PluginAPI } from "./plugin"
|
|||
import { WebhookAPI } from "./webhook"
|
||||
import { EnvironmentAPI } from "./environment"
|
||||
import { UserPublicAPI } from "./public/user"
|
||||
import { MiscAPI } from "./misc"
|
||||
|
||||
export default class API {
|
||||
application: ApplicationAPI
|
||||
|
@ -28,6 +29,7 @@ export default class API {
|
|||
datasource: DatasourceAPI
|
||||
environment: EnvironmentAPI
|
||||
legacyView: LegacyViewAPI
|
||||
misc: MiscAPI
|
||||
permission: PermissionAPI
|
||||
plugin: PluginAPI
|
||||
query: QueryAPI
|
||||
|
@ -53,6 +55,7 @@ export default class API {
|
|||
this.datasource = new DatasourceAPI(config)
|
||||
this.environment = new EnvironmentAPI(config)
|
||||
this.legacyView = new LegacyViewAPI(config)
|
||||
this.misc = new MiscAPI(config)
|
||||
this.permission = new PermissionAPI(config)
|
||||
this.plugin = new PluginAPI(config)
|
||||
this.query = new QueryAPI(config)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { AnalyticsEnabledResponse } from "@budibase/types"
|
||||
import { Expectations, TestAPI } from "./base"
|
||||
|
||||
export class MiscAPI extends TestAPI {
|
||||
health = async (expectations?: Expectations) => {
|
||||
return await this._get<void>("/health", { expectations })
|
||||
}
|
||||
|
||||
version = async (expectations?: Expectations) => {
|
||||
return (await this._requestRaw("get", "/version", { expectations })).text
|
||||
}
|
||||
|
||||
bbtel = async (expectations?: Expectations) => {
|
||||
return await this._get<AnalyticsEnabledResponse>("/api/bbtel", {
|
||||
expectations,
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue