diff --git a/qa-core/README.md b/qa-core/README.md new file mode 100644 index 0000000000..b812742ab3 --- /dev/null +++ b/qa-core/README.md @@ -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` \ No newline at end of file diff --git a/qa-core/package.json b/qa-core/package.json index 7cd566587e..e624b2d62d 100644 --- a/qa-core/package.json +++ b/qa-core/package.json @@ -25,7 +25,8 @@ "moduleNameMapper": { "@budibase/types": "/../packages/types/src", "@budibase/server": "/../packages/server/src", - "@budibase/backend-core": "/../packages/backend-core/src" + "@budibase/backend-core": "/../packages/backend-core/src", + "@budibase/backend-core/(.*)": "/../packages/backend-core/$1" }, "setupFiles": [ "./scripts/jestSetup.js" @@ -51,6 +52,7 @@ }, "dependencies": { "@budibase/backend-core": "^2.0.5", + "form-data": "^4.0.0", "node-fetch": "2" } } \ No newline at end of file diff --git a/qa-core/scripts/jestSetup.js b/qa-core/scripts/jestSetup.js index 8254fd6d34..77565783c3 100644 --- a/qa-core/scripts/jestSetup.js +++ b/qa-core/scripts/jestSetup.js @@ -15,3 +15,5 @@ tk.freeze(MOCK_DATE) if (!process.env.DEBUG) { global.console.log = jest.fn() // console.log are ignored in tests } + +jest.setTimeout(10000) diff --git a/qa-core/src/config/internal-api/TestConfiguration/applications.ts b/qa-core/src/config/internal-api/TestConfiguration/applications.ts index afee5d707a..10e4a6657b 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/applications.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/applications.ts @@ -1,8 +1,10 @@ import { Application, } from "@budibase/server/api/controllers/public/mapping/types" +import { App } from "@budibase/types" import { Response } from "node-fetch" import InternalAPIClient from "./InternalAPIClient" +import FormData from "form-data" export default class AppApi { api: InternalAPIClient @@ -17,9 +19,27 @@ export default class AppApi { 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( body: any - ): Promise<[Response, Application]> { + ): Promise<[Response, Partial]> { const response = await this.api.post(`/applications`, { body }) const json = await response.json() return [response, json] diff --git a/qa-core/src/config/internal-api/TestConfiguration/index.ts b/qa-core/src/config/internal-api/TestConfiguration/index.ts index 69c7e8df96..b433fd98ea 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/index.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/index.ts @@ -13,9 +13,12 @@ export default class TestConfiguration { this.context = {} } - async beforeAll() {} + async beforeAll() { + await this.auth.login() + } async afterAll() { this.context = {} + await this.auth.logout() } } diff --git a/qa-core/src/tests/internal-api/applications/create.spec.ts b/qa-core/src/tests/internal-api/applications/create.spec.ts index a11640153c..81d43d9c91 100644 --- a/qa-core/src/tests/internal-api/applications/create.spec.ts +++ b/qa-core/src/tests/internal-api/applications/create.spec.ts @@ -1,7 +1,9 @@ import TestConfiguration from "../../../config/internal-api/TestConfiguration" 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 generateApp from "../../../config/internal-api/fixtures/applications" +import generator from "../../../config/generator" describe("Internal API - /applications endpoints", () => { const api = new InternalAPIClient() @@ -9,18 +11,22 @@ describe("Internal API - /applications endpoints", () => { beforeAll(async () => { await config.beforeAll() - await config.auth.login() }) afterAll(async () => { await config.afterAll() - await config.auth.logout() }) - it("POST - Can login", async () => { - const [response] = await config.auth.login() - expect(response).toHaveStatusCode(200) - }) + async function createAppFromTemplate() { + return config.applications.create({ + name: generator.word(), + url: `/${generator.word()}`, + useTemplate: "true", + templateName: "Near Miss Register", + templateKey: "app/near-miss-register", + templateFile: undefined + }) + } it("GET - fetch applications", async () => { await config.applications.create({ @@ -29,7 +35,7 @@ describe("Internal API - /applications endpoints", () => { }) const [response, apps] = await config.applications.fetch() expect(response).toHaveStatusCode(200) - expect(apps.length).toBeGreaterThan(1) + expect(apps.length).toBeGreaterThanOrEqual(1) }) it("POST - Create an application", async () => { @@ -37,4 +43,44 @@ describe("Internal API - /applications endpoints", () => { expect(response).toHaveStatusCode(200) 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) + }) + }) diff --git a/qa-core/tsconfig.json b/qa-core/tsconfig.json index 028b4457f9..8cd0c30d46 100644 --- a/qa-core/tsconfig.json +++ b/qa-core/tsconfig.json @@ -14,7 +14,8 @@ "skipLibCheck": true, "paths": { "@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/*"], } }, @@ -23,6 +24,7 @@ }, "references": [ { "path": "../packages/types" }, + { "path": "../packages/backend-core" }, ], "include": [ "src/**/*", diff --git a/qa-core/yarn.lock b/qa-core/yarn.lock index 71c3d3efe4..5b86c6084f 100644 --- a/qa-core/yarn.lock +++ b/qa-core/yarn.lock @@ -1839,6 +1839,15 @@ form-data@^3.0.0: combined-stream "^1.0.8" 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: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"