From 2933b7c0c73326079ab69a44237f777a761f75c9 Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Sat, 21 Feb 2026 19:02:25 +0000 Subject: [PATCH 01/55] Fixed Type errors --- common/src/choices.ts | 12 ++++++ tests/e2e/web/pages/signUpPage.ts | 50 +++++++++-------------- tests/e2e/web/utils/accountInformation.ts | 42 ++++++++++--------- 3 files changed, 54 insertions(+), 50 deletions(-) diff --git a/common/src/choices.ts b/common/src/choices.ts index 35d173f3..c646d5b9 100644 --- a/common/src/choices.ts +++ b/common/src/choices.ts @@ -231,3 +231,15 @@ export const INVERTED_LANGUAGE_CHOICES = invert(LANGUAGE_CHOICES) export const INVERTED_RACE_CHOICES = invert(RACE_CHOICES) export const INVERTED_MBTI_CHOICES = invert(MBTI_CHOICES) export const INVERTED_GENDERS = invert(GENDERS) + +//Exported types for test files to use when referencing the keys of the choices objects +export type ConnectionTypeKey = keyof typeof RELATIONSHIP_CHOICES +export type RelationshipStatusKey = keyof typeof RELATIONSHIP_STATUS_CHOICES +export type RelationshipStyleKey = keyof typeof ROMANTIC_CHOICES +export type PoliticalBeliefsKey = keyof typeof POLITICAL_CHOICES +export type DietKey = keyof typeof DIET_CHOICES +export type EducationKey = keyof typeof EDUCATION_CHOICES +export type ReligionKey = keyof typeof RELIGION_CHOICES +export type LanguageKey = keyof typeof LANGUAGE_CHOICES +export type EthnicityKey = keyof typeof RACE_CHOICES +export type PersonalityKey = keyof typeof MBTI_CHOICES \ No newline at end of file diff --git a/tests/e2e/web/pages/signUpPage.ts b/tests/e2e/web/pages/signUpPage.ts index 35184402..e034a44c 100644 --- a/tests/e2e/web/pages/signUpPage.ts +++ b/tests/e2e/web/pages/signUpPage.ts @@ -1,35 +1,25 @@ import {expect, Locator, Page} from '@playwright/test' import { - RELATIONSHIP_CHOICES, - RELATIONSHIP_STATUS_CHOICES, - ROMANTIC_CHOICES, - POLITICAL_CHOICES, - DIET_CHOICES, - EDUCATION_CHOICES, - RELIGION_CHOICES, - LANGUAGE_CHOICES, - RACE_CHOICES, - MBTI_CHOICES, + ConnectionTypeKey, + RelationshipStatusKey, + RelationshipStyleKey, + PoliticalBeliefsKey, + DietKey, + EducationKey, + ReligionKey, + LanguageKey, + EthnicityKey, + PersonalityKey, } from 'common/choices' export type Gender = 'Woman' | 'Man' | 'Other' export type InterestedIn = 'Women' | 'Men' | 'Other' -export type ConnectionType = keyof typeof RELATIONSHIP_CHOICES -export type RelationshipStatus = keyof typeof RELATIONSHIP_STATUS_CHOICES -export type RelationshipStyle = keyof typeof ROMANTIC_CHOICES export type ChildrenExpectation = | 'Strongly against' | 'Against' | 'Neutral' | 'For' | 'Strongly for' -export type PoliticalBeliefs = keyof typeof POLITICAL_CHOICES -export type Diet = keyof typeof DIET_CHOICES -export type Education = keyof typeof EDUCATION_CHOICES -export type Religion = keyof typeof RELIGION_CHOICES -export type Language = keyof typeof LANGUAGE_CHOICES -export type Ethnicity = keyof typeof RACE_CHOICES -export type Personality = keyof typeof MBTI_CHOICES export type Interests = 'Chess' | 'Games' | 'Joy' | 'Livres' export type Causes = 'Animal Rights' | 'Feminism' export type Platforms = @@ -224,7 +214,7 @@ export class SignUpPage { await this.centimetersHeightField.fill(centimeters) } - async fillEthnicity(ethnicity: Ethnicity | undefined) { + async fillEthnicity(ethnicity: EthnicityKey | undefined) { if (ethnicity === 'Other') { await expect( this.page @@ -276,19 +266,19 @@ export class SignUpPage { } } - async setConnectionType(type: ConnectionType | undefined) { + async setConnectionType(type: ConnectionTypeKey | undefined) { await expect(this.page.getByLabel(`${type}`, {exact: true})).toBeVisible() await this.page.getByLabel(`${type}`, {exact: true}).click() await expect(this.page.getByLabel(`${type}`, {exact: true})).toBeChecked() } - async setRelationshipStatus(status: RelationshipStatus | undefined) { + async setRelationshipStatus(status: RelationshipStatusKey | undefined) { await expect(this.page.getByLabel(`${status}`, {exact: true})).toBeVisible() await this.page.getByLabel(`${status}`, {exact: true}).click() await expect(this.page.getByLabel(`${status}`, {exact: true})).toBeChecked() } - async setRelationshipStyle(style: RelationshipStyle | undefined) { + async setRelationshipStyle(style: RelationshipStyleKey | undefined) { await expect(this.page.getByLabel(`${style}`, {exact: true})).toBeVisible() await this.page.getByLabel(`${style}`, {exact: true}).click() await expect(this.page.getByLabel(`${style}`, {exact: true})).toBeChecked() @@ -366,7 +356,7 @@ export class SignUpPage { } } - async setHighestEducationLevel(education: Education | undefined) { + async setHighestEducationLevel(education: EducationKey | undefined) { await expect(this.page.getByText(`${education}`, {exact: true})).toBeVisible() await this.page.getByText(`${education}`, {exact: true}).click() await expect(this.page.getByText(`${education}`, {exact: true})).toBeChecked() @@ -412,7 +402,7 @@ export class SignUpPage { } async setPoliticalBeliefs( - politicalBeliefs?: PoliticalBeliefs | undefined, + politicalBeliefs?: PoliticalBeliefsKey | undefined, details?: string | undefined, ) { if (politicalBeliefs) { @@ -427,7 +417,7 @@ export class SignUpPage { } } - async setReligiousBeliefs(religiousBeliefs?: Religion | undefined, details?: string | undefined) { + async setReligiousBeliefs(religiousBeliefs?: ReligionKey | undefined, details?: string | undefined) { if (religiousBeliefs && religiousBeliefs === 'Other') { await expect( this.page @@ -458,7 +448,7 @@ export class SignUpPage { } } - async setPersonalityType(personalityType: Personality | undefined) { + async setPersonalityType(personalityType: PersonalityKey | undefined) { await expect(this.page.getByText(`${personalityType}`, {exact: true})).toBeVisible() await this.page.getByText(`${personalityType}`, {exact: true}).click() await expect(this.page.getByText(`${personalityType}`, {exact: true})).toBeChecked() @@ -619,7 +609,7 @@ export class SignUpPage { } } - async setDietType(dietType: Diet | undefined) { + async setDietType(dietType: DietKey | undefined) { if (dietType === 'Other') { await expect(this.page.locator('label').filter({hasText: 'Other'}).nth(4)).toBeVisible() await this.page.locator('label').filter({hasText: 'Other'}).nth(4).click() @@ -649,7 +639,7 @@ export class SignUpPage { await this.alcoholConsumedPerMonthField.fill(amount) } - async setLanguages(language: Language[] | undefined) { + async setLanguages(language: LanguageKey[] | undefined) { if (!language || language.length === 0) return for (let i = 0; i < language.length; i++) { await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeVisible() diff --git a/tests/e2e/web/utils/accountInformation.ts b/tests/e2e/web/utils/accountInformation.ts index 6dad4fd6..c5f6959c 100644 --- a/tests/e2e/web/utils/accountInformation.ts +++ b/tests/e2e/web/utils/accountInformation.ts @@ -1,22 +1,24 @@ import {faker} from '@faker-js/faker' import { - ConnectionType, - Ethnicity, Gender, InterestedIn, - RelationshipStatus, - RelationshipStyle, ChildrenExpectation, Interests, Causes, - Education, - PoliticalBeliefs, - Religion, - Personality, - Diet, - Language, Platforms, } from '../pages/signUpPage' +import { + ConnectionTypeKey, + RelationshipStatusKey, + RelationshipStyleKey, + PoliticalBeliefsKey, + DietKey, + EducationKey, + ReligionKey, + LanguageKey, + EthnicityKey, + PersonalityKey, +} from 'common/choices' export type OnboardingUser = { email: string @@ -27,28 +29,28 @@ export type OnboardingUser = { gender?: Gender age?: string height?: Height - ethnicity_origin?: Ethnicity + ethnicity_origin?: EthnicityKey interested_in?: InterestedIn Interested_in_ages?: InterestedInAges - connection_type?: ConnectionType - relationship_status?: RelationshipStatus - relationship_style?: RelationshipStyle + connection_type?: ConnectionTypeKey + relationship_status?: RelationshipStatusKey + relationship_style?: RelationshipStyleKey number_of_kids?: string children_expectation?: ChildrenExpectation interests?: (Interests | string)[] causes?: (Causes | string)[] - education_level?: Education + education_level?: EducationKey university?: string job_title?: string company?: string work_area?: string[] beliefs?: BeliefDetails - personality_type?: Personality + personality_type?: PersonalityKey big_five_personality_traits?: FiveBigPersonalityTraits - diet?: Diet + diet?: DietKey is_smoker?: boolean alcohol_consumed_per_month?: string - languages?: Language[] + languages?: LanguageKey[] social_media?: Socials[] } @@ -65,11 +67,11 @@ type InterestedInAges = { type BeliefDetails = { political?: { - belief?: PoliticalBeliefs + belief?: PoliticalBeliefsKey details?: string } religious?: { - belief?: Religion + belief?: ReligionKey details?: string } } From 0cbe73405468f5612fddb868d0419f0f0d2dd7a5 Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Sun, 22 Feb 2026 14:34:17 +0000 Subject: [PATCH 02/55] Organizing testing utilities --- tests/e2e/utils/firebaseUtils.ts | 20 ++++++++++++++++++++ tests/e2e/web/utils/deleteUser.ts | 23 ++++++++++++----------- 2 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 tests/e2e/utils/firebaseUtils.ts diff --git a/tests/e2e/utils/firebaseUtils.ts b/tests/e2e/utils/firebaseUtils.ts new file mode 100644 index 00000000..95d707c4 --- /dev/null +++ b/tests/e2e/utils/firebaseUtils.ts @@ -0,0 +1,20 @@ +import axios from "axios"; +import { config } from "../web/SPEC_CONFIG"; + +export async function login(email: string, password: string) { + const login = await axios.post( + `${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.SIGN_IN_PASSWORD}`, + { + email, + password, + returnSecureToken: true, + }, + ); + return login +}; + +export async function deleteAccount(login: any) { + await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.DELETE}`, { + idToken: login.data.idToken, + }); +}; \ No newline at end of file diff --git a/tests/e2e/web/utils/deleteUser.ts b/tests/e2e/web/utils/deleteUser.ts index a8bd5ec5..2b9f9d62 100644 --- a/tests/e2e/web/utils/deleteUser.ts +++ b/tests/e2e/web/utils/deleteUser.ts @@ -1,22 +1,23 @@ import axios from 'axios' import {createSupabaseDirectClient} from '../../../../backend/shared/src/supabase/init' +import { login, deleteAccount } from "../../utils/firebaseUtils"; import {config} from '../SPEC_CONFIG' export 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 deleteFromDb(login.data.localId) + // const login = await axios.post( + // `${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.SIGN_IN_PASSWORD}`, + // { + // email, + // password, + // returnSecureToken: true, + // }, + // ) + const loginInfo = await login(email, password); + await deleteFromDb(loginInfo.data.localId); await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.DELETE}`, { - idToken: login.data.idToken, + idToken: loginInfo.data.idToken, }) } catch (err: any) { console.log(err) From a2a23b7d02b461cc9643b9598f9f0df66991419c Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Sun, 22 Feb 2026 18:34:09 +0000 Subject: [PATCH 03/55] Added Database checks to the onboarding flow --- tests/e2e/utils/databaseUtils.ts | 41 +++++ tests/e2e/web/pages/signUpPage.ts | 7 +- tests/e2e/web/specs/onboardingFlow.spec.ts | 176 +++++++++++++-------- tests/e2e/web/utils/deleteUser.ts | 35 +--- 4 files changed, 157 insertions(+), 102 deletions(-) create mode 100644 tests/e2e/utils/databaseUtils.ts diff --git a/tests/e2e/utils/databaseUtils.ts b/tests/e2e/utils/databaseUtils.ts new file mode 100644 index 00000000..44b8c622 --- /dev/null +++ b/tests/e2e/utils/databaseUtils.ts @@ -0,0 +1,41 @@ +import { createSupabaseDirectClient } from "../../../backend/shared/src/supabase/init"; + +export async function deleteFromDb(user_id: string) { + const db = createSupabaseDirectClient() + try { + const deleteEntryById = `DELETE FROM users WHERE id = $1 RETURNING *` + const result = await db.query(deleteEntryById, [user_id]) + console.log('Deleted data: ', { + id: result[0].id, + name: result[0].name, + username: result[0].username, + }) + } catch (error) { + throw error + }; +}; + +export async function userInformationFromDb(account: any) { + const db = createSupabaseDirectClient() + try { + const queryUserById = ` + SELECT p.* + FROM users AS p + WHERE name = $1 + `; + const userResults = await db.query(queryUserById, [account.display_name]); + const queryProfileById = ` + SELECT p.* + FROM profiles AS p + WHERE user_id = $1 + ` + const profileResults = await db.query(queryProfileById, [userResults[0].id]); + + return { + user: userResults[0], + profile: profileResults[0] + } + } catch (error) { + throw error + } +} \ No newline at end of file diff --git a/tests/e2e/web/pages/signUpPage.ts b/tests/e2e/web/pages/signUpPage.ts index e034a44c..6f6f5c1a 100644 --- a/tests/e2e/web/pages/signUpPage.ts +++ b/tests/e2e/web/pages/signUpPage.ts @@ -641,10 +641,11 @@ export class SignUpPage { async setLanguages(language: LanguageKey[] | undefined) { if (!language || language.length === 0) return + await this.page.getByRole('checkbox', {name: `English`}).click(); for (let i = 0; i < language.length; i++) { - await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeVisible() - await this.page.getByRole('checkbox', {name: `${language[i]}`}).click() - await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeChecked() + await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeVisible(); + await this.page.getByRole('checkbox', {name: `${language[i]}`}).click(); + await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeChecked(); } } diff --git a/tests/e2e/web/specs/onboardingFlow.spec.ts b/tests/e2e/web/specs/onboardingFlow.spec.ts index eeb95cc7..2e11845f 100644 --- a/tests/e2e/web/specs/onboardingFlow.spec.ts +++ b/tests/e2e/web/specs/onboardingFlow.spec.ts @@ -1,4 +1,6 @@ import {test, expect} from '../fixtures/base' +import { userInformationFromDb } from "../../utils/databaseUtils"; + test.describe('when given valid input', () => { test('should successfully complete the onboarding flow', async ({ @@ -9,104 +11,139 @@ test.describe('when given valid input', () => { profilePage, testAccount, }) => { - await homePage.gotToHomePage() - await homePage.clickSignUpButton() - await authPage.fillEmailField(testAccount.email) - await authPage.fillPasswordField(testAccount.password) - await authPage.clickSignUpWithEmailButton() - await onboardingPage.clickContinueButton() //First continue - await onboardingPage.clickContinueButton() //Second continue - await onboardingPage.clickGetStartedButton() - await signUpPage.fillDisplayName(testAccount.display_name) - // TODO: fix? - await signUpPage.fillUsername(testAccount.username + Date.now().toString()) - await signUpPage.clickNextButton() - await signUpPage.fillBio(testAccount.bio) - await signUpPage.clickNextButton() - await signUpPage.chooseGender(testAccount.gender) - await signUpPage.fillAge(testAccount.age) + await homePage.gotToHomePage(); + await homePage.clickSignUpButton(); + await authPage.fillEmailField(testAccount.email); + await authPage.fillPasswordField(testAccount.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 + Date.now().toString()); + await signUpPage.clickNextButton(); + await signUpPage.fillBio(testAccount.bio); + await signUpPage.clickNextButton(); + await signUpPage.chooseGender(testAccount.gender); + await signUpPage.fillAge(testAccount.age); await signUpPage.fillHeight({ feet: testAccount.height?.feet, inches: testAccount.height?.inches, - }) - await signUpPage.fillEthnicity(testAccount.ethnicity_origin) - await signUpPage.fillInterestedInConnectingWith(testAccount.interested_in) + }); + await signUpPage.fillEthnicity(testAccount.ethnicity_origin); + await signUpPage.fillInterestedInConnectingWith(testAccount.interested_in); await signUpPage.fillAgeRangeInterest( testAccount.Interested_in_ages?.min, testAccount.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) //Is not displayed correctly + ); + 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); //Is not displayed correctly await signUpPage.setPoliticalBeliefs( testAccount.beliefs?.political?.belief, testAccount.beliefs?.political?.details, - ) + ); await signUpPage.setReligiousBeliefs( testAccount.beliefs?.religious?.belief, testAccount.beliefs?.religious?.details, - ) - await signUpPage.setPersonalityType(testAccount.personality_type) - await signUpPage.setOpennessPersonalityValue(testAccount.big_five_personality_traits?.openness) - 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.clickNextButton() - await profilePage.clickCloseButton() - await onboardingPage.clickRefineProfileButton() + ); + await signUpPage.setPersonalityType(testAccount.personality_type); + await signUpPage.setOpennessPersonalityValue(testAccount.big_five_personality_traits?.openness); + 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.clickNextButton(); + await profilePage.clickCloseButton(); + await onboardingPage.clickRefineProfileButton(); - await profilePage.verifyDisplayNameAndAge(testAccount.display_name, testAccount.age) + await profilePage.verifyDisplayNameAndAge(testAccount.display_name, testAccount.age); await profilePage.verifyGenderLocationHeight( testAccount.gender, undefined, testAccount.height?.feet, testAccount.height?.inches, - ) + ); await profilePage.verifyIntrestedInConnectingWith( testAccount.interested_in, testAccount.Interested_in_ages?.min, testAccount.Interested_in_ages?.max, - ) + ); 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(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.verifyEducationLevelAndUniversity( testAccount.education_level, testAccount.university, - ) - await profilePage.verifyJobInformation(testAccount.job_title, testAccount.company) + ); + await profilePage.verifyJobInformation(testAccount.job_title, testAccount.company); await profilePage.verifyPoliticalBeliefs( testAccount.beliefs?.political?.belief, testAccount.beliefs?.political?.details, - ) + ); await profilePage.verifyReligiousBeliefs( testAccount.beliefs?.religious?.belief, testAccount.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.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); + + const dbInfo = await userInformationFromDb(testAccount); + console.log(dbInfo); + + await expect(dbInfo.user.name).toBe(testAccount.display_name); + await expect(dbInfo.user.username).toContain(testAccount.username); + // await expect(dbInfo.profile.bio).toContain(testAccount.bio); //Need to sort out the bio locator + await expect(dbInfo.profile.gender).toEqual(`female`); + 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('south_asian'); + await expect(dbInfo.profile.pref_gender).toContain('male'); + 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}`.toLowerCase()); + await expect(dbInfo.profile.relationship_status).toContain(`open`); + await expect(dbInfo.profile.pref_romantic_styles).toContain(`open`); + await expect(dbInfo.profile.has_kids).toEqual(Number(testAccount.number_of_kids)); + await expect(dbInfo.profile.education_level).toContain(`${testAccount.education_level}`.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.political_beliefs).toContain('green'); + await expect(dbInfo.profile.political_details).toContain(testAccount.beliefs?.political?.details); + await expect(dbInfo.profile.religion).toContain('shinto'); + await expect(dbInfo.profile.religious_beliefs).toContain(testAccount.beliefs?.religious?.details); + await expect(dbInfo.profile.mbti).toContain(`${testAccount.personality_type}`.toLowerCase()); + await expect(dbInfo.profile.big5_openness).toEqual(testAccount.big_five_personality_traits?.openness); + await expect(dbInfo.profile.diet).toContain(`${testAccount.diet}`.toLowerCase()); + await expect(dbInfo.profile.is_smoker).toEqual(testAccount.is_smoker); + await expect(dbInfo.profile.languages).toHaveLength(2); + await expect(dbInfo.profile.languages).toEqual( + expect.arrayContaining(testAccount.languages?.map(l => l.toLowerCase()) ?? []) + ); + await expect(String(dbInfo.profile.drinks_per_month)).toEqual(testAccount.alcohol_consumed_per_month); + }) test('should successfully skip the onboarding flow', async ({ homePage, @@ -127,9 +164,14 @@ test.describe('when given valid input', () => { await signUpPage.clickNextButton() await signUpPage.clickNextButton() //Skip bio await signUpPage.clickNextButton() //Skip optional information - // TODO: fix below - // await profilePage.clickCloseButton(); - // await onboardingPage.clickRefineProfileButton(); + await profilePage.clickCloseButton(); + await onboardingPage.clickRefineProfileButton(); + + const dbInfo = await userInformationFromDb(fakerAccount); + + await expect(dbInfo.user.name).toContain(fakerAccount.display_name); + await expect(dbInfo.user.username).toContain(fakerAccount.username); + }) }) diff --git a/tests/e2e/web/utils/deleteUser.ts b/tests/e2e/web/utils/deleteUser.ts index 2b9f9d62..4f853a37 100644 --- a/tests/e2e/web/utils/deleteUser.ts +++ b/tests/e2e/web/utils/deleteUser.ts @@ -1,41 +1,12 @@ -import axios from 'axios' -import {createSupabaseDirectClient} from '../../../../backend/shared/src/supabase/init' import { login, deleteAccount } from "../../utils/firebaseUtils"; -import {config} from '../SPEC_CONFIG' +import { deleteFromDb } from "../../utils/databaseUtils"; export 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, - // }, - // ) const loginInfo = await login(email, password); await deleteFromDb(loginInfo.data.localId); - - await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.DELETE}`, { - idToken: loginInfo.data.idToken, - }) + await deleteAccount(loginInfo); } catch (err: any) { console.log(err) } -} - -async function deleteFromDb(user_id: string) { - const db = createSupabaseDirectClient() - try { - const deleteEntryById = `DELETE FROM users WHERE id = $1 RETURNING *` - const result = await db.query(deleteEntryById, [user_id]) - console.log('Deleted data: ', { - id: result[0].id, - name: result[0].name, - username: result[0].username, - }) - } catch (error) { - console.error('Failed to delete user data, all changes rolled back: ', error) - throw error - } -} +}; From 4d46b72763eb3bd73bb8e6b8ec04171deab4dccc Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Mon, 23 Feb 2026 15:11:12 +0000 Subject: [PATCH 04/55] Updated Onboarding flow Changed type ChildrenExpectation so that it can be used for database verification --- tests/e2e/utils/databaseUtils.ts | 4 ++-- tests/e2e/web/pages/profilePage.ts | 14 ++++++++++++-- tests/e2e/web/pages/signUpPage.ts | 20 +++++++++++--------- tests/e2e/web/specs/onboardingFlow.spec.ts | 8 ++++++-- tests/e2e/web/utils/accountInformation.ts | 2 +- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/tests/e2e/utils/databaseUtils.ts b/tests/e2e/utils/databaseUtils.ts index 44b8c622..10bc853b 100644 --- a/tests/e2e/utils/databaseUtils.ts +++ b/tests/e2e/utils/databaseUtils.ts @@ -37,5 +37,5 @@ export async function userInformationFromDb(account: any) { } } catch (error) { throw error - } -} \ No newline at end of file + }; +}; \ No newline at end of file diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index 775214c6..d80cea39 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -185,11 +185,12 @@ export class ProfilePage { await expect(textContent?.toLowerCase()).toContain(numberOfKids.toLowerCase()) } - async verifyWantChildrenExpectation(expectation: string | undefined) { + 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(expectation.toLowerCase()) + await expect(textContent?.toLowerCase()).toContain(label.toLowerCase()) } async verifyInterests(interest: string[] | undefined) { @@ -210,6 +211,15 @@ export class ProfilePage { } } + async verifyWorkArea(workArea: string[] | undefined) { + if (!workArea || workArea.length === 0) return + await expect(this.workAreaAboutSection).toBeVisible() + const textContent = await this.workAreaAboutSection.textContent() + for (let i = 0; i < workArea.length; i++) { + await expect(textContent?.toLowerCase()).toContain(workArea[i].toLowerCase()) + } + } + async verifyEducationLevelAndUniversity(educationLevel?: string, university?: string) { await expect(this.educationAboutSection).toBeVisible() const textContent = await this.educationAboutSection.textContent() diff --git a/tests/e2e/web/pages/signUpPage.ts b/tests/e2e/web/pages/signUpPage.ts index 6f6f5c1a..86d9e36f 100644 --- a/tests/e2e/web/pages/signUpPage.ts +++ b/tests/e2e/web/pages/signUpPage.ts @@ -15,11 +15,11 @@ import { export type Gender = 'Woman' | 'Man' | 'Other' export type InterestedIn = 'Women' | 'Men' | 'Other' export type ChildrenExpectation = - | 'Strongly against' - | 'Against' - | 'Neutral' - | 'For' - | 'Strongly for' + | ['Strongly against', 0] + | ['Against',1 ] + | ['Neutral', 2] + | ['For', 3] + | ['Strongly for', 4] export type Interests = 'Chess' | 'Games' | 'Joy' | 'Livres' export type Causes = 'Animal Rights' | 'Feminism' export type Platforms = @@ -291,19 +291,21 @@ export class SignUpPage { } async setWantChildrenExpectation(expectation: ChildrenExpectation | undefined) { - if (expectation === 'Strongly against') { + if (!expectation) return; + const [label, value] = expectation; + if (label === 'Strongly against') { await expect(this.stronglyDisagreeOnWantingKids).toBeVisible() await this.stronglyDisagreeOnWantingKids.click() await expect(this.stronglyDisagreeOnWantingKids).toBeChecked() - } else if (expectation === 'Against') { + } else if (label === 'Against') { await expect(this.disagreeOnWantingKids).toBeVisible() await this.disagreeOnWantingKids.click() await expect(this.disagreeOnWantingKids).toBeChecked() - } else if (expectation === 'Neutral') { + } else if (label === 'Neutral') { await expect(this.neutralOnWantingKids).toBeVisible() await this.neutralOnWantingKids.click() await expect(this.neutralOnWantingKids).toBeChecked() - } else if (expectation === 'For') { + } else if (label === 'For') { await expect(this.agreeOnWantingKids).toBeVisible() await this.agreeOnWantingKids.click() await expect(this.agreeOnWantingKids).toBeChecked() diff --git a/tests/e2e/web/specs/onboardingFlow.spec.ts b/tests/e2e/web/specs/onboardingFlow.spec.ts index 2e11845f..193a0e83 100644 --- a/tests/e2e/web/specs/onboardingFlow.spec.ts +++ b/tests/e2e/web/specs/onboardingFlow.spec.ts @@ -47,7 +47,7 @@ test.describe('when given valid input', () => { await signUpPage.fillUniversity(testAccount.university); await signUpPage.fillJobTitle(testAccount.job_title); await signUpPage.fillCompany(testAccount.company); - await signUpPage.setWorkArea(testAccount.work_area); //Is not displayed correctly + await signUpPage.setWorkArea(testAccount.work_area); await signUpPage.setPoliticalBeliefs( testAccount.beliefs?.political?.belief, testAccount.beliefs?.political?.details, @@ -66,7 +66,8 @@ test.describe('when given valid input', () => { await signUpPage.clickNextButton(); await profilePage.clickCloseButton(); await onboardingPage.clickRefineProfileButton(); - + + //Verify information is correct await profilePage.verifyDisplayNameAndAge(testAccount.display_name, testAccount.age); await profilePage.verifyGenderLocationHeight( testAccount.gender, @@ -93,6 +94,7 @@ test.describe('when given valid input', () => { testAccount.university, ); await profilePage.verifyJobInformation(testAccount.job_title, testAccount.company); + await profilePage.verifyWorkArea(testAccount.work_area); await profilePage.verifyPoliticalBeliefs( testAccount.beliefs?.political?.belief, testAccount.beliefs?.political?.details, @@ -109,6 +111,7 @@ test.describe('when given valid input', () => { await profilePage.verifyLanguages(testAccount.languages); await profilePage.verifySocialMedia(testAccount.social_media); + //Verify Database Information const dbInfo = await userInformationFromDb(testAccount); console.log(dbInfo); @@ -126,6 +129,7 @@ test.describe('when given valid input', () => { await expect(dbInfo.profile.relationship_status).toContain(`open`); await expect(dbInfo.profile.pref_romantic_styles).toContain(`open`); 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}`.toLowerCase()); await expect(dbInfo.profile.university).toContain(testAccount.university); await expect(dbInfo.profile.occupation_title).toContain(testAccount.job_title); diff --git a/tests/e2e/web/utils/accountInformation.ts b/tests/e2e/web/utils/accountInformation.ts index c5f6959c..6794d146 100644 --- a/tests/e2e/web/utils/accountInformation.ts +++ b/tests/e2e/web/utils/accountInformation.ts @@ -124,7 +124,7 @@ export const onboarding: OnboardingConfig = { relationship_status: 'In open relationship', relationship_style: 'Open Relationship', number_of_kids: '2', - children_expectation: 'Neutral', + children_expectation: ['Neutral', 2], interests: ['Chess', 'Eating'], causes: ['Animal Rights', 'Free Spotify'], education_level: 'Bachelors', From 78bfe6aa1ebddb378abb66114bff0e4edd7e995e Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Wed, 25 Feb 2026 15:19:06 +0000 Subject: [PATCH 05/55] Added compatibility page setup Added more compatibility questions --- tests/e2e/utils/seed-test-data.ts | 51 ++++++-- tests/e2e/web/fixtures/base.ts | 6 + tests/e2e/web/pages/compatibilityPage.ts | 28 +++++ tests/e2e/web/pages/profilePage.ts | 138 ++++++++++++--------- tests/e2e/web/pages/signUpPage.ts | 2 +- tests/e2e/web/specs/onboardingFlow.spec.ts | 71 ++++++++++- 6 files changed, 217 insertions(+), 79 deletions(-) create mode 100644 tests/e2e/web/pages/compatibilityPage.ts diff --git a/tests/e2e/utils/seed-test-data.ts b/tests/e2e/utils/seed-test-data.ts index 9b25cb4d..b3f153c0 100644 --- a/tests/e2e/utils/seed-test-data.ts +++ b/tests/e2e/utils/seed-test-data.ts @@ -35,17 +35,46 @@ async function createAuth(email: string, password: string) { async function seedCompatibilityPrompts(pg: any, userId: string | null = null) { // Need some prompts to prevent the onboarding from stopping once it reaches them (just after profile creation) - const question = 'What is your favorite color?' - const multiple_choice_options = {Blue: 0, Green: 1, Red: 2} - const {data, error} = await tryCatch( - insert(pg, 'compatibility_prompts', { - creator_id: userId, - question, - answer_type: 'compatibility_multiple_choice', - multiple_choice_options, - }), - ) - console.log('Compatibility prompts created', {data, error}) + const compatibilityPrompts = [ + { + question: "What is your favorite color?", + options: {Blue: 0, Green: 1, Red: 2} + }, + { + question: "What is your favorite animal?", + options: {Dog: 0, Cat: 1, Bird: 2} + }, + { + question: "What is your preferred time of day?", + options: {Morning: 0, Afternoon: 1, Night: 2} + }, + { + question: "What type of movies do you enjoy most?", + options: {Action: 0, Comedy: 1, Drama: 2} + } + ]; + // const question = 'What is your favorite color?' + // const multiple_choice_options = {Blue: 0, Green: 1, Red: 2} + for (let i = 0; i < compatibilityPrompts.length; i++) { + const {data, error} = await tryCatch( + insert(pg, 'compatibility_prompts', { + creator_id: userId, + question: compatibilityPrompts[i].question, + answer_type: 'compatibility_multiple_choice', + multiple_choice_options: compatibilityPrompts[i].options, + }), + ) + console.log('Compatibility prompts created', {data, error}) + } + // const {data, error} = await tryCatch( + // insert(pg, 'compatibility_prompts', { + // creator_id: userId, + // question, + // answer_type: 'compatibility_multiple_choice', + // multiple_choice_options, + // }), + // ) + // console.log('Compatibility prompts created', {data, error}) } type ProfileType = 'basic' | 'medium' | 'full' diff --git a/tests/e2e/web/fixtures/base.ts b/tests/e2e/web/fixtures/base.ts index a1ad6fb4..15bcacbd 100644 --- a/tests/e2e/web/fixtures/base.ts +++ b/tests/e2e/web/fixtures/base.ts @@ -6,6 +6,7 @@ import {HomePage} from '../pages/homePage' import {ProfilePage} from '../pages/profilePage' import {SignUpPage} from '../pages/signUpPage' import {AuthPage} from '../pages/AuthPage' +import { ComatibilityPage } from "../pages/compatibilityPage"; export const test = base.extend<{ homePage: HomePage @@ -13,6 +14,7 @@ export const test = base.extend<{ signUpPage: SignUpPage profilePage: ProfilePage authPage: AuthPage + compatabilityPage: ComatibilityPage cleanUpUsers: void testAccount: OnboardingUser fakerAccount: OnboardingUser @@ -43,6 +45,10 @@ export const test = base.extend<{ const profilePage = new ProfilePage(page) await use(profilePage) }, + compatabilityPage: async ({page}, use) => { + const compatibilityPage = new ComatibilityPage(page) + await use(compatibilityPage) + }, cleanUpUsers: [ async ({}, use) => { await use() diff --git a/tests/e2e/web/pages/compatibilityPage.ts b/tests/e2e/web/pages/compatibilityPage.ts new file mode 100644 index 00000000..b6753ff0 --- /dev/null +++ b/tests/e2e/web/pages/compatibilityPage.ts @@ -0,0 +1,28 @@ +import { expect, Locator, Page } from "@playwright/test"; + +export class ComatibilityPage { + private readonly answeredQuestionsTab: Locator + private readonly remaningQuestionsTab: Locator + private readonly skippedQuestionsTab: Locator + + constructor(public readonly page: Page) { + this.answeredQuestionsTab = page.getByText('Answered'); + this.remaningQuestionsTab = page.getByText('To Answer'); + this.skippedQuestionsTab = page.getByText('Skipped'); + }; + + async clickAnsweredQuestionsTab() { + await expect(this.answeredQuestionsTab).toBeVisible(); + await this.answeredQuestionsTab.click(); + }; + + async clickRemainingQuestionsTab() { + await expect(this.remaningQuestionsTab).toBeVisible(); + await this.remaningQuestionsTab.click(); + }; + + async clickSkippedQuestionsTab() { + await expect(this.skippedQuestionsTab).toBeVisible(); + await this.skippedQuestionsTab.click(); + }; +}; \ No newline at end of file diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index d80cea39..4b6a05cc 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -41,93 +41,107 @@ export class ProfilePage { private readonly bioOptionsDropdown: Locator private readonly editBioDropdownOptions: Locator private readonly deleteBioDropdownOptions: Locator + private readonly answerCoreQuestionsButton: Locator + private readonly viewQuestionListButton: Locator constructor(public readonly page: Page) { - this.startAnsweringButton = page.getByRole('button', {}) - this.doThisLaterLink = page.getByRole('button', {}) - this.closeButton = page.getByRole('button', {name: 'Close'}) - this.shareButton = page.getByRole('button', {name: 'Share'}) - this.editProfileButton = page.getByTestId('profile-edit') - this.profileOptionsDropdown = page.getByTestId('profile-options') - this.listProfilePubliclyDropdownOption = page.getByText('List Profile Publicly', {exact: true}) + this.startAnsweringButton = page.getByRole('button', {}); + this.doThisLaterLink = page.getByRole('button', {}); + this.closeButton = page.getByRole('button', {name: 'Close'}); + this.shareButton = page.getByRole('button', {name: 'Share'}); + this.editProfileButton = page.getByTestId('profile-edit'); + this.profileOptionsDropdown = page.getByTestId('profile-options'); + this.listProfilePubliclyDropdownOption = page.getByText('List Profile Publicly', {exact: true}); this.limitProfileToMembersDropdownOption = page.getByText('Limit to Members Only', { exact: true, - }) - this.disableProfileDropdownOption = page.getByText('Disable profile', {exact: true}) - this.displayNameAndAgeSection = page.getByTestId('profile-display-name-age') + }); + this.disableProfileDropdownOption = page.getByText('Disable profile', {exact: true}); + this.displayNameAndAgeSection = page.getByTestId('profile-display-name-age'); this.genderLocationHightInInchesSection = page.getByTestId( 'profile-gender-location-height-inches', - ) - this.politicalAboutSection = page.getByTestId('profile-about-political') - this.relegiousAboutSection = page.getByTestId('profile-about-religious') - this.interestsAboutSection = page.getByTestId('profile-about-interests') - this.causesAboutSection = page.getByTestId('profile-about-causes') - this.personalityAboutSection = page.getByTestId('profile-about-personality') - this.ethnicityAboutSection = page.getByTestId('profile-about-ethnicity') - 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-relationship-type') - this.relationshipStatusAboutSection = page.getByTestId('profile-about-relationship-status') - this.educationAboutSection = page.getByTestId('profile-about-education') - this.occupationAboutSection = page.getByTestId('profile-about-occupation') - this.workAreaAboutSection = page.getByTestId('profile-about-work-area') - this.smokerAboutSection = page.getByTestId('profile-about-smoker') - this.notDrinkerAboutSection = page.getByTestId('profile-about-not-drink') - this.drinkerAboutSection = page.getByTestId('profile-about-drinker') - this.wantsKidsAboutSection = page.getByTestId('profile-about-wants-kids') - this.lastOnlineAboutSection = page.getByTestId('profile-about-wants-last-online') + ); + this.politicalAboutSection = page.getByTestId('profile-about-political'); + this.relegiousAboutSection = page.getByTestId('profile-about-religious'); + this.interestsAboutSection = page.getByTestId('profile-about-interests'); + this.causesAboutSection = page.getByTestId('profile-about-causes'); + this.personalityAboutSection = page.getByTestId('profile-about-personality'); + this.ethnicityAboutSection = page.getByTestId('profile-about-ethnicity'); + 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-relationship-type'); + this.relationshipStatusAboutSection = page.getByTestId('profile-about-relationship-status'); + this.educationAboutSection = page.getByTestId('profile-about-education'); + this.occupationAboutSection = page.getByTestId('profile-about-occupation'); + this.workAreaAboutSection = page.getByTestId('profile-about-work-area'); + this.smokerAboutSection = page.getByTestId('profile-about-smoker'); + this.notDrinkerAboutSection = page.getByTestId('profile-about-not-drink'); + this.drinkerAboutSection = page.getByTestId('profile-about-drinker'); + this.wantsKidsAboutSection = page.getByTestId('profile-about-wants-kids'); + this.lastOnlineAboutSection = page.getByTestId('profile-about-wants-last-online'); this.bigFivePersonalityTraitsAboutSection = page.getByTestId( 'profile-about-big-five-personality-traits', - ) - this.hasKidsAboutSection = page.getByTestId('profile-about-has-kids') - this.socialMediaSection = page.getByTestId('profile-social-media-accounts') - this.bioSection = page.getByTestId('profile-bio') - this.bioOptionsDropdown = page.getByTestId('profile-bio-options') - this.editBioDropdownOptions = page.getByText('Edit', {exact: true}) - this.deleteBioDropdownOptions = page.getByText('Delete', {exact: true}) + ); + this.hasKidsAboutSection = page.getByTestId('profile-about-has-kids'); + this.socialMediaSection = page.getByTestId('profile-social-media-accounts'); + this.bioSection = page.getByTestId('profile-bio'); + this.bioOptionsDropdown = page.getByTestId('profile-bio-options'); + this.editBioDropdownOptions = page.getByText('Edit', {exact: true}); + this.deleteBioDropdownOptions = page.getByText('Delete', {exact: true}); + this.answerCoreQuestionsButton = page.getByRole('button', { name: 'Answer Core Questions' }); + this.viewQuestionListButton = page.getByRole('link', { name: 'View List of Questions' }); } async clickCloseButton() { - await expect(this.closeButton).toBeInViewport() - await this.closeButton.click() - } + await expect(this.closeButton).toBeInViewport(); + await this.closeButton.click(); + }; async clickStartAnsweringButton() { - await expect(this.startAnsweringButton).toBeVisible() - await this.startAnsweringButton.click() - } + await expect(this.startAnsweringButton).toBeVisible(); + await this.startAnsweringButton.click(); + }; async clickDoThisLaterButton() { - await expect(this.doThisLaterLink).toBeVisible() - await this.doThisLaterLink.click() - } + await expect(this.doThisLaterLink).toBeVisible(); + await this.doThisLaterLink.click(); + }; async clickShareButton() { - await expect(this.shareButton).toBeVisible() - await this.shareButton.click() - } + await expect(this.shareButton).toBeVisible(); + await this.shareButton.click(); + }; async clickEditProfileButton() { - await expect(this.editProfileButton).toBeVisible() - await this.editProfileButton.click() - } + await expect(this.editProfileButton).toBeVisible(); + await this.editProfileButton.click(); + }; + + async clickAnswerQuestionsButton() { + await expect(this.answerCoreQuestionsButton).toBeVisible(); + await this.answerCoreQuestionsButton.click(); + }; + + async clickViewQuestionListButton() { + await expect(this.viewQuestionListButton).toBeVisible(); + await this.viewQuestionListButton.click(); + }; async selectOptionFromProfileDropdown(option: ProfileDropdownOptions) { - await expect(this.profileOptionsDropdown).toBeVisible() - await this.profileOptionsDropdown.click() + await expect(this.profileOptionsDropdown).toBeVisible(); + await this.profileOptionsDropdown.click(); if (option === 'Public') { - await expect(this.listProfilePubliclyDropdownOption).toBeVisible() - await this.listProfilePubliclyDropdownOption.click() + await expect(this.listProfilePubliclyDropdownOption).toBeVisible(); + await this.listProfilePubliclyDropdownOption.click(); } else if (option === 'Disable') { - await expect(this.disableProfileDropdownOption).toBeVisible() - await this.disableProfileDropdownOption.click() + await expect(this.disableProfileDropdownOption).toBeVisible(); + await this.disableProfileDropdownOption.click(); } else if (option === 'Private') { - await expect(this.limitProfileToMembersDropdownOption).toBeVisible() - await this.limitProfileToMembersDropdownOption.click() - } - } + await expect(this.limitProfileToMembersDropdownOption).toBeVisible(); + await this.limitProfileToMembersDropdownOption.click(); + }; + }; async verifyDisplayNameAndAge(displayName?: string, age?: string) { await expect(this.displayNameAndAgeSection).toBeVisible() diff --git a/tests/e2e/web/pages/signUpPage.ts b/tests/e2e/web/pages/signUpPage.ts index 86d9e36f..a8530034 100644 --- a/tests/e2e/web/pages/signUpPage.ts +++ b/tests/e2e/web/pages/signUpPage.ts @@ -100,7 +100,7 @@ export class SignUpPage { this.displayNameField = page.getByPlaceholder('Display name') this.usernameField = page.getByPlaceholder('Username') this.nextButton = page.getByRole('button', {name: 'Next', exact: true}) - this.bioField = page.getByRole('paragraph').filter({hasText: /^$/}) + this.bioField = page.locator('.tiptap') this.locationField = page.getByPlaceholder('Search city...') this.ageField = page.getByPlaceholder('Age', {exact: true}) this.feetHeightField = page.getByTestId('height-feet') diff --git a/tests/e2e/web/specs/onboardingFlow.spec.ts b/tests/e2e/web/specs/onboardingFlow.spec.ts index 193a0e83..ae2cb287 100644 --- a/tests/e2e/web/specs/onboardingFlow.spec.ts +++ b/tests/e2e/web/specs/onboardingFlow.spec.ts @@ -148,7 +148,8 @@ test.describe('when given valid input', () => { ); await expect(String(dbInfo.profile.drinks_per_month)).toEqual(testAccount.alcohol_consumed_per_month); - }) + }); + test('should successfully skip the onboarding flow', async ({ homePage, onboardingPage, @@ -176,9 +177,69 @@ test.describe('when given valid input', () => { await expect(dbInfo.user.name).toContain(fakerAccount.display_name); await expect(dbInfo.user.username).toContain(fakerAccount.username); - }) -}) + }); + + test.describe('should successfully complete the onboarding flow after using the back button', () => { + test.beforeEach(async ({homePage, authPage, fakerAccount}) => { + await homePage.gotToHomePage() + await homePage.clickSignUpButton() + await authPage.fillEmailField(fakerAccount.email) + await authPage.fillPasswordField(fakerAccount.password) + await authPage.clickSignUpWithEmailButton() + }); + + test('the first time its an option', async ({ + onboardingPage, + signUpPage, + profilePage, + fakerAccount, + }) => { + await onboardingPage.clickContinueButton(); + await onboardingPage.clickBackButton(); + await onboardingPage.clickContinueButton(); + await onboardingPage.clickContinueButton(); + await onboardingPage.clickGetStartedButton(); + await signUpPage.fillDisplayName(fakerAccount.display_name) + await signUpPage.fillUsername(fakerAccount.username) + await signUpPage.clickNextButton() + await signUpPage.clickNextButton() //Skip bio + await signUpPage.clickNextButton() //Skip optional information + await profilePage.clickCloseButton(); + await onboardingPage.clickRefineProfileButton(); + + const dbInfo = await userInformationFromDb(fakerAccount); + + await expect(dbInfo.user.name).toContain(fakerAccount.display_name); + await expect(dbInfo.user.username).toContain(fakerAccount.username); + }); + + test('the second time its an option', async ({ + onboardingPage, + signUpPage, + profilePage, + fakerAccount, + }) => { + await onboardingPage.clickContinueButton(); + await onboardingPage.clickContinueButton(); + await onboardingPage.clickBackButton(); + await onboardingPage.clickContinueButton(); + await onboardingPage.clickGetStartedButton(); + await signUpPage.fillDisplayName(fakerAccount.display_name) + await signUpPage.fillUsername(fakerAccount.username) + await signUpPage.clickNextButton() + await signUpPage.clickNextButton() //Skip bio + await signUpPage.clickNextButton() //Skip optional information + await profilePage.clickCloseButton(); + await onboardingPage.clickRefineProfileButton(); + + const dbInfo = await userInformationFromDb(fakerAccount); + + await expect(dbInfo.user.name).toContain(fakerAccount.display_name); + await expect(dbInfo.user.username).toContain(fakerAccount.username); + }); + }); +}); test.describe('when an error occurs', () => { - test('placeholder', async () => {}) -}) + test('placeholder', async () => {}); +}); From 33c2141bf00040a612d7b1862b8a6f8f3dbc5385 Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 13:40:23 +0000 Subject: [PATCH 06/55] Fix --- tests/e2e/web/pages/profilePage.ts | 6 ++++++ tests/e2e/web/specs/onboardingFlow.spec.ts | 6 +++--- web/components/bio/profile-bio-block.tsx | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index 4b6a05cc..c7d6687d 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -318,4 +318,10 @@ export class ProfilePage { await expect(textContent?.toLowerCase()).toContain(socialMedia[i].urlOrUsername.toLowerCase()) } } + + async verifyBio(bio: string | undefined) { + if (!bio) return + await expect(this.bioSection).toBeVisible(); + await expect(this.bioSection).toContainText(bio) + } } diff --git a/tests/e2e/web/specs/onboardingFlow.spec.ts b/tests/e2e/web/specs/onboardingFlow.spec.ts index fd475a13..56603310 100644 --- a/tests/e2e/web/specs/onboardingFlow.spec.ts +++ b/tests/e2e/web/specs/onboardingFlow.spec.ts @@ -23,7 +23,6 @@ test.describe('when given valid input', () => { await signUpPage.fillUsername(testAccount.username + Date.now().toString()); await signUpPage.clickNextButton(); await signUpPage.fillBio(testAccount.bio); - await signUpPage.clickNextButton(); await signUpPage.chooseGender(testAccount.gender); await signUpPage.fillAge(testAccount.age); await signUpPage.fillHeight({ @@ -110,14 +109,15 @@ test.describe('when given valid input', () => { await profilePage.verifyDrinksPerMonth(testAccount.alcohol_consumed_per_month); await profilePage.verifyLanguages(testAccount.languages); await profilePage.verifySocialMedia(testAccount.social_media); + await profilePage.verifyBio(testAccount.bio); //Verify Database Information const dbInfo = await userInformationFromDb(testAccount); - console.log(dbInfo); + console.log(dbInfo.profile.bio_text); await expect(dbInfo.user.name).toBe(testAccount.display_name); await expect(dbInfo.user.username).toContain(testAccount.username); - // await expect(dbInfo.profile.bio).toContain(testAccount.bio); //Need to sort out the bio locator + await expect(dbInfo.profile.bio_text).toBe(testAccount.bio); //Need to sort out the bio locator await expect(dbInfo.profile.gender).toEqual(`female`); await expect(String(dbInfo.profile.age)).toEqual(testAccount.age); await expect(dbInfo.profile.height_in_inches).toEqual(Number(testAccount.height?.feet) * 12); diff --git a/web/components/bio/profile-bio-block.tsx b/web/components/bio/profile-bio-block.tsx index a965223b..e5bafe3e 100644 --- a/web/components/bio/profile-bio-block.tsx +++ b/web/components/bio/profile-bio-block.tsx @@ -30,9 +30,9 @@ export function BioBlock(props: { !edit && 'px-3 py-2', )} > - + {!edit && profile.bio && ( - + )} From 383ef1b3efaab62380435a3b4c095ff315d7cfaa Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 16:31:10 +0000 Subject: [PATCH 07/55] . --- tests/e2e/web/specs/onboardingFlow.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/web/specs/onboardingFlow.spec.ts b/tests/e2e/web/specs/onboardingFlow.spec.ts index 56603310..362e4245 100644 --- a/tests/e2e/web/specs/onboardingFlow.spec.ts +++ b/tests/e2e/web/specs/onboardingFlow.spec.ts @@ -117,7 +117,7 @@ test.describe('when given valid input', () => { await expect(dbInfo.user.name).toBe(testAccount.display_name); await expect(dbInfo.user.username).toContain(testAccount.username); - await expect(dbInfo.profile.bio_text).toBe(testAccount.bio); //Need to sort out the bio locator + await expect(dbInfo.profile.bio_text).toBe(testAccount.bio); await expect(dbInfo.profile.gender).toEqual(`female`); await expect(String(dbInfo.profile.age)).toEqual(testAccount.age); await expect(dbInfo.profile.height_in_inches).toEqual(Number(testAccount.height?.feet) * 12); From b85234d8aed04d8bc17e092b63bfd9cb877b8fcc Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 16:57:08 +0000 Subject: [PATCH 08/55] Fix: Typo --- web/components/required-profile-form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/components/required-profile-form.tsx b/web/components/required-profile-form.tsx index 9a29f2a1..090a72c4 100644 --- a/web/components/required-profile-form.tsx +++ b/web/components/required-profile-form.tsx @@ -92,7 +92,7 @@ export const RequiredProfileUserForm = (props: {
{t( 'profile.required.username_locked_warning', - 'You cannot change your username after creating a profile, but you can update you name later in your profile settings.', + 'You cannot change your username after creating a profile, but you can update your name later in your profile settings.', )}
)} From e5b3600c81bfe5b66b283ee7aa68d8d7a4cbfa20 Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 17:05:52 +0000 Subject: [PATCH 09/55] Fix: Faker usernames can no longer generate symbols --- tests/e2e/web/utils/accountInformation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/web/utils/accountInformation.ts b/tests/e2e/web/utils/accountInformation.ts index 6794d146..e79c4f9c 100644 --- a/tests/e2e/web/utils/accountInformation.ts +++ b/tests/e2e/web/utils/accountInformation.ts @@ -99,7 +99,7 @@ export const onboarding: OnboardingConfig = { email: faker.internet.email(), password: faker.internet.password(), display_name: faker.internet.displayName(), - username: faker.internet.username(), + username: faker.string.alphanumeric(), }, account_one: { email: 'onboardingOne@compass.com', From e06af458b96ef14482bafc3aa65776f7c69d4a87 Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 19:51:49 +0000 Subject: [PATCH 10/55] Fix: Changed how work area is verified --- tests/e2e/web/pages/profilePage.ts | 5 +++-- tests/e2e/web/specs/onboardingFlow.spec.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index c7d6687d..4f03e6f0 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -228,9 +228,10 @@ export class ProfilePage { async verifyWorkArea(workArea: string[] | undefined) { if (!workArea || workArea.length === 0) return await expect(this.workAreaAboutSection).toBeVisible() - const textContent = await this.workAreaAboutSection.textContent() + // const textContent = await this.workAreaAboutSection.textContent() for (let i = 0; i < workArea.length; i++) { - await expect(textContent?.toLowerCase()).toContain(workArea[i].toLowerCase()) + // await expect(textContent?.toLowerCase()).toContain(workArea[i].toLowerCase()) + await expect(this.workAreaAboutSection).toContainText(workArea[i], {ignoreCase: true}) } } diff --git a/tests/e2e/web/specs/onboardingFlow.spec.ts b/tests/e2e/web/specs/onboardingFlow.spec.ts index 362e4245..a5378579 100644 --- a/tests/e2e/web/specs/onboardingFlow.spec.ts +++ b/tests/e2e/web/specs/onboardingFlow.spec.ts @@ -113,7 +113,7 @@ test.describe('when given valid input', () => { //Verify Database Information const dbInfo = await userInformationFromDb(testAccount); - console.log(dbInfo.profile.bio_text); + // console.log(dbInfo.profile.bio_text); await expect(dbInfo.user.name).toBe(testAccount.display_name); await expect(dbInfo.user.username).toContain(testAccount.username); From 3cec27c30ee1d0609f97a113e1c8b05efd98c01e Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 20:09:12 +0000 Subject: [PATCH 11/55] . --- tests/e2e/web/pages/profilePage.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index 4f03e6f0..75273220 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -231,7 +231,8 @@ export class ProfilePage { // const textContent = await this.workAreaAboutSection.textContent() for (let i = 0; i < workArea.length; i++) { // await expect(textContent?.toLowerCase()).toContain(workArea[i].toLowerCase()) - await expect(this.workAreaAboutSection).toContainText(workArea[i], {ignoreCase: true}) + // await expect(this.workAreaAboutSection).toContainText(workArea[i], {ignoreCase: true}); + await expect(this.workAreaAboutSection).toContainText('Living Room', {ignoreCase: true}); } } From a2f1d21ad5b72a10ccb4d026dcd2f37b0f969818 Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 20:22:13 +0000 Subject: [PATCH 12/55] . --- tests/e2e/web/pages/profilePage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index 75273220..bbcac5e1 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -232,7 +232,7 @@ export class ProfilePage { for (let i = 0; i < workArea.length; i++) { // await expect(textContent?.toLowerCase()).toContain(workArea[i].toLowerCase()) // await expect(this.workAreaAboutSection).toContainText(workArea[i], {ignoreCase: true}); - await expect(this.workAreaAboutSection).toContainText('Living Room', {ignoreCase: true}); + await expect(this.workAreaAboutSection).toContainText('University', {ignoreCase: true}); } } From 42b15ba62ff4aeae9af8b5dbe606009844f7cce8 Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 20:38:01 +0000 Subject: [PATCH 13/55] Fix: Trying to work in headed mode --- playwright.config.ts | 1 + tests/e2e/web/pages/profilePage.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index d0b296c4..58d73cf3 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -10,6 +10,7 @@ export default defineConfig({ use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry', + headless: false, }, projects: [ { diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index bbcac5e1..d37e4793 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -231,8 +231,8 @@ export class ProfilePage { // const textContent = await this.workAreaAboutSection.textContent() for (let i = 0; i < workArea.length; i++) { // await expect(textContent?.toLowerCase()).toContain(workArea[i].toLowerCase()) - // await expect(this.workAreaAboutSection).toContainText(workArea[i], {ignoreCase: true}); - await expect(this.workAreaAboutSection).toContainText('University', {ignoreCase: true}); + await expect(this.workAreaAboutSection).toContainText(workArea[i], {ignoreCase: true}); + // await expect(this.workAreaAboutSection).toContainText('University', {ignoreCase: true}); } } From 199d392240da078a85731b89cf0d469a3556b79d Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 20:46:33 +0000 Subject: [PATCH 14/55] Fix: Change back to headless --- playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playwright.config.ts b/playwright.config.ts index 58d73cf3..8884c4af 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -10,7 +10,7 @@ export default defineConfig({ use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry', - headless: false, + // headless: false, }, projects: [ { From 6219f28ec1e6db5ddcea64ccf506624dfcc620a0 Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 21:21:02 +0000 Subject: [PATCH 15/55] Fix: Added timeout after workArea selection --- tests/e2e/web/pages/signUpPage.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/web/pages/signUpPage.ts b/tests/e2e/web/pages/signUpPage.ts index a8530034..7f2661d3 100644 --- a/tests/e2e/web/pages/signUpPage.ts +++ b/tests/e2e/web/pages/signUpPage.ts @@ -392,11 +392,13 @@ export class SignUpPage { if (isExisting) { await expect(this.page.getByLabel(`${workArea[i]}`, {exact: true})).toBeVisible() await this.page.getByLabel(`${workArea[i]}`, {exact: true}).click() + await this.page.waitForTimeout(500) } else { await expect(this.addWorkAreaField).toBeVisible() await expect(this.addWorkAreaButton).toBeVisible() await this.addWorkAreaField.fill(workArea[i]) await this.addWorkAreaButton.click() + await this.page.waitForTimeout(500) } await expect(this.page.getByLabel(`${workArea[i]}`, {exact: true})).toBeVisible() await expect(this.page.getByLabel(`${workArea[i]}`, {exact: true})).toBeChecked() From c516af575fdd3b1cb5096eb72254eafb37536e08 Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Fri, 27 Feb 2026 21:41:07 +0000 Subject: [PATCH 16/55] . --- tests/e2e/web/specs/onboardingFlow.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/web/specs/onboardingFlow.spec.ts b/tests/e2e/web/specs/onboardingFlow.spec.ts index a5378579..8502d99e 100644 --- a/tests/e2e/web/specs/onboardingFlow.spec.ts +++ b/tests/e2e/web/specs/onboardingFlow.spec.ts @@ -22,7 +22,6 @@ test.describe('when given valid input', () => { await signUpPage.fillDisplayName(testAccount.display_name); await signUpPage.fillUsername(testAccount.username + Date.now().toString()); await signUpPage.clickNextButton(); - await signUpPage.fillBio(testAccount.bio); await signUpPage.chooseGender(testAccount.gender); await signUpPage.fillAge(testAccount.age); await signUpPage.fillHeight({ @@ -62,6 +61,7 @@ test.describe('when given valid input', () => { 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.clickNextButton(); await profilePage.clickCloseButton(); await onboardingPage.clickRefineProfileButton(); From 2790fd0b1051713960b8dd6c9387dac555a5fbee Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 15:44:34 +0100 Subject: [PATCH 17/55] Clean e2e --- tests/e2e/utils/seed-test-data.ts | 33 +-- tests/e2e/web/fixtures/base.ts | 3 +- tests/e2e/web/specs/onboardingFlow.spec.ts | 291 +++++++++++---------- tests/e2e/web/utils/accountInformation.ts | 22 +- 4 files changed, 171 insertions(+), 178 deletions(-) diff --git a/tests/e2e/utils/seed-test-data.ts b/tests/e2e/utils/seed-test-data.ts index 96eaca2a..3403a96a 100644 --- a/tests/e2e/utils/seed-test-data.ts +++ b/tests/e2e/utils/seed-test-data.ts @@ -38,24 +38,22 @@ async function seedCompatibilityPrompts(pg: any, userId: string | null = null) { // Need some prompts to prevent the onboarding from stopping once it reaches them (just after profile creation) const compatibilityPrompts = [ { - question: "What is your favorite color?", - options: {Blue: 0, Green: 1, Red: 2} + question: 'What is your favorite color?', + options: {Blue: 0, Green: 1, Red: 2}, }, { - question: "What is your favorite animal?", - options: {Dog: 0, Cat: 1, Bird: 2} + question: 'What is your favorite animal?', + options: {Dog: 0, Cat: 1, Bird: 2}, }, { - question: "What is your preferred time of day?", - options: {Morning: 0, Afternoon: 1, Night: 2} + question: 'What is your preferred time of day?', + options: {Morning: 0, Afternoon: 1, Night: 2}, }, { - question: "What type of movies do you enjoy most?", - options: {Action: 0, Comedy: 1, Drama: 2} - } - ]; - // const question = 'What is your favorite color?' - // const multiple_choice_options = {Blue: 0, Green: 1, Red: 2} + question: 'What type of movies do you enjoy most?', + options: {Action: 0, Comedy: 1, Drama: 2}, + }, + ] for (let i = 0; i < compatibilityPrompts.length; i++) { const {data, error} = await tryCatch( insert(pg, 'compatibility_prompts', { @@ -67,15 +65,6 @@ async function seedCompatibilityPrompts(pg: any, userId: string | null = null) { ) console.log('Compatibility prompts created', {data, error}) } - // const {data, error} = await tryCatch( - // insert(pg, 'compatibility_prompts', { - // creator_id: userId, - // question, - // answer_type: 'compatibility_multiple_choice', - // multiple_choice_options, - // }), - // ) - // console.log('Compatibility prompts created', {data, error}) } async function seedNotifications() { @@ -105,7 +94,7 @@ type ProfileType = 'basic' | 'medium' | 'full' } userInfo.user_id = await createAuth(userInfo.email, userInfo.password) if (userInfo.user_id) { - console.log('User created in Supabase:', userInfo) + console.log('User created in Supabase:', userInfo.email) await seedDatabase(pg, userInfo, profileType) } } diff --git a/tests/e2e/web/fixtures/base.ts b/tests/e2e/web/fixtures/base.ts index ffa49715..277f5887 100644 --- a/tests/e2e/web/fixtures/base.ts +++ b/tests/e2e/web/fixtures/base.ts @@ -1,12 +1,11 @@ import {test as base} from '@playwright/test' import {AuthPage} from '../pages/AuthPage' +import {ComatibilityPage} from '../pages/compatibilityPage' import {HomePage} from '../pages/homePage' import {OnboardingPage} from '../pages/onboardingPage' import {ProfilePage} from '../pages/profilePage' import {SignUpPage} from '../pages/signUpPage' -import {AuthPage} from '../pages/AuthPage' -import { ComatibilityPage } from "../pages/compatibilityPage"; import {onboarding, OnboardingUser} from '../utils/accountInformation' import {deleteUser} from '../utils/deleteUser' diff --git a/tests/e2e/web/specs/onboardingFlow.spec.ts b/tests/e2e/web/specs/onboardingFlow.spec.ts index 8502d99e..25d4a5aa 100644 --- a/tests/e2e/web/specs/onboardingFlow.spec.ts +++ b/tests/e2e/web/specs/onboardingFlow.spec.ts @@ -1,6 +1,5 @@ -import {test, expect} from '../fixtures/base' -import { userInformationFromDb } from "../../utils/databaseUtils"; - +import {userInformationFromDb} from '../../utils/databaseUtils' +import {expect, test} from '../fixtures/base' test.describe('when given valid input', () => { test('should successfully complete the onboarding flow', async ({ @@ -11,145 +10,156 @@ test.describe('when given valid input', () => { profilePage, testAccount, }) => { - await homePage.gotToHomePage(); - await homePage.clickSignUpButton(); - await authPage.fillEmailField(testAccount.email); - await authPage.fillPasswordField(testAccount.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 + Date.now().toString()); - await signUpPage.clickNextButton(); - await signUpPage.chooseGender(testAccount.gender); - await signUpPage.fillAge(testAccount.age); + await homePage.gotToHomePage() + await homePage.clickSignUpButton() + await authPage.fillEmailField(testAccount.email) + await authPage.fillPasswordField(testAccount.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.clickNextButton() + await signUpPage.chooseGender(testAccount.gender) + await signUpPage.fillAge(testAccount.age) await signUpPage.fillHeight({ feet: testAccount.height?.feet, inches: testAccount.height?.inches, - }); - await signUpPage.fillEthnicity(testAccount.ethnicity_origin); - await signUpPage.fillInterestedInConnectingWith(testAccount.interested_in); + }) + await signUpPage.fillEthnicity(testAccount.ethnicity_origin) + await signUpPage.fillInterestedInConnectingWith(testAccount.interested_in) await signUpPage.fillAgeRangeInterest( testAccount.Interested_in_ages?.min, testAccount.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(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.setPoliticalBeliefs( testAccount.beliefs?.political?.belief, testAccount.beliefs?.political?.details, - ); + ) await signUpPage.setReligiousBeliefs( testAccount.beliefs?.religious?.belief, testAccount.beliefs?.religious?.details, - ); - await signUpPage.setPersonalityType(testAccount.personality_type); - await signUpPage.setOpennessPersonalityValue(testAccount.big_five_personality_traits?.openness); - 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.clickNextButton(); - await profilePage.clickCloseButton(); - await onboardingPage.clickRefineProfileButton(); - + ) + await signUpPage.setPersonalityType(testAccount.personality_type) + await signUpPage.setOpennessPersonalityValue(testAccount.big_five_personality_traits?.openness) + 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.clickNextButton() + await profilePage.clickCloseButton() + await onboardingPage.clickRefineProfileButton() + //Verify information is correct - await profilePage.verifyDisplayNameAndAge(testAccount.display_name, testAccount.age); + await profilePage.verifyDisplayNameAndAge(testAccount.display_name, testAccount.age) await profilePage.verifyGenderLocationHeight( testAccount.gender, undefined, testAccount.height?.feet, testAccount.height?.inches, - ); + ) await profilePage.verifyIntrestedInConnectingWith( testAccount.interested_in, testAccount.Interested_in_ages?.min, testAccount.Interested_in_ages?.max, - ); + ) 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(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.verifyEducationLevelAndUniversity( testAccount.education_level, testAccount.university, - ); - await profilePage.verifyJobInformation(testAccount.job_title, testAccount.company); - await profilePage.verifyWorkArea(testAccount.work_area); + ) + await profilePage.verifyJobInformation(testAccount.job_title, testAccount.company) + await profilePage.verifyWorkArea(testAccount.work_area) await profilePage.verifyPoliticalBeliefs( testAccount.beliefs?.political?.belief, testAccount.beliefs?.political?.details, - ); + ) await profilePage.verifyReligiousBeliefs( testAccount.beliefs?.religious?.belief, testAccount.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(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) //Verify Database Information - const dbInfo = await userInformationFromDb(testAccount); + const dbInfo = await userInformationFromDb(testAccount) // console.log(dbInfo.profile.bio_text); - await expect(dbInfo.user.name).toBe(testAccount.display_name); - await expect(dbInfo.user.username).toContain(testAccount.username); - await expect(dbInfo.profile.bio_text).toBe(testAccount.bio); - await expect(dbInfo.profile.gender).toEqual(`female`); - 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('south_asian'); - await expect(dbInfo.profile.pref_gender).toContain('male'); - 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}`.toLowerCase()); - await expect(dbInfo.profile.relationship_status).toContain(`open`); - await expect(dbInfo.profile.pref_romantic_styles).toContain(`open`); - 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}`.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.political_beliefs).toContain('green'); - await expect(dbInfo.profile.political_details).toContain(testAccount.beliefs?.political?.details); - await expect(dbInfo.profile.religion).toContain('shinto'); - await expect(dbInfo.profile.religious_beliefs).toContain(testAccount.beliefs?.religious?.details); - await expect(dbInfo.profile.mbti).toContain(`${testAccount.personality_type}`.toLowerCase()); - await expect(dbInfo.profile.big5_openness).toEqual(testAccount.big_five_personality_traits?.openness); - await expect(dbInfo.profile.diet).toContain(`${testAccount.diet}`.toLowerCase()); - await expect(dbInfo.profile.is_smoker).toEqual(testAccount.is_smoker); - await expect(dbInfo.profile.languages).toHaveLength(2); + 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(`female`) + 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('south_asian') + await expect(dbInfo.profile.pref_gender).toContain('male') + 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}`.toLowerCase(), + ) + await expect(dbInfo.profile.relationship_status).toContain(`open`) + await expect(dbInfo.profile.pref_romantic_styles).toContain(`open`) + 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}`.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.political_beliefs).toContain('green') + await expect(dbInfo.profile.political_details).toContain( + testAccount.beliefs?.political?.details, + ) + await expect(dbInfo.profile.religion).toContain('shinto') + await expect(dbInfo.profile.religious_beliefs).toContain( + testAccount.beliefs?.religious?.details, + ) + await expect(dbInfo.profile.mbti).toContain(`${testAccount.personality_type}`.toLowerCase()) + await expect(dbInfo.profile.big5_openness).toEqual( + testAccount.big_five_personality_traits?.openness, + ) + await expect(dbInfo.profile.diet).toContain(`${testAccount.diet}`.toLowerCase()) + await expect(dbInfo.profile.is_smoker).toEqual(testAccount.is_smoker) + await expect(dbInfo.profile.languages).toHaveLength(2) await expect(dbInfo.profile.languages).toEqual( - expect.arrayContaining(testAccount.languages?.map(l => l.toLowerCase()) ?? []) - ); - await expect(String(dbInfo.profile.drinks_per_month)).toEqual(testAccount.alcohol_consumed_per_month); - - }); - + expect.arrayContaining(testAccount.languages?.map((l) => l.toLowerCase()) ?? []), + ) + await expect(String(dbInfo.profile.drinks_per_month)).toEqual( + testAccount.alcohol_consumed_per_month, + ) + }) + test('should successfully skip the onboarding flow', async ({ homePage, onboardingPage, @@ -168,15 +178,14 @@ test.describe('when given valid input', () => { await signUpPage.fillUsername(fakerAccount.username) await signUpPage.clickNextButton() await signUpPage.clickNextButton() //Skip optional information - await profilePage.clickCloseButton(); - await onboardingPage.clickRefineProfileButton(); + await profilePage.clickCloseButton() + await onboardingPage.clickRefineProfileButton() - const dbInfo = await userInformationFromDb(fakerAccount); + 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.user.name).toContain(fakerAccount.display_name) + await expect(dbInfo.user.username).toContain(fakerAccount.username) + }) test.describe('should successfully complete the onboarding flow after using the back button', () => { test.beforeEach(async ({homePage, authPage, fakerAccount}) => { @@ -185,7 +194,7 @@ test.describe('when given valid input', () => { await authPage.fillEmailField(fakerAccount.email) await authPage.fillPasswordField(fakerAccount.password) await authPage.clickSignUpWithEmailButton() - }); + }) test('the first time its an option', async ({ onboardingPage, @@ -193,24 +202,24 @@ test.describe('when given valid input', () => { profilePage, fakerAccount, }) => { - await onboardingPage.clickContinueButton(); - await onboardingPage.clickBackButton(); - await onboardingPage.clickContinueButton(); - await onboardingPage.clickContinueButton(); - await onboardingPage.clickGetStartedButton(); + await onboardingPage.clickContinueButton() + await onboardingPage.clickBackButton() + await onboardingPage.clickContinueButton() + await onboardingPage.clickContinueButton() + await onboardingPage.clickGetStartedButton() await signUpPage.fillDisplayName(fakerAccount.display_name) await signUpPage.fillUsername(fakerAccount.username) await signUpPage.clickNextButton() await signUpPage.clickNextButton() //Skip bio await signUpPage.clickNextButton() //Skip optional information - await profilePage.clickCloseButton(); - await onboardingPage.clickRefineProfileButton(); - - const dbInfo = await userInformationFromDb(fakerAccount); - - await expect(dbInfo.user.name).toContain(fakerAccount.display_name); - await expect(dbInfo.user.username).toContain(fakerAccount.username); - }); + await profilePage.clickCloseButton() + await onboardingPage.clickRefineProfileButton() + + const dbInfo = await userInformationFromDb(fakerAccount) + + await expect(dbInfo.user.name).toContain(fakerAccount.display_name) + await expect(dbInfo.user.username).toContain(fakerAccount.username) + }) test('the second time its an option', async ({ onboardingPage, @@ -218,27 +227,27 @@ test.describe('when given valid input', () => { profilePage, fakerAccount, }) => { - await onboardingPage.clickContinueButton(); - await onboardingPage.clickContinueButton(); - await onboardingPage.clickBackButton(); - await onboardingPage.clickContinueButton(); - await onboardingPage.clickGetStartedButton(); + await onboardingPage.clickContinueButton() + await onboardingPage.clickContinueButton() + await onboardingPage.clickBackButton() + await onboardingPage.clickContinueButton() + await onboardingPage.clickGetStartedButton() await signUpPage.fillDisplayName(fakerAccount.display_name) await signUpPage.fillUsername(fakerAccount.username) await signUpPage.clickNextButton() await signUpPage.clickNextButton() //Skip bio await signUpPage.clickNextButton() //Skip optional information - await profilePage.clickCloseButton(); - await onboardingPage.clickRefineProfileButton(); - - const dbInfo = await userInformationFromDb(fakerAccount); - - await expect(dbInfo.user.name).toContain(fakerAccount.display_name); - await expect(dbInfo.user.username).toContain(fakerAccount.username); - }); - }); -}); + await profilePage.clickCloseButton() + await onboardingPage.clickRefineProfileButton() + + const dbInfo = await userInformationFromDb(fakerAccount) + + await expect(dbInfo.user.name).toContain(fakerAccount.display_name) + await expect(dbInfo.user.username).toContain(fakerAccount.username) + }) + }) +}) test.describe('when an error occurs', () => { - test('placeholder', async () => {}); -}); + test('placeholder', async () => {}) +}) diff --git a/tests/e2e/web/utils/accountInformation.ts b/tests/e2e/web/utils/accountInformation.ts index f41a1af5..d7f30bf0 100644 --- a/tests/e2e/web/utils/accountInformation.ts +++ b/tests/e2e/web/utils/accountInformation.ts @@ -1,28 +1,24 @@ import {faker} from '@faker-js/faker' import { + Causes, + ChildrenExpectation, Gender, InterestedIn, - ChildrenExpectation, Interests, - Causes, Platforms, - PoliticalBeliefs, - RelationshipStatus, - RelationshipStyle, - Religion, } from '../pages/signUpPage' import { ConnectionTypeKey, - RelationshipStatusKey, - RelationshipStyleKey, - PoliticalBeliefsKey, DietKey, EducationKey, - ReligionKey, - LanguageKey, EthnicityKey, + LanguageKey, PersonalityKey, + PoliticalBeliefsKey, + RelationshipStatusKey, + RelationshipStyleKey, + ReligionKey, } from 'common/choices' export type OnboardingUser = { @@ -110,10 +106,10 @@ export const onboarding: OnboardingConfig = { account_one: () => ({ // Use a non-real TLD like @test.compass to make it obvious these are test accounts and prevent accidental emails - email: `onboarding+${crypto.randomUUID()}@test.compass`, + email: `onboarding+${crypto.randomUUID().slice(0, 8)}@test.compass`, password: 'CompassTest', display_name: 'Compass Onboarding', - username: `TheGreatOnboarding_${crypto.randomUUID().slice(0, 8)}`, + username: `TheGreatOnboarding_${crypto.randomUUID().slice(0, 4)}`, bio: 'Born beneath twin moons, this wanderer maps forgotten roads, trades riddles for shelter, and keeps stories in glass bottles. Drawn to ancient libraries and glowing forests, they seek lost spells, quiet taverns, and adventures that rewrite fate. Their compass points to wonder. Ever onward. Always. Go', gender: 'Woman', age: '25', From 8cf1933ea3751c1f32793f8953d03398a8f1c730 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 16:22:17 +0100 Subject: [PATCH 18/55] Improve E2E setup --- playwright.config.ts | 2 +- tests/e2e/utils/firebaseUtils.ts | 45 ++++++++++++++-------- tests/e2e/utils/setup-auth.ts | 16 -------- tests/e2e/web/fixtures/signInFixture.ts | 14 ++++++- tests/e2e/web/specs/onboardingFlow.spec.ts | 9 +++++ 5 files changed, 51 insertions(+), 35 deletions(-) delete mode 100644 tests/e2e/utils/setup-auth.ts diff --git a/playwright.config.ts b/playwright.config.ts index 8884c4af..2a9d89cb 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -28,7 +28,7 @@ export default defineConfig({ // use: { ...devices['Desktop Safari'] }, // }, ], - timeout: 60000, + timeout: 120000, expect: { timeout: 120000, }, diff --git a/tests/e2e/utils/firebaseUtils.ts b/tests/e2e/utils/firebaseUtils.ts index 95d707c4..91e303e7 100644 --- a/tests/e2e/utils/firebaseUtils.ts +++ b/tests/e2e/utils/firebaseUtils.ts @@ -1,20 +1,33 @@ -import axios from "axios"; -import { config } from "../web/SPEC_CONFIG"; +import axios from 'axios' + +import {config} from '../web/SPEC_CONFIG' export async function login(email: string, password: string) { - const login = await axios.post( - `${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.SIGN_IN_PASSWORD}`, - { - email, - password, - returnSecureToken: true, - }, - ); - return login -}; + const login = await axios.post( + `${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.SIGN_IN_PASSWORD}`, + { + email, + password, + returnSecureToken: true, + }, + ) + return login +} + +export async function signUp(email: string, password: string) { + // const base = 'http://localhost:9099/identitytoolkit.googleapis.com/v1'; + + await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.SIGNUP}`, { + email, + password, + returnSecureToken: true, + }) + + console.log('Auth created for', email) +} export async function deleteAccount(login: any) { - await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.DELETE}`, { - idToken: login.data.idToken, - }); -}; \ No newline at end of file + await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.DELETE}`, { + idToken: login.data.idToken, + }) +} diff --git a/tests/e2e/utils/setup-auth.ts b/tests/e2e/utils/setup-auth.ts deleted file mode 100644 index 6c8ea3d0..00000000 --- a/tests/e2e/utils/setup-auth.ts +++ /dev/null @@ -1,16 +0,0 @@ -import axios from 'axios' - -import {config} from '../web/SPEC_CONFIG' - -async function createAuth() { - // const base = 'http://localhost:9099/identitytoolkit.googleapis.com/v1'; - - await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.SIGNUP}`, { - email: config.USERS.DEV_1.EMAIL, - password: config.USERS.DEV_1.PASSWORD, - returnSecureToken: true, - }) - - console.log('Auth created', config.USERS.DEV_1.EMAIL) -} -createAuth() diff --git a/tests/e2e/web/fixtures/signInFixture.ts b/tests/e2e/web/fixtures/signInFixture.ts index 9826b507..7ea6b6db 100644 --- a/tests/e2e/web/fixtures/signInFixture.ts +++ b/tests/e2e/web/fixtures/signInFixture.ts @@ -1,5 +1,6 @@ import {expect, Page, test as base} from '@playwright/test' +import {signUp} from '../../utils/firebaseUtils' import {AuthPage} from '../pages/AuthPage' import {config} from '../SPEC_CONFIG' @@ -9,9 +10,18 @@ export const test = base.extend<{ authenticatedPage: async ({page}, use) => { const authPage = new AuthPage(page) + const email = config.USERS.DEV_1.EMAIL + const password = config.USERS.DEV_1.PASSWORD + + try { + await signUp(email, password) + } catch (_e) { + console.log('User already exists for signinFixture', email) + } + await page.goto('/signin') - await authPage.fillEmailField(config.USERS.DEV_1.EMAIL) - await authPage.fillPasswordField(config.USERS.DEV_1.PASSWORD) + await authPage.fillEmailField(email) + await authPage.fillPasswordField(password) await authPage.clickSignInWithEmailButton() await page.waitForURL(/^(?!.*signin).*$/) diff --git a/tests/e2e/web/specs/onboardingFlow.spec.ts b/tests/e2e/web/specs/onboardingFlow.spec.ts index 25d4a5aa..600d0bd7 100644 --- a/tests/e2e/web/specs/onboardingFlow.spec.ts +++ b/tests/e2e/web/specs/onboardingFlow.spec.ts @@ -10,6 +10,9 @@ test.describe('when given valid input', () => { profilePage, testAccount, }) => { + console.log( + `Starting "should successfully complete the onboarding flow" with ${testAccount.username}`, + ) await homePage.gotToHomePage() await homePage.clickSignUpButton() await authPage.fillEmailField(testAccount.email) @@ -168,6 +171,9 @@ test.describe('when given valid input', () => { profilePage, fakerAccount, }) => { + console.log( + `Starting "should successfully skip the onboarding flow" with ${fakerAccount.username}`, + ) await homePage.gotToHomePage() await homePage.clickSignUpButton() await authPage.fillEmailField(fakerAccount.email) @@ -189,6 +195,7 @@ test.describe('when given valid input', () => { test.describe('should successfully complete the onboarding flow after using the back button', () => { test.beforeEach(async ({homePage, authPage, fakerAccount}) => { + console.log(`Before each with ${fakerAccount.username}`) await homePage.gotToHomePage() await homePage.clickSignUpButton() await authPage.fillEmailField(fakerAccount.email) @@ -202,6 +209,7 @@ test.describe('when given valid input', () => { profilePage, fakerAccount, }) => { + console.log(`Starting "the first time its an option" with ${fakerAccount.username}`) await onboardingPage.clickContinueButton() await onboardingPage.clickBackButton() await onboardingPage.clickContinueButton() @@ -227,6 +235,7 @@ test.describe('when given valid input', () => { profilePage, fakerAccount, }) => { + console.log(`Starting "the second time its an option" with ${fakerAccount.username}`) await onboardingPage.clickContinueButton() await onboardingPage.clickContinueButton() await onboardingPage.clickBackButton() From 2f7d8c9e67655b118baeffbeb0c65040140cefdf Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 16:33:28 +0100 Subject: [PATCH 19/55] Prettier --- .github/workflows/cd-android-live-update.yml | 4 +- .github/workflows/cd-android.yml | 2 +- .github/workflows/cd-api.yml | 4 +- .github/workflows/cd.yml | 2 +- .github/workflows/ci-e2e.yml | 4 +- common/src/choices.ts | 2 +- tests/e2e/utils/databaseUtils.ts | 58 ++++---- tests/e2e/web/pages/compatibilityPage.ts | 44 +++--- tests/e2e/web/pages/profilePage.ts | 147 ++++++++++--------- tests/e2e/web/pages/signUpPage.ts | 29 ++-- tests/e2e/web/utils/deleteUser.ts | 15 +- 11 files changed, 156 insertions(+), 155 deletions(-) diff --git a/.github/workflows/cd-android-live-update.yml b/.github/workflows/cd-android-live-update.yml index 9d4c2a64..2114750e 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' @@ -73,4 +73,4 @@ jobs: CAPAWESOME_TOKEN: ${{ secrets.CAPAWESOME_TOKEN }} commitRef: ${{ github.head_ref || github.ref_name }} commitSha: ${{ github.sha }} - run: yarn android-live-update \ No newline at end of file + run: yarn android-live-update diff --git a/.github/workflows/cd-android.yml b/.github/workflows/cd-android.yml index 64d8250c..dcac1e90 100644 --- a/.github/workflows/cd-android.yml +++ b/.github/workflows/cd-android.yml @@ -94,4 +94,4 @@ jobs: serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }} packageName: com.compassconnections.app releaseFiles: android/app/build/outputs/bundle/release/app-release.aab - track: internal \ No newline at end of file + track: internal diff --git a/.github/workflows/cd-api.yml b/.github/workflows/cd-api.yml index e5436a92..f1655e91 100644 --- a/.github/workflows/cd-api.yml +++ b/.github/workflows/cd-api.yml @@ -1,7 +1,7 @@ name: API Release on: push: - branches: [ main, master ] + branches: [main, master] paths: - 'backend/api/package.json' - '.github/workflows/cd-api.yml' @@ -92,4 +92,4 @@ jobs: - name: Run deploy script run: | chmod +x backend/api/deploy-api.sh - backend/api/deploy-api.sh \ No newline at end of file + backend/api/deploy-api.sh diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index fd0b8a0a..24c1ba7f 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -4,7 +4,7 @@ name: GitHub Release on: push: - branches: [ main, master ] + branches: [main, master] paths: - 'package.json' - '.github/workflows/cd.yml' diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index 56d215b5..e4e49c46 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -2,9 +2,9 @@ name: E2E Tests on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: e2e: diff --git a/common/src/choices.ts b/common/src/choices.ts index b6e5ed04..8507f180 100644 --- a/common/src/choices.ts +++ b/common/src/choices.ts @@ -258,4 +258,4 @@ export type EducationKey = keyof typeof EDUCATION_CHOICES export type ReligionKey = keyof typeof RELIGION_CHOICES export type LanguageKey = keyof typeof LANGUAGE_CHOICES export type EthnicityKey = keyof typeof RACE_CHOICES -export type PersonalityKey = keyof typeof MBTI_CHOICES \ No newline at end of file +export type PersonalityKey = keyof typeof MBTI_CHOICES diff --git a/tests/e2e/utils/databaseUtils.ts b/tests/e2e/utils/databaseUtils.ts index 10bc853b..6137200e 100644 --- a/tests/e2e/utils/databaseUtils.ts +++ b/tests/e2e/utils/databaseUtils.ts @@ -1,41 +1,41 @@ -import { createSupabaseDirectClient } from "../../../backend/shared/src/supabase/init"; +import {createSupabaseDirectClient} from 'shared/supabase/init' export async function deleteFromDb(user_id: string) { - const db = createSupabaseDirectClient() - try { - const deleteEntryById = `DELETE FROM users WHERE id = $1 RETURNING *` - const result = await db.query(deleteEntryById, [user_id]) - console.log('Deleted data: ', { - id: result[0].id, - name: result[0].name, - username: result[0].username, - }) - } catch (error) { - throw error - }; -}; + const db = createSupabaseDirectClient() + try { + const deleteEntryById = `DELETE FROM users WHERE id = $1 RETURNING *` + const result = await db.query(deleteEntryById, [user_id]) + console.log('Deleted data: ', { + id: result[0].id, + name: result[0].name, + username: result[0].username, + }) + } catch (error) { + throw error + } +} export async function userInformationFromDb(account: any) { - const db = createSupabaseDirectClient() - try { - const queryUserById = ` + const db = createSupabaseDirectClient() + try { + const queryUserById = ` SELECT p.* FROM users AS p WHERE name = $1 - `; - const userResults = await db.query(queryUserById, [account.display_name]); - const queryProfileById = ` + ` + const userResults = await db.query(queryUserById, [account.display_name]) + const queryProfileById = ` SELECT p.* FROM profiles AS p WHERE user_id = $1 ` - const profileResults = await db.query(queryProfileById, [userResults[0].id]); + const profileResults = await db.query(queryProfileById, [userResults[0].id]) - return { - user: userResults[0], - profile: profileResults[0] - } - } catch (error) { - throw error - }; -}; \ No newline at end of file + return { + user: userResults[0], + profile: profileResults[0], + } + } catch (error) { + throw error + } +} diff --git a/tests/e2e/web/pages/compatibilityPage.ts b/tests/e2e/web/pages/compatibilityPage.ts index b6753ff0..94b76c08 100644 --- a/tests/e2e/web/pages/compatibilityPage.ts +++ b/tests/e2e/web/pages/compatibilityPage.ts @@ -1,28 +1,28 @@ -import { expect, Locator, Page } from "@playwright/test"; +import {expect, Locator, Page} from '@playwright/test' export class ComatibilityPage { - private readonly answeredQuestionsTab: Locator - private readonly remaningQuestionsTab: Locator - private readonly skippedQuestionsTab: Locator + private readonly answeredQuestionsTab: Locator + private readonly remaningQuestionsTab: Locator + private readonly skippedQuestionsTab: Locator - constructor(public readonly page: Page) { - this.answeredQuestionsTab = page.getByText('Answered'); - this.remaningQuestionsTab = page.getByText('To Answer'); - this.skippedQuestionsTab = page.getByText('Skipped'); - }; + constructor(public readonly page: Page) { + this.answeredQuestionsTab = page.getByText('Answered') + this.remaningQuestionsTab = page.getByText('To Answer') + this.skippedQuestionsTab = page.getByText('Skipped') + } - async clickAnsweredQuestionsTab() { - await expect(this.answeredQuestionsTab).toBeVisible(); - await this.answeredQuestionsTab.click(); - }; + async clickAnsweredQuestionsTab() { + await expect(this.answeredQuestionsTab).toBeVisible() + await this.answeredQuestionsTab.click() + } - async clickRemainingQuestionsTab() { - await expect(this.remaningQuestionsTab).toBeVisible(); - await this.remaningQuestionsTab.click(); - }; + async clickRemainingQuestionsTab() { + await expect(this.remaningQuestionsTab).toBeVisible() + await this.remaningQuestionsTab.click() + } - async clickSkippedQuestionsTab() { - await expect(this.skippedQuestionsTab).toBeVisible(); - await this.skippedQuestionsTab.click(); - }; -}; \ No newline at end of file + async clickSkippedQuestionsTab() { + await expect(this.skippedQuestionsTab).toBeVisible() + await this.skippedQuestionsTab.click() + } +} diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index d37e4793..47c29cc5 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -1,4 +1,5 @@ import {expect, Locator, Page} from '@playwright/test' + import {Socials} from '../utils/accountInformation' type ProfileDropdownOptions = 'Public' | 'Private' | 'Disable' @@ -45,103 +46,103 @@ export class ProfilePage { private readonly viewQuestionListButton: Locator constructor(public readonly page: Page) { - this.startAnsweringButton = page.getByRole('button', {}); - this.doThisLaterLink = page.getByRole('button', {}); - this.closeButton = page.getByRole('button', {name: 'Close'}); - this.shareButton = page.getByRole('button', {name: 'Share'}); - this.editProfileButton = page.getByTestId('profile-edit'); - this.profileOptionsDropdown = page.getByTestId('profile-options'); - this.listProfilePubliclyDropdownOption = page.getByText('List Profile Publicly', {exact: true}); + this.startAnsweringButton = page.getByRole('button', {}) + this.doThisLaterLink = page.getByRole('button', {}) + this.closeButton = page.getByRole('button', {name: 'Close'}) + this.shareButton = page.getByRole('button', {name: 'Share'}) + this.editProfileButton = page.getByTestId('profile-edit') + this.profileOptionsDropdown = page.getByTestId('profile-options') + this.listProfilePubliclyDropdownOption = page.getByText('List Profile Publicly', {exact: true}) this.limitProfileToMembersDropdownOption = page.getByText('Limit to Members Only', { exact: true, - }); - this.disableProfileDropdownOption = page.getByText('Disable profile', {exact: true}); - this.displayNameAndAgeSection = page.getByTestId('profile-display-name-age'); + }) + this.disableProfileDropdownOption = page.getByText('Disable profile', {exact: true}) + this.displayNameAndAgeSection = page.getByTestId('profile-display-name-age') this.genderLocationHightInInchesSection = page.getByTestId( 'profile-gender-location-height-inches', - ); - this.politicalAboutSection = page.getByTestId('profile-about-political'); - this.relegiousAboutSection = page.getByTestId('profile-about-religious'); - this.interestsAboutSection = page.getByTestId('profile-about-interests'); - this.causesAboutSection = page.getByTestId('profile-about-causes'); - this.personalityAboutSection = page.getByTestId('profile-about-personality'); - this.ethnicityAboutSection = page.getByTestId('profile-about-ethnicity'); - 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-relationship-type'); - this.relationshipStatusAboutSection = page.getByTestId('profile-about-relationship-status'); - this.educationAboutSection = page.getByTestId('profile-about-education'); - this.occupationAboutSection = page.getByTestId('profile-about-occupation'); - this.workAreaAboutSection = page.getByTestId('profile-about-work-area'); - this.smokerAboutSection = page.getByTestId('profile-about-smoker'); - this.notDrinkerAboutSection = page.getByTestId('profile-about-not-drink'); - this.drinkerAboutSection = page.getByTestId('profile-about-drinker'); - this.wantsKidsAboutSection = page.getByTestId('profile-about-wants-kids'); - this.lastOnlineAboutSection = page.getByTestId('profile-about-wants-last-online'); + ) + this.politicalAboutSection = page.getByTestId('profile-about-political') + this.relegiousAboutSection = page.getByTestId('profile-about-religious') + this.interestsAboutSection = page.getByTestId('profile-about-interests') + this.causesAboutSection = page.getByTestId('profile-about-causes') + this.personalityAboutSection = page.getByTestId('profile-about-personality') + this.ethnicityAboutSection = page.getByTestId('profile-about-ethnicity') + 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-relationship-type') + this.relationshipStatusAboutSection = page.getByTestId('profile-about-relationship-status') + this.educationAboutSection = page.getByTestId('profile-about-education') + this.occupationAboutSection = page.getByTestId('profile-about-occupation') + this.workAreaAboutSection = page.getByTestId('profile-about-work-area') + this.smokerAboutSection = page.getByTestId('profile-about-smoker') + this.notDrinkerAboutSection = page.getByTestId('profile-about-not-drink') + this.drinkerAboutSection = page.getByTestId('profile-about-drinker') + this.wantsKidsAboutSection = page.getByTestId('profile-about-wants-kids') + this.lastOnlineAboutSection = page.getByTestId('profile-about-wants-last-online') this.bigFivePersonalityTraitsAboutSection = page.getByTestId( 'profile-about-big-five-personality-traits', - ); - this.hasKidsAboutSection = page.getByTestId('profile-about-has-kids'); - this.socialMediaSection = page.getByTestId('profile-social-media-accounts'); - this.bioSection = page.getByTestId('profile-bio'); - this.bioOptionsDropdown = page.getByTestId('profile-bio-options'); - this.editBioDropdownOptions = page.getByText('Edit', {exact: true}); - this.deleteBioDropdownOptions = page.getByText('Delete', {exact: true}); - this.answerCoreQuestionsButton = page.getByRole('button', { name: 'Answer Core Questions' }); - this.viewQuestionListButton = page.getByRole('link', { name: 'View List of Questions' }); + ) + this.hasKidsAboutSection = page.getByTestId('profile-about-has-kids') + this.socialMediaSection = page.getByTestId('profile-social-media-accounts') + this.bioSection = page.getByTestId('profile-bio') + this.bioOptionsDropdown = page.getByTestId('profile-bio-options') + this.editBioDropdownOptions = page.getByText('Edit', {exact: true}) + this.deleteBioDropdownOptions = page.getByText('Delete', {exact: true}) + this.answerCoreQuestionsButton = page.getByRole('button', {name: 'Answer Core Questions'}) + this.viewQuestionListButton = page.getByRole('link', {name: 'View List of Questions'}) } async clickCloseButton() { - await expect(this.closeButton).toBeInViewport(); - await this.closeButton.click(); - }; + await expect(this.closeButton).toBeInViewport() + await this.closeButton.click() + } async clickStartAnsweringButton() { - await expect(this.startAnsweringButton).toBeVisible(); - await this.startAnsweringButton.click(); - }; + await expect(this.startAnsweringButton).toBeVisible() + await this.startAnsweringButton.click() + } async clickDoThisLaterButton() { - await expect(this.doThisLaterLink).toBeVisible(); - await this.doThisLaterLink.click(); - }; + await expect(this.doThisLaterLink).toBeVisible() + await this.doThisLaterLink.click() + } async clickShareButton() { - await expect(this.shareButton).toBeVisible(); - await this.shareButton.click(); - }; + await expect(this.shareButton).toBeVisible() + await this.shareButton.click() + } async clickEditProfileButton() { - await expect(this.editProfileButton).toBeVisible(); - await this.editProfileButton.click(); - }; + await expect(this.editProfileButton).toBeVisible() + await this.editProfileButton.click() + } async clickAnswerQuestionsButton() { - await expect(this.answerCoreQuestionsButton).toBeVisible(); - await this.answerCoreQuestionsButton.click(); - }; + await expect(this.answerCoreQuestionsButton).toBeVisible() + await this.answerCoreQuestionsButton.click() + } async clickViewQuestionListButton() { - await expect(this.viewQuestionListButton).toBeVisible(); - await this.viewQuestionListButton.click(); - }; + await expect(this.viewQuestionListButton).toBeVisible() + await this.viewQuestionListButton.click() + } async selectOptionFromProfileDropdown(option: ProfileDropdownOptions) { - await expect(this.profileOptionsDropdown).toBeVisible(); - await this.profileOptionsDropdown.click(); + await expect(this.profileOptionsDropdown).toBeVisible() + await this.profileOptionsDropdown.click() if (option === 'Public') { - await expect(this.listProfilePubliclyDropdownOption).toBeVisible(); - await this.listProfilePubliclyDropdownOption.click(); + await expect(this.listProfilePubliclyDropdownOption).toBeVisible() + await this.listProfilePubliclyDropdownOption.click() } else if (option === 'Disable') { - await expect(this.disableProfileDropdownOption).toBeVisible(); - await this.disableProfileDropdownOption.click(); + await expect(this.disableProfileDropdownOption).toBeVisible() + await this.disableProfileDropdownOption.click() } else if (option === 'Private') { - await expect(this.limitProfileToMembersDropdownOption).toBeVisible(); - await this.limitProfileToMembersDropdownOption.click(); - }; - }; + await expect(this.limitProfileToMembersDropdownOption).toBeVisible() + await this.limitProfileToMembersDropdownOption.click() + } + } async verifyDisplayNameAndAge(displayName?: string, age?: string) { await expect(this.displayNameAndAgeSection).toBeVisible() @@ -201,7 +202,7 @@ export class ProfilePage { async verifyWantChildrenExpectation(expectation: [string, number] | undefined) { if (!expectation) return - const [label, value] = expectation; + const [label, value] = expectation await expect(this.wantsKidsAboutSection).toBeVisible() const textContent = await this.wantsKidsAboutSection.textContent() await expect(textContent?.toLowerCase()).toContain(label.toLowerCase()) @@ -231,7 +232,7 @@ export class ProfilePage { // const textContent = await this.workAreaAboutSection.textContent() for (let i = 0; i < workArea.length; i++) { // await expect(textContent?.toLowerCase()).toContain(workArea[i].toLowerCase()) - await expect(this.workAreaAboutSection).toContainText(workArea[i], {ignoreCase: true}); + await expect(this.workAreaAboutSection).toContainText(workArea[i], {ignoreCase: true}) // await expect(this.workAreaAboutSection).toContainText('University', {ignoreCase: true}); } } @@ -323,7 +324,7 @@ export class ProfilePage { async verifyBio(bio: string | undefined) { if (!bio) return - await expect(this.bioSection).toBeVisible(); + await expect(this.bioSection).toBeVisible() await expect(this.bioSection).toContainText(bio) } } diff --git a/tests/e2e/web/pages/signUpPage.ts b/tests/e2e/web/pages/signUpPage.ts index 7f2661d3..cb3a9d8f 100644 --- a/tests/e2e/web/pages/signUpPage.ts +++ b/tests/e2e/web/pages/signUpPage.ts @@ -1,22 +1,22 @@ import {expect, Locator, Page} from '@playwright/test' import { ConnectionTypeKey, - RelationshipStatusKey, - RelationshipStyleKey, - PoliticalBeliefsKey, DietKey, EducationKey, - ReligionKey, - LanguageKey, EthnicityKey, + LanguageKey, PersonalityKey, + PoliticalBeliefsKey, + RelationshipStatusKey, + RelationshipStyleKey, + ReligionKey, } from 'common/choices' export type Gender = 'Woman' | 'Man' | 'Other' export type InterestedIn = 'Women' | 'Men' | 'Other' export type ChildrenExpectation = | ['Strongly against', 0] - | ['Against',1 ] + | ['Against', 1] | ['Neutral', 2] | ['For', 3] | ['Strongly for', 4] @@ -291,8 +291,8 @@ export class SignUpPage { } async setWantChildrenExpectation(expectation: ChildrenExpectation | undefined) { - if (!expectation) return; - const [label, value] = expectation; + if (!expectation) return + const [label, value] = expectation if (label === 'Strongly against') { await expect(this.stronglyDisagreeOnWantingKids).toBeVisible() await this.stronglyDisagreeOnWantingKids.click() @@ -421,7 +421,10 @@ export class SignUpPage { } } - async setReligiousBeliefs(religiousBeliefs?: ReligionKey | undefined, details?: string | undefined) { + async setReligiousBeliefs( + religiousBeliefs?: ReligionKey | undefined, + details?: string | undefined, + ) { if (religiousBeliefs && religiousBeliefs === 'Other') { await expect( this.page @@ -645,11 +648,11 @@ export class SignUpPage { async setLanguages(language: LanguageKey[] | undefined) { if (!language || language.length === 0) return - await this.page.getByRole('checkbox', {name: `English`}).click(); + await this.page.getByRole('checkbox', {name: `English`}).click() for (let i = 0; i < language.length; i++) { - await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeVisible(); - await this.page.getByRole('checkbox', {name: `${language[i]}`}).click(); - await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeChecked(); + await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeVisible() + await this.page.getByRole('checkbox', {name: `${language[i]}`}).click() + await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeChecked() } } diff --git a/tests/e2e/web/utils/deleteUser.ts b/tests/e2e/web/utils/deleteUser.ts index 9f11b78d..3446f531 100644 --- a/tests/e2e/web/utils/deleteUser.ts +++ b/tests/e2e/web/utils/deleteUser.ts @@ -1,14 +1,11 @@ -import { login, deleteAccount } from "../../utils/firebaseUtils"; -import { deleteFromDb } from "../../utils/databaseUtils"; -import axios from 'axios' - -import {config} from '../SPEC_CONFIG' +import {deleteFromDb} from '../../utils/databaseUtils' +import {deleteAccount, login} from '../../utils/firebaseUtils' export async function deleteUser(email: string, password: string) { try { - const loginInfo = await login(email, password); - await deleteFromDb(loginInfo.data.localId); - await deleteAccount(loginInfo); + const loginInfo = await login(email, password) + await deleteFromDb(loginInfo.data.localId) + await deleteAccount(loginInfo) } catch (err: any) { // Skip deletion if user doesn't exist or other auth errors occur if ( @@ -20,4 +17,4 @@ export async function deleteUser(email: string, password: string) { } console.log(err) } -}; +} From f0808e444aa21abe0023b9e568c5a5d5bfc883cc Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 16:40:54 +0100 Subject: [PATCH 20/55] Log --- tests/e2e/web/pages/profilePage.ts | 1 + web/pages/[username]/index.tsx | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index 47c29cc5..2098ff54 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -229,6 +229,7 @@ export class ProfilePage { async verifyWorkArea(workArea: string[] | undefined) { if (!workArea || workArea.length === 0) return await expect(this.workAreaAboutSection).toBeVisible() + console.log('workAreaAboutSection', await this.workAreaAboutSection.innerHTML()) // const textContent = await this.workAreaAboutSection.textContent() for (let i = 0; i < workArea.length; i++) { // await expect(textContent?.toLowerCase()).toContain(workArea[i].toLowerCase()) diff --git a/web/pages/[username]/index.tsx b/web/pages/[username]/index.tsx index f7023783..42e330b2 100644 --- a/web/pages/[username]/index.tsx +++ b/web/pages/[username]/index.tsx @@ -168,12 +168,19 @@ export default function UserPage(props: UserPageProps) { const [fetchedProps, setFetchedProps] = useState(props) const [loading, setLoading] = useState(nativeMobile) - console.log('UserPage state:', { - username, - fetchedProps, - loading, - nativeMobile, - }) + console.log( + 'UserPage state:', + JSON.stringify( + { + username, + fetchedProps, + loading, + nativeMobile, + }, + null, + 2, + ), + ) useEffect(() => { if (nativeMobile) { From 6ba25b5f7fae2aa3e59402ecec26f14e64822bb8 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 20:27:03 +0100 Subject: [PATCH 21/55] Fix: should pull test account from unique identifier like email, username or id; not the display name --- tests/e2e/utils/databaseUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/utils/databaseUtils.ts b/tests/e2e/utils/databaseUtils.ts index 6137200e..00bc1bee 100644 --- a/tests/e2e/utils/databaseUtils.ts +++ b/tests/e2e/utils/databaseUtils.ts @@ -21,9 +21,9 @@ export async function userInformationFromDb(account: any) { const queryUserById = ` SELECT p.* FROM users AS p - WHERE name = $1 + WHERE username = $1 ` - const userResults = await db.query(queryUserById, [account.display_name]) + const userResults = await db.query(queryUserById, [account.username]) const queryProfileById = ` SELECT p.* FROM profiles AS p From e3c4666220fd6f80e9927913d99cb770680bcb2c Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 20:46:31 +0100 Subject: [PATCH 22/55] Source env vars in playwright directly --- playwright.config.ts | 27 ++++++++++++++++++++++++++- scripts/e2e-dev.sh | 17 ----------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 2a9d89cb..789385a8 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,10 +1,35 @@ import {defineConfig, devices} from '@playwright/test' +import {execSync} from 'child_process' +import dotenv from 'dotenv' + +// Load static env vars from .env.test +dotenv.config({path: '.env.test', quiet: true}) + +// Dynamically pull Supabase vars +function getSupabaseEnv() { + try { + const raw = execSync('npx supabase status --output json 2>/dev/null', {encoding: 'utf-8'}) + const status = JSON.parse(raw) + return { + NEXT_PUBLIC_SUPABASE_URL: status.API_URL, + NEXT_PUBLIC_SUPABASE_ANON_KEY: status.ANON_KEY, + DATABASE_URL: status.DB_URL, + } + } catch (e) { + throw new Error('Failed to get Supabase status. Is it running?') + } +} + +const supabaseEnv = getSupabaseEnv() + +// Inject into process.env so Playwright and your app code can read them +Object.assign(process.env, supabaseEnv) export default defineConfig({ testDir: './tests/e2e', fullyParallel: true, forbidOnly: !!process.env.CI, - retries: process.env.CI ? 2 : 0, + retries: process.env.CI ? 1 : 0, workers: process.env.CI ? 1 : undefined, reporter: [['html', {outputFolder: `tests/reports/playwright-report`, open: 'on-failure'}]], use: { diff --git a/scripts/e2e-dev.sh b/scripts/e2e-dev.sh index f4a12279..3378f6de 100755 --- a/scripts/e2e-dev.sh +++ b/scripts/e2e-dev.sh @@ -11,22 +11,10 @@ NC='\033[0m' print_status() { echo -e "${GREEN}[E2E-DEV]${NC} $1"; } print_error() { echo -e "${RED}[ERROR]${NC} $1"; } -get_supabase_status() { - SUPABASE_STATUS=$(supabase status --output json 2>/dev/null) -} - -get_supabase_status - # Check services are running (fail fast with helpful message) check_services() { local missing=0 - if [ -z "$(echo "$SUPABASE_STATUS" | jq -r '.API_URL')" ]; then - print_error "Supabase is not running. Starting..." - yarn test:db:reset - get_supabase_status - fi - if ! curl -s http://127.0.0.1:9099 > /dev/null 2>&1; then print_error "Firebase emulator is not running. Run: yarn emulate" missing=1 @@ -54,11 +42,6 @@ print_status "Checking services..." check_services print_status "All services running ✅" -export $(cat .env.test | grep -v '^#' | xargs) -export NEXT_PUBLIC_SUPABASE_URL=$(echo "$SUPABASE_STATUS" | jq -r '.API_URL') -export NEXT_PUBLIC_SUPABASE_ANON_KEY=$(echo "$SUPABASE_STATUS" | jq -r '.ANON_KEY') -export DATABASE_URL=$(echo "$SUPABASE_STATUS" | jq -r '.DB_URL') - # Run tests - pass all args through to playwright # Examples: # yarn test:e2e:dev → all e2e tests From 757b899ecae936616872159bce389c85188c2f09 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 20:46:50 +0100 Subject: [PATCH 23/55] Clean e2e data --- tests/e2e/web/utils/accountInformation.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/tests/e2e/web/utils/accountInformation.ts b/tests/e2e/web/utils/accountInformation.ts index d7f30bf0..aad62c0c 100644 --- a/tests/e2e/web/utils/accountInformation.ts +++ b/tests/e2e/web/utils/accountInformation.ts @@ -1,13 +1,4 @@ import {faker} from '@faker-js/faker' - -import { - Causes, - ChildrenExpectation, - Gender, - InterestedIn, - Interests, - Platforms, -} from '../pages/signUpPage' import { ConnectionTypeKey, DietKey, @@ -21,6 +12,8 @@ import { ReligionKey, } from 'common/choices' +import {Causes, ChildrenExpectation, Gender, InterestedIn, Interests, Platforms,} from '../pages/signUpPage' + export type OnboardingUser = { email: string password: string @@ -98,7 +91,7 @@ type OnboardingConfig = { export const onboarding: OnboardingConfig = { // Use a function so email is unique per test call faker_account: () => ({ - email: `faker+${crypto.randomUUID()}@test.com`, + email: `faker+${crypto.randomUUID().slice(0, 8)}@test.com`, password: faker.internet.password(), display_name: faker.internet.displayName(), username: `user_${crypto.randomUUID().slice(0, 8)}`, @@ -109,7 +102,7 @@ export const onboarding: OnboardingConfig = { email: `onboarding+${crypto.randomUUID().slice(0, 8)}@test.compass`, password: 'CompassTest', display_name: 'Compass Onboarding', - username: `TheGreatOnboarding_${crypto.randomUUID().slice(0, 4)}`, + username: `TheGreatOnboarding_${crypto.randomUUID().slice(0, 4)}`, // username max length is 25 (see /create-user) bio: 'Born beneath twin moons, this wanderer maps forgotten roads, trades riddles for shelter, and keeps stories in glass bottles. Drawn to ancient libraries and glowing forests, they seek lost spells, quiet taverns, and adventures that rewrite fate. Their compass points to wonder. Ever onward. Always. Go', gender: 'Woman', age: '25', @@ -135,7 +128,7 @@ export const onboarding: OnboardingConfig = { university: 'Open-Source University', job_title: 'Unemployed', company: 'Home', - work_area: ['Living Room', 'University'], + work_area: ['Engineering', 'Academia'], beliefs: { political: { belief: 'Green / Eco-Socialist', From b9b2174a2d55e1a81d9bb925130eba82b2be711f Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 20:50:23 +0100 Subject: [PATCH 24/55] Clean test account id to be the same for email and username --- tests/e2e/web/utils/accountInformation.ts | 126 +++++++++++----------- 1 file changed, 66 insertions(+), 60 deletions(-) diff --git a/tests/e2e/web/utils/accountInformation.ts b/tests/e2e/web/utils/accountInformation.ts index aad62c0c..d9abc867 100644 --- a/tests/e2e/web/utils/accountInformation.ts +++ b/tests/e2e/web/utils/accountInformation.ts @@ -90,68 +90,74 @@ type OnboardingConfig = { export const onboarding: OnboardingConfig = { // Use a function so email is unique per test call - faker_account: () => ({ - email: `faker+${crypto.randomUUID().slice(0, 8)}@test.com`, - password: faker.internet.password(), - display_name: faker.internet.displayName(), - username: `user_${crypto.randomUUID().slice(0, 8)}`, - }), + faker_account: () => { + const id = crypto.randomUUID().slice(0, 6) + return { + email: `faker+${id}@test.com`, + password: faker.internet.password(), + display_name: faker.internet.displayName(), + username: `user_${id}`, + } + }, - account_one: () => ({ - // Use a non-real TLD like @test.compass to make it obvious these are test accounts and prevent accidental emails - email: `onboarding+${crypto.randomUUID().slice(0, 8)}@test.compass`, - password: 'CompassTest', - display_name: 'Compass Onboarding', - username: `TheGreatOnboarding_${crypto.randomUUID().slice(0, 4)}`, // username max length is 25 (see /create-user) - bio: 'Born beneath twin moons, this wanderer maps forgotten roads, trades riddles for shelter, and keeps stories in glass bottles. Drawn to ancient libraries and glowing forests, they seek lost spells, quiet taverns, and adventures that rewrite fate. Their compass points to wonder. Ever onward. Always. Go', - gender: 'Woman', - age: '25', - height: { - feet: '6', - inches: '0', - centimeters: '182.88', - }, - ethnicity_origin: 'South/Southeast Asian', - interested_in: 'Men', - Interested_in_ages: { - min: '20', - max: '30', - }, - connection_type: 'Relationship', - relationship_status: 'In open relationship', - relationship_style: 'Open Relationship', - number_of_kids: '2', - children_expectation: ['Neutral', 2], - interests: ['Chess', 'Eating'], - causes: ['Animal Rights', 'Free Spotify'], - education_level: 'Bachelors', - university: 'Open-Source University', - job_title: 'Unemployed', - company: 'Home', - work_area: ['Engineering', 'Academia'], - beliefs: { - political: { - belief: 'Green / Eco-Socialist', - details: 'This will be details', + account_one: () => { + 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`, + password: 'CompassTest', + display_name: 'Compass Onboarding', + username: `TheGreatOnboarding_${id}`, // username max length is 25 (see /create-user) + bio: 'Born beneath twin moons, this wanderer maps forgotten roads, trades riddles for shelter, and keeps stories in glass bottles. Drawn to ancient libraries and glowing forests, they seek lost spells, quiet taverns, and adventures that rewrite fate. Their compass points to wonder. Ever onward. Always. Go', + gender: 'Woman', + age: '25', + height: { + feet: '6', + inches: '0', + centimeters: '182.88', }, - religious: { - belief: 'Shinto', - details: 'This will be details', + ethnicity_origin: 'South/Southeast Asian', + interested_in: 'Men', + Interested_in_ages: { + min: '20', + max: '30', }, - }, - personality_type: 'ENFJ', - big_five_personality_traits: { - openness: 43, - }, - diet: 'Omnivore', - is_smoker: false, - alcohol_consumed_per_month: '4', - languages: ['Akan', 'Cebuano'], - social_media: [ - { - platform: 'Bluesky', - urlOrUsername: 'TheGreatConnection', + connection_type: 'Relationship', + relationship_status: 'In open relationship', + relationship_style: 'Open Relationship', + number_of_kids: '2', + children_expectation: ['Neutral', 2], + interests: ['Chess', 'Eating'], + causes: ['Animal Rights', 'Free Spotify'], + education_level: 'Bachelors', + university: 'Open-Source University', + job_title: 'Unemployed', + company: 'Home', + work_area: ['Engineering', 'Academia'], + beliefs: { + political: { + belief: 'Green / Eco-Socialist', + details: 'This will be details', + }, + religious: { + belief: 'Shinto', + details: 'This will be details', + }, }, - ], - }), + personality_type: 'ENFJ', + big_five_personality_traits: { + openness: 43, + }, + diet: 'Omnivore', + is_smoker: false, + alcohol_consumed_per_month: '4', + languages: ['Akan', 'Cebuano'], + social_media: [ + { + platform: 'Bluesky', + urlOrUsername: 'TheGreatConnection', + }, + ], + } + }, } From 35fbd23b4dbb217b3912ad6d3171726c1fe7da9c Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 20:51:50 +0100 Subject: [PATCH 25/55] Fix import warning --- playwright.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 789385a8..c41459a8 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,9 +1,9 @@ import {defineConfig, devices} from '@playwright/test' import {execSync} from 'child_process' -import dotenv from 'dotenv' +import {config} from 'dotenv' // Load static env vars from .env.test -dotenv.config({path: '.env.test', quiet: true}) +config({path: '.env.test', quiet: true}) // Dynamically pull Supabase vars function getSupabaseEnv() { From 79e480f4475a015a49de42f4755f7b4fc2c22a73 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 21:02:30 +0100 Subject: [PATCH 26/55] Add error handling --- tests/e2e/utils/databaseUtils.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/e2e/utils/databaseUtils.ts b/tests/e2e/utils/databaseUtils.ts index 00bc1bee..04a25a36 100644 --- a/tests/e2e/utils/databaseUtils.ts +++ b/tests/e2e/utils/databaseUtils.ts @@ -5,6 +5,11 @@ export async function deleteFromDb(user_id: string) { try { const deleteEntryById = `DELETE FROM users WHERE id = $1 RETURNING *` const result = await db.query(deleteEntryById, [user_id]) + + if (!result.length) { + throw new Error(`No user found with id: ${user_id}`) + } + console.log('Deleted data: ', { id: result[0].id, name: result[0].name, From b90fc76d7793a35b367353f945045b6f86d30ff8 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 21:02:37 +0100 Subject: [PATCH 27/55] Add log --- tests/e2e/utils/firebaseUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/utils/firebaseUtils.ts b/tests/e2e/utils/firebaseUtils.ts index 91e303e7..24543afb 100644 --- a/tests/e2e/utils/firebaseUtils.ts +++ b/tests/e2e/utils/firebaseUtils.ts @@ -11,6 +11,7 @@ export async function login(email: string, password: string) { returnSecureToken: true, }, ) + console.log({login}) return login } From 6a01d30e2be92015176a88f1eea21d88064a3073 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 21:13:28 +0100 Subject: [PATCH 28/55] Temp remove env load --- playwright.config.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index c41459a8..8dc48c9e 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,9 +1,8 @@ import {defineConfig, devices} from '@playwright/test' import {execSync} from 'child_process' -import {config} from 'dotenv' // Load static env vars from .env.test -config({path: '.env.test', quiet: true}) +// config({path: '.env.test', quiet: true}) // Dynamically pull Supabase vars function getSupabaseEnv() { @@ -23,13 +22,15 @@ function getSupabaseEnv() { const supabaseEnv = getSupabaseEnv() // Inject into process.env so Playwright and your app code can read them -Object.assign(process.env, supabaseEnv) +// Object.assign(process.env, supabaseEnv) export default defineConfig({ testDir: './tests/e2e', fullyParallel: true, forbidOnly: !!process.env.CI, - retries: process.env.CI ? 1 : 0, + // No retries by default (even in CI) because it slows the CI pipeline and masks real bugs + // If there is a known intermittent browser timing issue for some tests, it's fine to give 1 retry to those flaky tests + retries: process.env.CI ? 0 : 0, workers: process.env.CI ? 1 : undefined, reporter: [['html', {outputFolder: `tests/reports/playwright-report`, open: 'on-failure'}]], use: { From f6dca71fe4b5ca6a68c591b1a15c3467beb93faf Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 21:27:25 +0100 Subject: [PATCH 29/55] Update --- scripts/e2e.sh | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/scripts/e2e.sh b/scripts/e2e.sh index eaf07b1e..f63aa445 100755 --- a/scripts/e2e.sh +++ b/scripts/e2e.sh @@ -60,16 +60,7 @@ supabase stop --no-backup 2>/dev/null || true sleep 2 # Give ports time to free up # Build backend (required?) -./scripts/build_api.sh - -# Get connection details -export NEXT_PUBLIC_SUPABASE_URL=$(supabase status --output json | jq -r '.API_URL') -export NEXT_PUBLIC_SUPABASE_ANON_KEY=$(supabase status --output json | jq -r '.ANON_KEY') -export DATABASE_URL=$(supabase status --output json | jq -r '.DB_URL') - -echo $NEXT_PUBLIC_SUPABASE_URL -echo $NEXT_PUBLIC_SUPABASE_ANON_KEY -echo $DATABASE_URL +#./scripts/build_api.sh print_status "Supabase started at: $DATABASE_URL" @@ -90,6 +81,17 @@ npx wait-on \ # Start Supabase (includes Postgres, Auth, Storage, etc.) and Apply migrations and seed (needs firebase emulator running) yarn test:db:reset +# Get connection details +STATUS_JSON=$(supabase status --output json) +export NEXT_PUBLIC_SUPABASE_URL=$(echo "$STATUS_JSON" | jq -r '.API_URL') +export NEXT_PUBLIC_SUPABASE_ANON_KEY=$(echo "$STATUS_JSON" | jq -r '.ANON_KEY') +export DATABASE_URL=$(echo "$STATUS_JSON" | jq -r '.DB_URL') + +echo "Supabase env vars:" +echo $NEXT_PUBLIC_SUPABASE_URL +echo $NEXT_PUBLIC_SUPABASE_ANON_KEY +echo $DATABASE_URL + # Start backend API print_status "Starting backend API..." yarn --cwd=backend/api dev & PIDS+=($!) From dd3e1eeb106f20ee6422be1adbe45d004c000a71 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 21:40:22 +0100 Subject: [PATCH 30/55] Add logs and safeguards against using remote supabase during e2e tests --- backend/shared/src/supabase/init.ts | 8 ++++++++ scripts/e2e-dev.sh | 2 ++ scripts/e2e.sh | 6 ++++-- scripts/e2e_services.sh | 2 ++ web/lib/supabase/db.ts | 10 +++++++++- 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/backend/shared/src/supabase/init.ts b/backend/shared/src/supabase/init.ts index 774204f6..0d27cdff 100644 --- a/backend/shared/src/supabase/init.ts +++ b/backend/shared/src/supabase/init.ts @@ -60,6 +60,14 @@ const newClient = ( console.log('Creating Supabase direct client') } + if (!databaseUrl && process.env.NEXT_PUBLIC_ISOLATED_ENV) { + throw new Error( + `You are running isolated tests (NEXT_PUBLIC_ISOLATED_ENV=true), so you do not want to call the remote supabase. ${{ + databaseUrl, + }}`, + ) + } + const config: any = databaseUrl ? { // Use connection string for local/dev Postgres diff --git a/scripts/e2e-dev.sh b/scripts/e2e-dev.sh index 3378f6de..b1c3ed52 100755 --- a/scripts/e2e-dev.sh +++ b/scripts/e2e-dev.sh @@ -4,6 +4,8 @@ set -euo pipefail cd "$(dirname "$0")"/.. +export NEXT_PUBLIC_ISOLATED_ENV=true + # Colors GREEN='\033[0;32m' RED='\033[0;31m' diff --git a/scripts/e2e.sh b/scripts/e2e.sh index f63aa445..6898573e 100755 --- a/scripts/e2e.sh +++ b/scripts/e2e.sh @@ -5,6 +5,8 @@ set -euo pipefail # Change to project root cd "$(dirname "$0")"/.. +export NEXT_PUBLIC_ISOLATED_ENV=true + # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' @@ -62,8 +64,6 @@ sleep 2 # Give ports time to free up # Build backend (required?) #./scripts/build_api.sh -print_status "Supabase started at: $DATABASE_URL" - # Install Playwright browsers print_status "Installing Playwright browsers..." npx playwright install chromium # --with-deps @@ -87,6 +87,8 @@ export NEXT_PUBLIC_SUPABASE_URL=$(echo "$STATUS_JSON" | jq -r '.API_URL') export NEXT_PUBLIC_SUPABASE_ANON_KEY=$(echo "$STATUS_JSON" | jq -r '.ANON_KEY') export DATABASE_URL=$(echo "$STATUS_JSON" | jq -r '.DB_URL') +print_status "Supabase started at: $DATABASE_URL" + echo "Supabase env vars:" echo $NEXT_PUBLIC_SUPABASE_URL echo $NEXT_PUBLIC_SUPABASE_ANON_KEY diff --git a/scripts/e2e_services.sh b/scripts/e2e_services.sh index c9bd280e..98c87002 100755 --- a/scripts/e2e_services.sh +++ b/scripts/e2e_services.sh @@ -8,6 +8,8 @@ set -euo pipefail # Change to project root cd "$(dirname "$0")"/.. +export NEXT_PUBLIC_ISOLATED_ENV=true + export $(cat .env.test | grep -v '^#' | xargs) # Ensure Supabase local stack is running; if not, reset/start it diff --git a/web/lib/supabase/db.ts b/web/lib/supabase/db.ts index 357855dc..d1e28cb3 100644 --- a/web/lib/supabase/db.ts +++ b/web/lib/supabase/db.ts @@ -11,10 +11,18 @@ export function initSupabaseClient() { if (urlOverride && anonKeyOverride) { console.log('Initializing Supabase client (env URL override)') return createClient(urlOverride, anonKeyOverride) + } else if (process.env.NEXT_PUBLIC_ISOLATED_ENV) { + throw new Error( + `You are running isolated tests (NEXT_PUBLIC_ISOLATED_ENV=true), so you do not want to call the remote supabase. ${{ + urlOverride, + anonKeyOverride, + }}`, + ) } + if (urlOverride || anonKeyOverride) { console.warn( - 'Supabase env override is partially set. Both URL and ANON_KEY are required. Falling back to ENV_CONFIG.' + 'Supabase env override is partially set. Both URL and ANON_KEY are required. Falling back to ENV_CONFIG.', ) } From 8b2fa10e3eaec587d5bad61a148bcf0945fe3167 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 21:46:57 +0100 Subject: [PATCH 31/55] Fix playwright report path in C@ --- .github/workflows/ci-e2e.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index e4e49c46..eee45f4f 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -2,9 +2,9 @@ name: E2E Tests on: push: - branches: [main] + branches: [ main ] pull_request: - branches: [main] + branches: [ main ] jobs: e2e: @@ -39,7 +39,7 @@ jobs: - name: Install Playwright browsers run: npx playwright install chromium --with-deps - - name: Start Supabase # optional step, as if supabase is stopped, it would be started in test:e2e, but done here to avoid cluttering the logs of the E2E tests + - name: Start Supabase # optional step: indeed, if supabase is stopped, it would be started in test:e2e, but done here to avoid cluttering the logs of the E2E tests run: | echo "::group::Supabase start (docker pull logs)" npx supabase start @@ -58,7 +58,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: playwright-report - path: playwright-report/ + path: tests/reports/playwright-report/ retention-days: 7 - name: Upload test results From 16a693b3da802bb6c67191f4f94eae37e0f5a350 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 21:52:20 +0100 Subject: [PATCH 32/55] Remove locale log --- web/components/auth-context.tsx | 3 --- web/pages/_app.tsx | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/web/components/auth-context.tsx b/web/components/auth-context.tsx index f9c9598b..ecef285e 100644 --- a/web/components/auth-context.tsx +++ b/web/components/auth-context.tsx @@ -10,7 +10,6 @@ import {useStateCheckEquality} from 'web/hooks/use-state-check-equality' import {useWebsocketPrivateUser, useWebsocketUser} from 'web/hooks/use-user' import {api} from 'web/lib/api' import {auth} from 'web/lib/firebase/users' -import {useLocale} from 'web/lib/locale' import {getLocale} from 'web/lib/locale-cookie' import {identifyUser, setUserProperty} from 'web/lib/service/analytics' import {getPrivateUserSafe, getUserSafe} from 'web/lib/supabase/users' @@ -118,8 +117,6 @@ export function AuthProvider(props: {children: ReactNode; serverUser?: AuthUser} ) const [authLoaded, setAuthLoaded] = useState(false) const firebaseUser = useAndSetupFirebaseUser() - const {locale} = useLocale() - console.log('AuthProvider hook locale', locale) const authUser = !user ? user diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index 77d077e3..7ee606ef 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -94,7 +94,7 @@ function MyApp(props: AppProps) { const router = useRouter() const [locale, setLocaleState] = useState(getLocale()) - console.log('_app locale', locale) + // console.log('_app locale', locale) const setLocale = (newLocale: string) => { console.log('setLocale', newLocale) document.cookie = `lang=${newLocale}; path=/; max-age=31536000` From 269adb35c6aa7566f3985a1076f6322c25a07a9c Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 21:54:07 +0100 Subject: [PATCH 33/55] Check if userInformationFromDb loading with name instead of username was the issue --- tests/e2e/utils/databaseUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/utils/databaseUtils.ts b/tests/e2e/utils/databaseUtils.ts index 04a25a36..82ddc24f 100644 --- a/tests/e2e/utils/databaseUtils.ts +++ b/tests/e2e/utils/databaseUtils.ts @@ -26,9 +26,9 @@ export async function userInformationFromDb(account: any) { const queryUserById = ` SELECT p.* FROM users AS p - WHERE username = $1 + WHERE name = $1 ` - const userResults = await db.query(queryUserById, [account.username]) + const userResults = await db.query(queryUserById, [account.display_name]) const queryProfileById = ` SELECT p.* FROM profiles AS p From 60cdeabd6dc76b3e61cb6151872d535e99eb0518 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 21:55:19 +0100 Subject: [PATCH 34/55] Remove login log --- tests/e2e/utils/firebaseUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/e2e/utils/firebaseUtils.ts b/tests/e2e/utils/firebaseUtils.ts index 24543afb..91e303e7 100644 --- a/tests/e2e/utils/firebaseUtils.ts +++ b/tests/e2e/utils/firebaseUtils.ts @@ -11,7 +11,6 @@ export async function login(email: string, password: string) { returnSecureToken: true, }, ) - console.log({login}) return login } From d69ce9b9b9542b7d7efe42e97e54e04164527be6 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:06:14 +0100 Subject: [PATCH 35/55] Check if initial work area names were the issue --- tests/e2e/web/utils/accountInformation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/web/utils/accountInformation.ts b/tests/e2e/web/utils/accountInformation.ts index d9abc867..aa93546c 100644 --- a/tests/e2e/web/utils/accountInformation.ts +++ b/tests/e2e/web/utils/accountInformation.ts @@ -133,7 +133,7 @@ export const onboarding: OnboardingConfig = { university: 'Open-Source University', job_title: 'Unemployed', company: 'Home', - work_area: ['Engineering', 'Academia'], + work_area: ['Living Room', 'University'], beliefs: { political: { belief: 'Green / Eco-Socialist', From 0da8f5b863b6ff8a6c058405c824e8e029eb4253 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:14:40 +0100 Subject: [PATCH 36/55] Ignore if no files found --- .github/workflows/ci-e2e.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index eee45f4f..fc99524d 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -68,3 +68,4 @@ jobs: name: test-results path: test-results/ retention-days: 7 + if-no-files-found: ignore From b2077a3afe0a5849b399f330a8bb39cf301fa7cd Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:17:55 +0100 Subject: [PATCH 37/55] Cache Firebase emulators in CI --- .github/workflows/ci-e2e.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index fc99524d..d857d541 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -38,6 +38,13 @@ jobs: - name: Install Playwright browsers run: npx playwright install chromium --with-deps + + - name: Cache Firebase emulators + uses: actions/cache@v4 + with: + path: ~/.cache/firebase/emulators + key: firebase-emulators-${{ hashFiles('firebase.json') }} + restore-keys: firebase-emulators- - name: Start Supabase # optional step: indeed, if supabase is stopped, it would be started in test:e2e, but done here to avoid cluttering the logs of the E2E tests run: | From 28302aa73c0b8470826267392cb82d07d6b2fe41 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:20:42 +0100 Subject: [PATCH 38/55] Reload env vars in playwright --- playwright.config.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 8dc48c9e..18cb34a6 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,8 +1,9 @@ import {defineConfig, devices} from '@playwright/test' import {execSync} from 'child_process' +import {config} from 'dotenv' // Load static env vars from .env.test -// config({path: '.env.test', quiet: true}) +config({path: '.env.test', quiet: true}) // Dynamically pull Supabase vars function getSupabaseEnv() { @@ -22,7 +23,7 @@ function getSupabaseEnv() { const supabaseEnv = getSupabaseEnv() // Inject into process.env so Playwright and your app code can read them -// Object.assign(process.env, supabaseEnv) +Object.assign(process.env, supabaseEnv) export default defineConfig({ testDir: './tests/e2e', From d6b3fbe27a7a5e264d218085fb74948f6f772778 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:23:11 +0100 Subject: [PATCH 39/55] It did not break tests... --- tests/e2e/web/utils/accountInformation.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/e2e/web/utils/accountInformation.ts b/tests/e2e/web/utils/accountInformation.ts index aa93546c..06b7a859 100644 --- a/tests/e2e/web/utils/accountInformation.ts +++ b/tests/e2e/web/utils/accountInformation.ts @@ -12,7 +12,14 @@ import { ReligionKey, } from 'common/choices' -import {Causes, ChildrenExpectation, Gender, InterestedIn, Interests, Platforms,} from '../pages/signUpPage' +import { + Causes, + ChildrenExpectation, + Gender, + InterestedIn, + Interests, + Platforms, +} from '../pages/signUpPage' export type OnboardingUser = { email: string @@ -133,7 +140,7 @@ export const onboarding: OnboardingConfig = { university: 'Open-Source University', job_title: 'Unemployed', company: 'Home', - work_area: ['Living Room', 'University'], + work_area: ['Engineering', 'Academia'], beliefs: { political: { belief: 'Green / Eco-Socialist', From 744133c76817d40faf0661d47054ea9dc33eaab7 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:23:36 +0100 Subject: [PATCH 40/55] Clean verifyWorkArea --- tests/e2e/web/pages/profilePage.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/e2e/web/pages/profilePage.ts b/tests/e2e/web/pages/profilePage.ts index 2098ff54..8ff573fb 100644 --- a/tests/e2e/web/pages/profilePage.ts +++ b/tests/e2e/web/pages/profilePage.ts @@ -229,12 +229,8 @@ export class ProfilePage { async verifyWorkArea(workArea: string[] | undefined) { if (!workArea || workArea.length === 0) return await expect(this.workAreaAboutSection).toBeVisible() - console.log('workAreaAboutSection', await this.workAreaAboutSection.innerHTML()) - // const textContent = await this.workAreaAboutSection.textContent() for (let i = 0; i < workArea.length; i++) { - // await expect(textContent?.toLowerCase()).toContain(workArea[i].toLowerCase()) await expect(this.workAreaAboutSection).toContainText(workArea[i], {ignoreCase: true}) - // await expect(this.workAreaAboutSection).toContainText('University', {ignoreCase: true}); } } From b77a36263a93d4202b36094c60fbd7c955aa50f9 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:29:54 +0100 Subject: [PATCH 41/55] Add caching for node modules in CI --- .github/workflows/ci-e2e.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index d857d541..7471e19d 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -16,6 +16,12 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Cache node_modules + uses: actions/cache@v4 + with: + path: node_modules + key: node-modules-${{ hashFiles('yarn.lock') }} + - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -38,7 +44,7 @@ jobs: - name: Install Playwright browsers run: npx playwright install chromium --with-deps - + - name: Cache Firebase emulators uses: actions/cache@v4 with: From e19a4fadef2fb924779cc029735c2f13995a4023 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:41:01 +0100 Subject: [PATCH 42/55] Add caching for node modules in CI (2) --- .github/workflows/ci-e2e.yml | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index 7471e19d..d1f728a9 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -16,7 +16,20 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Cache Firebase emulators + uses: actions/cache@v4 + with: + path: ~/.cache/firebase/emulators + key: firebase-emulators-${{ hashFiles('firebase.json') }} + restore-keys: firebase-emulators- + + - name: Cache Docker layers + uses: ScribeMD/docker-cache@0.5.0 + with: + key: docker-${{ runner.os }}-${{ hashFiles('supabase/config.toml') }} + - name: Cache node_modules + id: cache-node-modules uses: actions/cache@v4 with: path: node_modules @@ -34,24 +47,15 @@ jobs: distribution: 'temurin' java-version: '21' # Required for firebase-tools@15+ - - name: Setup Supabase CLI - uses: supabase/setup-cli@v1 - with: - version: latest - - name: Install dependencies + if: steps.cache-node-modules.outputs.cache-hit != 'true' run: yarn install --frozen-lockfile + env: + HUSKY: 0 - name: Install Playwright browsers run: npx playwright install chromium --with-deps - - name: Cache Firebase emulators - uses: actions/cache@v4 - with: - path: ~/.cache/firebase/emulators - key: firebase-emulators-${{ hashFiles('firebase.json') }} - restore-keys: firebase-emulators- - - name: Start Supabase # optional step: indeed, if supabase is stopped, it would be started in test:e2e, but done here to avoid cluttering the logs of the E2E tests run: | echo "::group::Supabase start (docker pull logs)" From 2266e5372113b8dc7aa6f59db48eb7325713d55f Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:50:28 +0100 Subject: [PATCH 43/55] Do not raise if emulator not running during db seed --- scripts/seed.sh | 10 ++++------ tests/e2e/utils/seed-test-data.ts | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/scripts/seed.sh b/scripts/seed.sh index 22f94b95..4a975020 100755 --- a/scripts/seed.sh +++ b/scripts/seed.sh @@ -8,12 +8,10 @@ cd "$(dirname "$0")"/.. export $(cat .env.test | grep -v '^#' | xargs) # Get connection details -export NEXT_PUBLIC_SUPABASE_URL=$(supabase status --output json | jq -r '.API_URL') -export NEXT_PUBLIC_SUPABASE_ANON_KEY=$(supabase status --output json | jq -r '.ANON_KEY') -export DATABASE_URL=$(supabase status --output json | jq -r '.DB_URL') - -# Build backend (required?) -#./scripts/build_api.sh +STATUS_JSON=$(supabase status --output json) +export NEXT_PUBLIC_SUPABASE_URL=$(echo "$STATUS_JSON" | jq -r '.API_URL') +export NEXT_PUBLIC_SUPABASE_ANON_KEY=$(echo "$STATUS_JSON" | jq -r '.ANON_KEY') +export DATABASE_URL=$(echo "$STATUS_JSON" | jq -r '.DB_URL') cd tests/e2e/utils diff --git a/tests/e2e/utils/seed-test-data.ts b/tests/e2e/utils/seed-test-data.ts index 3403a96a..82b5c283 100644 --- a/tests/e2e/utils/seed-test-data.ts +++ b/tests/e2e/utils/seed-test-data.ts @@ -27,8 +27,8 @@ async function createAuth(email: string, password: string) { ) { return } - if (err.code === 'ECONNREFUSED') - throw Error('Firebase emulator not running. Start it with:\n yarn test:e2e:services\n') + if (err.code === 'ECONNREFUSED') return + // throw Error('Firebase emulator not running. Start it with:\n yarn test:e2e:services\n') console.log(err) throw err } From 728245a02ff1708a638dde98ac661e62301bf9b2 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:53:45 +0100 Subject: [PATCH 44/55] Do not raise if using firebase emulator --- backend/shared/src/firebase-utils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/shared/src/firebase-utils.ts b/backend/shared/src/firebase-utils.ts index 5b65f546..ceb0a4d4 100644 --- a/backend/shared/src/firebase-utils.ts +++ b/backend/shared/src/firebase-utils.ts @@ -21,7 +21,8 @@ export const getServiceAccountCredentials = () => { try { return JSON.parse(readFileSync(keyPath, {encoding: 'utf8'})) } catch (e) { - throw new Error(`Failed to load service account key from ${keyPath}: ${e}`) + if (!process.env.NEXT_PUBLIC_ISOLATED_ENV && !process.env.FIREBASE_AUTH_EMULATOR_HOST) + throw new Error(`Failed to load service account key from ${keyPath}: ${e}`) } } From e441572df2020d946d186a619c7bd2fddd05da23 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 22:58:02 +0100 Subject: [PATCH 45/55] Fix supabase cache in CI --- .github/workflows/ci-e2e.yml | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index d1f728a9..f3648460 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -23,10 +23,10 @@ jobs: key: firebase-emulators-${{ hashFiles('firebase.json') }} restore-keys: firebase-emulators- - - name: Cache Docker layers - uses: ScribeMD/docker-cache@0.5.0 - with: - key: docker-${{ runner.os }}-${{ hashFiles('supabase/config.toml') }} + # - name: Cache Docker layers + # uses: ScribeMD/docker-cache@0.5.0 + # with: + # key: docker-${{ runner.os }}-${{ hashFiles('supabase/config.toml') }} - name: Cache node_modules id: cache-node-modules @@ -56,11 +56,31 @@ jobs: - name: Install Playwright browsers run: npx playwright install chromium --with-deps - - name: Start Supabase # optional step: indeed, if supabase is stopped, it would be started in test:e2e, but done here to avoid cluttering the logs of the E2E tests + - name: Cache Supabase Docker images + uses: actions/cache@v4 + with: + path: /tmp/supabase-docker + key: supabase-docker-${{ hashFiles('supabase/config.toml') }} + + - name: Load cached Docker images + run: | + if [ -d /tmp/supabase-docker ]; then + for tar in /tmp/supabase-docker/*.tar; do + [ -f "$tar" ] && docker load -i "$tar" + done + fi + + - name: Start Supabase + run: npx supabase start + + - name: Save Supabase Docker images run: | - echo "::group::Supabase start (docker pull logs)" - npx supabase start - echo "::endgroup::" + mkdir -p /tmp/supabase-docker + docker images --format '{{.Repository}}:{{.Tag}}' \ + | grep -E 'supabase|postgrest|gotrue|realtime|storage' \ + | grep -v '' \ + | xargs -I{} sh -c \ + 'docker save {} -o /tmp/supabase-docker/$(echo {} | tr "/:" "--").tar' - name: Run E2E tests env: From cb4119771674e88db8e52110a9d3aa0f9f28b67a Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 23:08:09 +0100 Subject: [PATCH 46/55] Add Cache Playwright browsers in CI --- .github/workflows/ci-e2e.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index f3648460..eeff88cb 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -35,6 +35,12 @@ jobs: path: node_modules key: node-modules-${{ hashFiles('yarn.lock') }} + - name: Cache Playwright browsers + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-${{ hashFiles('package.json') }} + - name: Setup Node.js uses: actions/setup-node@v4 with: From 166bbe230e1c705a7751531c41706467678f26fc Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 23:09:37 +0100 Subject: [PATCH 47/55] Fix --- .github/workflows/ci-e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index eeff88cb..6b559cb2 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -54,7 +54,7 @@ jobs: java-version: '21' # Required for firebase-tools@15+ - name: Install dependencies - if: steps.cache-node-modules.outputs.cache-hit != 'true' + # if: steps.cache-node-modules.outputs.cache-hit != 'true' run: yarn install --frozen-lockfile env: HUSKY: 0 From a3f93ce9722b86f5c1a8392511c3c944cba56b2f Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 23:20:07 +0100 Subject: [PATCH 48/55] Test cache --- .github/workflows/ci-e2e.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index 6b559cb2..8fd189a8 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -54,7 +54,6 @@ jobs: java-version: '21' # Required for firebase-tools@15+ - name: Install dependencies - # if: steps.cache-node-modules.outputs.cache-hit != 'true' run: yarn install --frozen-lockfile env: HUSKY: 0 From 3a19a6b3a0e493289fe1e058aadf3a268c880822 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 28 Feb 2026 23:38:25 +0100 Subject: [PATCH 49/55] Turn off unused supabase services to speed things up --- .github/workflows/ci-e2e.yml | 2 +- package.json | 2 +- scripts/supabase_start.sh | 11 +++++++++++ scripts/test_db_reset.sh | 13 +++++++++++++ supabase/config.toml | 12 ++++++------ 5 files changed, 32 insertions(+), 8 deletions(-) create mode 100755 scripts/supabase_start.sh create mode 100755 scripts/test_db_reset.sh diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index 8fd189a8..8c82bf0f 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -76,7 +76,7 @@ jobs: fi - name: Start Supabase - run: npx supabase start + run: ./scripts/supabase_start.sh - name: Save Supabase Docker images run: | diff --git a/package.json b/package.json index a6aa48a4..6c863ea7 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "test:e2e:ui": "./scripts/e2e.sh --ui", "test:e2e:debug": "./scripts/e2e.sh --debug", "test:e2e:services": "./scripts/e2e_services.sh", - "test:db:reset": "npx supabase start && ./scripts/combine-migrations.sh && npx supabase db reset && yarn test:db:seed", + "test:db:reset": "./scripts/test_db_reset.sh", "test:db:reset-postgres": "docker compose -f scripts/docker-compose.test.yml down -v && docker compose -f scripts/docker-compose.test.yml up -d", "test:db:migrate": "./scripts/test_db_migration.sh", "test:db:seed": "./scripts/seed.sh", diff --git a/scripts/supabase_start.sh b/scripts/supabase_start.sh new file mode 100755 index 00000000..0aaf5552 --- /dev/null +++ b/scripts/supabase_start.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -euo pipefail + +cd "$(dirname "$0")/.." + +if [ "${CI:-false}" = "true" ]; then + npx supabase start --exclude studio +else + npx supabase start +fi diff --git a/scripts/test_db_reset.sh b/scripts/test_db_reset.sh new file mode 100755 index 00000000..b7d2d691 --- /dev/null +++ b/scripts/test_db_reset.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -euo pipefail + +cd "$(dirname "$0")/.." + +./scripts/supabase_start.sh + +./scripts/combine-migrations.sh + +npx supabase db reset + +yarn test:db:seed diff --git a/supabase/config.toml b/supabase/config.toml index 5863984b..56005c04 100644 --- a/supabase/config.toml +++ b/supabase/config.toml @@ -58,7 +58,7 @@ enabled = true sql_paths = ["./seed.sql"] [realtime] -enabled = true +enabled = false # Bind realtime via either IPv4 or IPv6. (default: IPv4) # ip_version = "IPv6" # The maximum length in bytes of HTTP request headers. (default: 4096) @@ -76,7 +76,7 @@ openai_api_key = "env(OPENAI_API_KEY)" # Email testing server. Emails sent with the local dev setup are not actually sent - rather, they # are monitored, and you can view the emails that would have been sent from the web interface. [inbucket] -enabled = true +enabled = false # Port to use for the email testing server web interface. port = 54324 # Uncomment to expose additional ports for testing user applications that send emails. @@ -86,7 +86,7 @@ port = 54324 # sender_name = "Admin" [storage] -enabled = true +enabled = false # The maximum file size allowed (e.g. "5MB", "500KB"). file_size_limit = "50MiB" @@ -102,7 +102,7 @@ file_size_limit = "50MiB" # objects_path = "./images" [auth] -enabled = true +enabled = false # The base URL of your website. Used as an allow-list for redirects and for constructing URLs used # in emails. site_url = "http://127.0.0.1:3000" @@ -256,7 +256,7 @@ enabled = false # user_pool_region = "us-east-1" [edge_runtime] -enabled = true +enabled = false # Configure one of the supported request policies: `oneshot`, `per_worker`. # Use `oneshot` for hot reload, or `per_worker` for load testing. policy = "oneshot" @@ -276,7 +276,7 @@ inspector_port = 8083 # static_files = [ "./functions/MY_FUNCTION_NAME/*.html" ] [analytics] -enabled = true +enabled = false port = 54327 # Configure one of the supported backends: `postgres`, `bigquery`. backend = "postgres" From 3a4ad9405518cebed38a3c901ef2b9690cdb05da Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sun, 1 Mar 2026 00:01:59 +0100 Subject: [PATCH 50/55] Back to good one --- tests/e2e/utils/databaseUtils.ts | 57 ++++++++++++++++---------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/tests/e2e/utils/databaseUtils.ts b/tests/e2e/utils/databaseUtils.ts index 82ddc24f..8370d0fd 100644 --- a/tests/e2e/utils/databaseUtils.ts +++ b/tests/e2e/utils/databaseUtils.ts @@ -2,45 +2,46 @@ import {createSupabaseDirectClient} from 'shared/supabase/init' export async function deleteFromDb(user_id: string) { const db = createSupabaseDirectClient() - try { - const deleteEntryById = `DELETE FROM users WHERE id = $1 RETURNING *` - const result = await db.query(deleteEntryById, [user_id]) - - if (!result.length) { - throw new Error(`No user found with id: ${user_id}`) - } - - console.log('Deleted data: ', { - id: result[0].id, - name: result[0].name, - username: result[0].username, - }) - } catch (error) { - throw error + const deleteEntryById = `DELETE FROM users WHERE id = $1 RETURNING *` + const result = await db.query(deleteEntryById, [user_id]) + + if (!result.length) { + throw new Error(`No user found with id: ${user_id}`) } + + console.log('Deleted data: ', { + id: result[0].id, + name: result[0].name, + username: result[0].username, + }) } export async function userInformationFromDb(account: any) { const db = createSupabaseDirectClient() - try { - const queryUserById = ` + const queryUserById = ` SELECT p.* FROM users AS p - WHERE name = $1 + WHERE username = $1 ` - const userResults = await db.query(queryUserById, [account.display_name]) - const queryProfileById = ` + const userResults = await db.query(queryUserById, [account.username]) + + if (userResults.length === 0) { + throw new Error(`No user found with username: ${account.username}`) + } + + const queryProfileById = ` SELECT p.* FROM profiles AS p WHERE user_id = $1 ` - const profileResults = await db.query(queryProfileById, [userResults[0].id]) - - return { - user: userResults[0], - profile: profileResults[0], - } - } catch (error) { - throw error + const profileResults = await db.query(queryProfileById, [userResults[0].id]) + + if (profileResults.length === 0) { + throw new Error(`No profile found for user: ${userResults[0].id}`) + } + + return { + user: userResults[0], + profile: profileResults[0], } } From ad0c67713d2c31de4df8ed8b70dc2042d5a5afca Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sun, 1 Mar 2026 00:31:20 +0100 Subject: [PATCH 51/55] Set CI=true --- scripts/e2e.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/e2e.sh b/scripts/e2e.sh index 6898573e..7411e2f5 100755 --- a/scripts/e2e.sh +++ b/scripts/e2e.sh @@ -6,6 +6,7 @@ set -euo pipefail cd "$(dirname "$0")"/.. export NEXT_PUBLIC_ISOLATED_ENV=true +export CI=true # Colors for output RED='\033[0;31m' From 86b8ef440d05cd3b614504b1ac4cc0f7dbac780f Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sun, 1 Mar 2026 01:01:17 +0100 Subject: [PATCH 52/55] api is required for client connection --- supabase/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supabase/config.toml b/supabase/config.toml index 56005c04..768ff1ab 100644 --- a/supabase/config.toml +++ b/supabase/config.toml @@ -102,7 +102,7 @@ file_size_limit = "50MiB" # objects_path = "./images" [auth] -enabled = false +enabled = true # The base URL of your website. Used as an allow-list for redirects and for constructing URLs used # in emails. site_url = "http://127.0.0.1:3000" From 038b994102032b3541f2f65682fa32cf163a1dfc Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sun, 1 Mar 2026 01:05:52 +0100 Subject: [PATCH 53/55] Add safeguards for missing supabase env vars --- common/src/supabase/utils.ts | 1 + playwright.config.ts | 4 ++++ scripts/e2e.sh | 7 +++++++ scripts/e2e_services.sh | 7 +++++++ web/lib/supabase/db.ts | 2 +- 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/common/src/supabase/utils.ts b/common/src/supabase/utils.ts index e0463451..d6080565 100644 --- a/common/src/supabase/utils.ts +++ b/common/src/supabase/utils.ts @@ -29,6 +29,7 @@ export function createClient( key: string, opts?: SupabaseClientOptionsGeneric<'public'>, ) { + if (key === 'null') throw new Error(`Invalid supabase anon key: ${key}`) // Allow passing a full Supabase URL directly (e.g., http://localhost:54321) const url = /:\/\//.test(instanceIdOrUrl) ? instanceIdOrUrl diff --git a/playwright.config.ts b/playwright.config.ts index 18cb34a6..cbdc6cf2 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -10,12 +10,16 @@ function getSupabaseEnv() { try { const raw = execSync('npx supabase status --output json 2>/dev/null', {encoding: 'utf-8'}) const status = JSON.parse(raw) + if (!status.API_URL) throw new Error('No supabase API URL') + if (!status.ANON_KEY) throw new Error('No supabase ANON_KEY') + if (!status.DB_URL) throw new Error('No supabase DB_URL') return { NEXT_PUBLIC_SUPABASE_URL: status.API_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY: status.ANON_KEY, DATABASE_URL: status.DB_URL, } } catch (e) { + console.error(e) throw new Error('Failed to get Supabase status. Is it running?') } } diff --git a/scripts/e2e.sh b/scripts/e2e.sh index 7411e2f5..27353178 100755 --- a/scripts/e2e.sh +++ b/scripts/e2e.sh @@ -95,6 +95,13 @@ echo $NEXT_PUBLIC_SUPABASE_URL echo $NEXT_PUBLIC_SUPABASE_ANON_KEY echo $DATABASE_URL +for var in NEXT_PUBLIC_SUPABASE_URL NEXT_PUBLIC_SUPABASE_ANON_KEY DATABASE_URL; do + if [ -z "${!var}" ] || [ "${!var}" = "null" ]; then + echo "Error: $var is not set or null" >&2 + exit 1 + fi +done + # Start backend API print_status "Starting backend API..." yarn --cwd=backend/api dev & PIDS+=($!) diff --git a/scripts/e2e_services.sh b/scripts/e2e_services.sh index 98c87002..0e0bcd19 100755 --- a/scripts/e2e_services.sh +++ b/scripts/e2e_services.sh @@ -26,6 +26,13 @@ export NEXT_PUBLIC_SUPABASE_URL=$(echo "$STATUS_JSON" | jq -r '.API_URL') export NEXT_PUBLIC_SUPABASE_ANON_KEY=$(echo "$STATUS_JSON" | jq -r '.ANON_KEY') export DATABASE_URL=$(echo "$STATUS_JSON" | jq -r '.DB_URL') +for var in NEXT_PUBLIC_SUPABASE_URL NEXT_PUBLIC_SUPABASE_ANON_KEY DATABASE_URL; do + if [ -z "${!var}" ] || [ "${!var}" = "null" ]; then + echo "Error: $var is not set or null" >&2 + exit 1 + fi +done + # Build backend (required?) ./scripts/build_api.sh diff --git a/web/lib/supabase/db.ts b/web/lib/supabase/db.ts index d1e28cb3..7d9736e9 100644 --- a/web/lib/supabase/db.ts +++ b/web/lib/supabase/db.ts @@ -9,7 +9,7 @@ export function initSupabaseClient() { const anonKeyOverride = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || process.env.SUPABASE_ANON_KEY if (urlOverride && anonKeyOverride) { - console.log('Initializing Supabase client (env URL override)') + console.log('Initializing Supabase client (env URL override)', {urlOverride, anonKeyOverride}) return createClient(urlOverride, anonKeyOverride) } else if (process.env.NEXT_PUBLIC_ISOLATED_ENV) { throw new Error( From 07c91c7314593c1817f9de34421a60c1811e23ef Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sun, 1 Mar 2026 01:11:16 +0100 Subject: [PATCH 54/55] Remove echo --- scripts/combine-migrations.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/combine-migrations.sh b/scripts/combine-migrations.sh index fc018196..47eadc9a 100755 --- a/scripts/combine-migrations.sh +++ b/scripts/combine-migrations.sh @@ -72,7 +72,7 @@ while IFS= read -r file; do cat "$file" } > "$OUTPUT" - echo "✅ $file -> $OUTPUT" +# echo "✅ $file -> $OUTPUT" COUNTER=$((COUNTER + 100)) done <<< "$FILES" From dbc594d415fa9ad7a8574688f28a198205f0bc39 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sun, 1 Mar 2026 01:19:29 +0100 Subject: [PATCH 55/55] Remove supabase cache --- .github/workflows/ci-e2e.yml | 43 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci-e2e.yml b/.github/workflows/ci-e2e.yml index 8c82bf0f..22474414 100644 --- a/.github/workflows/ci-e2e.yml +++ b/.github/workflows/ci-e2e.yml @@ -61,31 +61,32 @@ jobs: - name: Install Playwright browsers run: npx playwright install chromium --with-deps - - name: Cache Supabase Docker images - uses: actions/cache@v4 - with: - path: /tmp/supabase-docker - key: supabase-docker-${{ hashFiles('supabase/config.toml') }} - - - name: Load cached Docker images - run: | - if [ -d /tmp/supabase-docker ]; then - for tar in /tmp/supabase-docker/*.tar; do - [ -f "$tar" ] && docker load -i "$tar" - done - fi + # Docker load from cache is actually slower than pulling the images every time with supabase start + # - name: Cache Supabase Docker images + # uses: actions/cache@v4 + # with: + # path: /tmp/supabase-docker + # key: supabase-docker-${{ hashFiles('supabase/config.toml') }} + # + # - name: Load cached Docker images + # run: | + # if [ -d /tmp/supabase-docker ]; then + # for tar in /tmp/supabase-docker/*.tar; do + # [ -f "$tar" ] && docker load -i "$tar" + # done + # fi - name: Start Supabase run: ./scripts/supabase_start.sh - - name: Save Supabase Docker images - run: | - mkdir -p /tmp/supabase-docker - docker images --format '{{.Repository}}:{{.Tag}}' \ - | grep -E 'supabase|postgrest|gotrue|realtime|storage' \ - | grep -v '' \ - | xargs -I{} sh -c \ - 'docker save {} -o /tmp/supabase-docker/$(echo {} | tr "/:" "--").tar' + # - name: Save Supabase Docker images + # run: | + # mkdir -p /tmp/supabase-docker + # docker images --format '{{.Repository}}:{{.Tag}}' \ + # | grep -E 'supabase|postgrest|gotrue|realtime|storage' \ + # | grep -v '' \ + # | xargs -I{} sh -c \ + # 'docker save {} -o /tmp/supabase-docker/$(echo {} | tr "/:" "--").tar' - name: Run E2E tests env: