From 699184081d7dab95e79c4ae8d3e759ceca45a0ec Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Fri, 29 May 2026 02:18:10 +0200 Subject: [PATCH] FIx E2E context manager --- playwright.config.ts | 2 +- tests/e2e/utils/contextManager.ts | 19 +++++-- tests/e2e/web/pages/app.ts | 15 ++++-- tests/e2e/web/pages/peoplePage.ts | 63 +++++++++++++---------- tests/e2e/web/specs/signIn.spec.ts | 83 ++++++++++++++++++------------ 5 files changed, 111 insertions(+), 71 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index ec94cf50..a568c83d 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -65,6 +65,6 @@ export default defineConfig({ ], timeout: 120000, expect: { - timeout: 120000, + timeout: 60000, }, }) diff --git a/tests/e2e/utils/contextManager.ts b/tests/e2e/utils/contextManager.ts index d1f061d2..dc056248 100644 --- a/tests/e2e/utils/contextManager.ts +++ b/tests/e2e/utils/contextManager.ts @@ -14,10 +14,15 @@ export class ContextManager { if (existing) await existing.page.context().close() const context = await this.browser.newContext() - const page = await context.newPage() - const app = new App(page) - this.contexts.set(name, app) - return app + try { + const page = await context.newPage() + const app = new App(page, false) + this.contexts.set(name, app) + return app + } catch (error) { + await context.close() + throw error + } } getContext(name: string): App | undefined { @@ -26,7 +31,11 @@ export class ContextManager { async closeAll(): Promise { for (const app of this.contexts.values()) { - await app.page.context().close() + try { + await app.page.context().close() + } catch { + // context may already be closed + } } this.contexts.clear() } diff --git a/tests/e2e/web/pages/app.ts b/tests/e2e/web/pages/app.ts index b684dc4c..148afe0d 100644 --- a/tests/e2e/web/pages/app.ts +++ b/tests/e2e/web/pages/app.ts @@ -28,10 +28,13 @@ export class App { readonly people: PeoplePage readonly notifs: NotificationPage readonly messages: MessagesPage - readonly contextManager: ContextManager + readonly contextManager: ContextManager | undefined readonly context: BrowserContext - constructor(public readonly page: Page) { + constructor( + public readonly page: Page, + createContextManager = true, + ) { this.auth = new AuthPage(page) this.compatibility = new CompatibilityPage(page) this.home = new HomePage(page) @@ -46,9 +49,11 @@ export class App { this.messages = new MessagesPage(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) + if (createContextManager) { + 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/pages/peoplePage.ts b/tests/e2e/web/pages/peoplePage.ts index 50ff146d..b2c5bb42 100644 --- a/tests/e2e/web/pages/peoplePage.ts +++ b/tests/e2e/web/pages/peoplePage.ts @@ -1,17 +1,18 @@ import {expect, Locator, Page} from '@playwright/test' import { - ConnectionTypeTuple, - EducationTuple, - DietTuple, - PsychedelicsTuple, CannabisTuple, - LanguageTuple, - PoliticalTuple, - ReligionTuple, - PersonalityKey, - LastActiveTuple, + ConnectionTypeTuple, + DietTuple, + EducationTuple, InterestedInGenderTuple, + LanguageTuple, + LastActiveTuple, + PersonalityKey, + PoliticalTuple, + PsychedelicsTuple, + ReligionTuple, } from 'common/choices' + import {MinMaxNumbers} from '../utils/accountInformation' export type BackgroundFilter = { @@ -459,22 +460,7 @@ export class PeoplePage { if (totalResults === 0) throw Error('No profiles found') const chosenProfileNumber = Math.floor(Math.random() * totalResults) const chosenProfile = await this.profileResults.nth(chosenProfileNumber) - const profileName = await chosenProfile.getByTestId('people-profile-name').textContent() - const ageGender = await chosenProfile.getByTestId('people-profile-age-gender').textContent() - const seekingInfo = await chosenProfile.getByTestId('people-profile-seeking').textContent() - const hideProfile = await chosenProfile.getByTestId('hide-profile-button') - const starProfile = await chosenProfile.getByTestId('star-profile-button') - const messageProfile = await chosenProfile.getByTestId('message-profile-button') - - return { - profile: chosenProfile ?? '', - name: profileName ?? '', - ageGender: ageGender ?? '', - seeking: seekingInfo ?? '', - hide: hideProfile ?? '', - star: starProfile ?? '', - message: messageProfile ?? '', - } + return chosenProfile } async verifyProfileCount(totalProfiles: string) { @@ -512,7 +498,8 @@ export class PeoplePage { } } - async verifySavedPerson(displayName: string) { + async verifySavedPerson(displayName: string | null | undefined) { + if (!displayName) throw new Error('No display name provided') await expect(this.savedPeopleHeading).toBeVisible() await this.page.waitForTimeout(1000) const isThereSavedPeople = (await this.savedPeopleList.count()) > 0 @@ -530,3 +517,27 @@ export class PeoplePage { } } } + +export async function getCardName(profile: Locator) { + return await profile.getByTestId('people-profile-name').textContent() +} + +export async function getCardAgeGender(profile: Locator) { + return await profile.getByTestId('people-profile-age-gender').textContent() +} + +export async function getCardSeekingInfo(profile: Locator) { + return await profile.getByTestId('people-profile-seeking').textContent() +} + +export async function getCardHide(profile: Locator) { + return await profile.getByTestId('hide-profile-button') +} + +export async function getCardStar(profile: Locator) { + return await profile.getByTestId('star-profile-button') +} + +export async function getCardMessage(profile: Locator) { + return await profile.getByTestId('message-profile-button') +} diff --git a/tests/e2e/web/specs/signIn.spec.ts b/tests/e2e/web/specs/signIn.spec.ts index b5cad8d9..151451ff 100644 --- a/tests/e2e/web/specs/signIn.spec.ts +++ b/tests/e2e/web/specs/signIn.spec.ts @@ -2,6 +2,7 @@ import {sleep} from 'common/util/time' import {TEST_USER_DISPLAY_NAME} from '../../utils/seedDatabase' import {expect, test} from '../fixtures/signInFixture' +import {getCardAgeGender, getCardName, getCardSeekingInfo, getCardStar} from '../pages/peoplePage' test.describe('when given valid input', () => { test('should be able to sign in to an available account', async ({ @@ -17,11 +18,13 @@ test.describe('when given valid input', () => { await app.signinWithEmail(account) await app.home.clickPeopleLink() const profile = await app.people.getProfileInfo() - await expect(profile.star).toBeVisible() - await profile.star.click() + const star = await getCardStar(profile) + const name = await getCardName(profile) + await expect(star).toBeVisible() + await star.click() await sleep(1000) await app.people.clickSavedPeopleButton() - await app.people.verifySavedPerson(profile.name) + await app.people.verifySavedPerson(name) }) test.describe('the applied filter should', () => { @@ -42,9 +45,10 @@ test.describe('when given valid input', () => { Number(filteredProfiles?.split(' ')[0]), ) - const results = await app.people.getProfileInfo() - if (!results) return - await expect(results.seeking).toContain('Collaboration') + const profile = await app.people.getProfileInfo() + if (!profile) throw new Error('No profile found') + const seeking = await getCardSeekingInfo(profile) + await expect(seeking).toContain('Collaboration') }) /** @@ -57,17 +61,19 @@ test.describe('when given valid input', () => { await app.people.setDisplayFilter({filters: {Age: true}}) const totalProfiles = await app.people.profileCountLocator.textContent() - const profileResults = await app.people.getProfileInfo() - const profileAge = parseInt(profileResults.ageGender.match(/\d+/)?.[0] ?? '0') + const profile = await app.people.getProfileInfo() + const ageGender = await getCardAgeGender(profile) + if (!ageGender) throw new Error('Age not found') + const profileAge = parseInt(ageGender.match(/\d+/)?.[0] ?? '0') const age = profileAge <= 60 ? profileAge : 60 - console.log(profileResults, age) + console.log(profile, age) await app.people.setAgeRangeFilter({min: String(age), max: String(age)}) - const filterdProfiles = await app.people.profileCountLocator.textContent() + const filteredProfiles = await app.people.profileCountLocator.textContent() - if (!totalProfiles || !filterdProfiles) return - await expect(parseInt(totalProfiles)).not.toEqual(parseInt(filterdProfiles)) + if (!totalProfiles || !filteredProfiles) return + await expect(parseInt(totalProfiles)).not.toEqual(parseInt(filteredProfiles)) }) test('show profiles with the correct gender', async ({app, signedOutAccount: account}) => { @@ -185,36 +191,41 @@ test.describe('when given valid input', () => { await app.home.clickPeopleLink() await app.people.useSearch(TEST_USER_DISPLAY_NAME) await sleep(1000) - const results = await app.people.getProfileInfo() - console.log(results) - const hideProfileButton = await results.profile.getByRole('button', { + const profile = await app.people.getProfileInfo() + if (!profile) throw new Error('Profile not found') + const name = await getCardName(profile) + console.log(profile) + const hideProfileButton = profile.getByRole('button', { name: 'Hide this profile', }) await expect(hideProfileButton).toBeVisible() await hideProfileButton.click() await expect( - app.page.getByText(`You won't see ${results.name} in your search results anymore.`), + app.page.getByText(`You won't see ${name} in your search results anymore.`), ).toBeVisible() }) test('should be reversible using undo', async ({app, signedOutAccount: account}) => { await app.signinWithEmail(account) await app.home.clickPeopleLink() - const results = await app.people.getProfileInfo() - if (!results) return - const hideProfileButton = await results.profile.getByRole('button', { + await app.people.useSearch(TEST_USER_DISPLAY_NAME) + await sleep(1000) + const profile = await app.people.getProfileInfo() + if (!profile) throw new Error('Profile not found') + const name = await getCardName(profile) + const hideProfileButton = profile.getByRole('button', { name: 'Hide this profile', }) await expect(hideProfileButton).toBeVisible() await hideProfileButton.click() - const hideProfileMessage = await app.page.getByText( - `You won't see ${results.name} in your search results anymore.`, + const hideProfileMessage = app.page.getByText( + `You won't see ${name} in your search results anymore.`, ) await expect(hideProfileMessage).toBeVisible() await app.people.page.getByRole('button', {name: 'Undo'}).click() await expect(hideProfileMessage).not.toBeVisible() - const profile = await app.people.page.getByRole('heading', {name: `${results.name}`}) - await expect(profile).toBeVisible() + const undoProfile = app.people.page.getByRole('heading', {name: `${name}`}) + await expect(undoProfile).toBeVisible() }) test('should be reversible using manage hidden profiles feature in settings', async ({ @@ -223,25 +234,29 @@ test.describe('when given valid input', () => { }) => { await app.signinWithEmail(account) await app.home.clickPeopleLink() - const results = await app.people.getProfileInfo() - if (!results) return - const hideProfileButton = await results.profile.getByRole('button', { + await app.people.useSearch(TEST_USER_DISPLAY_NAME) + await sleep(1000) + const profile = await app.people.getProfileInfo() + if (!profile) throw new Error('Profile not found') + const name = await getCardName(profile) + if (!name) throw new Error('Name not found') + const hideProfileButton = profile.getByRole('button', { name: 'Hide this profile', }) await expect(hideProfileButton).toBeVisible() await hideProfileButton.click() - const hideProfileMessage = await app.page.getByText( - `You won't see ${results.name} in your search results anymore.`, + const hideProfileMessage = app.page.getByText( + `You won't see ${name} in your search results anymore.`, ) await expect(hideProfileMessage).toBeVisible() await app.home.clickSettingsLink() await app.settings.clickManageHiddenProfilesButton() - await app.settings.verifyHiddenProfiles([results.name]) - await app.settings.unhideProfiles(results.name) + await app.settings.verifyHiddenProfiles([name]) + await app.settings.unhideProfiles(name) await app.settings.clickCloseButton() await app.home.clickPeopleLink() - const profile = await app.people.page.getByRole('heading', {name: `${results.name}`}) - await expect(profile).toBeVisible() + const undoProfile = app.people.page.getByRole('heading', {name: `${name}`}) + await expect(undoProfile).toBeVisible() }) }) @@ -252,7 +267,7 @@ test.describe('when given valid input', () => { signedInAccount: sender, signedOutAccount: receiver, }) => { - const receiverApp = await app.contextManager.createContext() + const receiverApp = await app.contextManager!.createContext() await receiverApp.signinWithEmail(receiver) await app.home.clickMessagesLink() @@ -269,7 +284,7 @@ test.describe('when given valid input', () => { signedInAccount: sender, signedOutAccount: receiver, }) => { - const receiverApp = await app.contextManager.createContext() + const receiverApp = await app.contextManager!.createContext() await receiverApp.signinWithEmail(receiver) // To pass the min character limit for message intro (250 chars)