diff --git a/.env-dist b/.env-dist index cc676c30e7c..0519ef4f161 100755 --- a/.env-dist +++ b/.env-dist @@ -122,6 +122,9 @@ E2E_TEST_ACCOUNT_PASSWORD= E2E_TEST_ACCOUNT_EMAIL_ZERO_BREACHES= E2E_TEST_ACCOUNT_EMAIL_EXPOSURES_STARTED= +E2E_TEST_PAYPAL_LOGIN = +E2E_TEST_PAYPAL_PASSWORD = + # Monitor Premium features # Link to start user on the subscription process. PREMIUM_ENABLED must be set to `true`. FXA_SUBSCRIPTIONS_URL=https://accounts.stage.mozaws.net/subscriptions diff --git a/.github/workflows/e2e_cron.yml b/.github/workflows/e2e_cron.yml index 8807ac0e69b..70672bd93ac 100644 --- a/.github/workflows/e2e_cron.yml +++ b/.github/workflows/e2e_cron.yml @@ -57,6 +57,8 @@ jobs: E2E_TEST_ACCOUNT_PASSWORD: ${{ secrets.E2E_TEST_ACCOUNT_PASSWORD }} E2E_TEST_ACCOUNT_EMAIL_ZERO_BREACHES: ${{ secrets.E2E_TEST_ACCOUNT_EMAIL_ZERO_BREACHES }} E2E_TEST_ACCOUNT_EMAIL_EXPOSURES_STARTED: ${{ secrets.E2E_TEST_ACCOUNT_EMAIL_EXPOSURES_STARTED }} + E2E_TEST_PAYPAL_LOGIN: ${{ secrets.E2E_TEST_PAYPAL_LOGIN }} + E2E_TEST_PAYPAL_PASSWORD: ${{ secrets.E2E_TEST_PAYPAL_PASSWORD }} ADMINS: ${{ secrets.ADMINS }} FXA_ENABLED: true OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }} diff --git a/.github/workflows/e2e_pr.yml b/.github/workflows/e2e_pr.yml index a9f32bd7a77..0a8ade92d82 100644 --- a/.github/workflows/e2e_pr.yml +++ b/.github/workflows/e2e_pr.yml @@ -73,6 +73,8 @@ jobs: E2E_TEST_ACCOUNT_EMAIL_ZERO_BREACHES: ${{ secrets.E2E_TEST_ACCOUNT_EMAIL_ZERO_BREACHES }} E2E_TEST_ACCOUNT_EMAIL_EXPOSURES_STARTED: ${{ secrets.E2E_TEST_ACCOUNT_EMAIL_EXPOSURES_STARTED }} E2E_TEST_ACCOUNT_PASSWORD: ${{ secrets.E2E_TEST_ACCOUNT_PASSWORD }} + E2E_TEST_PAYPAL_LOGIN: ${{ secrets.E2E_TEST_PAYPAL_LOGIN }} + E2E_TEST_PAYPAL_PASSWORD: ${{ secrets.E2E_TEST_PAYPAL_PASSWORD }} ADMINS: ${{ secrets.ADMINS }} FXA_ENABLED: true OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }} diff --git a/src/e2e/pages/purchasePage.ts b/src/e2e/pages/purchasePage.ts index 8dbe7501b8f..217a46c1c90 100644 --- a/src/e2e/pages/purchasePage.ts +++ b/src/e2e/pages/purchasePage.ts @@ -2,8 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { Locator, Page, expect } from "@playwright/test"; +import { BrowserContext, Locator, Page, expect } from "@playwright/test"; import { removeUnicodeChars } from "../utils/helpers"; +import { DashboardPage } from "./dashBoardPage"; export class PurchasePage { readonly page: Page; @@ -17,6 +18,7 @@ export class PurchasePage { readonly returnToDashboardButton: Locator; readonly goToNextStep: Locator; readonly planDetails: Locator; + readonly paypalButton: Locator; constructor(page: Page) { this.page = page; @@ -37,6 +39,7 @@ export class PurchasePage { this.returnToDashboardButton = page.getByLabel("Return to dashboard"); this.goToNextStep = page.getByLabel("Go to next step"); this.planDetails = page.locator(".plan-details-description"); + this.paypalButton = page.getByTitle("PayPal").nth(1); } async fillOutStripeCardInfo() { @@ -68,6 +71,42 @@ export class PurchasePage { await frame.fill(".InputElement[name=postal]", "77777"); } + async fillOutPaypalInfo(context: BrowserContext) { + const emailToUse = process.env.E2E_TEST_PAYPAL_LOGIN as string; + const pwdToUse = process.env.E2E_TEST_PAYPAL_PASSWORD as string; + expect(emailToUse).not.toBeUndefined(); + expect(pwdToUse).not.toBeUndefined(); + + //away from mozilla + const pagePromise = context.waitForEvent("page"); + await this.paypalButton.click(); + const newPage = await pagePromise; + await newPage.waitForLoadState(); + await newPage.waitForURL(/.*paypal\.com.*\/checkout.*/); + + const emailPrompt = newPage.locator("#email"); + await expect(emailPrompt).toBeVisible(); + + await emailPrompt.fill(emailToUse); + const nextButton = newPage.locator("#btnNext"); + if (await nextButton.isVisible()) { + await newPage.locator("#btnNext").click(); + await newPage.waitForSelector("#password", { state: "visible" }); + } + const pwdInput = newPage.locator("#password"); + await expect(pwdInput).toBeVisible(); + await pwdInput.fill(pwdToUse); + + await newPage.locator("#btnLogin").click(); + await newPage.waitForURL(/^(?!.*checkoutnow).*/); + + const saveAndContinue = newPage.locator("#consentButton"); + await expect(saveAndContinue).toBeVisible(); + await saveAndContinue.click(); + + //back to mozilla + } + async verifyMonthlyPlanDetails() { await this.subscriptionHeader.waitFor(); const planDetails = removeUnicodeChars( @@ -86,4 +125,48 @@ export class PurchasePage { `${process.env.E2E_TEST_ENV === "prod" ? "yearly" : "every 2 months"}`, ); } + + async gotoPurchaseFromDashboard( + dashboardPage: DashboardPage, + yearly: boolean, + ) { + // navigate to subscription + await dashboardPage.open(); + await dashboardPage.subscribeButton.click(); + + // verify user purchase choices + await expect(dashboardPage.subscribeDialogCloseButton).toBeVisible(); + await expect(dashboardPage.yearlyMonthlyTablist).toBeVisible(); + await dashboardPage.yearlyTab.click(); + await expect( + dashboardPage.subscribeDialogSelectYearlyPlanLink, + ).toBeVisible(); + + await dashboardPage.monthlyTab.click(); + await expect( + dashboardPage.subscribeDialogSelectMonthlyPlanLink, + ).toBeVisible(); + + if (yearly) { + await dashboardPage.yearlyTab.click(); + await dashboardPage.subscribeDialogSelectYearlyPlanLink.click(); + } else { + await dashboardPage.monthlyTab.click(); + await dashboardPage.subscribeDialogSelectMonthlyPlanLink.click(); + } + await this.subscriptionHeader.waitFor(); + } + + async postPaymentPageCheck(dashboardPage: DashboardPage) { + await this.page.getByText("Subscription confirmation").waitFor(); + // navigate to confirmation + await this.getStartedButton.click(); + await this.goToNextStep.click(); + // confirm successful payment + await dashboardPage.plusSubscription.waitFor({ + state: "attached", + timeout: 10000, + }); + await expect(dashboardPage.plusSubscription).toBeVisible(); + } } diff --git a/src/e2e/specs/purchase.spec.ts b/src/e2e/specs/purchase.spec.ts index 32a0929ead0..50b4727fcbd 100644 --- a/src/e2e/specs/purchase.spec.ts +++ b/src/e2e/specs/purchase.spec.ts @@ -154,4 +154,50 @@ test.describe(`${process.env.E2E_TEST_ENV} - Breach Scan, Monitor Plus Purchase }); await expect(dashboardPage.plusSubscription).toBeVisible(); }); + + test("Verify that the user can purchase the plus subscription with a PayPal account - yearly", async ({ + purchasePage, + dashboardPage, + context, + }) => { + test.skip( + process.env.E2E_TEST_ENV === "production", + "payment method test not available in production", + ); + // link to testrail case + test.info().annotations.push({ + type: "testrail", + description: + "https://testrail.stage.mozaws.net/index.php?/cases/view/2463628", + }); + + await purchasePage.gotoPurchaseFromDashboard(dashboardPage, true); + // fill out subscription payment + await purchasePage.authorizationCheckbox.check(); + await purchasePage.fillOutPaypalInfo(context); + await purchasePage.postPaymentPageCheck(dashboardPage); + }); + + test("Verify that the user can purchase the plus subscription with a PayPal account - monthly", async ({ + purchasePage, + dashboardPage, + context, + }) => { + test.skip( + process.env.E2E_TEST_ENV === "production", + "payment method test not available in production", + ); + // link to testrail case + test.info().annotations.push({ + type: "testrail", + description: + "https://testrail.stage.mozaws.net/index.php?/cases/view/2463628", + }); + + await purchasePage.gotoPurchaseFromDashboard(dashboardPage, false); + // fill out subscription payment + await purchasePage.authorizationCheckbox.check(); + await purchasePage.fillOutPaypalInfo(context); + await purchasePage.postPaymentPageCheck(dashboardPage); + }); });