Typing and config.api'ing application.spec.ts, WIP

This commit is contained in:
Sam Rose 2024-02-21 17:52:58 +00:00
parent f417c2d8a4
commit b2c4f04aa6
No known key found for this signature in database
11 changed files with 105 additions and 91 deletions

View File

@ -47,6 +47,7 @@ import {
PlanType,
Screen,
UserCtx,
CreateAppRequest,
} from "@budibase/types"
import { BASE_LAYOUT_PROP_IDS } from "../../constants/layouts"
import sdk from "../../sdk"
@ -116,8 +117,8 @@ function checkAppName(
}
interface AppTemplate {
templateString: string
useTemplate: string
templateString?: string
useTemplate?: string
file?: {
type: string
path: string
@ -231,17 +232,21 @@ export async function fetchAppPackage(ctx: UserCtx) {
}
}
async function performAppCreate(ctx: UserCtx) {
async function performAppCreate(ctx: UserCtx<CreateAppRequest, App>) {
const apps = (await dbCore.getAllApps({ dev: true })) as App[]
const name = ctx.request.body.name,
possibleUrl = ctx.request.body.url,
encryptionPassword = ctx.request.body.encryptionPassword
const {
name,
url,
encryptionPassword,
useTemplate,
templateKey,
templateString,
} = ctx.request.body
checkAppName(ctx, apps, name)
const url = sdk.applications.getAppUrl({ name, url: possibleUrl })
checkAppUrl(ctx, apps, url)
const appUrl = sdk.applications.getAppUrl({ name, url })
checkAppUrl(ctx, apps, appUrl)
const { useTemplate, templateKey, templateString } = ctx.request.body
const instanceConfig: AppTemplate = {
useTemplate,
key: templateKey,
@ -268,7 +273,7 @@ async function performAppCreate(ctx: UserCtx) {
version: envCore.VERSION,
componentLibraries: ["@budibase/standard-components"],
name: name,
url: url,
url: appUrl,
template: templateKey,
instance,
tenantId: tenancy.getTenantId(),

View File

@ -35,41 +35,30 @@ describe("/applications", () => {
describe("create", () => {
it("creates empty app", async () => {
const res = await request
.post("/api/applications")
.field("name", utils.newid())
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body._id).toBeDefined()
const app = await config.api.application.create({ name: utils.newid() })
expect(app._id).toBeDefined()
expect(events.app.created).toBeCalledTimes(1)
})
it("creates app from template", async () => {
const res = await request
.post("/api/applications")
.field("name", utils.newid())
.field("useTemplate", "true")
.field("templateKey", "test")
.field("templateString", "{}") // override the file download
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body._id).toBeDefined()
const app = await config.api.application.create({
name: utils.newid(),
useTemplate: "true",
templateKey: "test",
templateString: "{}",
})
expect(app._id).toBeDefined()
expect(events.app.created).toBeCalledTimes(1)
expect(events.app.templateImported).toBeCalledTimes(1)
})
it("creates app from file", async () => {
const res = await request
.post("/api/applications")
.field("name", utils.newid())
.field("useTemplate", "true")
.set(config.defaultHeaders())
.attach("templateFile", "src/api/routes/tests/data/export.txt")
.expect("Content-Type", /json/)
.expect(200)
expect(res.body._id).toBeDefined()
const app = await config.api.application.create({
name: utils.newid(),
useTemplate: "true",
templateFile: "src/api/routes/tests/data/export.txt",
})
expect(app._id).toBeDefined()
expect(events.app.created).toBeCalledTimes(1)
expect(events.app.fileImported).toBeCalledTimes(1)
})
@ -84,24 +73,21 @@ describe("/applications", () => {
})
it("migrates navigation settings from old apps", async () => {
const res = await request
.post("/api/applications")
.field("name", "Old App")
.field("useTemplate", "true")
.set(config.defaultHeaders())
.attach("templateFile", "src/api/routes/tests/data/old-app.txt")
.expect("Content-Type", /json/)
.expect(200)
expect(res.body._id).toBeDefined()
expect(res.body.navigation).toBeDefined()
expect(res.body.navigation.hideLogo).toBe(true)
expect(res.body.navigation.title).toBe("Custom Title")
expect(res.body.navigation.hideLogo).toBe(true)
expect(res.body.navigation.navigation).toBe("Left")
expect(res.body.navigation.navBackground).toBe(
const app = await config.api.application.create({
name: "Old App",
useTemplate: "true",
templateFile: "src/api/routes/tests/data/old-app.txt",
})
expect(app._id).toBeDefined()
expect(app.navigation).toBeDefined()
expect(app.navigation!.hideLogo).toBe(true)
expect(app.navigation!.title).toBe("Custom Title")
expect(app.navigation!.hideLogo).toBe(true)
expect(app.navigation!.navigation).toBe("Left")
expect(app.navigation!.navBackground).toBe(
"var(--spectrum-global-color-blue-600)"
)
expect(res.body.navigation.navTextColor).toBe(
expect(app.navigation!.navTextColor).toBe(
"var(--spectrum-global-color-gray-50)"
)
expect(events.app.created).toBeCalledTimes(1)
@ -118,15 +104,10 @@ describe("/applications", () => {
it("lists all applications", async () => {
await config.createApp("app1")
await config.createApp("app2")
const res = await request
.get(`/api/applications?status=${AppStatus.DEV}`)
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
const apps = await config.api.application.fetch({ status: AppStatus.DEV })
// two created apps + the inited app
expect(res.body.length).toBe(3)
expect(apps.length).toBe(3)
})
})

View File

@ -1,13 +1,38 @@
import { Response } from "supertest"
import { App } from "@budibase/types"
import { App, type CreateAppRequest } from "@budibase/types"
import TestConfiguration from "../TestConfiguration"
import { TestAPI } from "./base"
import { AppStatus } from "../../../db/utils"
import { dbObjectAsPojo } from "oracledb"
export class ApplicationAPI extends TestAPI {
constructor(config: TestConfiguration) {
super(config)
}
create = async (app: CreateAppRequest): Promise<App> => {
const request = this.request
.post("/api/applications")
.set(this.config.defaultHeaders())
.expect("Content-Type", /json/)
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) {
fail(JSON.stringify(result.body))
}
return result.body as App
}
getRaw = async (appId: string): Promise<Response> => {
const result = await this.request
.get(`/api/applications/${appId}/appPackage`)
@ -21,4 +46,18 @@ export class ApplicationAPI extends TestAPI {
const result = await this.getRaw(appId)
return result.body.application as App
}
fetch = async ({ status }: { status?: AppStatus } = {}): Promise<App[]> => {
let query = []
if (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[]
}
}

View File

@ -73,3 +73,15 @@ export interface AppFeatures {
export interface AutomationSettings {
chainAutomations?: boolean
}
export interface CreateAppRequest {
name: string
url?: string
useTemplate?: string
templateName?: string
templateKey?: string
templateFile?: string
includeSampleData?: boolean
encryptionPassword?: string
templateString?: string
}

View File

@ -4,10 +4,10 @@ set -e
if [[ -n $CI ]]
then
# Running in ci, where resources are limited
echo "jest --coverage --maxWorkers=2 --forceExit --bail"
jest --coverage --maxWorkers=2 --forceExit --bail
echo "jest --coverage --maxWorkers=2 --forceExit --bail $@"
jest --coverage --maxWorkers=2 --forceExit --bail $@
else
# --maxWorkers performs better in development
echo "jest --coverage --maxWorkers=2 --forceExit"
jest --coverage --maxWorkers=2 --forceExit
echo "jest --coverage --maxWorkers=2 --forceExit $@"
jest --coverage --maxWorkers=2 --forceExit $@
fi

View File

@ -1,11 +1,10 @@
import { App } from "@budibase/types"
import { App, CreateAppRequest } from "@budibase/types"
import { Response } from "node-fetch"
import {
RouteConfig,
AppPackageResponse,
DeployConfig,
MessageResponse,
CreateAppRequest,
} from "../../../types"
import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient"
import BaseAPI from "./BaseAPI"

View File

@ -1,5 +1,5 @@
import { generator } from "../../shared"
import { CreateAppRequest } from "../../types"
import { CreateAppRequest } from "@budibase/types"
function uniqueWord() {
return generator.word() + generator.hash()

View File

@ -13,17 +13,6 @@ describe("Internal API - Table Operations", () => {
await config.afterAll()
})
async function createAppFromTemplate() {
return config.api.apps.create({
name: generator.word(),
url: `/${generator.word()}`,
useTemplate: "true",
templateName: "Near Miss Register",
templateKey: "app/near-miss-register",
templateFile: undefined,
})
}
it("Create and delete table, columns and rows", async () => {
// create the app
await config.createApp(fixtures.apps.appFromTemplate())

View File

@ -1,8 +1,8 @@
import { BudibaseInternalAPI } from "../internal-api"
import { AccountInternalAPI } from "../account-api"
import { APIRequestOpts, CreateAppRequest, State } from "../types"
import { APIRequestOpts, State } from "../types"
import * as fixtures from "../internal-api/fixtures"
import { CreateAccountRequest } from "@budibase/types"
import { CreateAccountRequest, CreateAppRequest } from "@budibase/types"
export default class BudibaseTestConfiguration {
// apis

View File

@ -1,10 +0,0 @@
// TODO: Integrate with budibase
export interface CreateAppRequest {
name: string
url: string
useTemplate?: string
templateName?: string
templateKey?: string
templateFile?: string
includeSampleData?: boolean
}

View File

@ -1,6 +1,5 @@
export * from "./api"
export * from "./apiKeyResponse"
export * from "./app"
export * from "./appPackage"
export * from "./deploy"
export * from "./newAccount"