From 944b6e0baae7f01f5de5e79ff9413edc3dd25ba5 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Tue, 18 Jul 2023 21:14:07 +0100 Subject: [PATCH] Update account api clients to consistently handle status code handling and return types --- .../src/account-api/api/apis/AccountAPI.ts | 166 +++++++++--------- qa-core/src/account-api/api/apis/AuthAPI.ts | 33 ++-- qa-core/src/account-api/api/apis/BaseAPI.ts | 22 +++ .../src/account-api/api/apis/LicenseAPI.ts | 29 ++- 4 files changed, 140 insertions(+), 110 deletions(-) create mode 100644 qa-core/src/account-api/api/apis/BaseAPI.ts diff --git a/qa-core/src/account-api/api/apis/AccountAPI.ts b/qa-core/src/account-api/api/apis/AccountAPI.ts index 9450f6b2cd..8c6ccec6b8 100644 --- a/qa-core/src/account-api/api/apis/AccountAPI.ts +++ b/qa-core/src/account-api/api/apis/AccountAPI.ts @@ -2,127 +2,135 @@ import { Response } from "node-fetch" import { Account, CreateAccountRequest, SearchAccountsRequest, SearchAccountsResponse } from "@budibase/types" import AccountInternalAPIClient from "../AccountInternalAPIClient" import { APIRequestOpts } from "../../../types" +import { Header } from "@budibase/backend-core" +import BaseAPI from "./BaseAPI" -export default class AccountAPI { +export default class AccountAPI extends BaseAPI { client: AccountInternalAPIClient constructor(client: AccountInternalAPIClient) { + super() this.client = client } async validateEmail( email: string, - opts: APIRequestOpts = { doExpect: true } - ): Promise { - const [response, json] = await this.client.post( - `/api/accounts/validate/email`, - { - body: { email }, - } - ) - return response + opts: APIRequestOpts = { status: 200 } + ) { + return this.doRequest(() => { + return this.client.post( + `/api/accounts/validate/email`, + { + body: { email }, + } + ) + }, opts) } async validateTenantId( tenantId: string, - opts: APIRequestOpts = { doExpect: true } - ): Promise { - const [response, json] = await this.client.post( - `/api/accounts/validate/tenantId`, - { - body: { tenantId }, - } - ) - return response + opts: APIRequestOpts = { status: 200 } + ) { + return this.doRequest(() => { + return this.client.post( + `/api/accounts/validate/tenantId`, + { + body: { tenantId }, + } + ) + }, opts) } async create( body: CreateAccountRequest, - opts: APIRequestOpts & { autoVerify: boolean } = { doExpect: true, autoVerify: true } + opts: APIRequestOpts & { autoVerify: boolean } = { status: 201, autoVerify: false } ): Promise<[Response, Account]> { - const headers = { - "no-verify": opts.autoVerify ? "1" : "0" - } - const [response, json] = await this.client.post(`/api/accounts`, { - body, - headers, - }) - if (opts.doExpect) { - expect(response).toHaveStatusCode(201) - } - return [response, json] - } - - async delete(accountID: string, opts: APIRequestOpts = {status:204}) { - const [response, json] = await this.client.del( - `/api/accounts/${accountID}`, - { - internal: true, + return this.doRequest(() => { + const headers = { + "no-verify": opts.autoVerify ? "1" : "0" } - ) - // can't use expect here due to use in global teardown - if (response.status !== opts.status) { - throw new Error(`status: ${response.status} not equal to expected: ${opts.status}`) - } - return response + return this.client.post(`/api/accounts`, { + body, + headers, + }) + }, opts) } - async deleteCurrentAccount() { - const [response, json] = await this.client.del( + async delete( + accountID: string, + opts: APIRequestOpts = { status: 204 }) { + return this.doRequest(() => { + return this.client.del( + `/api/accounts/${accountID}`, + { + internal: true, + } + ) + }, opts) + } + + async deleteCurrentAccount( + opts: APIRequestOpts = { status: 204 } + ) { + return this.doRequest(() => { + return this.client.del( `/api/accounts` - ) - return response + ) + }, opts) } async verifyAccount( - verificationCode: string, - opts: APIRequestOpts = { doExpect: true } - ): Promise { - const [response, json] = await this.client.post( + verificationCode: string, + opts: APIRequestOpts = { status: 200 } + ){ + return this.doRequest(() => { + return this.client.post( `/api/accounts/verify`, { body: { verificationCode }, } - ) - if (opts.doExpect) { - expect(response).toHaveStatusCode(200) - } - return response + ) + }, opts) } - async verifyAccountSendEmail( + async sendVerificationEmail( email: string, - opts: APIRequestOpts = { doExpect: true } - ): Promise { - const [response, json] = await this.client.post( + opts: APIRequestOpts = { status: 200 } + ): Promise<[Response, string]> { + return this.doRequest(async () => { + const [response] = await this.client.post( `/api/accounts/verify/send`, { body: { email }, + headers: { + [Header.RETURN_VERIFICATION_CODE]: "1" + } } - ) - if (opts.doExpect) { - expect(response).toHaveStatusCode(200) - } - return response + ) + const code = response.headers.get(Header.VERIFICATION_CODE) + return [response, code] + }, opts) } async search( searchType: string, search: 'email' | 'tenantId', - opts: APIRequestOpts = { doExpect: true } + opts: APIRequestOpts = { status: 200 } ): Promise<[Response, SearchAccountsResponse]> { - let body: SearchAccountsRequest = {} - - if (search === 'email') { - body.email = searchType - } else if (search === 'tenantId') { - body.tenantId = searchType - } - - const [response, json] = await this.client.post( + return this.doRequest(() => { + let body: SearchAccountsRequest = {} + if (search === 'email') { + body.email = searchType + } else if (search === 'tenantId') { + body.tenantId = searchType + } + return this.client.post( `/api/accounts/search`, - {body: body} - ) - return [response, json] + { + body, + internal: true + } + ) + }, opts) } } diff --git a/qa-core/src/account-api/api/apis/AuthAPI.ts b/qa-core/src/account-api/api/apis/AuthAPI.ts index 5f2df6d250..c5d654ade0 100644 --- a/qa-core/src/account-api/api/apis/AuthAPI.ts +++ b/qa-core/src/account-api/api/apis/AuthAPI.ts @@ -1,32 +1,33 @@ import { Response } from "node-fetch" import AccountInternalAPIClient from "../AccountInternalAPIClient" import { APIRequestOpts } from "../../../types" +import BaseAPI from "./BaseAPI" -export default class AuthAPI { +export default class AuthAPI extends BaseAPI { client: AccountInternalAPIClient constructor(client: AccountInternalAPIClient) { + super() this.client = client } async login( email: string, password: string, - opts: APIRequestOpts = { doExpect: true } + opts: APIRequestOpts = { doExpect: true, status: 200 } ): Promise<[Response, string]> { - const [response, json] = await this.client.post( - `/api/auth/login`, - { - body: { - email: email, - password: password, - }, - } - ) - // if (opts.doExpect) { - // expect(response).toHaveStatusCode(200) - // } - const cookie = response.headers.get("set-cookie") - return [response, cookie!] + return this.doRequest(async () => { + const [res] = await this.client.post( + `/api/auth/login`, + { + body: { + email: email, + password: password, + }, + } + ) + const cookie = res.headers.get("set-cookie") + return [res, cookie] + }, opts) } } diff --git a/qa-core/src/account-api/api/apis/BaseAPI.ts b/qa-core/src/account-api/api/apis/BaseAPI.ts new file mode 100644 index 0000000000..db0d921dd6 --- /dev/null +++ b/qa-core/src/account-api/api/apis/BaseAPI.ts @@ -0,0 +1,22 @@ +import { Response } from "node-fetch" +import { APIRequestOpts } from "../../../types" + +// TODO: Add to LicenseAPI + +export default class BaseAPI { + + async doRequest( + request: () => Promise<[Response, any]>, + opts: APIRequestOpts): Promise<[Response, any]> { + const [response, body] = await request() + + // do expect on by default + if (opts.doExpect === undefined) { + opts.doExpect = true + } + if (opts.doExpect && opts.status) { + expect(response).toHaveStatusCode(opts.status) + } + return [response, body] + } +} \ No newline at end of file diff --git a/qa-core/src/account-api/api/apis/LicenseAPI.ts b/qa-core/src/account-api/api/apis/LicenseAPI.ts index e0601fe127..67e67edcb1 100644 --- a/qa-core/src/account-api/api/apis/LicenseAPI.ts +++ b/qa-core/src/account-api/api/apis/LicenseAPI.ts @@ -1,31 +1,30 @@ import AccountInternalAPIClient from "../AccountInternalAPIClient" import { Account, UpdateLicenseRequest } from "@budibase/types" import { Response } from "node-fetch" +import BaseAPI from "./BaseAPI" +import { APIRequestOpts } from "../../../types" -export default class LicenseAPI { +export default class LicenseAPI extends BaseAPI { client: AccountInternalAPIClient constructor(client: AccountInternalAPIClient) { + super() this.client = client } async updateLicense( accountId: string, - body: UpdateLicenseRequest + body: UpdateLicenseRequest, + opts: APIRequestOpts = { status: 200 } ): Promise<[Response, Account]> { - const [response, json] = await this.client.put( - `/api/accounts/${accountId}/license`, - { - body, - internal: true, - } - ) - - if (response.status !== 200) { - throw new Error( - `Could not update license for accountId=${accountId}: ${response.status}` + return this.doRequest(() => { + return this.client.put( + `/api/accounts/${accountId}/license`, + { + body, + internal: true, + } ) - } - return [response, json] + }, opts) } }