Merge pull request #8080 from Budibase/qa/createaptests
/application endpoints API tests
This commit is contained in:
commit
8f88e605ad
|
@ -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`
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -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/**/*",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue