From 00e7662d609483538813d4db1c31d5215ec2ddca Mon Sep 17 00:00:00 2001 From: Okechi Jones-Williams Date: Wed, 27 May 2026 20:01:43 +0100 Subject: [PATCH] Added a context manager to test with multiple accounts interacting with each other Added an option to verify the users email when creating an account --- tests/e2e/utils/contextManager.ts | 27 ++++++++++++ tests/e2e/utils/firebaseUtils.ts | 30 +++++++++++++ tests/e2e/utils/seedDatabase.ts | 4 +- tests/e2e/web/SPEC_CONFIG.ts | 3 ++ tests/e2e/web/fixtures/signInFixture.ts | 43 ++++++++++++++++++- tests/e2e/web/pages/app.ts | 10 ++++- .../web/specs/firebaseAccountCreationTest.ts | 26 ++++++++--- tests/e2e/web/specs/signIn.spec.ts | 12 ++++++ 8 files changed, 145 insertions(+), 10 deletions(-) create mode 100644 tests/e2e/utils/contextManager.ts diff --git a/tests/e2e/utils/contextManager.ts b/tests/e2e/utils/contextManager.ts new file mode 100644 index 00000000..33f9dbec --- /dev/null +++ b/tests/e2e/utils/contextManager.ts @@ -0,0 +1,27 @@ +import {Browser, BrowserContext} from '@playwright/test' +import {App} from '../web/pages/app' + +export class ContextManager { + private contexts: Map = new Map() + + constructor(private browser: Browser) {} + + async createContext(name: string): Promise { + const context = await this.browser.newContext() + const page = await context.newPage() + const app = new App(page) + this.contexts.set(name, app) + return app + } + + getContext(name: string): App | undefined { + return this.contexts.get(name) + } + + async closeAll(): Promise { + for (const app of this.contexts.values()) { + await app.page.context().close() + } + this.contexts.clear() + } +} diff --git a/tests/e2e/utils/firebaseUtils.ts b/tests/e2e/utils/firebaseUtils.ts index c3dd114e..0fedeb7c 100644 --- a/tests/e2e/utils/firebaseUtils.ts +++ b/tests/e2e/utils/firebaseUtils.ts @@ -37,6 +37,36 @@ export async function findUser(idToken: string) { } } +export async function sendVerificationEmail(idToken: string) { + await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.SEND_EMAIL_VERIFICATION}`, { + requestType: 'VERIFY_EMAIL', + idToken, + }) +} +export async function getOobCode(oobCodes: any[], email: string) { + return oobCodes.find((item) => item.email.toLowerCase() === email.toLowerCase())?.oobCode +} + +export async function verifyEmail(email: string, password: string) { + try { + const loginInfo = await firebaseLoginEmailPassword(email, password) + await sendVerificationEmail(loginInfo.data.idToken) + const oobResponse = await axios.get(`${config.FIREBASE_URL.FIREBASE_EMULATOR_API}`) + const oobCode = await getOobCode(oobResponse.data.oobCodes, email) + console.log(oobCode) + + const response = await axios.post( + `${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.CONFIRM_EMAIL_VERIFICATION}`, + { + oobCode, + }, + ) + } catch (err: any) { + console.log(err) + throw err + } +} + export async function firebaseSignUp(email: string, password: string) { try { const response = await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.SIGNUP}`, { diff --git a/tests/e2e/utils/seedDatabase.ts b/tests/e2e/utils/seedDatabase.ts index f6524346..a9c9a4ea 100644 --- a/tests/e2e/utils/seedDatabase.ts +++ b/tests/e2e/utils/seedDatabase.ts @@ -9,7 +9,7 @@ import {insert} from 'shared/supabase/utils' import {getUser} from 'shared/utils' import UserAccountInformationForSeeding from '../backend/utils/userInformation' -import {firebaseSignUp} from './firebaseUtils' +import {firebaseSignUp, verifyEmail} from './firebaseUtils' /** * Function used to populate the database with profiles. @@ -151,6 +151,7 @@ export async function seedUser( profileType?: string | undefined, displayName?: string | undefined, userName?: string | undefined, + verifyUserEmail?: boolean, ) { const userInfo = new UserAccountInformationForSeeding() if (email) userInfo.email = email @@ -162,4 +163,5 @@ export async function seedUser( // Fall back to the pre-generated faker id when Firebase is unreachable const created = await seedDbUser(userInfo, profileType ?? 'full') if (created) debug('User created in Supabase:', userInfo.email) + if (verifyUserEmail) await verifyEmail(userInfo.email, userInfo.password) } diff --git a/tests/e2e/web/SPEC_CONFIG.ts b/tests/e2e/web/SPEC_CONFIG.ts index 3b08779b..38bd3a8d 100644 --- a/tests/e2e/web/SPEC_CONFIG.ts +++ b/tests/e2e/web/SPEC_CONFIG.ts @@ -2,10 +2,13 @@ export const config = { BASE_URL: 'http://localhost:3000', FIREBASE_URL: { BASE: 'http://localhost:9099/identitytoolkit.googleapis.com/v1', + FIREBASE_EMULATOR_API: 'http://localhost:9099/emulator/v1/projects/compass-57c3c/oobCodes', SIGNUP: '/accounts:signUp?key=fake-api-key', SIGN_IN_PASSWORD: '/accounts:signInWithPassword?key=fake-api-key', ACCOUNT_LOOKUP: '/accounts:lookup?key=fake-api-key', DELETE: '/accounts:delete?key=fake-api-key', + SEND_EMAIL_VERIFICATION: '/accounts:sendOobCode?key=fake-api-key', + CONFIRM_EMAIL_VERIFICATION: '/accounts:update?key=fake-api-key', }, USERS: { DEV_1: { diff --git a/tests/e2e/web/fixtures/signInFixture.ts b/tests/e2e/web/fixtures/signInFixture.ts index a55ecbdc..fa30f5be 100644 --- a/tests/e2e/web/fixtures/signInFixture.ts +++ b/tests/e2e/web/fixtures/signInFixture.ts @@ -7,7 +7,9 @@ import {deleteUser} from '../utils/deleteUser' export const test = base.extend<{ app: App - dev_one_account: UserAccountInformation + devOneAccount: UserAccountInformation + devTwoAccount: UserAccountInformation + specAccount: UserAccountInformation fakerAccount: UserAccountInformation googleAccountOne: UserAccountInformation googleAccountTwo: UserAccountInformation @@ -43,6 +45,45 @@ export const test = base.extend<{ await use(account) await deleteUser('Email/Password', account) }, + devOneAccount: async ({}, use) => { + const account = testAccounts.dev_one_account() + await seedUser( + account.email, + account.password, + undefined, + account.display_name, + account.username, + true, + ) + await use(account) + await deleteUser('Email/Password', account) + }, + devTwoAccount: async ({}, use) => { + const account = testAccounts.dev_two_account() + await seedUser( + account.email, + account.password, + undefined, + account.display_name, + account.username, + true, + ) + await use(account) + await deleteUser('Email/Password', account) + }, + specAccount: async ({}, use) => { + const account = testAccounts.spec_account() + await seedUser( + account.email, + account.password, + undefined, + account.display_name, + account.username, + true, + ) + await use(account) + await deleteUser('Email/Password', account) + }, fakerAccount: async ({}, use) => { const account = testAccounts.faker_account() await use(account) diff --git a/tests/e2e/web/pages/app.ts b/tests/e2e/web/pages/app.ts index 49048762..da66dec9 100644 --- a/tests/e2e/web/pages/app.ts +++ b/tests/e2e/web/pages/app.ts @@ -1,6 +1,7 @@ -import {Page} from '@playwright/test' +import {BrowserContext, Page} from '@playwright/test' import {UserAccountInformation} from '../utils/accountInformation' +import {ContextManager} from '../../utils/contextManager' import {AuthPage} from './authPage' import {CompatibilityPage} from './compatibilityPage' import {HomePage} from './homePage' @@ -25,6 +26,8 @@ export class App { readonly social: SocialPage readonly people: PeoplePage readonly notifs: NotificationPage + readonly contextManager: ContextManager + readonly context: BrowserContext constructor(public readonly page: Page) { this.auth = new AuthPage(page) @@ -38,6 +41,11 @@ export class App { this.social = new SocialPage(page) this.people = new PeoplePage(page) this.notifs = new NotificationPage(page) + this.context = page.context() + + const browser = page.context().browser() + if (!browser) throw new Error('Could not get Browser from page.context().browser()') + this.contextManager = new ContextManager(browser) } async deleteProfileFromSettings() { diff --git a/tests/e2e/web/specs/firebaseAccountCreationTest.ts b/tests/e2e/web/specs/firebaseAccountCreationTest.ts index 964b32dd..c4688b17 100644 --- a/tests/e2e/web/specs/firebaseAccountCreationTest.ts +++ b/tests/e2e/web/specs/firebaseAccountCreationTest.ts @@ -1,15 +1,27 @@ import axios from 'axios' import {config} from '../SPEC_CONFIG' +import { + firebaseLoginEmailPassword, + getOobCode, + getUserId, + sendVerificationEmail, +} from '../../utils/firebaseUtils' async function setup() { - const results = await axios.post(`${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.SIGNUP}`, { - email: 'trial_test@email.com', - password: 'trialTestPassword', - returnSecureToken: true, - }) + const loginInfo = await firebaseLoginEmailPassword('AnotherTest@email.com', 'Password') + await sendVerificationEmail(loginInfo.data.idToken) + const oobResponse = await axios.get(`${config.FIREBASE_URL.FIREBASE_EMULATOR_API}`) + const oobCode = await getOobCode(oobResponse.data.oobCodes, 'AnotherTest@email.com') + console.log(oobCode) - console.log('Auth created: ', 'trial_test@email.com') - console.log('Id: ', results.data.localId) + const response = await axios.post( + `${config.FIREBASE_URL.BASE}${config.FIREBASE_URL.CONFIRM_EMAIL_VERIFICATION}`, + { + oobCode, + }, + ) + console.log(response) + console.log(response.status) } setup() diff --git a/tests/e2e/web/specs/signIn.spec.ts b/tests/e2e/web/specs/signIn.spec.ts index 00813de9..2f1e2d0d 100644 --- a/tests/e2e/web/specs/signIn.spec.ts +++ b/tests/e2e/web/specs/signIn.spec.ts @@ -1,4 +1,5 @@ import {expect, test} from '../fixtures/signInFixture' +import {ContextManager} from '../../utils/contextManager' test.describe('when given valid input', () => { test('should be able to sign in to an available account', async ({ @@ -223,6 +224,17 @@ test.describe('when given valid input', () => { await expect(profile).toBeVisible() }) }) + + test.describe('a verified account should', () => { + test('be able to send a message', async ({app, devOneAccount, devTwoAccount}) => { + const devOne = await app.contextManager.createContext('devOne') + const devTwo = await app.contextManager.createContext('devTwo') + await devOne.signinWithEmail(devOneAccount) + await devOne.home.clickPeopleLink() + await devTwo.signinWithEmail(devTwoAccount) + await devTwo.home.clickPeopleLink() + }) + }) }) test.describe('when given invalid input', () => {