Skip to content

Commit

Permalink
e2e tests enhancement and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
rafeerahman committed Apr 4, 2024
1 parent e1ba825 commit 37853f8
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 100 deletions.
59 changes: 32 additions & 27 deletions e2e-tests/fixtures/basePages.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
import { LandingPage } from "../pages/landingPage";
import { AuthPage } from "../pages/authPage";
import { test as baseTest } from '@playwright/test'
import { DashboardPage } from "../pages/dashboardPage";
import { SubscriptionPaymentPage } from "../pages/subscriptionPaymentPage";

const test = baseTest.extend<{
landingPage: LandingPage;
authPage: AuthPage;
dashboardPage: DashboardPage;
subscriptionPage: SubscriptionPaymentPage
}>({
authPage: async ({ page }, use) => {
await use(new AuthPage(page))
},
landingPage: async ({ page }, use) => {
await use(new LandingPage(page))
},
dashboardPage: async ({ page }, use) => {
await use(new DashboardPage(page))
},
subscriptionPage: async ({ page }, use) => {
await use(new SubscriptionPaymentPage(page))
},
})

export default test;
import { LandingPage } from "../pages/landingPage";
import { AuthPage } from "../pages/authPage";
import { test as baseTest } from '@playwright/test'
import { DashboardPage } from "../pages/dashboardPage";
import { SubscriptionPaymentPage } from "../pages/subscriptionPaymentPage";
import { MozillaMonitorPage } from "../pages/mozillaMonitorPage";

const test = baseTest.extend<{
landingPage: LandingPage;
authPage: AuthPage;
dashboardPage: DashboardPage;
subscriptionPage: SubscriptionPaymentPage
mozillaMonitorPage: MozillaMonitorPage
}>({
authPage: async ({ page }, use) => {
await use(new AuthPage(page))
},
landingPage: async ({ page }, use) => {
await use(new LandingPage(page))
},
dashboardPage: async ({ page }, use) => {
await use(new DashboardPage(page))
},
subscriptionPage: async ({ page }, use) => {
await use(new SubscriptionPaymentPage(page))
},
mozillaMonitorPage: async ({ page }, use) => {
await use(new MozillaMonitorPage(page))
}
})

