Merge pull request #8080 from Budibase/qa/createaptests

/application endpoints API tests
This commit is contained in:
Martin McKeaveney 2022-10-03 10:06:18 +01:00 committed by GitHub
commit 8f88e605ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 117 additions and 11 deletions

22
qa-core/README.md Normal file
View File

@ -0,0 +1,22 @@
# QA Core API Tests
The QA Core API tests are a jest suite that run directly against the budibase backend APIs.
## Auto Setup
You can run the whole test suite with one command, that spins up the budibase server and runs the jest tests:
`yarn api:test`
## Setup Server Only
You can also just stand up the budibase server alone.
`yarn api:server:setup`
## Run Tests
If you configured the server using the previous command, you can run the whole test suite by using:
`yarn test`
for watch mode, where the tests will run on every change:
`yarn test:watch`

View File

@ -25,7 +25,8 @@
"moduleNameMapper": { "moduleNameMapper": {
"@budibase/types": "<rootDir>/../packages/types/src", "@budibase/types": "<rootDir>/../packages/types/src",
"@budibase/server": "<rootDir>/../packages/server/src", "@budibase/server": "<rootDir>/../packages/server/src",
"@budibase/backend-core": "<rootDir>/../packages/backend-core/src" "@budibase/backend-core": "<rootDir>/../packages/backend-core/src",
"@budibase/backend-core/(.*)": "<rootDir>/../packages/backend-core/$1"
}, },
"setupFiles": [ "setupFiles": [
"./scripts/jestSetup.js" "./scripts/jestSetup.js"
@ -51,6 +52,7 @@
}, },
"dependencies": { "dependencies": {
"@budibase/backend-core": "^2.0.5", "@budibase/backend-core": "^2.0.5",
"form-data": "^4.0.0",
"node-fetch": "2" "node-fetch": "2"
} }
} }

View File

@ -15,3 +15,5 @@ tk.freeze(MOCK_DATE)
if (!process.env.DEBUG) { if (!process.env.DEBUG) {
global.console.log = jest.fn() // console.log are ignored in tests global.console.log = jest.fn() // console.log are ignored in tests
} }
jest.setTimeout(10000)

View File

@ -1,8 +1,10 @@
import { import {
Application, Application,
} from "@budibase/server/api/controllers/public/mapping/types" } from "@budibase/server/api/controllers/public/mapping/types"
import { App } from "@budibase/types"
import { Response } from "node-fetch" import { Response } from "node-fetch"
import InternalAPIClient from "./InternalAPIClient" import InternalAPIClient from "./InternalAPIClient"
import FormData from "form-data"
export default class AppApi { export default class AppApi {
api: InternalAPIClient api: InternalAPIClient
@ -17,9 +19,27 @@ export default class AppApi {
return [response, json] return [response, json]
} }
async canRender(): Promise<[Response, boolean]> {
const response = await this.api.get("/routing/client")
const json = await response.json()
return [response, Object.keys(json.routes).length > 0]
}
async getAppPackage(appId: string): Promise<[Response, any]> {
const response = await this.api.get(`/applications/${appId}/appPackage`)
const json = await response.json()
return [response, json]
}
async publish(): Promise<[Response, string]> {
const response = await this.api.post("/deploy")
const json = await response.json()
return [response, json]
}
async create( async create(
body: any body: any
): Promise<[Response, Application]> { ): Promise<[Response, Partial<App>]> {
const response = await this.api.post(`/applications`, { body }) const response = await this.api.post(`/applications`, { body })
const json = await response.json() const json = await response.json()
return [response, json] return [response, json]

View File

@ -13,9 +13,12 @@ export default class TestConfiguration<T> {
this.context = <T>{} this.context = <T>{}
} }
async beforeAll() {} async beforeAll() {
await this.auth.login()
}
async afterAll() { async afterAll() {
this.context = <T>{} this.context = <T>{}
await this.auth.logout()
} }
} }

View File

