diff --git a/qa-core/src/account-api/api/AccountInternalAPI.ts b/qa-core/src/account-api/api/AccountInternalAPI.ts index ef2c39d5a4..f89bf556f2 100644 --- a/qa-core/src/account-api/api/AccountInternalAPI.ts +++ b/qa-core/src/account-api/api/AccountInternalAPI.ts @@ -15,6 +15,6 @@ export default class AccountInternalAPI { this.auth = new AuthAPI(this.client) this.accounts = new AccountAPI(this.client) this.licenses = new LicenseAPI(this.client) - this.stripe = new StripeAPI((this.client)) + this.stripe = new StripeAPI(this.client) } } diff --git a/qa-core/src/account-api/api/apis/LicenseAPI.ts b/qa-core/src/account-api/api/apis/LicenseAPI.ts index 9f06ec7198..dba1a661d4 100644 --- a/qa-core/src/account-api/api/apis/LicenseAPI.ts +++ b/qa-core/src/account-api/api/apis/LicenseAPI.ts @@ -16,9 +16,9 @@ export default class LicenseAPI extends BaseAPI { this.client = client } async updateLicense( - accountId: string, - body: UpdateLicenseRequest, - opts: APIRequestOpts = { status: 200 } + accountId: string, + body: UpdateLicenseRequest, + opts: APIRequestOpts = { status: 200 } ): Promise<[Response, Account]> { return this.doRequest(() => { return this.client.put(`/api/accounts/${accountId}/license`, { @@ -29,53 +29,53 @@ export default class LicenseAPI extends BaseAPI { } // TODO: Better approach for setting tenant id header async createOfflineLicense( - accountId: string, - tenantId: string, - body: CreateOfflineLicenseRequest, - opts: { status?: number } = {} + accountId: string, + tenantId: string, + body: CreateOfflineLicenseRequest, + opts: { status?: number } = {} ): Promise { const [response, json] = await this.client.post( - `/api/internal/accounts/${accountId}/license/offline`, - { - body, - internal: true, - headers: { - "x-budibase-tenant-id": tenantId, - }, - } + `/api/internal/accounts/${accountId}/license/offline`, + { + body, + internal: true, + headers: { + "x-budibase-tenant-id": tenantId, + }, + } ) expect(response.status).toBe(opts.status ? opts.status : 201) return response } async getOfflineLicense( - accountId: string, - tenantId: string, - opts: { status?: number } = {} + accountId: string, + tenantId: string, + opts: { status?: number } = {} ): Promise<[Response, GetOfflineLicenseResponse]> { const [response, json] = await this.client.get( - `/api/internal/accounts/${accountId}/license/offline`, - { - internal: true, - headers: { - "x-budibase-tenant-id": tenantId, - }, - } + `/api/internal/accounts/${accountId}/license/offline`, + { + internal: true, + headers: { + "x-budibase-tenant-id": tenantId, + }, + } ) expect(response.status).toBe(opts.status ? opts.status : 200) return [response, json] } async getLicenseKey( - opts: { status?: number } = {} + opts: { status?: number } = {} ): Promise<[Response, GetLicenseKeyResponse]> { const [response, json] = await this.client.get(`/api/license/key`) expect(response.status).toBe(opts.status ? opts.status : 200) return [response, json] } async activateLicense( - apiKey: string, - tenantId: string, - licenseKey: string, - opts: APIRequestOpts = { status: 200 } + apiKey: string, + tenantId: string, + licenseKey: string, + opts: APIRequestOpts = { status: 200 } ) { return this.doRequest(() => { return this.client.post(`/api/license/activate`, { @@ -106,14 +106,14 @@ export default class LicenseAPI extends BaseAPI { } async refreshAccountLicense( - accountId: string, - opts: { status?: number } = {} + accountId: string, + opts: { status?: number } = {} ): Promise { const [response, json] = await this.client.post( - `/api/accounts/${accountId}/license/refresh`, - { - internal: true, - } + `/api/accounts/${accountId}/license/refresh`, + { + internal: true, + } ) expect(response.status).toBe(opts.status ? opts.status : 201) return response @@ -126,12 +126,12 @@ export default class LicenseAPI extends BaseAPI { } async licenseUsageTriggered( - opts: { status?: number } = {} + opts: { status?: number } = {} ): Promise { const [response, json] = await this.client.post( - `/api/license/usage/triggered` + `/api/license/usage/triggered` ) expect(response.status).toBe(opts.status ? opts.status : 201) return response } -} \ No newline at end of file +} diff --git a/qa-core/src/account-api/api/apis/StripeAPI.ts b/qa-core/src/account-api/api/apis/StripeAPI.ts index ffa96b3c2b..c9c776e89b 100644 --- a/qa-core/src/account-api/api/apis/StripeAPI.ts +++ b/qa-core/src/account-api/api/apis/StripeAPI.ts @@ -3,62 +3,62 @@ import BaseAPI from "./BaseAPI" import { APIRequestOpts } from "../../../types" export default class StripeAPI extends BaseAPI { - client: AccountInternalAPIClient + client: AccountInternalAPIClient - constructor(client: AccountInternalAPIClient) { - super() - this.client = client - } + constructor(client: AccountInternalAPIClient) { + super() + this.client = client + } - async createCheckoutSession( - priceId: string, - opts: APIRequestOpts = { status: 200 } - ) { - return this.doRequest(() => { - return this.client.post(`/api/stripe/checkout-session`, { - body: { priceId }, - }) - }, opts) - } + async createCheckoutSession( + priceId: string, + opts: APIRequestOpts = { status: 200 } + ) { + return this.doRequest(() => { + return this.client.post(`/api/stripe/checkout-session`, { + body: { priceId }, + }) + }, opts) + } - async checkoutSuccess(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.post(`/api/stripe/checkout-success`) - }, opts) - } + async checkoutSuccess(opts: APIRequestOpts = { status: 200 }) { + return this.doRequest(() => { + return this.client.post(`/api/stripe/checkout-success`) + }, opts) + } - async createPortalSession( - stripeCustomerId: string, - opts: APIRequestOpts = { status: 200 } - ) { - return this.doRequest(() => { - return this.client.post(`/api/stripe/portal-session`, { - body: { stripeCustomerId }, - }) - }, opts) - } + async createPortalSession( + stripeCustomerId: string, + opts: APIRequestOpts = { status: 200 } + ) { + return this.doRequest(() => { + return this.client.post(`/api/stripe/portal-session`, { + body: { stripeCustomerId }, + }) + }, opts) + } - async linkStripeCustomer(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.post(`/api/stripe/link`) - }, opts) - } + async linkStripeCustomer(opts: APIRequestOpts = { status: 200 }) { + return this.doRequest(() => { + return this.client.post(`/api/stripe/link`) + }, opts) + } - async getInvoices(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.get(`/api/stripe/invoices`) - }, opts) - } + async getInvoices(opts: APIRequestOpts = { status: 200 }) { + return this.doRequest(() => { + return this.client.get(`/api/stripe/invoices`) + }, opts) + } - async getUpcomingInvoice(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.get(`/api/stripe/upcoming-invoice`) - }, opts) - } + async getUpcomingInvoice(opts: APIRequestOpts = { status: 200 }) { + return this.doRequest(() => { + return this.client.get(`/api/stripe/upcoming-invoice`) + }, opts) + } - async getStripeCustomers(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.get(`/api/stripe/customers`) - }, opts) - } + async getStripeCustomers(opts: APIRequestOpts = { status: 200 }) { + return this.doRequest(() => { + return this.client.get(`/api/stripe/customers`) + }, opts) + } } diff --git a/qa-core/src/account-api/tests/licensing/license.activate.spec.ts b/qa-core/src/account-api/tests/licensing/license.activate.spec.ts index 709e2c33f0..a494ceb354 100644 --- a/qa-core/src/account-api/tests/licensing/license.activate.spec.ts +++ b/qa-core/src/account-api/tests/licensing/license.activate.spec.ts @@ -3,72 +3,73 @@ import * as fixures from "../../fixtures" import { Feature, Hosting } from "@budibase/types" describe("license activation", () => { - const config = new TestConfiguration() + const config = new TestConfiguration() - beforeAll(async () => { - await config.beforeAll() + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("creates, activates and deletes online license - self host", async () => { + // Remove existing license key + await config.internalApi.license.deleteLicenseKey() + + // Verify license key not found + await config.internalApi.license.getLicenseKey({ status: 404 }) + + // Create self host account + const createAccountRequest = fixures.accounts.generateAccount({ + hosting: Hosting.SELF, + }) + const [createAccountRes, account] = + await config.accountsApi.accounts.create(createAccountRequest, { + autoVerify: true, + }) + + let licenseKey: string = " " + await config.doInNewState(async () => { + await config.loginAsAccount(createAccountRequest) + // Retrieve license key + const [res, body] = await config.accountsApi.licenses.getLicenseKey() + licenseKey = body.licenseKey }) - afterAll(async () => { - await config.afterAll() + const accountId = account.accountId! + + // Update license to have paid feature + const [res, acc] = await config.accountsApi.licenses.updateLicense( + accountId, + { + overrides: { + features: [Feature.APP_BACKUPS], + }, + } + ) + + // Activate license key + await config.internalApi.license.activateLicenseKey({ licenseKey }) + + // Verify license updated with new feature + await config.doInNewState(async () => { + await config.loginAsAccount(createAccountRequest) + const [selfRes, body] = await config.api.accounts.self() + expect(body.license.features[0]).toBe("appBackups") }) - it("creates, activates and deletes online license - self host", async () => { - // Remove existing license key - await config.internalApi.license.deleteLicenseKey() + // Remove license key + await config.internalApi.license.deleteLicenseKey() - // Verify license key not found - await config.internalApi.license.getLicenseKey({ status: 404 }) + // Verify license key not found + await config.internalApi.license.getLicenseKey({ status: 404 }) - // Create self host account - const createAccountRequest = fixures.accounts.generateAccount({ - hosting: Hosting.SELF, - }) - const [createAccountRes, account] = - await config.accountsApi.accounts.create(createAccountRequest, { autoVerify: true }) - - let licenseKey: string = " " - await config.doInNewState(async () => { - await config.loginAsAccount(createAccountRequest) - // Retrieve license key - const [res, body] = - await config.accountsApi.licenses.getLicenseKey() - licenseKey = body.licenseKey - }) - - const accountId = account.accountId! - - // Update license to have paid feature - const [res, acc] = await config.accountsApi.licenses.updateLicense( - accountId, - { - overrides: { - features: [Feature.APP_BACKUPS], - }, - } - ) - - // Activate license key - await config.internalApi.license.activateLicenseKey({licenseKey}) - - // Verify license updated with new feature - await config.doInNewState(async () => { - await config.loginAsAccount(createAccountRequest) - const [selfRes, body] = await config.api.accounts.self() - expect(body.license.features[0]).toBe("appBackups") - }) - - // Remove license key - await config.internalApi.license.deleteLicenseKey() - - // Verify license key not found - await config.internalApi.license.getLicenseKey({ status: 404 }) - - // Verify user downgraded to free license - await config.doInNewState(async () => { - await config.loginAsAccount(createAccountRequest) - const [selfRes, body] = await config.api.accounts.self() - expect(body.license.plan.type).toBe("free") - }) + // Verify user downgraded to free license + await config.doInNewState(async () => { + await config.loginAsAccount(createAccountRequest) + const [selfRes, body] = await config.api.accounts.self() + expect(body.license.plan.type).toBe("free") }) + }) }) diff --git a/qa-core/src/account-api/tests/licensing/license.manage.spec.ts b/qa-core/src/account-api/tests/licensing/license.manage.spec.ts index 967252a0f9..3f87838ee4 100644 --- a/qa-core/src/account-api/tests/licensing/license.manage.spec.ts +++ b/qa-core/src/account-api/tests/licensing/license.manage.spec.ts @@ -3,55 +3,55 @@ import * as fixtures from "../../fixtures" import { Hosting, PlanType } from "@budibase/types" describe("license management", () => { - const config = new TestConfiguration() + const config = new TestConfiguration() - beforeAll(async () => { - await config.beforeAll() + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("retrieves plans, creates checkout session, and updates license", async () => { + // Create cloud account + const createAccountRequest = fixtures.accounts.generateAccount({ + hosting: Hosting.CLOUD, }) - afterAll(async () => { - await config.afterAll() - }) + // Self response has free license + const [selfRes, selfBody] = await config.api.accounts.self() + expect(selfBody.license.plan.type).toBe(PlanType.FREE) - it("retrieves plans, creates checkout session, and updates license", async () => { - // Create cloud account - const createAccountRequest = fixtures.accounts.generateAccount({ - hosting: Hosting.CLOUD, - }) + // Retrieve plans + const [plansRes, planBody] = await config.api.licenses.getPlans() - // Self response has free license - const [selfRes, selfBody] = await config.api.accounts.self() - expect(selfBody.license.plan.type).toBe(PlanType.FREE) + // Select priceId from premium plan + let premiumPriceId = null + for (const plan of planBody) { + if (plan.type === PlanType.PREMIUM) { + premiumPriceId = plan.prices[0].priceId + break + } + } - // Retrieve plans - const [plansRes, planBody] = await config.api.licenses.getPlans() + // Create checkout session for price + const checkoutSessionRes = await config.api.stripe.createCheckoutSession( + premiumPriceId + ) + const checkoutSessionUrl = checkoutSessionRes[1].url + expect(checkoutSessionUrl).toContain("checkout.stripe.com") - // Select priceId from premium plan - let premiumPriceId = null - for (const plan of planBody) { - if (plan.type === PlanType.PREMIUM) { - premiumPriceId = plan.prices[0].priceId - break - } - } + // TODO: Mimic checkout success + // Create stripe customer + // Create subscription for premium plan + // Assert license updated from free to premium - // Create checkout session for price - const checkoutSessionRes = await config.api.stripe.createCheckoutSession( - premiumPriceId - ) - const checkoutSessionUrl = checkoutSessionRes[1].url - expect(checkoutSessionUrl).toContain("checkout.stripe.com") + // Create portal session + //await config.api.stripe.createPortalSession() - // TODO: Mimic checkout success - // Create stripe customer - // Create subscription for premium plan - // Assert license updated from free to premium + // Update from free to business license - // Create portal session - //await config.api.stripe.createPortalSession() - - // Update from free to business license - - // License updated - }) + // License updated + }) }) diff --git a/qa-core/src/internal-api/api/apis/LicenseAPI.ts b/qa-core/src/internal-api/api/apis/LicenseAPI.ts index 268f8781c3..ef322e069a 100644 --- a/qa-core/src/internal-api/api/apis/LicenseAPI.ts +++ b/qa-core/src/internal-api/api/apis/LicenseAPI.ts @@ -15,11 +15,11 @@ export default class LicenseAPI extends BaseAPI { super(client) } async getOfflineLicenseToken( - opts: { status?: number } = {} + opts: { status?: number } = {} ): Promise<[Response, GetOfflineLicenseTokenResponse]> { const [response, body] = await this.get( - `/global/license/offline`, - opts.status + `/global/license/offline`, + opts.status ) return [response, body] } @@ -28,29 +28,29 @@ export default class LicenseAPI extends BaseAPI { return [response] } async activateOfflineLicenseToken( - body: ActivateOfflineLicenseTokenRequest + body: ActivateOfflineLicenseTokenRequest ): Promise<[Response]> { const [response] = await this.post(`/global/license/offline`, body) return [response] } async getOfflineIdentifier(): Promise< - [Response, GetOfflineIdentifierResponse] + [Response, GetOfflineIdentifierResponse] > { const [response, body] = await this.get( - `/global/license/offline/identifier` + `/global/license/offline/identifier` ) return [response, body] } async getLicenseKey( - opts: { status?: number } = {} + opts: { status?: number } = {} ): Promise<[Response, GetLicenseKeyResponse]> { const [response, body] = await this.get(`/global/license/key`, opts.status) return [response, body] } async activateLicenseKey( - body: ActivateLicenseKeyRequest + body: ActivateLicenseKeyRequest ): Promise<[Response]> { const [response] = await this.post(`/global/license/key`, body) return [response] @@ -60,4 +60,4 @@ export default class LicenseAPI extends BaseAPI { const [response] = await this.del(`/global/license/key`, 204) return [response] } -} \ No newline at end of file +}