Refactor billing process in e2e tests

Code for billing process was refactored in end-to-end tests for clean code and better structure. In the described tests, related codes and classes have been moved to a new class named BillingPageObject. All corresponding calls were updated accordingly.
This commit is contained in:
giancarlo
2024-04-14 17:54:15 +08:00
parent d078e0021c
commit 0824ac8e9f
8 changed files with 88 additions and 51 deletions

View File

@@ -1,18 +1,17 @@
import { Page } from '@playwright/test'; import { Page } from '@playwright/test';
import { StripePageObject } from '../utils/stripe.po';
import { TeamAccountsPageObject } from '../team-accounts/team-accounts.po'; import { TeamAccountsPageObject } from '../team-accounts/team-accounts.po';
import { BillingPageObject } from '../utils/billing.po';
export class TeamBillingPageObject { export class TeamBillingPageObject {
private readonly teamAccounts: TeamAccountsPageObject; public readonly teamAccounts: TeamAccountsPageObject;
public readonly stripe: StripePageObject; public readonly billing: BillingPageObject;
constructor(page: Page) { constructor(page: Page) {
this.teamAccounts = new TeamAccountsPageObject(page); this.teamAccounts = new TeamAccountsPageObject(page);
this.stripe = new StripePageObject(page); this.billing = new BillingPageObject(page);
} }
async setup() { async setup() {
await this.teamAccounts.setup(); await this.teamAccounts.setup();
await this.teamAccounts.goToBilling();
} }
} }

View File

@@ -1,24 +1,32 @@
import { expect, Page, test } from '@playwright/test'; import { expect, Page, test } from '@playwright/test';
import { TeamBillingPageObject } from './team-billing.po'; import { TeamBillingPageObject } from './team-billing.po';
import exp from 'node:constants';
test.describe('Team Billing', () => { test.describe('Team Billing', () => {
let page: Page; let page: Page;
let billing: TeamBillingPageObject; let po: TeamBillingPageObject;
test.beforeAll(async ({ browser }) => { test.beforeAll(async ({ browser }) => {
page = await browser.newPage(); page = await browser.newPage();
billing = new TeamBillingPageObject(page); po = new TeamBillingPageObject(page);
await billing.setup(); await po.setup();
await po.teamAccounts.goToBilling();
}); });
test('a team can subscribe to a plan', async () => { test('a team can subscribe to a plan', async () => {
await billing.stripe.selectPlan(0); await po.billing.selectPlan(0);
await billing.stripe.proceedToCheckout(); await po.billing.proceedToCheckout();
await billing.stripe.fillForm(); await po.billing.stripe.fillForm();
await billing.stripe.submitForm(); await po.billing.stripe.submitForm();
await expect(billing.stripe.successStatus()).toBeVisible(); await expect(po.billing.successStatus()).toBeVisible();
await po.billing.returnToHome();
await po.teamAccounts.goToBilling();
await expect(await po.billing.getStatus()).toContainText('active');
await expect(po.billing.manageBillingButton()).toBeVisible();
}); });
}); });

View File