@ -1,7 +1,9 @@
import TestConfiguration from "../../../config/internal-api/TestConfiguration" import TestConfiguration from "../../../config/internal-api/TestConfiguration"
import { Application } from "@budibase/server/api/controllers/public/mapping/types" import { Application } from "@budibase/server/api/controllers/public/mapping/types"
import { db } from "@budibase/backend-core"
import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient" import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient"
import generateApp from "../../../config/internal-api/fixtures/applications" import generateApp from "../../../config/internal-api/fixtures/applications"
import generator from "../../../config/generator"
describe("Internal API - /applications endpoints", () => { describe("Internal API - /applications endpoints", () => {
const api = new InternalAPIClient() const api = new InternalAPIClient()
@ -9,18 +11,22 @@ describe("Internal API - /applications endpoints", () => {
beforeAll(async () => { beforeAll(async () => {
await config.beforeAll() await config.beforeAll()
await config.auth.login()
}) })
afterAll(async () => { afterAll(async () => {
await config.afterAll() await config.afterAll()
await config.auth.logout()
}) })
it("POST - Can login", async () => { async function createAppFromTemplate() {
const [response] = await config.auth.login() return config.applications.create({
expect(response).toHaveStatusCode(200) name: generator.word(),
}) url: `/${generator.word()}`,
useTemplate: "true",
templateName: "Near Miss Register",
templateKey: "app/near-miss-register",
templateFile: undefined
})
}
it("GET - fetch applications", async () => { it("GET - fetch applications", async () => {
await config.applications.create({ await config.applications.create({
@ -29,7 +35,7 @@ describe("Internal API - /applications endpoints", () => {
}) })
const [response, apps] = await config.applications.fetch() const [response, apps] = await config.applications.fetch()
expect(response).toHaveStatusCode(200) expect(response).toHaveStatusCode(200)
expect(apps.length).toBeGreaterThan(1) expect(apps.length).toBeGreaterThanOrEqual(1)
}) })
it("POST - Create an application", async () => { it("POST - Create an application", async () => {
@ -37,4 +43,44 @@ describe("Internal API - /applications endpoints", () => {
expect(response).toHaveStatusCode(200) expect(response).toHaveStatusCode(200)
expect(app._id).toBeDefined() expect(app._id).toBeDefined()
}) })
it("POST - Publish application", async () => {
// create app
const [response, app] = await config.applications.create(generateApp())
expect(response).toHaveStatusCode(200)
expect(app.appId).toBeDefined()
// publish app
config.applications.api.appId = app.appId
const [publishResponse, publish] = await config.applications.publish()
expect(publishResponse).toHaveStatusCode(200)
expect(publish).toEqual({
_id: expect.any(String),
appUrl: app.url,
status: "SUCCESS"
})
})
it("POST - Create an application from a template, publish and check it renders", async () => {
// create the app
const appName = generator.word()
const [response, app] = await createAppFromTemplate()
expect(response).toHaveStatusCode(200)
expect(app.appId).toBeDefined()
config.applications.api.appId = app.appId
// check preview renders
const [previewResponse, previewRenders] = await config.applications.canRender()
expect(previewResponse).toHaveStatusCode(200)
expect(previewRenders).toBe(true)
// publish app
await config.applications.publish()
// check published app renders
config.applications.api.appId = db.getProdAppID(app.appId)
const [publishedAppResponse, publishedAppRenders] = await config.applications.canRender()
expect(publishedAppRenders).toBe(true)
})
}) })

View File

@ -14,7 +14,8 @@
"skipLibCheck": true, "skipLibCheck": true,
"paths": { "paths": {
"@budibase/types": ["../packages/types/src"], "@budibase/types": ["../packages/types/src"],
"@budibase/backend-core": ["../packages/backend-core"], "@budibase/backend-core": ["../packages/backend-core/src"],
"@budibase/backend-core/*": ["../packages/backend-core/*"],
"@budibase/server/*": ["../packages/server/src/*"], "@budibase/server/*": ["../packages/server/src/*"],
} }
}, },
@ -23,6 +24,7 @@
}, },
"references": [ "references": [
{ "path": "../packages/types" }, { "path": "../packages/types" },
{ "path": "../packages/backend-core" },
], ],
"include": [ "include": [
"src/**/*", "src/**/*",

View File

@ -1839,6 +1839,15 @@ form-data@^3.0.0:
combined-stream "^1.0.8" combined-stream "^1.0.8"
mime-types "^2.1.12" mime-types "^2.1.12"
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@~2.3.2: form-data@~2.3.2:
version "2.3.3" version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"