From 9474d249080eb25c27a4abd73608fbb814ca5425 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Thu, 23 Feb 2023 16:32:42 +0000 Subject: [PATCH] Add base for multiple environment support --- .../TestConfiguration/InternalAPIClient.ts | 2 - .../TestConfiguration/PublicAPIClient.ts | 26 ++++++-- .../public-api/TestConfiguration/accounts.ts | 38 +++++++++++ .../TestConfiguration/accountsAPIClient.ts | 64 +++++++++++++++++++ .../public-api/TestConfiguration/auth.ts | 48 ++++++++++++++ .../public-api/TestConfiguration/index.ts | 41 +++++++++++- .../config/public-api/fixtures/accounts.ts | 21 ++++++ .../fixtures/types/apiKeyResponse.ts | 6 ++ .../public-api/fixtures/types/newAccount.ts | 5 ++ .../applications/applications.spec.ts | 4 +- .../src/tests/public-api/tables/rows.spec.ts | 7 +- .../tests/public-api/tables/tables.spec.ts | 6 +- .../src/tests/public-api/users/users.spec.ts | 4 +- 13 files changed, 256 insertions(+), 16 deletions(-) create mode 100644 qa-core/src/config/public-api/TestConfiguration/accounts.ts create mode 100644 qa-core/src/config/public-api/TestConfiguration/accountsAPIClient.ts create mode 100644 qa-core/src/config/public-api/TestConfiguration/auth.ts create mode 100644 qa-core/src/config/public-api/fixtures/accounts.ts create mode 100644 qa-core/src/config/public-api/fixtures/types/apiKeyResponse.ts create mode 100644 qa-core/src/config/public-api/fixtures/types/newAccount.ts diff --git a/qa-core/src/config/internal-api/TestConfiguration/InternalAPIClient.ts b/qa-core/src/config/internal-api/TestConfiguration/InternalAPIClient.ts index ef47d8a12b..ce33a623b2 100644 --- a/qa-core/src/config/internal-api/TestConfiguration/InternalAPIClient.ts +++ b/qa-core/src/config/internal-api/TestConfiguration/InternalAPIClient.ts @@ -55,8 +55,6 @@ class InternalAPIClient { console.error(response) console.error("Response body:") console.error(response.body) - console.error("Request body:") - console.error(requestOptions.body) } return response } diff --git a/qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts b/qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts index 3721e31da3..14bc93ef06 100644 --- a/qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts +++ b/qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts @@ -11,20 +11,29 @@ interface ApiOptions { class PublicAPIClient { host: string - apiKey: string + apiKey?: string + tenantName?: string appId?: string + cookie?: string constructor(appId?: string) { - if (!env.BUDIBASE_PUBLIC_API_KEY || !env.BUDIBASE_SERVER_URL) { + if (!env.BUDIBASE_HOST) { throw new Error( "Must set BUDIBASE_PUBLIC_API_KEY and BUDIBASE_SERVER_URL env vars" ) } - this.host = `${env.BUDIBASE_SERVER_URL}/api/public/v1` - this.apiKey = env.BUDIBASE_PUBLIC_API_KEY + this.host = `${env.BUDIBASE_HOST}/api/public/v1` this.appId = appId } + setTenantName(tenantName: string) { + this.tenantName = tenantName + } + + setApiKey(apiKey: string) { + this.apiKey = apiKey + } + apiCall = (method: APIMethod) => async (url = "", options: ApiOptions = {}) => { @@ -32,16 +41,21 @@ class PublicAPIClient { method, body: JSON.stringify(options.body), headers: { - "x-budibase-api-key": this.apiKey, + "x-budibase-api-key": this.apiKey ? this.apiKey : null, "x-budibase-app-id": this.appId, "Content-Type": "application/json", Accept: "application/json", ...options.headers, + cookie: this.cookie, + redirect: "follow", + follow: 20, }, } + // prettier-ignore // @ts-ignore - const response = await fetch(`${this.host}${url}`, requestOptions) + const response = await fetch(`https://${process.env.TENANT_ID}.${this.host}${url}`, requestOptions) + if (response.status !== 200) { console.error(response) } diff --git a/qa-core/src/config/public-api/TestConfiguration/accounts.ts b/qa-core/src/config/public-api/TestConfiguration/accounts.ts new file mode 100644 index 0000000000..fdf5aedbd0 --- /dev/null +++ b/qa-core/src/config/public-api/TestConfiguration/accounts.ts @@ -0,0 +1,38 @@ +import { Response } from "node-fetch" +import { Account } from "@budibase/types" +import AccountsAPIClient from "./accountsAPIClient" +import { NewAccount } from "../fixtures/types/newAccount" + +export default class AccountsApi { + api: AccountsAPIClient + + constructor(AccountsAPIClient: AccountsAPIClient) { + this.api = AccountsAPIClient + } + + async validateEmail(email: string): Promise { + const response = await this.api.post(`/accounts/validate/email`, { + body: { email }, + }) + expect(response).toHaveStatusCode(200) + return response + } + + async validateTenantId(tenantId: string): Promise { + const response = await this.api.post(`/accounts/validate/tenantId`, { + body: { tenantId }, + }) + expect(response).toHaveStatusCode(200) + return response + } + + async create(body: Partial): Promise<[Response, Account]> { + const headers = { + "no-verify": "1", + } + const response = await this.api.post(`/accounts`, { body, headers }) + const json = await response.json() + expect(response).toHaveStatusCode(201) + return [response, json] + } +} diff --git a/qa-core/src/config/public-api/TestConfiguration/accountsAPIClient.ts b/qa-core/src/config/public-api/TestConfiguration/accountsAPIClient.ts new file mode 100644 index 0000000000..aff821a7ac --- /dev/null +++ b/qa-core/src/config/public-api/TestConfiguration/accountsAPIClient.ts @@ -0,0 +1,64 @@ +import env from "../../../environment" +import fetch, { HeadersInit } from "node-fetch" + +type APIMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" + +interface ApiOptions { + method?: APIMethod + body?: object + headers?: HeadersInit | undefined +} + +class AccountsAPIClient { + host: string + appId?: string + cookie?: string + + constructor(appId?: string) { + if (!env.BUDIBASE_ACCOUNTS_URL) { + throw new Error("Must set BUDIBASE_SERVER_URL env var") + } + this.host = `${env.BUDIBASE_ACCOUNTS_URL}/api` + this.appId = appId + } + + apiCall = + (method: APIMethod) => + async (url = "", options: ApiOptions = {}) => { + const requestOptions = { + method, + body: JSON.stringify(options.body), + headers: { + "x-budibase-app-id": this.appId, + "Content-Type": "application/json", + Accept: "application/json", + cookie: this.cookie, + redirect: "follow", + follow: 20, + ...options.headers, + }, + credentials: "include", + } + + // @ts-ignore + const response = await fetch(`${this.host}${url}`, requestOptions) + if (response.status == 404 || response.status == 500) { + console.error("Error in apiCall") + console.error("Response:") + console.error(response) + console.error("Response body:") + console.error(response.body) + console.error("Request body:") + console.error(requestOptions.body) + } + return response + } + + post = this.apiCall("POST") + get = this.apiCall("GET") + patch = this.apiCall("PATCH") + del = this.apiCall("DELETE") + put = this.apiCall("PUT") +} + +export default AccountsAPIClient diff --git a/qa-core/src/config/public-api/TestConfiguration/auth.ts b/qa-core/src/config/public-api/TestConfiguration/auth.ts new file mode 100644 index 0000000000..663b39e5e9 --- /dev/null +++ b/qa-core/src/config/public-api/TestConfiguration/auth.ts @@ -0,0 +1,48 @@ +import { Response } from "node-fetch" +import PublicAPIClient from "./PublicAPIClient" +import { ApiKeyResponse } from "../fixtures/types/apiKeyResponse" + +export default class AuthApi { + api: PublicAPIClient + + constructor(apiClient: PublicAPIClient) { + this.api = apiClient + } + + async loginAsAdmin(): Promise<[Response, any]> { + const response = await this.api.post(`/global/auth/default/login`, { + body: { + username: process.env.BB_ADMIN_USER_EMAIL, + password: process.env.BB_ADMIN_USER_PASSWORD, + }, + }) + const cookie = response.headers.get("set-cookie") + this.api.cookie = cookie as any + return [response, cookie] + } + + async login(email: String, password: String): Promise<[Response, any]> { + const response = await this.api.post(`/global/auth/default/login`, { + body: { + username: email, + password: password, + }, + }) + expect(response).toHaveStatusCode(200) + const cookie = response.headers.get("set-cookie") + this.api.cookie = cookie as any + return [response, cookie] + } + + async logout(): Promise { + return this.api.post(`/global/auth/logout`) + } + + async getApiKey(): Promise { + const response = await this.api.get(`/global/self/api_key`) + const json = await response.json() + expect(response).toHaveStatusCode(200) + expect(json).toHaveProperty("apiKey") + return json + } +} diff --git a/qa-core/src/config/public-api/TestConfiguration/index.ts b/qa-core/src/config/public-api/TestConfiguration/index.ts index 36cc3022b0..1a760ae883 100644 --- a/qa-core/src/config/public-api/TestConfiguration/index.ts +++ b/qa-core/src/config/public-api/TestConfiguration/index.ts @@ -3,15 +3,31 @@ import ApplicationApi from "./applications" import TableApi from "./tables" import UserApi from "./users" import RowApi from "./rows" +import AuthApi from "./auth" +import AccountsApiClient from "./accountsAPIClient" +import AccountsApi from "./accounts" +import { generateAccount } from "../fixtures/accounts" export default class TestConfiguration { applications: ApplicationApi + auth: AuthApi users: UserApi tables: TableApi rows: RowApi context: T + accounts: AccountsApi + apiClient: PublicAPIClient + accountsApiClient: AccountsApiClient - constructor(apiClient: PublicAPIClient) { + constructor( + apiClient: PublicAPIClient, + accountsApiClient: AccountsApiClient + ) { + this.apiClient = apiClient + this.accountsApiClient = accountsApiClient + + this.auth = new AuthApi(this.apiClient) + this.accounts = new AccountsApi(this.accountsApiClient) this.applications = new ApplicationApi(apiClient) this.users = new UserApi(apiClient) this.tables = new TableApi(apiClient) @@ -19,6 +35,29 @@ export default class TestConfiguration { this.context = {} } + async setupAccountAndTenant() { + const account = generateAccount() + await this.accounts.validateEmail(account.email) + await this.accounts.validateTenantId(account.tenantId) + process.env.TENANT_ID = account.tenantId + await this.accounts.create(account) + await this.updateApiClients(account.tenantName) + await this.auth.login(account.email, account.password) + } + + async setApiKey() { + const apiKeyResponse = await this.auth.getApiKey() + this.apiClient.setApiKey(apiKeyResponse.apiKey) + } + async updateApiClients(tenantName: string) { + this.apiClient.setTenantName(tenantName) + this.applications = new ApplicationApi(this.apiClient) + this.rows = new RowApi(this.apiClient) + this.auth = new AuthApi(this.apiClient) + + this.context = {} + } + async beforeAll() {} async afterAll() { diff --git a/qa-core/src/config/public-api/fixtures/accounts.ts b/qa-core/src/config/public-api/fixtures/accounts.ts new file mode 100644 index 0000000000..dbeabae928 --- /dev/null +++ b/qa-core/src/config/public-api/fixtures/accounts.ts @@ -0,0 +1,21 @@ +import { NewAccount } from "./types/newAccount" + +import generator from "../../generator" +import { Hosting } from "@budibase/types" + +export const generateAccount = (): Partial => { + const randomGuid = generator.guid() + let tenant: string = "a" + randomGuid + tenant = tenant.replace(/-/g, "") + + return { + email: `qa+${randomGuid}@budibase.com`, + hosting: Hosting.CLOUD, + name: `qa+${randomGuid}@budibase.com`, + password: `${randomGuid}`, + profession: "software_engineer", + size: "10+", + tenantId: `${tenant}`, + tenantName: `${tenant}`, + } +} diff --git a/qa-core/src/config/public-api/fixtures/types/apiKeyResponse.ts b/qa-core/src/config/public-api/fixtures/types/apiKeyResponse.ts new file mode 100644 index 0000000000..4a62d60796 --- /dev/null +++ b/qa-core/src/config/public-api/fixtures/types/apiKeyResponse.ts @@ -0,0 +1,6 @@ +export interface ApiKeyResponse { + apiKey: string + createdAt: string + updatedAt: string + userId: string +} diff --git a/qa-core/src/config/public-api/fixtures/types/newAccount.ts b/qa-core/src/config/public-api/fixtures/types/newAccount.ts new file mode 100644 index 0000000000..e7ad88e697 --- /dev/null +++ b/qa-core/src/config/public-api/fixtures/types/newAccount.ts @@ -0,0 +1,5 @@ +import { Account } from "@budibase/types" + +export interface NewAccount extends Account { + password: string +} diff --git a/qa-core/src/tests/public-api/applications/applications.spec.ts b/qa-core/src/tests/public-api/applications/applications.spec.ts index cf85e6daf2..4a8751ce56 100644 --- a/qa-core/src/tests/public-api/applications/applications.spec.ts +++ b/qa-core/src/tests/public-api/applications/applications.spec.ts @@ -1,12 +1,14 @@ import TestConfiguration from "../../../config/public-api/TestConfiguration" import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" +import AccountsAPIClient from "../../../config/public-api/TestConfiguration/accountsAPIClient" import generateApp from "../../../config/public-api/fixtures/applications" import { Application } from "@budibase/server/api/controllers/public/mapping/types" import { db as dbCore } from "@budibase/backend-core" describe("Public API - /applications endpoints", () => { const api = new PublicAPIClient() - const config = new TestConfiguration(api) + const accountsAPI = new AccountsAPIClient() + const config = new TestConfiguration(api, accountsAPI) beforeAll(async () => { await config.beforeAll() diff --git a/qa-core/src/tests/public-api/tables/rows.spec.ts b/qa-core/src/tests/public-api/tables/rows.spec.ts index 89149159ab..87dbd509cc 100644 --- a/qa-core/src/tests/public-api/tables/rows.spec.ts +++ b/qa-core/src/tests/public-api/tables/rows.spec.ts @@ -2,11 +2,12 @@ import { Row } from "@budibase/server/api/controllers/public/mapping/types" import { generateRow } from "../../../config/public-api/fixtures/tables" import TestConfiguration from "../../../config/public-api/TestConfiguration" import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" +import AccountsAPIClient from "../../../config/public-api/TestConfiguration/accountsAPIClient" describe("Public API - /rows endpoints", () => { - let api = new PublicAPIClient() - - const config = new TestConfiguration(api) + const api = new PublicAPIClient() + const accountsAPI = new AccountsAPIClient() + const config = new TestConfiguration(api, accountsAPI) beforeAll(async () => { await config.beforeAll() diff --git a/qa-core/src/tests/public-api/tables/tables.spec.ts b/qa-core/src/tests/public-api/tables/tables.spec.ts index de1ce142ce..d0601d0835 100644 --- a/qa-core/src/tests/public-api/tables/tables.spec.ts +++ b/qa-core/src/tests/public-api/tables/tables.spec.ts @@ -2,10 +2,12 @@ import { Table } from "@budibase/server/api/controllers/public/mapping/types" import { generateTable } from "../../../config/public-api/fixtures/tables" import TestConfiguration from "../../../config/public-api/TestConfiguration" import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" +import AccountsAPIClient from "../../../config/public-api/TestConfiguration/accountsAPIClient" describe("Public API - /tables endpoints", () => { - let api = new PublicAPIClient() - const config = new TestConfiguration(api) + const api = new PublicAPIClient() + const accountsAPI = new AccountsAPIClient() + const config = new TestConfiguration
(api, accountsAPI) beforeAll(async () => { await config.beforeAll() diff --git a/qa-core/src/tests/public-api/users/users.spec.ts b/qa-core/src/tests/public-api/users/users.spec.ts index 5e68c77c50..edc675fd81 100644 --- a/qa-core/src/tests/public-api/users/users.spec.ts +++ b/qa-core/src/tests/public-api/users/users.spec.ts @@ -2,10 +2,12 @@ import TestConfiguration from "../../../config/public-api/TestConfiguration" import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" import generateUser from "../../../config/public-api/fixtures/users" import { User } from "@budibase/server/api/controllers/public/mapping/types" +import AccountsAPIClient from "../../../config/public-api/TestConfiguration/accountsAPIClient" describe("Public API - /users endpoints", () => { const api = new PublicAPIClient() - const config = new TestConfiguration(api) + const accountsAPI = new AccountsAPIClient() + const config = new TestConfiguration(api, accountsAPI) beforeAll(async () => { await config.beforeAll()