@@ -1,14 +1,14 @@
import { Page } from '@playwright/test'; import { Page } from '@playwright/test';
import { AuthPageObject } from '../authentication/auth.po'; import { AuthPageObject } from '../authentication/auth.po';
import { StripePageObject } from '../utils/stripe.po'; import { BillingPageObject } from '../utils/billing.po';
export class UserBillingPageObject { export class UserBillingPageObject {
private readonly auth: AuthPageObject; private readonly auth: AuthPageObject;
public readonly stripe: StripePageObject; public readonly billing: BillingPageObject;
constructor(page: Page) { constructor(page: Page) {
this.auth = new AuthPageObject(page); this.auth = new AuthPageObject(page);
this.stripe = new StripePageObject(page); this.billing = new BillingPageObject(page);
} }
async setup() { async setup() {

View File

@@ -3,22 +3,27 @@ import { UserBillingPageObject } from './user-billing.po';
test.describe('User Billing', () => { test.describe('User Billing', () => {
let page: Page; let page: Page;
let billing: UserBillingPageObject; let po: UserBillingPageObject;
test.beforeAll(async ({ browser }) => { test.beforeAll(async ({ browser }) => {
page = await browser.newPage(); page = await browser.newPage();
billing = new UserBillingPageObject(page); po = new UserBillingPageObject(page);
await billing.setup(); await po.setup();
}); });
test('user can subscribe to a plan', async () => { test('user can subscribe to a plan', async ({page}) => {
await billing.stripe.selectPlan(0); await po.billing.selectPlan(0);
await billing.stripe.proceedToCheckout(); await po.billing.proceedToCheckout();
await billing.stripe.fillForm(); await po.billing.stripe.fillForm();
await billing.stripe.submitForm(); await po.billing.stripe.submitForm();
await expect(billing.stripe.successStatus()).toBeVisible(); await expect(po.billing.successStatus()).toBeVisible();
await page.goto('/home/billing');
await expect(await po.billing.getStatus()).toContainText('active');
await expect(po.billing.manageBillingButton()).toBeVisible();
}); });
}); });

View File

@@ -0,0 +1,42 @@
import { Page } from '@playwright/test';
import { StripePageObject } from './stripe.po';
export class BillingPageObject {
public readonly stripe: StripePageObject;
constructor(
private readonly page: Page,
) {
this.stripe = new StripePageObject(page);
}
plans() {
return this.page.locator('[data-test-plan]');
}
selectPlan(index: number = 0) {
const plans = this.plans();
return plans.nth(index).click();
}
manageBillingButton() {
return this.page.locator('manage-billing-redirect-button');
}
successStatus() {
return this.page.locator('[data-test="payment-return-success"]');
}
async returnToHome() {
await this.successStatus().locator('button').click();
}
proceedToCheckout() {
return this.page.click('[data-test="checkout-submit-button"]');
}
async getStatus() {
return this.page.locator('[data-test="current-plan-card-status-badge"]');
}
}

View File

@@ -1,14 +1,13 @@
import { Page, expect } from '@playwright/test'; import { Page, expect } from '@playwright/test';
import { BillingPageObject } from './billing.po';
export class StripePageObject { export class StripePageObject {
private page: Page; private readonly page: Page;
public readonly billing: BillingPageObject;
constructor(page: Page) { constructor(page: Page) {
this.page = page; this.page = page;
} this.billing = new BillingPageObject(page);
plans() {
return this.page.locator('[data-test-plan]');
} }
getStripeCheckoutIframe() { getStripeCheckoutIframe() {
@@ -66,22 +65,4 @@ export class StripePageObject {
billingCountry() { billingCountry() {
return this.getStripeCheckoutIframe().locator('#billingCountry'); return this.getStripeCheckoutIframe().locator('#billingCountry');
} }
selectPlan(index: number = 0) {
const plans = this.plans();
return plans.nth(index).click();
}
manageBillingButton() {
return this.page.locator('manage-billing-redirect-button');
}
successStatus() {
return this.page.locator('[data-test="payment-return-success"]');
}
proceedToCheckout() {
return this.page.click('[data-test="checkout-submit-button"]');
}
} }

View File

@@ -45,7 +45,7 @@ export function CurrentPlanBadge(
} }
return ( return (
<Badge variant={variant}> <Badge data-test={'current-plan-card-status-badge'} variant={variant}>
<Trans i18nKey={text} /> <Trans i18nKey={text} />
</Badge> </Badge>
); );

View File

@@ -73,7 +73,9 @@ export function CurrentSubscriptionCard({
} }
/> />
<span>{product.name}</span> <span data-test={'current-plan-card-product-name'}>
{product.name}
</span>
<CurrentPlanBadge status={subscription.status} /> <CurrentPlanBadge status={subscription.status} />
</div> </div>
@@ -84,7 +86,7 @@ export function CurrentSubscriptionCard({
(e.g. trial ending soon, subscription canceled, etc.) (e.g. trial ending soon, subscription canceled, etc.)
*/} */}
<If condition={!subscription.active}> <If condition={!subscription.active}>
<div> <div data-test={'current-plan-card-status-alert'}>
<CurrentPlanAlert status={subscription.status} /> <CurrentPlanAlert status={subscription.status} />
</div> </div>
</If> </If>