diff --git a/packages/types/src/documents/app/table.ts b/packages/types/src/documents/app/table.ts index 72cff4f056..12135b60cf 100644 --- a/packages/types/src/documents/app/table.ts +++ b/packages/types/src/documents/app/table.ts @@ -49,4 +49,6 @@ export interface Table extends Document { sourceId?: string relatedFormula?: string[] constrained?: string[] + indexes?: { [key: string]: any } + dataImport?: { [key: string]: any } } diff --git a/qa-core/src/config/internal-api/TestConfiguration/applications.ts b/qa-core/src/config/internal-api/TestConfiguration/applications.ts index 3b50a62781..8d276911c8 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/applications.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/applications.ts @@ -6,8 +6,9 @@ import FormData from "form-data" import { RouteConfig } from "../fixtures/types/routing" import { AppPackageResponse } from "../fixtures/types/appPackage" import { DeployConfig } from "../fixtures/types/deploy" +import { responseMessage } from "../fixtures/types/responseMessage" + -type messageResponse = { message: string } export default class AppApi { api: InternalAPIClient @@ -40,10 +41,12 @@ export default class AppApi { return [response, json] } - async create(body: any): Promise<[Response, Partial]> { + async create(body: any): Promise> { const response = await this.api.post(`/applications`, { body }) const json = await response.json() - return [response, json] + expect(response).toHaveStatusCode(200) + expect(json._id).toBeDefined() + return json } async read(id: string): Promise<[Response, Application]> { @@ -52,7 +55,7 @@ export default class AppApi { return [response, json.data] } - async sync(appId: string): Promise<[Response, messageResponse]> { + async sync(appId: string): Promise<[Response, responseMessage]> { const response = await this.api.post(`/applications/${appId}/sync`) const json = await response.json() return [response, json] @@ -70,7 +73,7 @@ export default class AppApi { return [response, json] } - async revert(appId: string): Promise<[Response, messageResponse]> { + async revert(appId: string): Promise<[Response, responseMessage]> { const response = await this.api.post(`/dev/${appId}/revert`) 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 d90c315849..ab996f7144 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/index.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/index.ts @@ -1,6 +1,8 @@ import ApplicationApi from "./applications" import AuthApi from "./auth" import InternalAPIClient from "./InternalAPIClient" +import TablesApi from "./tables" +import RowApi from "./rows" import ScreenApi from "./screens" export default class TestConfiguration { @@ -8,9 +10,13 @@ export default class TestConfiguration { auth: AuthApi screen: ScreenApi context: T + tables: TablesApi + rows: RowApi constructor(apiClient: InternalAPIClient) { this.applications = new ApplicationApi(apiClient) + this.tables = new TablesApi(apiClient) + this.rows = new RowApi(apiClient) this.auth = new AuthApi(apiClient) this.screen = new ScreenApi(apiClient) this.context = {} diff --git a/qa-core/src/config/internal-api/TestConfiguration/rows.ts b/qa-core/src/config/internal-api/TestConfiguration/rows.ts new file mode 100644 index 0000000000..010c8936c1 --- /dev/null +++ b/qa-core/src/config/internal-api/TestConfiguration/rows.ts @@ -0,0 +1,28 @@ +import { Response } from "node-fetch" +import { Row } from "@budibase/types" +import InternalAPIClient from "./InternalAPIClient" + +export default class RowsApi { + api: InternalAPIClient + + constructor(apiClient: InternalAPIClient) { + this.api = apiClient + } + + async getAll(tableId: string): Promise<[Response, Row[]]> { + const response = await this.api.get(`/${tableId}/rows`) + const json = await response.json() + 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() + 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() + 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 new file mode 100644 index 0000000000..bbafc73de5 --- /dev/null +++ b/qa-core/src/config/internal-api/TestConfiguration/tables.ts @@ -0,0 +1,40 @@ +import { Response } from "node-fetch" +import { Table } from "@budibase/types" +import InternalAPIClient from "./InternalAPIClient" +import { responseMessage } from "../fixtures/types/responseMessage" + + +export default class TablesApi { + api: InternalAPIClient + + constructor(apiClient: InternalAPIClient) { + this.api = apiClient + } + + async getAll(expectedNumber: Number): Promise<[Response, Table[]]> { + const response = await this.api.get(`/tables`) + const json = await response.json() + expect(response).toHaveStatusCode(200) + expect(json.length).toBe(expectedNumber) + return [response, json] + } + + async getTableById(id: string): Promise<[Response, Table]> { + const response = await this.api.get(`/tables/${id}`) + const json = await response.json() + return [response, json] + } + + async save(body: any): Promise<[Response, Table]> { + const response = await this.api.post(`/tables`, { body }) + const json = await response.json() + return [response, json] + } + + async delete(id: string, revId: string): Promise<[Response, responseMessage]> { + const response = await this.api.del(`/tables/${id}/${revId}`) + const json = await response.json() + return [response, json] + } + +} diff --git a/qa-core/src/config/internal-api/fixtures/rows.ts b/qa-core/src/config/internal-api/fixtures/rows.ts new file mode 100644 index 0000000000..f3c12d9ddd --- /dev/null +++ b/qa-core/src/config/internal-api/fixtures/rows.ts @@ -0,0 +1,8 @@ +import { Row } from "@budibase/types" + +export const generateNewRowForTable = (tableId: string): Row => { + return { + TestColumn: "TestRow", + tableId: tableId + } +} diff --git a/qa-core/src/config/internal-api/fixtures/table.ts b/qa-core/src/config/internal-api/fixtures/table.ts new file mode 100644 index 0000000000..9787dc500a --- /dev/null +++ b/qa-core/src/config/internal-api/fixtures/table.ts @@ -0,0 +1,34 @@ +import { Table } from "@budibase/types" + +export const generateTable = (): Table => { + return { + name: "Test Table", + schema: {}, + sourceId: "bb_internal", + type: "internal", + dataImport: { + valid: true, + schema: {} + } + } +} + +export const generateNewColumnForTable = (tableData: any): Table => { + const newColumn = tableData + newColumn.schema = { + TestColumn: { + type: "string", + name: "TestColumn", + constraints: { + presence: { allowEmpty: false }, + length: { maximum: null }, + type: "string" + } + } + } + newColumn.indexes = { + 0: "TestColumn" + } + newColumn.updatedAt = new Date().toISOString() + return newColumn +} diff --git a/qa-core/src/config/internal-api/fixtures/types/responseMessage.ts b/qa-core/src/config/internal-api/fixtures/types/responseMessage.ts new file mode 100644 index 0000000000..74931123fa --- /dev/null +++ b/qa-core/src/config/internal-api/fixtures/types/responseMessage.ts @@ -0,0 +1 @@ +export interface responseMessage { message: string } 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 aa71724cac..f96c915f14 100644 --- a/qa-core/src/tests/internal-api/applications/create.spec.ts +++ b/qa-core/src/tests/internal-api/applications/create.spec.ts @@ -5,6 +5,8 @@ import InternalAPIClient from "../../../config/internal-api/TestConfiguration/In 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 - /applications endpoints", () => { const api = new InternalAPIClient() @@ -40,16 +42,12 @@ describe("Internal API - /applications endpoints", () => { }) it("POST - Create an application", async () => { - const [response, app] = await config.applications.create(generateApp()) - expect(response).toHaveStatusCode(200) - expect(app._id).toBeDefined() + config.applications.create(generateApp()) }) it("POST - Publish application", async () => { // create app - const [response, app] = await config.applications.create(generateApp()) - expect(response).toHaveStatusCode(200) - expect(app.appId).toBeDefined() + const app = await config.applications.create(generateApp()) // publish app config.applications.api.appId = app.appId @@ -65,9 +63,7 @@ describe("Internal API - /applications endpoints", () => { 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() + const app = await createAppFromTemplate() config.applications.api.appId = app.appId // check preview renders @@ -87,9 +83,7 @@ describe("Internal API - /applications endpoints", () => { }) it("POST - Sync application before deployment", async () => { - const [response, app] = await config.applications.create(generateApp()) - expect(response).toHaveStatusCode(200) - expect(app.appId).toBeDefined() + const app = await config.applications.create(generateApp()) config.applications.api.appId = app.appId const [syncResponse, sync] = await config.applications.sync( @@ -102,9 +96,7 @@ describe("Internal API - /applications endpoints", () => { }) it("POST - Sync application after deployment", async () => { - const [response, app] = await config.applications.create(generateApp()) - expect(response).toHaveStatusCode(200) - expect(app.appId).toBeDefined() + const app = await config.applications.create(generateApp()) config.applications.api.appId = app.appId // publish app @@ -120,15 +112,14 @@ describe("Internal API - /applications endpoints", () => { }) it("PUT - Update an application", async () => { - const [response, app] = await config.applications.create(generateApp()) - expect(response).toHaveStatusCode(200) - expect(app.appId).toBeDefined() + const app = await config.applications.create(generateApp()) + config.applications.api.appId = app.appId const [updateResponse, updatedApp] = await config.applications.update( app.appId, { - name: generator.word(), + name: generator.word() } ) expect(updateResponse).toHaveStatusCode(200) @@ -136,9 +127,7 @@ describe("Internal API - /applications endpoints", () => { }) it("POST - Revert Changes without changes", async () => { - const [response, app] = await config.applications.create(generateApp()) - expect(response).toHaveStatusCode(200) - expect(app.appId).toBeDefined() + const app = await config.applications.create(generateApp()) config.applications.api.appId = app.appId const [revertResponse, revert] = await config.applications.revert( @@ -152,9 +141,7 @@ describe("Internal API - /applications endpoints", () => { }) it("POST - Revert Changes", async () => { - const [response, app] = await config.applications.create(generateApp()) - expect(response).toHaveStatusCode(200) - expect(app.appId).toBeDefined() + const app = await config.applications.create(generateApp()) config.applications.api.appId = app.appId // publish app @@ -185,11 +172,72 @@ describe("Internal API - /applications endpoints", () => { }) it("DELETE - Delete an application", async () => { - const [response, app] = await config.applications.create(generateApp()) - expect(response).toHaveStatusCode(200) - expect(app.appId).toBeDefined() + const app = await config.applications.create(generateApp()) const [deleteResponse] = await config.applications.delete(app.appId) expect(deleteResponse).toHaveStatusCode(200) }) + + 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 68e1022cb4..0ef9fcf279 100644 --- a/qa-core/src/tests/internal-api/screens/screens.spec.ts +++ b/qa-core/src/tests/internal-api/screens/screens.spec.ts @@ -2,7 +2,7 @@ import TestConfiguration from "../../../config/internal-api/TestConfiguration" import { App } from "@budibase/types" import InternalAPIClient from "../../../config/internal-api/TestConfiguration/InternalAPIClient" import generateApp from "../../../config/internal-api/fixtures/applications" -import { Screen } from "@budibase/types" +import { Screen } from "@budibase/types" import generateScreen from "../../../config/internal-api/fixtures/screens" @@ -21,8 +21,8 @@ describe("Internal API - /screens endpoints", () => { it("POST - Create a screen with each role type", async () => { // Create app - const [appResponse, app] = await appConfig.applications.create(generateApp()) - + const app = await appConfig.applications.create(generateApp()) + // Create Screen const roleArray = ["BASIC", "POWER", "ADMIN", "PUBLIC"] appConfig.applications.api.appId = app.appId @@ -35,8 +35,8 @@ describe("Internal API - /screens endpoints", () => { it("GET - Fetch screens", async () => { // Create app - const [appResponse, app] = await appConfig.applications.create(generateApp()) - + const app = await appConfig.applications.create(generateApp()) + // Create Screen appConfig.applications.api.appId = app.appId const [response, screen] = await config.screen.create(generateScreen("BASIC")) @@ -49,8 +49,8 @@ describe("Internal API - /screens endpoints", () => { it("DELETE - Delete a screen", async () => { // Create app - const [appResponse, app] = await appConfig.applications.create(generateApp()) - + const app = await appConfig.applications.create(generateApp()) + // Create Screen appConfig.applications.api.appId = app.appId const [screenResponse, screen] = await config.screen.create(generateScreen("BASIC"))