export default test;
export const expect = test.expect;
8 changes: 4 additions & 4 deletions e2e-tests/pages/authPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ export class AuthPage {
constructor(page: Page){
this.page = page;
this.emailInputField = page.locator('input[name="email"]');
this.passwordInputField = process.env["E2E_TEST_ENV"] === "prod" ? page.locator('#password') : page.getByTestId('new-password-input-field');
this.passwordConfirmInputField = process.env["E2E_TEST_ENV"] === "prod" ? page.locator('#vpassword') : page.getByTestId('verify-password-input-field');
this.ageInputField = process.env["E2E_TEST_ENV"] === "prod" ? page.locator('#age') : page.getByTestId('age-input-field');
this.passwordInputField = page.locator('#password');
this.passwordConfirmInputField = page.locator('#vpassword');
this.ageInputField = page.locator('#age');
this.continueButton = page.locator('#submit-btn');
this.createAccountButton = page.getByRole('button', { name: 'Create account' });
this.verifyCodeInputField = process.env["E2E_TEST_ENV"] === "prod" ? page.locator('div.card input') : page.getByTestId('confirm-signup-code-input-field');
this.verifyCodeInputField = page.locator('div.card input');
this.confirmCodeButton = page.getByRole('button', { name: 'Confirm' });
}

Expand Down
35 changes: 12 additions & 23 deletions e2e-tests/pages/dashboardPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ export class DashboardPage {

// dashboard header elements
this.header = page.locator('div header').first();
this.FAQButton = page.locator('header >> text=FAQ')
this.newsButton = page.locator('header >> text=News')
this.homeButton = page.locator('header >> text=Email Masks')
this.FAQButton = page.getByText('FAQ').first()
this.newsButton = page.getByText('News')
this.homeButton = page.getByRole('link', { name: 'Email masks'})
this.userMenuButton = page.locator('//div[starts-with(@class, "UserMenu_wrapper")]')
this.userMenuPopUp = page.locator('//ul[starts-with(@class, "UserMenu_popup")]')
this.userMenuLetter = page.locator('//div[starts-with(@class, "UserMenu_wrapper")]')
Expand Down Expand Up @@ -102,6 +102,13 @@ export class DashboardPage {
await this.page.goto('/accounts/profile/');
}

async skipOnboarding() {
const onboardingElem = this.page.locator('button.FreeOnboarding_skip-link__8kh60');
if (await onboardingElem.isVisible()) {
await onboardingElem.click();
}
}

async generateMask(numberOfMasks = 1){
// check if max number of masks have been created
if(numberOfMasks === 0){
Expand Down Expand Up @@ -186,7 +193,7 @@ export class DashboardPage {
await this.maybeDeleteMasks(true, numberOfMasks - 1)
}

async sendMaskEmail(){
async generateOneRandomMask() {
// reset data
await this.open()
await checkAuthState(this.page)
Expand All @@ -196,25 +203,7 @@ export class DashboardPage {
await this.generateMask(1)
const generatedMaskEmail = await this.maskCardGeneratedEmail.textContent()

// TODO: Replace with a page under control of Relay team
await this.page.goto("https://monitor.firefox.com/", { waitUntil: 'networkidle' })
await this.page.locator('#scan-email-address').fill(generatedMaskEmail as string)
await this.page.locator('button.primary').click()
await this.page.waitForURL('**/scan**')

await this.page.getByRole('link', {name: 'Get alerts about new breaches'}).click()

await this.page.locator('input[name=email]').fill(generatedMaskEmail as string)
await this.page.locator('#submit-btn').click()

await this.page.locator('#password').fill(process.env.E2E_TEST_ACCOUNT_PASSWORD as string);
await this.page.locator('#vpassword').fill(process.env.E2E_TEST_ACCOUNT_PASSWORD as string);
await this.page.locator('#age').fill('31');
await this.page.locator('#submit-btn').click()
await this.page.waitForURL('**/confirm_signup_code**')

// verification email from fxa to generatedMaskEmail should be forwarded to E2E_TEST_ACCOUNT_FREE
await getVerificationCode(process.env.E2E_TEST_ACCOUNT_FREE as string, this.page)
return generatedMaskEmail;
}

async checkForwardedEmailCount(attempts = 10) {
Expand Down
55 changes: 47 additions & 8 deletions e2e-tests/pages/landingPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,46 @@ export class LandingPage {
readonly homeButton: Locator
readonly signUpButton: Locator
readonly subscriptionTitle: Locator
readonly planPricingSignUpButton: Locator
readonly planMatrixDesktop: Locator
readonly planMatrixMobile: Locator
yearlyEmailsPlan: Locator
monthlyEmailsPlan: Locator
emailsPlanSubmit: Locator
yearlyEmailsPhonesBundle: Locator
monthlyEmailsPhonesBundle: Locator
emailsPhonesBundleSubmit: Locator
vpnBundleSubmit: Locator
readonly signInButton: Locator
readonly firefoxAppsServices: Locator
readonly firefoxAppsServicesHeading: Locator
readonly firefoxLogo: Locator

constructor(page: Page){
this.page = page
this.header = page.locator('#overlayProvider header')
this.FAQButton = page.getByRole('link', { name: 'FAQ', exact: true })
this.homeButton = page.getByRole('link', { name: 'Home', exact: true })
this.signUpButton = page.locator('a:has-text("Sign Up")').first()
this.planPricingSignUpButton = page.locator('//a[contains(@class, "Plans_premium-plan")]/div')
this.planMatrixDesktop = page.locator('//table[starts-with(@class, "PlanMatrix_desktop")]')
this.planMatrixMobile = page.locator('//div[starts-with(@class, "PlanMatrix_mobile")]')
this.subscriptionTitle = page.locator('[data-testid="subscription-create-title"]')
this.signInButton = page.locator('a:has-text("Sign In")')
this.firefoxAppsServices = page.getByRole('button', { name: 'Firefox apps and services' })
this.firefoxAppsServicesHeading = page.getByRole('heading', { name: 'Firefox is tech that fights for your online privacy.' })
this.firefoxLogo = page.locator('//a[starts-with(@class, "Layout_logo")]')
this.setPlanElements();
}

async setPlanElements () {
const isDesktop = await this.planMatrixDesktop.isVisible();
const currPlanMatrix = isDesktop ? this.planMatrixDesktop : this.planMatrixMobile;
this.yearlyEmailsPlan = currPlanMatrix.locator('[id*="tab-yearly"]').first();
this.monthlyEmailsPlan = currPlanMatrix.locator('[id*="tab-monthly"]').first();
this.emailsPlanSubmit = currPlanMatrix.getByText('Sign Up').first();
this.yearlyEmailsPhonesBundle = currPlanMatrix.locator('[id*="tab-yearly"]').nth(1);
this.monthlyEmailsPhonesBundle = currPlanMatrix.locator('[id*="tab-monthly"]').nth(1);
this.emailsPhonesBundleSubmit = currPlanMatrix.getByText('Sign Up').nth(1);
this.vpnBundleSubmit = currPlanMatrix.getByText('Sign Up').nth(2);
}

async open(){
Expand All @@ -49,11 +71,28 @@ export class LandingPage {
await this.signUpButton.click()
}

async selectPricingPlanSignUp(){
await Promise.all([
this.page.waitForNavigation(),
this.planPricingSignUpButton.click()
]);
async selectYearlyEmailsPlan(){
await this.yearlyEmailsPlan.click();
await this.emailsPlanSubmit.click();
}

async selectMonthlyEmailsPlan() {
await this.monthlyEmailsPlan.click();
await this.emailsPlanSubmit.click();
}

async selectYearlyPhonesEmailsBundle() {
await this.yearlyEmailsPhonesBundle.click();
await this.emailsPhonesBundleSubmit.click();
}

async selectMonthlyPhonesEmailsBundle() {
await this.monthlyEmailsPhonesBundle.click();
await this.emailsPhonesBundleSubmit.click();
}

async selectVpnBundlePlan() {
await this.vpnBundleSubmit.click();
}

async goToSignIn(){
Expand Down
35 changes: 35 additions & 0 deletions e2e-tests/pages/mozillaMonitorPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Page, Locator} from "@playwright/test";
import { getVerificationCode } from "../e2eTestUtils/helpers";

export class MozillaMonitorPage {
readonly page: Page
readonly monitorSignUpInput: Locator;
readonly monitorSignUpButton: Locator;

constructor(page: Page){
this.page = page;
this.monitorSignUpInput = page.locator("//form[contains(@class, 'SignUpForm_form')]/input").first();
this.monitorSignUpButton = page.locator('button.Button_primary___XZsP').first();

}

async signupWithMask(randomMask: string | null) {
if (randomMask === null) {
return new Error("Mask could not be created.")
}

await this.page.goto("https://monitor.mozilla.org/", { waitUntil: 'networkidle' })
await this.monitorSignUpInput.fill(randomMask as string)
await this.monitorSignUpButton.click()
await this.page.waitForURL('**/oauth/signup**')

await this.page.locator('#password').fill(process.env.E2E_TEST_ACCOUNT_PASSWORD as string);
await this.page.locator('#vpassword').fill(process.env.E2E_TEST_ACCOUNT_PASSWORD as string);
await this.page.locator('#age').fill('31');
await this.page.locator('#submit-btn').click()
await this.page.waitForURL('**/confirm_signup_code**')

// verification email from fxa to generatedMaskEmail should be forwarded to E2E_TEST_ACCOUNT_FREE
await getVerificationCode(process.env.E2E_TEST_ACCOUNT_FREE as string, this.page)
}
}
63 changes: 35 additions & 28 deletions e2e-tests/pages/subscriptionPaymentPage.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
import { Locator, Page } from "@playwright/test";

export class SubscriptionPaymentPage {
readonly page: Page
readonly paypalButton: Locator
readonly paymentDiv: Locator
readonly productDetails: Locator
readonly discountForm: Locator
readonly paymentNameField: Locator
readonly cardNumberField: Locator
readonly cardExpiryField: Locator
readonly cardCvcField: Locator
readonly postalCodeField: Locator
readonly authorizationCheckbox: Locator

constructor(page: Page) {
this.page = page
this.authorizationCheckbox = page.locator('[data-testid="confirm"]')
this.paypalButton = page.locator('[data-testid="pay-with-other"]')
this.paymentDiv = page.locator('[data-testid="subscription-create"]')
this.productDetails = page.locator('.plan-details-component-inner')
this.discountForm = page.locator('[data-testid="coupon-component"]')
this.paymentNameField = page.locator('[data-testid="name"]')
this.cardNumberField = page.locator('[data-elements-stable-field-name="cardNumber"]')
this.cardExpiryField = page.locator('[data-elements-stable-field-name="cardExpiry"]')
this.cardCvcField = page.locator('[data-elements-stable-field-name="cardCvc"]')
this.postalCodeField = page.locator('[data-elements-stable-field-name="postalCode"]')
}
import { Locator, Page } from "@playwright/test";

export class SubscriptionPaymentPage {
readonly page: Page
readonly paypalButton: Locator
readonly paymentDiv: Locator
readonly productDetails: Locator
readonly discountForm: Locator
readonly paymentNameField: Locator
readonly cardNumberField: Locator
readonly cardExpiryField: Locator
readonly cardCvcField: Locator
readonly postalCodeField: Locator
readonly authorizationCheckbox: Locator
readonly subscriptionTitle: Locator
readonly subscriptionType: Locator
readonly planDetails: Locator
readonly planType: Locator

constructor(page: Page) {
this.page = page
this.authorizationCheckbox = page.locator('[data-testid="confirm"]')
this.paypalButton = page.locator('[data-testid="pay-with-other"]')
this.paymentDiv = page.locator('[data-testid="subscription-create"]')
this.productDetails = page.locator('.plan-details-component-inner')
this.discountForm = page.locator('[data-testid="coupon-component"]')
this.paymentNameField = page.locator('[data-testid="name"]')
this.cardNumberField = page.locator('[data-elements-stable-field-name="cardNumber"]')
this.cardExpiryField = page.locator('[data-elements-stable-field-name="cardExpiry"]')
this.cardCvcField = page.locator('[data-elements-stable-field-name="cardCvc"]')
this.postalCodeField = page.locator('[data-elements-stable-field-name="postalCode"]')
this.subscriptionTitle = page.locator('[data-testid="subscription-create-title"]')
this.planDetails = page.locator('#plan-details-product')
this.planType = page.locator('.plan-details-description')
}
}
Loading

0 comments on commit 37853f8

Please sign in to comment.