From cfeab0278c048c17edfdd8591d578f312de913ea Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams <55924431+O-Bots@users.noreply.github.com> Date: Mon, 16 Mar 2026 15:02:48 +0000 Subject: [PATCH] [Housekeeping] Organizing the test structure and files, adding fix for issue #36 (None descriptive error) (#38) * Added Database checks to the onboarding flow * Added compatibility page setup Added more compatibility questions * Finished up the onboarding flow suite Added compatibility question tests and verifications Updated tests to cover Keywords and Headline changes recently made Updated tests to cover all of the big5 personality traits * Fix: Added 'tsconfig-paths/register' to playwright config so it applies tsconfig/ts-node to test files and imported modules....there was a syntax error: SyntaxError: tests/e2e/web/pages/homePage.ts: Unexpected token (2:0) * . * Updated ProfilePage: In some cases removed the use of "one shot grabs" using .textContent() to prevent flaky tests Added test for entering profile information post signup flow * Linting and Prettier * Fix: Merge conflict * Fix: Modified sortedAndFilteredAnswers to use "UseMemo" so that it doesnt run every time something changes * . * . * Merged "verifyInterestedInConnectingWith" and "verifyRelationShipTypeAndInterest" into "verifySeeking" to match ui changes * Added error message outlining the minimum character requirement for display names and usernames * Updated displayName error message to show when editing the user profile post signup * Fix: Added fix for None discriptive error issue #36 Updated signUp.spec.ts to use new fixture Updated Account information variable names Deleted "deleteUserFixture.ts" as it was incorporated into the "base.ts" file * Linting and Prettier * Minor cleaning * Organizing helper func * Linting and Prettier --------- Co-authored-by: MartinBraquet --- .github/workflows/cd-android-live-update.yml | 2 +- playwright.config.ts | 1 + tests/e2e/web/fixtures/base.ts | 19 +- tests/e2e/web/fixtures/deleteUserFixture.ts | 48 --- tests/e2e/web/pages/AuthPage.ts | 5 + tests/e2e/web/pages/profilePage.ts | 123 ++++--- tests/e2e/web/pages/signUpPage.ts | 22 +- tests/e2e/web/specs/onboardingFlow.spec.ts | 353 ++++++++++++------- tests/e2e/web/specs/signUp.spec.ts | 54 +-- tests/e2e/web/utils/accountInformation.ts | 54 ++- tests/e2e/web/utils/deleteUser.ts | 2 +- tests/e2e/web/utils/testCleanupHelpers.ts | 18 + web/README.md | 2 - web/components/required-profile-form.tsx | 40 ++- 14 files changed, 463 insertions(+), 280 deletions(-) delete mode 100644 tests/e2e/web/fixtures/deleteUserFixture.ts create mode 100644 tests/e2e/web/utils/testCleanupHelpers.ts diff --git a/.github/workflows/cd-android-live-update.yml b/.github/workflows/cd-android-live-update.yml index 48ff11ee..292235ff 100644 --- a/.github/workflows/cd-android-live-update.yml +++ b/.github/workflows/cd-android-live-update.yml @@ -1,7 +1,7 @@ name: CD Android Live Update on: push: - branches: [ main, master ] + branches: [main, master] paths: - 'android/capawesome.json' - '.github/workflows/cd-android-live-update.yml' diff --git a/playwright.config.ts b/playwright.config.ts index cbdc6cf2..094ee5a4 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,4 +1,5 @@ import {defineConfig, devices} from '@playwright/test' +import 'tsconfig-paths/register' import {execSync} from 'child_process' import {config} from 'dotenv' diff --git a/tests/e2e/web/fixtures/base.ts b/tests/e2e/web/fixtures/base.ts index 277f5887..23ec87fc 100644 --- a/tests/e2e/web/fixtures/base.ts +++ b/tests/e2e/web/fixtures/base.ts @@ -6,7 +6,7 @@ import {HomePage} from '../pages/homePage' import {OnboardingPage} from '../pages/onboardingPage' import {ProfilePage} from '../pages/profilePage' import {SignUpPage} from '../pages/signUpPage' -import {onboarding, OnboardingUser} from '../utils/accountInformation' +import {testAccounts, UserAccountInformation} from '../utils/accountInformation' import {deleteUser} from '../utils/deleteUser' export const test = base.extend<{ @@ -17,21 +17,28 @@ export const test = base.extend<{ authPage: AuthPage compatabilityPage: ComatibilityPage cleanUpUsers: void - testAccount: OnboardingUser - fakerAccount: OnboardingUser + onboardingAccount: UserAccountInformation + fakerAccount: UserAccountInformation + specAccount: UserAccountInformation }>({ - testAccount: async ({}, use) => { - const account = onboarding.account_one() // email captured here + onboardingAccount: async ({}, use) => { + const account = testAccounts.account_all_info() // email captured here await use(account) console.log('Cleaning up onboarding 1 account...') await deleteUser(account.email, account.password) // same account, guaranteed }, fakerAccount: async ({}, use) => { - const account = onboarding.faker_account() // email captured here + const account = testAccounts.faker_account() // email captured here await use(account) console.log('Cleaning up faker account...') await deleteUser(account.email, account.password) // same account, guaranteed }, + specAccount: async ({}, use) => { + const account = testAccounts.spec_account() + await use(account) + console.log('Cleaning up spec account...') + await deleteUser(account.email, account.password) + }, onboardingPage: async ({page}, use) => { const onboardingPage = new OnboardingPage(page) await use(onboardingPage) diff --git a/tests/e2e/web/fixtures/deleteUserFixture.ts b/tests/e2e/web/fixtures/deleteUserFixture.ts deleted file mode 100644 index 583c4335..00000000 --- a/tests/e2e/web/fixtures/deleteUserFixture.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {test as base} from '@playwright/test' -import axios from 'axios' -import {config} from '../SPEC_CONFIG' - -// const baseUrl = 'http://localhost:9099/identitytoolkit.googleapis.com/v1'; - -async function deleteUser(email: string, password: string) { - try { - const login = await axios.post( - `${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.SIGN_IN_PASSWORD}`, - { - email, - password, - returnSecureToken: true, - }, - ) - - await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.DELETE}`, { - idToken: login.data.idToken, - }) - } catch (err: any) { - // Skip deletion if user doesn't exist or other auth errors occur - if ( - err.response?.status === 400 || - err.response?.data?.error?.message?.includes('EMAIL_NOT_FOUND') - ) { - return - } - console.log(err) - } -} - -type CleanupFixtures = { - cleanupUsers: void -} - -export const test = base.extend({ - cleanupUsers: [ - async ({}, use) => { - // Run all tests first - await use() - - //then delete users - await deleteUser(config.USERS.SPEC.EMAIL, config.USERS.SPEC.PASSWORD) - }, - {auto: true}, - ], -}) diff --git a/tests/e2e/web/pages/AuthPage.ts b/tests/e2e/web/pages/AuthPage.ts index c3c56107..36b33ece 100644 --- a/tests/e2e/web/pages/AuthPage.ts +++ b/tests/e2e/web/pages/AuthPage.ts @@ -21,22 +21,27 @@ export class AuthPage { } async clickSignInLink() { + await expect(this.signInLink).toBeVisible() await this.signInLink.click() } async clickSignUpButton() { + await expect(this.signUpButton).toBeVisible() await this.signUpButton.click() } async clickSignInWithEmailButton() { + await expect(this.signInWithEmailButton).toBeVisible() await this.signInWithEmailButton.click() } async clickSignInWithGoogleButton() { + await expect(this.signInWithGoogleButton).toBeVisible() await this.signInWithGoogleButton.click() } async clickSignUpWithEmailButton() { + await expect(this.signUpWithEmailButton).toBeVisible() await this.signUpWithEmailButton.click() } diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index 1f999cc8..e6eef8cb 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -29,7 +29,6 @@ export class ProfilePage { private readonly dietAboutSection: Locator private readonly languagesAboutSection: Locator private readonly seekingAboutSection: Locator - private readonly relationshipTypeAboutSection: Locator private readonly relationshipStatusAboutSection: Locator private readonly educationAboutSection: Locator private readonly occupationAboutSection: Locator @@ -64,8 +63,8 @@ export class ProfilePage { private readonly profileCompatibilityExplanation: Locator constructor(public readonly page: Page) { - this.startAnsweringButton = page.getByRole('button', {}) - this.doThisLaterLink = page.getByRole('button', {}) + this.startAnsweringButton = page.getByRole('button', {name: 'Start answering'}) + this.doThisLaterLink = page.getByRole('button', {name: 'Do this later'}) this.closeButton = page.getByRole('button', {name: 'Close'}) this.shareButton = page.getByRole('button', {name: 'Share'}) this.editProfileButton = page.getByTestId('profile-edit') @@ -90,7 +89,6 @@ export class ProfilePage { this.dietAboutSection = page.getByTestId('profile-about-diet') this.languagesAboutSection = page.getByTestId('profile-about-languages') this.seekingAboutSection = page.getByTestId('profile-about-seeking') - this.relationshipTypeAboutSection = page.getByTestId('profile-about-seeking') this.relationshipStatusAboutSection = page.getByTestId('profile-about-relationship-status') this.educationAboutSection = page.getByTestId('profile-about-education') this.occupationAboutSection = page.getByTestId('profile-about-occupation') @@ -321,8 +319,8 @@ export class ProfilePage { async verifyDisplayName(displayName?: string) { await expect(this.displayNameAndAgeSection).toBeVisible() - const textContent = await this.displayNameAndAgeSection.textContent() - if (displayName) await expect(textContent?.toLowerCase()).toContain(displayName.toLowerCase()) + if (displayName) + await expect(this.displayNameAndAgeSection).toContainText(displayName, {ignoreCase: true}) } async verifyGenderLocationHeightAge( @@ -333,72 +331,73 @@ export class ProfilePage { age?: string, ) { await expect(this.genderLocationHightInInchesSection).toBeVisible() - const textContent = await this.genderLocationHightInInchesSection.textContent() - if (gender) await expect(textContent?.toLowerCase()).toContain(gender[0].toLowerCase()) - if (location) await expect(textContent?.toLowerCase()).toContain(location.toLowerCase()) - if (heightFeet) await expect(textContent?.toLowerCase()).toContain(heightFeet.toLowerCase()) - if (heightInches) await expect(textContent?.toLowerCase()).toContain(heightInches.toLowerCase()) - if (age) await expect(textContent?.toLowerCase()).toContain(age.toLowerCase()) + if (gender) + await expect(this.genderLocationHightInInchesSection).toContainText(gender[0], { + ignoreCase: true, + }) + if (location) + await expect(this.genderLocationHightInInchesSection).toContainText(location, { + ignoreCase: true, + }) + if (heightFeet) await expect(this.genderLocationHightInInchesSection).toContainText(heightFeet) + if (heightInches) + await expect(this.genderLocationHightInInchesSection).toContainText(heightInches) + if (age) await expect(this.genderLocationHightInInchesSection).toContainText(age) } async verifyEthnicityOrigin(origin: string) { await expect(this.ethnicityAboutSection).toBeVisible() - const textContent = await this.ethnicityAboutSection.textContent() - await expect(textContent?.toLowerCase()).toContain(origin.toLowerCase()) + await expect(this.ethnicityAboutSection).toContainText(origin, {ignoreCase: true}) } - async verifyInterestedInConnectingWith(gender?: string[], minAge?: string, maxAge?: string) { + async verifySeeking( + gender?: string[], + minAge?: string, + maxAge?: string, + type?: string[], + interest?: string[], + ) { await expect(this.seekingAboutSection).toBeVisible() - const textContent = await this.seekingAboutSection.textContent() - if (gender) await expect(textContent?.toLowerCase()).toContain(gender[0].toLowerCase()) - if (minAge) await expect(textContent?.toLowerCase()).toContain(minAge.toLowerCase()) - if (maxAge) await expect(textContent?.toLowerCase()).toContain(maxAge.toLowerCase()) - } - - async verifyRelationShipTypeAndInterest(type?: string[], interest?: string[]) { - await expect(this.relationshipTypeAboutSection).toBeVisible() - const textContent = await this.relationshipTypeAboutSection.textContent() - if (type) await expect(textContent?.toLowerCase()).toContain(type[0].toLowerCase()) - if (interest) await expect(textContent?.toLowerCase()).toContain(interest[0].toLowerCase()) + if (gender) await expect(this.seekingAboutSection).toContainText(gender[0], {ignoreCase: true}) + if (minAge) await expect(this.seekingAboutSection).toContainText(minAge) + if (maxAge) await expect(this.seekingAboutSection).toContainText(maxAge) + if (type) await expect(this.seekingAboutSection).toContainText(type[0], {ignoreCase: true}) + if (interest) + await expect(this.seekingAboutSection).toContainText(interest[0], {ignoreCase: true}) } async verifyRelationshipStatus(status: string[] | undefined) { if (!status) return await expect(this.relationshipStatusAboutSection).toBeVisible() - const textContent = await this.relationshipStatusAboutSection.textContent() - await expect(textContent?.toLowerCase()).toContain(status[0].toLowerCase()) + await expect(this.relationshipStatusAboutSection).toContainText(status[0], {ignoreCase: true}) } async verifyCurrentNumberOfKids(numberOfKids: string | undefined) { if (!numberOfKids) return await expect(this.hasKidsAboutSection).toBeVisible() - const textContent = await this.hasKidsAboutSection.textContent() - await expect(textContent?.toLowerCase()).toContain(numberOfKids.toLowerCase()) + await expect(this.hasKidsAboutSection).toContainText(numberOfKids) } async verifyWantChildrenExpectation(expectation: [string, number] | undefined) { if (!expectation) return const [label, _value] = expectation await expect(this.wantsKidsAboutSection).toBeVisible() - const textContent = await this.wantsKidsAboutSection.textContent() - await expect(textContent?.toLowerCase()).toContain(label.toLowerCase()) + await expect(this.wantsKidsAboutSection).toContainText(label, {ignoreCase: true}) } async verifyInterests(interest: string[] | undefined) { if (!interest || interest.length === 0) return await expect(this.interestsAboutSection).toBeVisible() - const textContent = await this.interestsAboutSection.textContent() for (let i = 0; i < interest.length; i++) { - await expect(textContent?.toLowerCase()).toContain(interest[i].toLowerCase()) + await expect(this.interestsAboutSection).toContainText(interest[i], {ignoreCase: true}) } } async verifyCauses(causes: string[] | undefined) { if (!causes || causes.length === 0) return await expect(this.causesAboutSection).toBeVisible() - const textContent = await this.causesAboutSection.textContent() for (let i = 0; i < causes.length; i++) { - await expect(textContent?.toLowerCase()).toContain(causes[i].toLowerCase()) + await expect(this.causesAboutSection).toContainText(causes[i], {ignoreCase: true}) } } @@ -412,86 +411,82 @@ export class ProfilePage { async verifyEducationLevelAndUniversity(educationLevel?: string[], university?: string) { await expect(this.educationAboutSection).toBeVisible() - const textContent = await this.educationAboutSection.textContent() if (educationLevel) - await expect(textContent?.toLowerCase()).toContain(educationLevel[0].toLowerCase()) - if (university) await expect(textContent?.toLowerCase()).toContain(university.toLowerCase()) + await expect(this.educationAboutSection).toContainText(educationLevel[0], {ignoreCase: true}) + if (university) + await expect(this.educationAboutSection).toContainText(university, {ignoreCase: true}) } async verifyJobInformation(jobTitle?: string, company?: string) { await expect(this.occupationAboutSection).toBeVisible() - const textContent = await this.occupationAboutSection.textContent() - if (jobTitle) await expect(textContent?.toLowerCase()).toContain(jobTitle.toLowerCase()) - if (company) await expect(textContent?.toLowerCase()).toContain(company.toLowerCase()) + if (jobTitle) + await expect(this.occupationAboutSection).toContainText(jobTitle, {ignoreCase: true}) + if (company) + await expect(this.occupationAboutSection).toContainText(company, {ignoreCase: true}) } async verifyPoliticalBeliefs(belief?: string[], details?: string) { await expect(this.politicalAboutSection).toBeVisible() - const textContent = await this.politicalAboutSection.textContent() - if (belief) await expect(textContent?.toLowerCase()).toContain(belief[0].toLowerCase()) - if (details) await expect(textContent?.toLowerCase()).toContain(details.toLowerCase()) + if (belief) + await expect(this.politicalAboutSection).toContainText(belief[0], {ignoreCase: true}) + if (details) await expect(this.politicalAboutSection).toContainText(details, {ignoreCase: true}) } async verifyReligiousBeliefs(belief?: string[], details?: string) { await expect(this.relegiousAboutSection).toBeVisible() - const textContent = await this.relegiousAboutSection.textContent() - if (belief) await expect(textContent?.toLowerCase()).toContain(belief[0].toLowerCase()) - if (details) await expect(textContent?.toLowerCase()).toContain(details.toLowerCase()) + if (belief) + await expect(this.relegiousAboutSection).toContainText(belief[0], {ignoreCase: true}) + if (details) await expect(this.relegiousAboutSection).toContainText(details, {ignoreCase: true}) } async verifyPersonalityType(personalityType: string | undefined) { if (!personalityType) return await expect(this.personalityAboutSection).toBeVisible() - const textContent = await this.personalityAboutSection.textContent() - await expect(textContent?.toLowerCase()).toContain(personalityType.toLowerCase()) + await expect(this.personalityAboutSection).toContainText(personalityType, {ignoreCase: true}) } async verifyBigFivePersonalitySection(personalityType: Record | undefined) { if (!personalityType) return await expect(this.bigFivePersonalityTraitsAboutSection).toBeVisible() - const textContent = await this.bigFivePersonalityTraitsAboutSection.textContent() for (const [key, value] of Object.entries(personalityType)) { - await expect(textContent?.toLowerCase()).toContain(key.toLowerCase()) - await expect(textContent?.toLowerCase()).toContain(String(value)) + await expect(this.bigFivePersonalityTraitsAboutSection).toContainText(key, {ignoreCase: true}) + await expect(this.bigFivePersonalityTraitsAboutSection).toContainText(String(value)) } } async verifyDiet(diet: string[] | undefined) { if (!diet) return await expect(this.dietAboutSection).toBeVisible() - const textContent = await this.dietAboutSection.textContent() - await expect(textContent?.toLowerCase()).toContain(diet[0].toLowerCase()) + await expect(this.dietAboutSection).toContainText(diet[0], {ignoreCase: true}) } async verifySmoker(smoker: boolean | undefined) { await expect(this.smokerAboutSection).toBeVisible() - const textContent = await this.smokerAboutSection.textContent() - if (smoker === true) await expect(textContent?.toLowerCase()).toContain('Smokes'.toLowerCase()) + if (smoker === true) + await expect(this.smokerAboutSection).toContainText('Smokes', {ignoreCase: true}) if (smoker === false) - await expect(textContent?.toLowerCase()).toContain("Doesn't smoke".toLowerCase()) + await expect(this.smokerAboutSection).toContainText("Doesn't smoke", {ignoreCase: true}) } async verifyDrinksPerMonth(drinks: string | undefined) { + if (!drinks) return await expect(this.drinkerAboutSection).toBeVisible() - const textContent = await this.drinkerAboutSection.textContent() - await expect(textContent?.toLowerCase()).toContain(drinks) + await expect(this.drinkerAboutSection).toContainText(drinks) } async verifyLanguages(languages: LanguageTuple[] | undefined) { if (!languages || languages.length === 0) return await expect(this.languagesAboutSection).toBeVisible() - const textContent = await this.languagesAboutSection.textContent() for (const language of languages) { - await expect(textContent?.toLowerCase()).toContain(language[0].toLowerCase()) + await expect(this.languagesAboutSection).toContainText(language[0], {ignoreCase: true}) } } async verifySocialMedia(socialMedia: Socials[] | undefined) { if (!socialMedia || socialMedia.length === 0) return await expect(this.socialMediaSection).toBeVisible() - const textContent = await this.socialMediaSection.textContent() for (const {urlOrUsername} of socialMedia) { - await expect(textContent?.toLowerCase()).toContain(urlOrUsername.toLowerCase()) + await expect(this.socialMediaSection).toContainText(urlOrUsername, {ignoreCase: true}) } } diff --git a/tests/e2e/web/pages/signUpPage.ts b/tests/e2e/web/pages/signUpPage.ts index e725d154..067167f4 100644 --- a/tests/e2e/web/pages/signUpPage.ts +++ b/tests/e2e/web/pages/signUpPage.ts @@ -45,7 +45,9 @@ export type Platforms = export class SignUpPage { private readonly displayNameField: Locator + private readonly displayNameError: Locator private readonly usernameField: Locator + private readonly usernameError: Locator private readonly nextButton: Locator private readonly bioField: Locator private readonly locationField: Locator @@ -101,7 +103,9 @@ export class SignUpPage { constructor(public readonly page: Page) { this.displayNameField = page.getByPlaceholder('Display name') + this.displayNameError = page.getByTestId('signup-display-name') this.usernameField = page.getByPlaceholder('Username') + this.usernameError = page.getByTestId('signup-username') this.nextButton = page.getByRole('button', {name: 'Next', exact: true}) this.bioField = page.locator('.tiptap') this.locationField = page.getByPlaceholder('Search city...') @@ -155,6 +159,10 @@ export class SignUpPage { this.saveButton = page.getByRole('button', {name: 'Save'}) } + get nextButtonLocator(): Locator { + return this.nextButton + } + async fillUsername(username: string) { await expect(this.usernameField).toBeVisible() await this.usernameField.fill(username) @@ -179,9 +187,9 @@ export class SignUpPage { async chooseGender(gender: GenderTuple | undefined) { if (!gender) return - await expect(this.page.locator(`span:has-text("${gender[0]}")`)).toBeVisible() - await this.page.locator(`span:has-text("${gender[0]}")`).click() - await expect(this.page.locator(`span:has-text("${gender[0]}")`)).toBeChecked() + await expect(this.page.locator(`:text-is("${gender[0]}")`)).toBeVisible() + await this.page.locator(`:text-is("${gender[0]}")`).click() + await expect(this.page.locator(`:text-is("${gender[0]}")`)).toBeChecked() } async fillAge(age: string | undefined) { @@ -716,4 +724,12 @@ export class SignUpPage { await expect(this.keywordsField).toBeVisible() await this.keywordsField.fill(keywords) } + + async verifyDisplayNameError() { + await expect(this.displayNameError).toBeVisible() + } + + async verifyUsernameError() { + await expect(this.usernameError).toBeVisible() + } } diff --git a/tests/e2e/web/specs/onboardingFlow.spec.ts b/tests/e2e/web/specs/onboardingFlow.spec.ts index a6aadb0e..a91a3c40 100644 --- a/tests/e2e/web/specs/onboardingFlow.spec.ts +++ b/tests/e2e/web/specs/onboardingFlow.spec.ts @@ -1,4 +1,5 @@ import {userInformationFromDb} from '../../utils/databaseUtils' +import {progressToRequiredForm} from '../utils/testCleanupHelpers' import {expect, test} from '../fixtures/base' test.describe('when given valid input', () => { @@ -8,82 +9,84 @@ test.describe('when given valid input', () => { signUpPage, authPage, profilePage, - testAccount, + onboardingAccount, }) => { console.log( - `Starting "should successfully complete the onboarding flow" with ${testAccount.username}`, + `Starting "should successfully complete the onboarding flow" with ${onboardingAccount.username}`, ) await homePage.gotToHomePage() await homePage.clickSignUpButton() - await authPage.fillEmailField(testAccount.email) - await authPage.fillPasswordField(testAccount.password) + await authPage.fillEmailField(onboardingAccount.email) + await authPage.fillPasswordField(onboardingAccount.password) await authPage.clickSignUpWithEmailButton() await onboardingPage.clickContinueButton() //First continue await onboardingPage.clickContinueButton() //Second continue await onboardingPage.clickGetStartedButton() - await signUpPage.fillDisplayName(testAccount.display_name) - await signUpPage.fillUsername(testAccount.username) + await signUpPage.fillDisplayName(onboardingAccount.display_name) + await signUpPage.fillUsername(onboardingAccount.username) await signUpPage.clickNextButton() - await signUpPage.chooseGender(testAccount.gender) - await signUpPage.fillAge(testAccount.age) + await signUpPage.chooseGender(onboardingAccount.gender) + await signUpPage.fillAge(onboardingAccount.age) await signUpPage.fillHeight({ - feet: testAccount.height?.feet, - inches: testAccount.height?.inches, + feet: onboardingAccount.height?.feet, + inches: onboardingAccount.height?.inches, }) - await signUpPage.fillEthnicity(testAccount.ethnicity_origin) - await signUpPage.fillHeadline(testAccount.headline) - await signUpPage.fillKeywords(testAccount.keywords) - await signUpPage.fillInterestedInConnectingWith(testAccount.interested_in) + await signUpPage.fillEthnicity(onboardingAccount.ethnicity_origin) + await signUpPage.fillHeadline(onboardingAccount.headline) + await signUpPage.fillKeywords(onboardingAccount.keywords) + await signUpPage.fillInterestedInConnectingWith(onboardingAccount.interested_in) await signUpPage.fillAgeRangeInterest( - testAccount.Interested_in_ages?.min, - testAccount.Interested_in_ages?.max, + onboardingAccount.Interested_in_ages?.min, + onboardingAccount.Interested_in_ages?.max, ) - await signUpPage.setConnectionType(testAccount.connection_type) - await signUpPage.setRelationshipStatus(testAccount.relationship_status) - await signUpPage.setRelationshipStyle(testAccount.relationship_style) - await signUpPage.fillCurrentNumberOfChildren(testAccount.number_of_kids) - await signUpPage.setWantChildrenExpectation(testAccount.children_expectation) - await signUpPage.setInterests(testAccount.interests) - await signUpPage.setCauses(testAccount.causes) - await signUpPage.setHighestEducationLevel(testAccount.education_level) - await signUpPage.fillUniversity(testAccount.university) - await signUpPage.fillJobTitle(testAccount.job_title) - await signUpPage.fillCompany(testAccount.company) - await signUpPage.setWorkArea(testAccount.work_area) + await signUpPage.setConnectionType(onboardingAccount.connection_type) + await signUpPage.setRelationshipStatus(onboardingAccount.relationship_status) + await signUpPage.setRelationshipStyle(onboardingAccount.relationship_style) + await signUpPage.fillCurrentNumberOfChildren(onboardingAccount.number_of_kids) + await signUpPage.setWantChildrenExpectation(onboardingAccount.children_expectation) + await signUpPage.setInterests(onboardingAccount.interests) + await signUpPage.setCauses(onboardingAccount.causes) + await signUpPage.setHighestEducationLevel(onboardingAccount.education_level) + await signUpPage.fillUniversity(onboardingAccount.university) + await signUpPage.fillJobTitle(onboardingAccount.job_title) + await signUpPage.fillCompany(onboardingAccount.company) + await signUpPage.setWorkArea(onboardingAccount.work_area) await signUpPage.setPoliticalBeliefs( - testAccount.beliefs?.political?.belief, - testAccount.beliefs?.political?.details, + onboardingAccount.beliefs?.political?.belief, + onboardingAccount.beliefs?.political?.details, ) await signUpPage.setReligiousBeliefs( - testAccount.beliefs?.religious?.belief, - testAccount.beliefs?.religious?.details, + onboardingAccount.beliefs?.religious?.belief, + onboardingAccount.beliefs?.religious?.details, + ) + await signUpPage.setPersonalityType(onboardingAccount.personality_type) + await signUpPage.setOpennessPersonalityValue( + onboardingAccount.big_five_personality_traits?.openness, ) - await signUpPage.setPersonalityType(testAccount.personality_type) - await signUpPage.setOpennessPersonalityValue(testAccount.big_five_personality_traits?.openness) await signUpPage.setAgreeablenessPersonalityValue( - testAccount.big_five_personality_traits?.agreeableness, + onboardingAccount.big_five_personality_traits?.agreeableness, ) await signUpPage.setConscientiousnessPersonalityValue( - testAccount.big_five_personality_traits?.conscientiousness, + onboardingAccount.big_five_personality_traits?.conscientiousness, ) await signUpPage.setExtraversionPersonalityValue( - testAccount.big_five_personality_traits?.extraversion, + onboardingAccount.big_five_personality_traits?.extraversion, ) await signUpPage.setNeuroticismPersonalityValue( - testAccount.big_five_personality_traits?.neuroticism, + onboardingAccount.big_five_personality_traits?.neuroticism, ) - await signUpPage.setDietType(testAccount.diet) - await signUpPage.setIsSmoker(testAccount.is_smoker) - await signUpPage.fillAlcoholPerMonth(testAccount.alcohol_consumed_per_month) - await signUpPage.setLanguages(testAccount.languages) - await signUpPage.addSocialMediaPlatform(testAccount.social_media) - await signUpPage.fillBio(testAccount.bio) + await signUpPage.setDietType(onboardingAccount.diet) + await signUpPage.setIsSmoker(onboardingAccount.is_smoker) + await signUpPage.fillAlcoholPerMonth(onboardingAccount.alcohol_consumed_per_month) + await signUpPage.setLanguages(onboardingAccount.languages) + await signUpPage.addSocialMediaPlatform(onboardingAccount.social_media) + await signUpPage.fillBio(onboardingAccount.bio) await signUpPage.clickNextButton() await profilePage.clickCloseButton() await onboardingPage.clickRefineProfileButton() await profilePage.clickAnswerQuestionsButton() const compatQuestionOne = await profilePage.answerCompatibilityQuestion( - testAccount.compatibility, + onboardingAccount.compatibility, ) await profilePage.clickNextCompatibilityQuestionButton() await profilePage.clickSkipCompatibilityQuestionButton() @@ -92,119 +95,133 @@ test.describe('when given valid input', () => { await profilePage.clickCloseButton() //Verify information is correct - await profilePage.verifyDisplayName(testAccount.display_name) - await profilePage.verifyHeadline(testAccount.headline) - await profilePage.verifyKeywords(testAccount.keywords) + await profilePage.verifyDisplayName(onboardingAccount.display_name) + await profilePage.verifyHeadline(onboardingAccount.headline) + await profilePage.verifyKeywords(onboardingAccount.keywords) await profilePage.verifyGenderLocationHeightAge( - testAccount.gender, + onboardingAccount.gender, undefined, - testAccount.height?.feet, - testAccount.height?.inches, - testAccount.age, + onboardingAccount.height?.feet, + onboardingAccount.height?.inches, + onboardingAccount.age, ) - await profilePage.verifyInterestedInConnectingWith( - testAccount.interested_in, - testAccount.Interested_in_ages?.min, - testAccount.Interested_in_ages?.max, + await profilePage.verifySeeking( + onboardingAccount.interested_in, + onboardingAccount.Interested_in_ages?.min, + onboardingAccount.Interested_in_ages?.max, + onboardingAccount.connection_type, + onboardingAccount.relationship_style, ) - await profilePage.verifyRelationShipTypeAndInterest( - testAccount.connection_type, - testAccount.relationship_style, - ) - await profilePage.verifyRelationshipStatus(testAccount.relationship_status) - await profilePage.verifyCurrentNumberOfKids(testAccount.number_of_kids) - await profilePage.verifyWantChildrenExpectation(testAccount.children_expectation) - await profilePage.verifyInterests(testAccount.interests) - await profilePage.verifyCauses(testAccount.causes) + await profilePage.verifyRelationshipStatus(onboardingAccount.relationship_status) + await profilePage.verifyCurrentNumberOfKids(onboardingAccount.number_of_kids) + await profilePage.verifyWantChildrenExpectation(onboardingAccount.children_expectation) + await profilePage.verifyInterests(onboardingAccount.interests) + await profilePage.verifyCauses(onboardingAccount.causes) await profilePage.verifyEducationLevelAndUniversity( - testAccount.education_level, - testAccount.university, + onboardingAccount.education_level, + onboardingAccount.university, ) - await profilePage.verifyJobInformation(testAccount.job_title, testAccount.company) - await profilePage.verifyWorkArea(testAccount.work_area) + await profilePage.verifyJobInformation(onboardingAccount.job_title, onboardingAccount.company) + await profilePage.verifyWorkArea(onboardingAccount.work_area) await profilePage.verifyPoliticalBeliefs( - testAccount.beliefs?.political?.belief, - testAccount.beliefs?.political?.details, + onboardingAccount.beliefs?.political?.belief, + onboardingAccount.beliefs?.political?.details, ) await profilePage.verifyReligiousBeliefs( - testAccount.beliefs?.religious?.belief, - testAccount.beliefs?.religious?.details, + onboardingAccount.beliefs?.religious?.belief, + onboardingAccount.beliefs?.religious?.details, ) - await profilePage.verifyPersonalityType(testAccount.personality_type) - await profilePage.verifyBigFivePersonalitySection(testAccount.big_five_personality_traits) - await profilePage.verifyDiet(testAccount.diet) - await profilePage.verifySmoker(testAccount.is_smoker) - await profilePage.verifyDrinksPerMonth(testAccount.alcohol_consumed_per_month) - await profilePage.verifyLanguages(testAccount.languages) - await profilePage.verifySocialMedia(testAccount.social_media) - await profilePage.verifyBio(testAccount.bio) + await profilePage.verifyPersonalityType(onboardingAccount.personality_type) + await profilePage.verifyBigFivePersonalitySection(onboardingAccount.big_five_personality_traits) + await profilePage.verifyDiet(onboardingAccount.diet) + await profilePage.verifySmoker(onboardingAccount.is_smoker) + await profilePage.verifyDrinksPerMonth(onboardingAccount.alcohol_consumed_per_month) + await profilePage.verifyLanguages(onboardingAccount.languages) + await profilePage.verifySocialMedia(onboardingAccount.social_media) + await profilePage.verifyBio(onboardingAccount.bio) await profilePage.verifyCompatibilityAnswers(compatQuestionOne) //Verify Database Information - const dbInfo = await userInformationFromDb(testAccount) + const dbInfo = await userInformationFromDb(onboardingAccount) console.log(dbInfo.profile) - await expect(dbInfo.user.name).toBe(testAccount.display_name) - await expect(dbInfo.user.username).toBe(testAccount.username) - await expect(dbInfo.profile.bio_text).toBe(testAccount.bio) - await expect(dbInfo.profile.gender).toEqual(testAccount.gender?.[1]) - await expect(dbInfo.profile.headline).toEqual(testAccount.headline) + await expect(dbInfo.user.name).toBe(onboardingAccount.display_name) + await expect(dbInfo.user.username).toBe(onboardingAccount.username) + await expect(dbInfo.profile.bio_text).toBe(onboardingAccount.bio) + await expect(dbInfo.profile.gender).toEqual(onboardingAccount.gender?.[1]) + await expect(dbInfo.profile.headline).toEqual(onboardingAccount.headline) await expect(dbInfo.profile.keywords).toEqual( - expect.arrayContaining(testAccount.keywords?.split(', ') ?? []), + expect.arrayContaining(onboardingAccount.keywords?.split(', ') ?? []), + ) + await expect(String(dbInfo.profile.age)).toEqual(onboardingAccount.age) + await expect(dbInfo.profile.height_in_inches).toEqual( + Number(onboardingAccount.height?.feet) * 12, + ) + await expect(dbInfo.profile.ethnicity).toContain(onboardingAccount.ethnicity_origin?.[1]) + await expect(dbInfo.profile.pref_gender).toContain(onboardingAccount.interested_in?.[1]) + await expect(String(dbInfo.profile.pref_age_min)).toContain( + onboardingAccount.Interested_in_ages?.min, + ) + await expect(String(dbInfo.profile.pref_age_max)).toContain( + onboardingAccount.Interested_in_ages?.max, ) - await expect(String(dbInfo.profile.age)).toEqual(testAccount.age) - await expect(dbInfo.profile.height_in_inches).toEqual(Number(testAccount.height?.feet) * 12) - await expect(dbInfo.profile.ethnicity).toContain(testAccount.ethnicity_origin?.[1]) - await expect(dbInfo.profile.pref_gender).toContain(testAccount.interested_in?.[1]) - await expect(String(dbInfo.profile.pref_age_min)).toContain(testAccount.Interested_in_ages?.min) - await expect(String(dbInfo.profile.pref_age_max)).toContain(testAccount.Interested_in_ages?.max) await expect(dbInfo.profile.pref_relation_styles).toContain( - `${testAccount.connection_type?.[1]}`.toLowerCase(), + `${onboardingAccount.connection_type?.[1]}`.toLowerCase(), + ) + await expect(dbInfo.profile.relationship_status).toContain( + onboardingAccount.relationship_status?.[1], + ) + await expect(dbInfo.profile.pref_romantic_styles).toContain( + onboardingAccount.relationship_style?.[1], + ) + await expect(dbInfo.profile.has_kids).toEqual(Number(onboardingAccount.number_of_kids)) + await expect(dbInfo.profile.wants_kids_strength).toEqual( + onboardingAccount.children_expectation?.[1], ) - await expect(dbInfo.profile.relationship_status).toContain(testAccount.relationship_status?.[1]) - await expect(dbInfo.profile.pref_romantic_styles).toContain(testAccount.relationship_style?.[1]) - await expect(dbInfo.profile.has_kids).toEqual(Number(testAccount.number_of_kids)) - await expect(dbInfo.profile.wants_kids_strength).toEqual(testAccount.children_expectation?.[1]) await expect(dbInfo.profile.education_level).toContain( - `${testAccount.education_level?.[1]}`.toLowerCase(), + `${onboardingAccount.education_level?.[1]}`.toLowerCase(), ) - await expect(dbInfo.profile.university).toContain(testAccount.university) - await expect(dbInfo.profile.occupation_title).toContain(testAccount.job_title) - await expect(dbInfo.profile.company).toContain(testAccount.company) + await expect(dbInfo.profile.university).toContain(onboardingAccount.university) + await expect(dbInfo.profile.occupation_title).toContain(onboardingAccount.job_title) + await expect(dbInfo.profile.company).toContain(onboardingAccount.company) await expect(dbInfo.profile.political_beliefs).toContain( - testAccount.beliefs?.political?.belief?.[1], + onboardingAccount.beliefs?.political?.belief?.[1], ) await expect(dbInfo.profile.political_details).toContain( - testAccount.beliefs?.political?.details, + onboardingAccount.beliefs?.political?.details, + ) + await expect(dbInfo.profile.religion).toContain( + onboardingAccount.beliefs?.religious?.belief?.[1], ) - await expect(dbInfo.profile.religion).toContain(testAccount.beliefs?.religious?.belief?.[1]) await expect(dbInfo.profile.religious_beliefs).toContain( - testAccount.beliefs?.religious?.details, + onboardingAccount.beliefs?.religious?.details, + ) + await expect(dbInfo.profile.mbti).toContain( + `${onboardingAccount.personality_type}`.toLowerCase(), ) - await expect(dbInfo.profile.mbti).toContain(`${testAccount.personality_type}`.toLowerCase()) await expect(dbInfo.profile.big5_openness).toEqual( - testAccount.big_five_personality_traits?.openness, + onboardingAccount.big_five_personality_traits?.openness, ) await expect(dbInfo.profile.big5_conscientiousness).toEqual( - testAccount.big_five_personality_traits?.conscientiousness, + onboardingAccount.big_five_personality_traits?.conscientiousness, ) await expect(dbInfo.profile.big5_extraversion).toEqual( - testAccount.big_five_personality_traits?.extraversion, + onboardingAccount.big_five_personality_traits?.extraversion, ) await expect(dbInfo.profile.big5_agreeableness).toEqual( - testAccount.big_five_personality_traits?.agreeableness, + onboardingAccount.big_five_personality_traits?.agreeableness, ) await expect(dbInfo.profile.big5_neuroticism).toEqual( - testAccount.big_five_personality_traits?.neuroticism, + onboardingAccount.big_five_personality_traits?.neuroticism, ) - await expect(dbInfo.profile.diet).toContain(testAccount.diet?.[1].toLowerCase()) - await expect(dbInfo.profile.is_smoker).toEqual(testAccount.is_smoker) + await expect(dbInfo.profile.diet).toContain(onboardingAccount.diet?.[1].toLowerCase()) + await expect(dbInfo.profile.is_smoker).toEqual(onboardingAccount.is_smoker) await expect(dbInfo.profile.languages).toHaveLength(2) await expect(dbInfo.profile.languages).toEqual( - expect.arrayContaining(testAccount.languages?.map(([_, l]) => l.toLowerCase()) ?? []), + expect.arrayContaining(onboardingAccount.languages?.map(([_, l]) => l.toLowerCase()) ?? []), ) await expect(String(dbInfo.profile.drinks_per_month)).toEqual( - testAccount.alcohol_consumed_per_month, + onboardingAccount.alcohol_consumed_per_month, ) }) @@ -219,12 +236,7 @@ test.describe('when given valid input', () => { console.log( `Starting "should successfully skip the onboarding flow" with ${fakerAccount.username}`, ) - await homePage.gotToHomePage() - await homePage.clickSignUpButton() - await authPage.fillEmailField(fakerAccount.email) - await authPage.fillPasswordField(fakerAccount.password) - await authPage.clickSignUpWithEmailButton() - await onboardingPage.clickSkipOnboardingButton() + await progressToRequiredForm(homePage, authPage, fakerAccount, onboardingPage) await signUpPage.fillDisplayName(fakerAccount.display_name) await signUpPage.fillUsername(fakerAccount.username) await signUpPage.clickNextButton() @@ -232,6 +244,93 @@ test.describe('when given valid input', () => { await profilePage.clickCloseButton() await onboardingPage.clickRefineProfileButton() + //Verify displayed information is correct + await profilePage.verifyDisplayName(fakerAccount.display_name) + + //Verify database info + const dbInfo = await userInformationFromDb(fakerAccount) + + await expect(dbInfo.user.name).toContain(fakerAccount.display_name) + await expect(dbInfo.user.username).toContain(fakerAccount.username) + }) + + test('should successfully enter optional information after completing flow', async ({ + homePage, + onboardingPage, + signUpPage, + authPage, + profilePage, + fakerAccount, + }) => { + console.log( + `Starting "should successfully enter optional information after completing flow" with ${fakerAccount.username}`, + ) + await progressToRequiredForm(homePage, authPage, fakerAccount, onboardingPage) + await signUpPage.fillDisplayName(fakerAccount.display_name) + await signUpPage.fillUsername(fakerAccount.username) + await signUpPage.clickNextButton() + await signUpPage.clickNextButton() //Skip optional information + await profilePage.clickCloseButton() + await onboardingPage.clickRefineProfileButton() + await profilePage.clickEditProfileButton() + await signUpPage.chooseGender(fakerAccount.gender) + await signUpPage.fillAge(fakerAccount.age) + await signUpPage.fillHeight({ + feet: fakerAccount.height?.feet, + inches: fakerAccount.height?.inches, + }) + await signUpPage.saveProfileChanges() + + //Verify displayed information is correct + await profilePage.verifyDisplayName(fakerAccount.display_name) + await profilePage.verifyGenderLocationHeightAge( + fakerAccount.gender, + undefined, + fakerAccount.height?.feet, + fakerAccount.height?.inches, + fakerAccount.age, + ) + + //Verify database info + const dbInfo = await userInformationFromDb(fakerAccount) + + await expect(dbInfo.user.name).toContain(fakerAccount.display_name) + await expect(dbInfo.user.username).toContain(fakerAccount.username) + await expect(dbInfo.profile.gender).toEqual(fakerAccount.gender?.[1]) + await expect(String(dbInfo.profile.age)).toEqual(fakerAccount.age) + await expect(dbInfo.profile.height_in_inches).toEqual(Number(fakerAccount.height?.feet) * 12) + }) + + test('should successfully use the start answering option', async ({ + homePage, + onboardingPage, + signUpPage, + authPage, + profilePage, + fakerAccount, + onboardingAccount, + }) => { + console.log( + `Starting "should successfully use the start answering option" with ${fakerAccount.username}`, + ) + await progressToRequiredForm(homePage, authPage, fakerAccount, onboardingPage) + await signUpPage.fillDisplayName(fakerAccount.display_name) + await signUpPage.fillUsername(fakerAccount.username) + await signUpPage.clickNextButton() + await signUpPage.clickNextButton() //Skip optional information + await profilePage.clickStartAnsweringButton() + const compatTwoQuestionOne = await profilePage.answerCompatibilityQuestion( + onboardingAccount.compatibility, + ) + await profilePage.clickNextCompatibilityQuestionButton() + await profilePage.clickCloseButton() + await onboardingPage.clickRefineProfileButton() + + //Verify displayed information is correct + await profilePage.verifyDisplayName(fakerAccount.display_name) + await profilePage.verifyCompatibilityAnswers(compatTwoQuestionOne) + + //Verify database info const dbInfo = await userInformationFromDb(fakerAccount) await expect(dbInfo.user.name).toContain(fakerAccount.display_name) @@ -267,6 +366,10 @@ test.describe('when given valid input', () => { await profilePage.clickCloseButton() await onboardingPage.clickRefineProfileButton() + //Verify displayed information is correct + await profilePage.verifyDisplayName(fakerAccount.display_name) + + //Verify database info const dbInfo = await userInformationFromDb(fakerAccount) await expect(dbInfo.user.name).toContain(fakerAccount.display_name) @@ -292,6 +395,10 @@ test.describe('when given valid input', () => { await profilePage.clickCloseButton() await onboardingPage.clickRefineProfileButton() + //Verify displayed information is correct + await profilePage.verifyDisplayName(fakerAccount.display_name) + + //Verify database info const dbInfo = await userInformationFromDb(fakerAccount) await expect(dbInfo.user.name).toContain(fakerAccount.display_name) diff --git a/tests/e2e/web/specs/signUp.spec.ts b/tests/e2e/web/specs/signUp.spec.ts index 0434a27d..948f546d 100644 --- a/tests/e2e/web/specs/signUp.spec.ts +++ b/tests/e2e/web/specs/signUp.spec.ts @@ -1,22 +1,36 @@ -import {expect} from '@playwright/test' +import {expect, test} from '../fixtures/base' +import {progressToRequiredForm} from '../utils/testCleanupHelpers' -import {test} from '../fixtures/deleteUserFixture' -import {AuthPage} from '../pages/AuthPage' -import {config} from '../SPEC_CONFIG' - -test('user can sign up with email + password', async ({page}) => { - const auth = new AuthPage(page) - - await page.goto('/') - - await auth.clickSignUpButton() - - await auth.fillEmailField(config.USERS.SPEC.EMAIL) - await auth.fillPasswordField(config.USERS.SPEC.PASSWORD) - - await auth.clickSignUpWithEmailButton() - - await page.waitForURL(/^(?!.*\/signup).*$/) - - expect(page.url()).not.toContain('/signup') +test.describe('when given valid input', () => { + test('placeholder', async () => {}) +}) + +test.describe('when an error occurs', () => { + test('should disable the button "Next" when the display name field is empty', async ({ + specAccount, + homePage, + authPage, + onboardingPage, + signUpPage, + }) => { + await progressToRequiredForm(homePage, authPage, specAccount, onboardingPage) + await signUpPage.fillDisplayName('') + await signUpPage.fillUsername(specAccount.username) + await signUpPage.verifyDisplayNameError() + await expect(signUpPage.nextButtonLocator).toBeDisabled() + }) + + test('should disable the button "Next" when the username field is empty', async ({ + specAccount, + homePage, + authPage, + onboardingPage, + signUpPage, + }) => { + await progressToRequiredForm(homePage, authPage, specAccount, onboardingPage) + await signUpPage.fillDisplayName(specAccount.display_name) + await signUpPage.fillUsername('') + await signUpPage.verifyUsernameError() + await expect(signUpPage.nextButtonLocator).toBeDisabled() + }) }) diff --git a/tests/e2e/web/utils/accountInformation.ts b/tests/e2e/web/utils/accountInformation.ts index 603ddcb4..a8bb3fdb 100644 --- a/tests/e2e/web/utils/accountInformation.ts +++ b/tests/e2e/web/utils/accountInformation.ts @@ -17,7 +17,7 @@ import {ImportanceTuple} from 'web/components/answers/answer-compatibility-quest import {Causes, ChildrenExpectation, Interests, Platforms} from '../pages/signUpPage' -export type OnboardingUser = { +export type UserAccountInformation = { email: string password: string display_name: string @@ -97,12 +97,15 @@ type FiveBigPersonalityTraits = { neuroticism?: number } -type OnboardingConfig = { - faker_account: () => OnboardingUser - account_one: () => OnboardingUser +type AccountConfig = { + faker_account: () => UserAccountInformation + spec_account: () => UserAccountInformation + dev_one_account: () => UserAccountInformation + dev_two_account: () => UserAccountInformation + account_all_info: () => UserAccountInformation } -export const onboarding: OnboardingConfig = { +export const testAccounts: AccountConfig = { // Use a function so email is unique per test call faker_account: () => { const id = crypto.randomUUID().slice(0, 6) @@ -111,14 +114,51 @@ export const onboarding: OnboardingConfig = { password: faker.internet.password(), display_name: faker.internet.displayName(), username: `user_${id}`, + gender: ['Man', 'male'], + age: '35', + height: { + feet: '5', + inches: '0', + centimeters: '152.4', + }, } }, - account_one: () => { + spec_account: () => { + const id = crypto.randomUUID().slice(0, 6) + return { + email: `spec${id}@compass.com`, + password: 'compassConnections1!', + display_name: 'Spec.Compass', + username: `Spec.Connections_${id}`, + } + }, + + dev_one_account: () => { + const id = crypto.randomUUID().slice(0, 6) + return { + email: `dev_1_${id}@compass.com`, + password: 'dev_1Password', + display_name: 'Dev1.Compass', + username: `Dev1.Connections_${id}`, + } + }, + + dev_two_account: () => { + const id = crypto.randomUUID().slice(0, 6) + return { + email: 'dev_2@compass.com', + password: 'dev_2Password', + display_name: 'Dev2.Compass', + username: `Dev2.Connections_${id}`, + } + }, + + account_all_info: () => { const id = crypto.randomUUID().slice(0, 6) return { // Use a non-real TLD like @test.compass to make it obvious these are test accounts and prevent accidental emails - email: `onboarding${id}@test.compass`, + email: `testAccounts${id}@test.compass`, password: 'CompassTest', display_name: 'Compass Onboarding', username: `TheGreatOnboarding_${id}`, // username max length is 25 (see /create-user) diff --git a/tests/e2e/web/utils/deleteUser.ts b/tests/e2e/web/utils/deleteUser.ts index eca1da27..96968b22 100644 --- a/tests/e2e/web/utils/deleteUser.ts +++ b/tests/e2e/web/utils/deleteUser.ts @@ -4,8 +4,8 @@ import {deleteAccount, firebaseLogin} from '../../utils/firebaseUtils' export async function deleteUser(email: string, password: string) { try { const loginInfo = await firebaseLogin(email, password) - await deleteFromDb(loginInfo.data.localId) await deleteAccount(loginInfo) + await deleteFromDb(loginInfo.data.localId) } catch (err: any) { // Skip deletion if user doesn't exist or other auth errors occur if ( diff --git a/tests/e2e/web/utils/testCleanupHelpers.ts b/tests/e2e/web/utils/testCleanupHelpers.ts new file mode 100644 index 00000000..1e11d794 --- /dev/null +++ b/tests/e2e/web/utils/testCleanupHelpers.ts @@ -0,0 +1,18 @@ +import {AuthPage} from '../pages/AuthPage' +import {HomePage} from '../pages/homePage' +import {OnboardingPage} from '../pages/onboardingPage' +import {UserAccountInformation} from '../utils/accountInformation' + +export async function progressToRequiredForm( + homePage: HomePage, + authPage: AuthPage, + account: UserAccountInformation, + onboardingPage: OnboardingPage, +) { + await homePage.gotToHomePage() + await homePage.clickSignUpButton() + await authPage.fillEmailField(account.email) + await authPage.fillPasswordField(account.password) + await authPage.clickSignUpWithEmailButton() + await onboardingPage.clickSkipOnboardingButton() +} diff --git a/web/README.md b/web/README.md index 3fa82f20..3e7d90a3 100644 --- a/web/README.md +++ b/web/README.md @@ -220,7 +220,6 @@ Catches React errors and shows user-friendly message: ```tsx import {ErrorBoundary} from 'web/components/error-boundary' - ; @@ -250,7 +249,6 @@ Keyboard users can skip to main content: ```tsx import {SkipLink, MainContent} from 'web/components/skip-link' - ;<> ... diff --git a/web/components/required-profile-form.tsx b/web/components/required-profile-form.tsx index 2f90092b..576c9569 100644 --- a/web/components/required-profile-form.tsx +++ b/web/components/required-profile-form.tsx @@ -49,13 +49,21 @@ export const RequiredProfileUserForm = (props: { const [step, setStep] = useState(0) const [loadingUsername, setLoadingUsername] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false) - const [errorUsername, setErrorUsername] = useState('') + const [errorMessageUsername, setErrorUsername] = useState(null) + const [errorMessageDisplayName, setErrorDisplayName] = useState(null) const t = useT() + const isDisabled = !!errorMessageDisplayName || !!errorMessageUsername || isSubmitting const updateUsername = async () => { let success = true setLoadingUsername(true) try { + if (data.username.length < 3) { + setErrorUsername('Minimum 3 characters required for usernames') + success = false + setLoadingUsername(false) + return success + } const { valid, message = undefined, @@ -94,13 +102,25 @@ export const RequiredProfileUserForm = (props: { ) => { - setData('name', e.target.value || '') + const value = e.target.value || '' + if (value.length < 3) { + setErrorDisplayName('Minimum 3 characters for display names') + } else { + setErrorDisplayName(null) + } + setData('name', value) }} /> + {errorMessageDisplayName && ( +

+ {errorMessageDisplayName} +

+ )} )} @@ -118,7 +138,13 @@ export const RequiredProfileUserForm = (props: { placeholder="Username" value={data.username || ''} onChange={(e: React.ChangeEvent) => { - setData('username', e.target.value || '') + const value = e.target.value || '' + if (value.length < 3) { + setErrorUsername('Minimum 3 characters required for usernames') + } else { + setErrorUsername(null) + } + setData('username', value) }} /> {loadingUsername && } @@ -131,7 +157,11 @@ export const RequiredProfileUserForm = (props: { )} } - {errorUsername && {errorUsername}} + {errorMessageUsername && ( + + {errorMessageUsername} + + )} )} @@ -154,7 +184,7 @@ export const RequiredProfileUserForm = (props: { {onSubmit && (