diff --git a/qa-core/src/config/internal-api/TestConfiguration/applications.ts b/qa-core/src/config/internal-api/TestConfiguration/applications.ts index dd98936d3c..e73d361118 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/applications.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/applications.ts @@ -11,32 +11,50 @@ import { UnpublishAppResponse } from "../fixtures/types/unpublishAppResponse" export default class AppApi { api: InternalAPIClient - + appCreated: boolean constructor(apiClient: InternalAPIClient) { this.api = apiClient + this.appCreated = false } async fetch(): Promise<[Response, Application[]]> { const response = await this.api.get(`/applications?status=all`) const json = await response.json() + expect(response).toHaveStatusCode(200) + if (this.appCreated) { + expect(json.length).toBeGreaterThanOrEqual(1) + } else { + expect(json.length).toEqual(0) + } 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] + const publishedAppRenders = Object.keys(json.routes).length > 0 + expect(response).toHaveStatusCode(200) + expect(publishedAppRenders).toBe(true) + return [response, publishedAppRenders] } async getAppPackage(appId: string): Promise<[Response, AppPackageResponse]> { const response = await this.api.get(`/applications/${appId}/appPackage`) const json = await response.json() + expect(response).toHaveStatusCode(200) + expect(json.application.apppId).toBe(appId) return [response, json] } - async publish(): Promise<[Response, DeployConfig]> { + async publish(appUrl: string): Promise<[Response, DeployConfig]> { const response = await this.api.post("/deploy") const json = await response.json() + expect(response).toHaveStatusCode(200) + expect(json).toEqual({ + _id: expect.any(String), + appUrl: appUrl, + status: "SUCCESS", + }) return [response, json] } @@ -45,6 +63,7 @@ export default class AppApi { const json = await response.json() expect(response).toHaveStatusCode(200) expect(json._id).toBeDefined() + this.appCreated = true return json } @@ -57,6 +76,7 @@ export default class AppApi { async sync(appId: string): Promise<[Response, responseMessage]> { const response = await this.api.post(`/applications/${appId}/sync`) const json = await response.json() + expect(response).toHaveStatusCode(200) return [response, json] } @@ -72,21 +92,36 @@ export default class AppApi { return [response, json] } - async revert(appId: string): Promise<[Response, responseMessage]> { + async revert(appId: string, negativeTest?: boolean): Promise<[Response, responseMessage]> { const response = await this.api.post(`/dev/${appId}/revert`) const json = await response.json() + if (negativeTest) { + expect(response).toHaveStatusCode(400) + expect(json).toEqual({ + message: "App has not yet been deployed", + status: 400, + }) + } else { + expect(response).toHaveStatusCode(200) + expect(json).toEqual({ + message: "Reverted changes successfully.", + }) + } return [response, json] } async delete(appId: string): Promise<[Response, any]> { const response = await this.api.del(`/applications/${appId}`) const json = await response.json() + expect(response).toHaveStatusCode(200) return [response, json] } - async update(appId: string, body: any): Promise<[Response, Application]> { + async update(appId: string, oldName: string, body: any): Promise<[Response, Application]> { const response = await this.api.put(`/applications/${appId}`, { body }) const json = await response.json() + expect(response).toHaveStatusCode(200) + expect(json.name).not.toEqual(oldName) return [response, json] } @@ -96,9 +131,17 @@ export default class AppApi { return [response, json] } - async getRoutes(): Promise<[Response, RouteConfig]> { + async getRoutes(screenExists?: boolean): Promise<[Response, RouteConfig]> { const response = await this.api.get(`/routing`) const json = await response.json() + expect(response).toHaveStatusCode(200) + if (screenExists) { + + expect(json.routes["/test"]).toBeTruthy() + } else { + expect(json.routes["/test"]).toBeUndefined() + } + return [response, json] } diff --git a/qa-core/src/config/internal-api/TestConfiguration/rows.ts b/qa-core/src/config/internal-api/TestConfiguration/rows.ts index a0e9b7c408..39ba01f467 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/rows.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/rows.ts @@ -4,25 +4,36 @@ import InternalAPIClient from "./InternalAPIClient" export default class RowsApi { api: InternalAPIClient - + rowAdded: boolean constructor(apiClient: InternalAPIClient) { this.api = apiClient + this.rowAdded = false } async getAll(tableId: string): Promise<[Response, Row[]]> { const response = await this.api.get(`/${tableId}/rows`) const json = await response.json() + if (this.rowAdded) { + expect(response).toHaveStatusCode(200) + expect(json.length).toEqual(1) + } return [response, json] } async add(tableId: string, body: any): Promise<[Response, Row]> { const response = await this.api.post(`/${tableId}/rows`, { body }) const json = await response.json() + expect(response).toHaveStatusCode(200) + expect(json._id).toBeDefined() + expect(json._rev).toBeDefined() + expect(json.tableId).toEqual(tableId) + this.rowAdded = true return [response, json] } async delete(tableId: string, body: any): Promise<[Response, Row[]]> { const response = await this.api.del(`/${tableId}/rows/`, { body }) const json = await response.json() + expect(response).toHaveStatusCode(200) return [response, json] } } diff --git a/qa-core/src/config/internal-api/TestConfiguration/screens.ts b/qa-core/src/config/internal-api/TestConfiguration/screens.ts index 7814ffdfbc..8ec377599e 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/screens.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/screens.ts @@ -12,12 +12,16 @@ export default class ScreenApi { async create(body: any): Promise<[Response, Screen]> { const response = await this.api.post(`/screens`, { body }) const json = await response.json() + expect(response).toHaveStatusCode(200) + expect(json._id).toBeDefined() + expect(json.routing.roleId).toBe(body.routing.roleId) return [response, json] } async delete(screenId: string, rev: string): Promise<[Response, Screen]> { const response = await this.api.del(`/screens/${screenId}/${rev}`) const json = await response.json() + expect(response).toHaveStatusCode(200) return [response, json] } } diff --git a/qa-core/src/config/internal-api/TestConfiguration/tables.ts b/qa-core/src/config/internal-api/TestConfiguration/tables.ts index 58dc1a5a74..ed0ab78cad 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/tables.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/tables.ts @@ -21,12 +21,21 @@ export default class TablesApi { async getTableById(id: string): Promise<[Response, Table]> { const response = await this.api.get(`/tables/${id}`) const json = await response.json() + expect(response).toHaveStatusCode(200) + expect(json._id).toEqual(id) return [response, json] } - async save(body: any): Promise<[Response, Table]> { + async save(body: any, columnAdded?: boolean): Promise<[Response, Table]> { const response = await this.api.post(`/tables`, { body }) const json = await response.json() + expect(response).toHaveStatusCode(200) + expect(json._id).toBeDefined() + expect(json._rev).toBeDefined() + if (columnAdded) { + expect(json.schema.TestColumn).toBeDefined() + } + return [response, json] } @@ -36,6 +45,10 @@ export default class TablesApi { ): Promise<[Response, responseMessage]> { const response = await this.api.del(`/tables/${id}/${revId}`) const json = await response.json() + expect(response).toHaveStatusCode(200) + expect(json.message).toEqual( + `Table ${id} deleted.` + ) return [response, json] } } 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 bd76a4a882..af77eb002f 100644 --- a/qa-core/src/tests/internal-api/applications/create.spec.ts +++ b/qa-core/src/tests/internal-api/applications/create.spec.ts @@ -11,7 +11,7 @@ import { } from "../../../config/internal-api/fixtures/table" import { generateNewRowForTable } from "../../../config/internal-api/fixtures/rows" -describe("Internal API - /applications endpoints", () => { +describe("Internal API - Application creation, update, publish and delete", () => { const api = new InternalAPIClient() const config = new TestConfiguration(api) @@ -34,55 +34,33 @@ describe("Internal API - /applications endpoints", () => { }) } - it("GET - fetch applications", async () => { + it("Get all Applications", async () => { + await config.applications.fetch() + await config.applications.create({ ...generateApp(), useTemplate: false, }) - const [response, apps] = await config.applications.fetch() - expect(response).toHaveStatusCode(200) - expect(apps.length).toBeGreaterThanOrEqual(1) + + await config.applications.fetch() }) - it("POST - Create an application", async () => { - config.applications.create(generateApp()) - }) - - it("POST - Publish application", async () => { - // create app - const app = await config.applications.create(generateApp()) - - // 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("Publish app flow", async () => { + it("Publish app", async () => { // create the app const appName = generator.word() const app = await createAppFromTemplate() config.applications.api.appId = app.appId // check preview renders - const [previewResponse, previewRenders] = - await config.applications.canRender() - expect(previewResponse).toHaveStatusCode(200) - expect(previewRenders).toBe(true) + await config.applications.canRender() // publish app - await config.applications.publish() + await config.applications.publish(app.url) // check published app renders config.applications.api.appId = db.getProdAppID(app.appId) - const [publishedAppResponse, publishedAppRenders] = - await config.applications.canRender() - expect(publishedAppRenders).toBe(true) + await config.applications.canRender() + // unpublish app await config.applications.unpublish(app.appId) @@ -95,7 +73,6 @@ describe("Internal API - /applications endpoints", () => { const [syncResponse, sync] = await config.applications.sync( app.appId ) - expect(syncResponse).toHaveStatusCode(200) expect(sync).toEqual({ message: "App sync not required, app not deployed.", }) @@ -106,12 +83,11 @@ describe("Internal API - /applications endpoints", () => { config.applications.api.appId = app.appId // publish app - await config.applications.publish() + await config.applications.publish(app.url) const [syncResponse, sync] = await config.applications.sync( app.appId ) - expect(syncResponse).toHaveStatusCode(200) expect(sync).toEqual({ message: "App sync completed successfully.", }) @@ -122,28 +98,23 @@ describe("Internal API - /applications endpoints", () => { config.applications.api.appId = app.appId - const [updateResponse, updatedApp] = await config.applications.update( + await config.applications.update( app.appId, + app.name, { name: generator.word(), } ) - expect(updateResponse).toHaveStatusCode(200) - expect(updatedApp.name).not.toEqual(app.name) }) it("POST - Revert Changes without changes", async () => { const app = await config.applications.create(generateApp()) config.applications.api.appId = app.appId - const [revertResponse, revert] = await config.applications.revert( - app.appId + await config.applications.revert( + app.appId, + true ) - expect(revertResponse).toHaveStatusCode(400) - expect(revert).toEqual({ - message: "App has not yet been deployed", - status: 400, - }) }) it("POST - Revert Changes", async () => { @@ -151,116 +122,28 @@ describe("Internal API - /applications endpoints", () => { config.applications.api.appId = app.appId // publish app - const [publishResponse, publish] = await config.applications.publish() - expect(publishResponse).toHaveStatusCode(200) - expect(publish.status).toEqual("SUCCESS") + await config.applications.publish(app.url) + // Change/add component to the app - const [screenResponse, screen] = await config.applications.addScreentoApp( + await config.screen.create( generateScreen("BASIC") ) - expect(screenResponse).toHaveStatusCode(200) - expect(screen._id).toBeDefined() // // Revert the app to published state - const [revertResponse, revert] = await config.applications.revert( + await config.applications.revert( app.appId ) - expect(revertResponse).toHaveStatusCode(200) - expect(revert).toEqual({ - message: "Reverted changes successfully.", - }) // Check screen is removed - const [routesResponse, routes] = await config.applications.getRoutes() - expect(routesResponse).toHaveStatusCode(200) - expect(routes.routes["/test"]).toBeUndefined() + await config.applications.getRoutes() + }) it("DELETE - Delete an application", async () => { const app = await config.applications.create(generateApp()) - const [deleteResponse] = await config.applications.delete(app.appId) - expect(deleteResponse).toHaveStatusCode(200) + await config.applications.delete(app.appId) }) - it("Operations on Tables", async () => { - // create the app - const appName = generator.word() - const app = await createAppFromTemplate() - config.applications.api.appId = app.appId - - // Get current tables: expect 2 in this template - await config.tables.getAll(2) - - // Add new table - const [createdTableResponse, createdTableData] = await config.tables.save( - generateTable() - ) - expect(createdTableResponse).toHaveStatusCode(200) - expect(createdTableData._id).toBeDefined() - expect(createdTableData._rev).toBeDefined() - - //Table was added - await config.tables.getAll(3) - - //Get information about the table - const [tableInfoResponse, tableInfo] = await config.tables.getTableById( - createdTableData._id - ) - expect(tableInfoResponse).toHaveStatusCode(200) - expect(tableInfo._id).toEqual(createdTableData._id) - - //Add Column to table - const newColumn = generateNewColumnForTable(createdTableData) - const [addColumnResponse, addColumnData] = await config.tables.save( - newColumn - ) - expect(addColumnResponse).toHaveStatusCode(200) - expect(addColumnData._id).toEqual(createdTableData._id) - expect(addColumnData.schema.TestColumn).toBeDefined() - - //Add Row to table - const newRow = generateNewRowForTable(addColumnData._id) - const [addRowResponse, addRowData] = await config.rows.add( - addColumnData._id, - newRow - ) - console.log(addRowData) - expect(addRowResponse).toHaveStatusCode(200) - expect(addRowData._id).toBeDefined() - expect(addRowData._rev).toBeDefined() - expect(addRowData.tableId).toEqual(addColumnData._id) - - //Get Row from table - const [getRowResponse, getRowData] = await config.rows.getAll( - addColumnData._id - ) - expect(getRowResponse).toHaveStatusCode(200) - expect(getRowData.length).toEqual(1) - - //Delete Row from table - const rowToDelete = { - rows: [getRowData[0]], - } - const [deleteRowResponse, deleteRowData] = await config.rows.delete( - addColumnData._id, - rowToDelete - ) - expect(deleteRowResponse).toHaveStatusCode(200) - expect(deleteRowData[0]._id).toEqual(getRowData[0]._id) - - //Delete the table - const [deleteTableResponse, deleteTable] = await config.tables.delete( - addColumnData._id, - addColumnData._rev - ) - expect(deleteTableResponse).toHaveStatusCode(200) - expect(deleteTable.message).toEqual( - `Table ${createdTableData._id} deleted.` - ) - - //Table was deleted - await config.tables.getAll(2) - }) }) diff --git a/qa-core/src/tests/internal-api/screens/screens.spec.ts b/qa-core/src/tests/internal-api/screens/screens.spec.ts index 34266d6622..2dc7962914 100644 --- a/qa-core/src/tests/internal-api/screens/screens.spec.ts +++ b/qa-core/src/tests/internal-api/screens/screens.spec.ts @@ -29,8 +29,6 @@ describe("Internal API - /screens endpoints", () => { const [response, screen] = await config.screen.create( generateScreen(roleArray[role]) ) - expect(response).toHaveStatusCode(200) - expect(screen.routing.roleId).toEqual(roleArray[role]) } }) @@ -40,14 +38,12 @@ describe("Internal API - /screens endpoints", () => { // Create Screen appConfig.applications.api.appId = app.appId - const [response, screen] = await config.screen.create( + await config.screen.create( generateScreen("BASIC") ) // Check screen exists - const [routesResponse, routes] = await appConfig.applications.getRoutes() - expect(routesResponse).toHaveStatusCode(200) - expect(routes.routes["/test"]).toBeTruthy() + await appConfig.applications.getRoutes(true) }) it("DELETE - Delete a screen", async () => { @@ -61,7 +57,7 @@ describe("Internal API - /screens endpoints", () => { ) // Delete Screen - const [response] = await config.screen.delete(screen._id!, screen._rev!) - expect(response).toHaveStatusCode(200) + await config.screen.delete(screen._id!, screen._rev!) + }) }) diff --git a/qa-core/src/tests/internal-api/tables/tables.spec.ts b/qa-core/src/tests/internal-api/tables/tables.spec.ts new file mode 100644 index 0000000000..d1d52a5fd1 --- /dev/null +++ b/qa-core/src/tests/internal-api/tables/tables.spec.ts @@ -0,0 +1,98 @@ +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" +import generateScreen from "../../../config/internal-api/fixtures/screens" +import { + generateTable, + generateNewColumnForTable, +} from "../../../config/internal-api/fixtures/table" +import { generateNewRowForTable } from "../../../config/internal-api/fixtures/rows" + +describe("Internal API - Application creation, update, publish and delete", () => { + const api = new InternalAPIClient() + const config = new TestConfiguration(api) + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + 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("Operations on Tables", async () => { + // create the app + const appName = generator.word() + const app = await createAppFromTemplate() + config.applications.api.appId = app.appId + + // Get current tables: expect 2 in this template + await config.tables.getAll(2) + + // Add new table + const [createdTableResponse, createdTableData] = await config.tables.save( + generateTable() + ) + + //Table was added + await config.tables.getAll(3) + + //Get information about the table + await config.tables.getTableById( + createdTableData._id + ) + + //Add Column to table + const newColumn = generateNewColumnForTable(createdTableData) + const [addColumnResponse, addColumnData] = await config.tables.save( + newColumn, + true + ) + + //Add Row to table + const newRow = generateNewRowForTable(addColumnData._id) + await config.rows.add( + addColumnData._id, + newRow + ) + + //Get Row from table + const [getRowResponse, getRowData] = await config.rows.getAll( + addColumnData._id + ) + + //Delete Row from table + const rowToDelete = { + rows: [getRowData[0]], + } + const [deleteRowResponse, deleteRowData] = await config.rows.delete( + addColumnData._id, + rowToDelete + ) + expect(deleteRowData[0]._id).toEqual(getRowData[0]._id) + + //Delete the table + const [deleteTableResponse, deleteTable] = await config.tables.delete( + addColumnData._id, + addColumnData._rev + ) + + + //Table was deleted + await config.tables.getAll(2) + }) +})