Skip to content

Commit e610b92

Browse files
authored
chore(e2e): Test coverage for billing statements and payment attempts (#7188)
1 parent e07ad69 commit e610b92

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

.changeset/yellow-pants-act.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

integration/tests/pricing-table.test.ts

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,161 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing tabl
655655
await fakeUser.deleteIfExists();
656656
});
657657

658+
test('displays billing history and navigates through statement and payment attempt details', async ({
659+
page,
660+
context,
661+
}) => {
662+
const u = createTestUtils({ app, page, context });
663+
664+
const fakeUser = u.services.users.createFakeUser();
665+
await u.services.users.createBapiUser(fakeUser);
666+
667+
try {
668+
await u.po.signIn.goTo();
669+
await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password });
670+
671+
await u.po.page.goToRelative('/user');
672+
await u.po.userProfile.waitForMounted();
673+
await u.po.userProfile.switchToBillingTab();
674+
675+
const openBillingTab = async (label: RegExp) => {
676+
await page.getByRole('tab', { name: label }).click();
677+
await page
678+
.locator('.cl-userProfile-root [role="tabpanel"] .cl-table')
679+
.waitFor({ state: 'visible', timeout: 15000 });
680+
};
681+
const getBillingTableRows = () => {
682+
return page.locator('.cl-userProfile-root .cl-tableBody .cl-tableRow');
683+
};
684+
const waitForBillingTableRows = async (options?: { hasText?: string | RegExp }) => {
685+
const rows = getBillingTableRows();
686+
if (options?.hasText) {
687+
await rows
688+
.filter({
689+
hasText: options.hasText,
690+
})
691+
.first()
692+
.waitFor({ state: 'visible', timeout: 15000 });
693+
} else {
694+
await rows.first().waitFor({ state: 'visible', timeout: 15000 });
695+
}
696+
return rows;
697+
};
698+
const getBillingEmptyStateMessage = (text: string | RegExp) => {
699+
return page.locator('.cl-userProfile-root .cl-table').getByText(text);
700+
};
701+
const waitForStatementPage = async () => {
702+
const statementRoot = page.locator('.cl-statementRoot');
703+
await statementRoot.waitFor({ state: 'visible', timeout: 15000 });
704+
return statementRoot;
705+
};
706+
const waitForPaymentAttemptPage = async () => {
707+
const paymentAttemptRoot = page.locator('.cl-paymentAttemptRoot');
708+
await paymentAttemptRoot.waitFor({ state: 'visible', timeout: 15000 });
709+
return paymentAttemptRoot;
710+
};
711+
const goBackToPaymentsList = async () => {
712+
const paymentAttemptRoot = page.locator('.cl-paymentAttemptRoot');
713+
await Promise.all([
714+
page.waitForURL(/tab=payments/, { timeout: 15000 }),
715+
page.getByRole('link', { name: /Payments/i }).click(),
716+
]);
717+
await paymentAttemptRoot.waitFor({ state: 'detached', timeout: 15000 });
718+
};
719+
720+
await openBillingTab(/Statements/i);
721+
await expect(getBillingEmptyStateMessage('No statements to display')).toBeVisible();
722+
723+
await u.po.page.goToRelative('/user');
724+
await u.po.userProfile.waitForMounted();
725+
await u.po.userProfile.switchToBillingTab();
726+
await u.po.page.getByRole('button', { name: 'Switch plans' }).click();
727+
728+
await u.po.pricingTable.waitForMounted();
729+
await u.po.pricingTable.startCheckout({ planSlug: 'plus' });
730+
await u.po.checkout.waitForMounted();
731+
await u.po.checkout.fillTestCard();
732+
await u.po.checkout.clickPayOrSubscribe();
733+
await expect(u.po.page.getByText('Payment was successful!')).toBeVisible({
734+
timeout: 15000,
735+
});
736+
await u.po.checkout.confirmAndContinue();
737+
738+
await u.po.pricingTable.startCheckout({ planSlug: 'pro', shouldSwitch: true });
739+
await u.po.checkout.waitForMounted();
740+
await u.po.checkout.root.getByText('Add payment method').click();
741+
await u.po.checkout.fillCard({
742+
number: '4100000000000019',
743+
expiration: '1234',
744+
cvc: '123',
745+
country: 'United States',
746+
zip: '12345',
747+
});
748+
await u.po.checkout.clickPayOrSubscribe();
749+
await expect(u.po.checkout.root.getByText('The card was declined.').first()).toBeVisible({
750+
timeout: 15000,
751+
});
752+
await u.po.checkout.closeDrawer();
753+
754+
await u.po.page.goToRelative('/user');
755+
await u.po.userProfile.waitForMounted();
756+
await u.po.userProfile.switchToBillingTab();
757+
758+
await openBillingTab(/Statements/i);
759+
const date = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long' });
760+
await waitForBillingTableRows({ hasText: new RegExp(date, 'i') });
761+
await expect(getBillingEmptyStateMessage('No statements to display')).toBeHidden();
762+
763+
const firstStatementRow = getBillingTableRows().first();
764+
await firstStatementRow.click();
765+
766+
const statementRoot = await waitForStatementPage();
767+
await expect(
768+
statementRoot.locator('.cl-statementSectionContentDetailsHeaderTitle').filter({ hasText: /Plus/i }).first(),
769+
).toBeVisible();
770+
771+
const statementTotalText = (await statementRoot.locator('.cl-statementFooterValue').textContent())?.trim();
772+
expect(statementTotalText).toBeTruthy();
773+
774+
await statementRoot
775+
.getByRole('button', { name: /View payment/i })
776+
.first()
777+
.click();
778+
const paymentAttemptRoot = await waitForPaymentAttemptPage();
779+
await expect(paymentAttemptRoot.locator('.cl-paymentAttemptHeaderBadge')).toHaveText(/paid/i);
780+
781+
const paymentTotalText = (
782+
await paymentAttemptRoot.locator('.cl-paymentAttemptFooterValue').textContent()
783+
)?.trim();
784+
expect(paymentTotalText).toBe(statementTotalText);
785+
786+
await expect(
787+
paymentAttemptRoot.locator('.cl-lineItemsTitle').filter({ hasText: /Plus/i }).first(),
788+
).toBeVisible();
789+
790+
await goBackToPaymentsList();
791+
await openBillingTab(/Payments/i);
792+
await waitForBillingTableRows({ hasText: /paid/i });
793+
await waitForBillingTableRows({ hasText: /Failed/i });
794+
await expect(getBillingEmptyStateMessage('No payment history')).toBeHidden();
795+
796+
const failedPaymentRow = getBillingTableRows()
797+
.filter({ hasText: /Failed/i })
798+
.first();
799+
await failedPaymentRow.click();
800+
801+
const failedPaymentAttemptRoot = await waitForPaymentAttemptPage();
802+
await expect(failedPaymentAttemptRoot.locator('.cl-paymentAttemptHeaderBadge')).toHaveText(/failed/i);
803+
await expect(
804+
failedPaymentAttemptRoot.locator('.cl-lineItemsTitle').filter({ hasText: /Pro/i }).first(),
805+
).toBeVisible();
806+
807+
await goBackToPaymentsList();
808+
} finally {
809+
await fakeUser.deleteIfExists();
810+
}
811+
});
812+
658813
test('adds two payment methods and sets the last as default', async ({ page, context }) => {
659814
const u = createTestUtils({ app, page, context });
660815

0 commit comments

Comments
 (0)