From 7c447c8848b3be6bcbb410c7d2854379ce83e1b1 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Tue, 7 May 2024 17:29:54 +0700 Subject: [PATCH] Refactored e2e tests to use Promise.all for parallel execution In this update, several end-to-end (e2e) tests were refactored to use Promise.all for parallel execution of operations. This was done to improve the efficiency and stability of the tests, as waiting for each operation one by one could cause bottlenecks and potential failures in the test execution. Receives and click actions were grouped together to allow them to be executed concurrently where possible. The changes were applied across different test scenarios. --- apps/e2e/tests/account/account.po.ts | 38 ++++++++----- apps/e2e/tests/account/account.spec.ts | 34 ++++++----- apps/e2e/tests/authentication/auth.spec.ts | 21 ++++--- apps/e2e/tests/invitations/invitations.po.ts | 6 +- .../tests/team-accounts/team-accounts.po.ts | 57 ++++++++++++------- .../tests/team-accounts/team-accounts.spec.ts | 7 ++- 6 files changed, 105 insertions(+), 58 deletions(-) diff --git a/apps/e2e/tests/account/account.po.ts b/apps/e2e/tests/account/account.po.ts index 0c774e900..2ebe53e9a 100644 --- a/apps/e2e/tests/account/account.po.ts +++ b/apps/e2e/tests/account/account.po.ts @@ -32,13 +32,17 @@ export class AccountPageObject { email, ); - await this.page.click('[data-test="account-email-form"] button'); + const click = this.page.click('[data-test="account-email-form"] button'); - const req = await this.page.waitForResponse((resp) => { - return resp.url().includes('auth/v1/user'); - }); + const req = await this.page + .waitForResponse((resp) => { + return resp.url().includes('auth/v1/user'); + }) + .then((response) => { + expect(response.status()).toBe(200); + }); - expect(req.status()).toBe(200); + return Promise.all([click, req]); }).toPass(); } @@ -57,20 +61,28 @@ export class AccountPageObject { async deleteAccount() { await expect(async () => { await this.page.click('[data-test="delete-account-button"]'); + await this.page.fill( '[data-test="delete-account-input-field"]', 'DELETE', ); - await this.page.click('[data-test="confirm-delete-account-button"]'); - const response = await this.page.waitForResponse((resp) => { - return ( - resp.url().includes('home/settings') && - resp.request().method() === 'POST' - ); - }); + const click = this.page.click( + '[data-test="confirm-delete-account-button"]', + ); - expect(response.status()).toBe(204); + const response = await this.page + .waitForResponse((resp) => { + return ( + resp.url().includes('home/settings') && + resp.request().method() === 'POST' + ); + }) + .then((response) => { + expect(response.status()).toBe(303); + }); + + await Promise.all([click, response]); }).toPass(); } diff --git a/apps/e2e/tests/account/account.spec.ts b/apps/e2e/tests/account/account.spec.ts index f743c5114..21297fff8 100644 --- a/apps/e2e/tests/account/account.spec.ts +++ b/apps/e2e/tests/account/account.spec.ts @@ -16,12 +16,14 @@ test.describe('Account Settings', () => { test('user can update their profile name', async () => { const name = 'John Doe'; - await account.updateName(name); + const request = account.updateName(name); - await page.waitForResponse((resp) => { + const response = page.waitForResponse((resp) => { return resp.url().includes('accounts'); }); + await Promise.all([request, response]); + await expect(account.getProfileName()).toHaveText(name); }); @@ -34,12 +36,14 @@ test.describe('Account Settings', () => { test('user can update their password', async () => { const password = (Math.random() * 100000).toString(); - await account.updatePassword(password); + const request = account.updatePassword(password); - await page.waitForResponse((resp) => { + const response = page.waitForResponse((resp) => { return resp.url().includes('auth/v1/user'); }); + await Promise.all([request, response]); + await account.auth.signOut(); }); }); @@ -49,16 +53,20 @@ test.describe('Account Deletion', () => { const account = new AccountPageObject(page); await account.setup(); - await account.deleteAccount(); - const response = await page.waitForResponse((resp) => { - return ( - resp.url().includes('home/settings') && - resp.request().method() === 'POST' - ); - }); + const request = account.deleteAccount(); - // The server should respond with a 303 redirect - expect(response.status()).toBe(303); + const response = page + .waitForResponse((resp) => { + return ( + resp.url().includes('home/settings') && + resp.request().method() === 'POST' + ); + }) + .then((response) => { + expect(response.status()).toBe(303); + }); + + await Promise.all([request, response]); }); }); diff --git a/apps/e2e/tests/authentication/auth.spec.ts b/apps/e2e/tests/authentication/auth.spec.ts index 1e21835af..547cf1685 100644 --- a/apps/e2e/tests/authentication/auth.spec.ts +++ b/apps/e2e/tests/authentication/auth.spec.ts @@ -1,4 +1,5 @@ -import { test, expect } from '@playwright/test'; +import { expect, test } from '@playwright/test'; + import { AuthPageObject } from './auth.po'; test.describe('Auth flow', () => { @@ -14,19 +15,21 @@ test.describe('Auth flow', () => { console.log(`Signing up with email ${email} ...`); - await auth.signUp({ + const signUp = auth.signUp({ email, password: 'password', repeatPassword: 'password', }); - await page.waitForResponse(resp => { + const response = page.waitForResponse((resp) => { return resp.url().includes('auth'); }); + await Promise.all([signUp, response]); + await auth.visitConfirmEmailLink(email); - await page.waitForURL('http://localhost:3000/home'); + await page.waitForURL('**/home'); expect(page.url()).toContain('http://localhost:3000/home'); }); @@ -42,7 +45,7 @@ test.describe('Auth flow', () => { password: 'password', }); - await page.waitForURL('http://localhost:3000/home'); + await page.waitForURL('**/home'); expect(page.url()).toContain('/home'); @@ -53,15 +56,17 @@ test.describe('Auth flow', () => { }); test.describe('Protected routes', () => { - test('will redirect to the sign-in page if not authenticated', async ({ page }) => { + test('will redirect to the sign-in page if not authenticated', async ({ + page, + }) => { await page.goto('/home/settings'); expect(page.url()).toContain('/auth/sign-in?next=/home/settings'); }); test('will return a 404 for the admin page', async ({ page }) => { - await page.goto('/admin') + await page.goto('/admin'); expect(page.url()).toContain('/auth/sign-in'); }); -}) \ No newline at end of file +}); diff --git a/apps/e2e/tests/invitations/invitations.po.ts b/apps/e2e/tests/invitations/invitations.po.ts index 4aaa293b4..628296f53 100644 --- a/apps/e2e/tests/invitations/invitations.po.ts +++ b/apps/e2e/tests/invitations/invitations.po.ts @@ -111,16 +111,18 @@ export class InvitationsPageObject { async acceptInvitation() { console.log('Accepting invitation...'); - await this.page + const click = this.page .locator('[data-test="join-team-form"] button[type="submit"]') .click(); - await this.page.waitForResponse((response) => { + const response = this.page.waitForResponse((response) => { return ( response.url().includes('/join') && response.request().method() === 'POST' ); }); + + await Promise.all([click, response]); } private getInviteForm() { diff --git a/apps/e2e/tests/team-accounts/team-accounts.po.ts b/apps/e2e/tests/team-accounts/team-accounts.po.ts index 0b639e401..dbf9d1910 100644 --- a/apps/e2e/tests/team-accounts/team-accounts.po.ts +++ b/apps/e2e/tests/team-accounts/team-accounts.po.ts @@ -28,23 +28,31 @@ export class TeamAccountsPageObject { } goToSettings() { - return this.page - .locator('a', { - hasText: 'Settings', - }) - .click(); + return expect(async () => { + await this.page + .locator('a', { + hasText: 'Settings', + }) + .click(); + + await this.page.waitForURL('**/home/*/settings'); + }).toPass(); } goToBilling() { - return this.page - .locator('a', { - hasText: 'Billing', - }) - .click(); + return expect(async () => { + await this.page + .locator('a', { + hasText: 'Billing', + }) + .click(); + + return await this.page.waitForURL('**/home/*/billing'); + }).toPass(); } - async openAccountsSelector() { - await expect(async () => { + openAccountsSelector() { + return expect(async () => { await this.page.click('[data-test="account-selector-trigger"]'); return expect( @@ -58,9 +66,14 @@ export class TeamAccountsPageObject { await this.page.click('[data-test="create-team-account-trigger"]'); await this.page.fill('[data-test="create-team-form"] input', teamName); - await this.page.click('[data-test="create-team-form"] button:last-child'); - await this.page.waitForURL(`/home/${slug}`); + const click = this.page.click( + '[data-test="create-team-form"] button:last-child', + ); + + const response = this.page.waitForURL(`/home/${slug}`); + + await Promise.all([click, response]); } async updateName(name: string, slug: string) { @@ -70,14 +83,14 @@ export class TeamAccountsPageObject { name, ); - await this.page.click( + const click = this.page.click( '[data-test="update-team-account-name-form"] button', ); // the slug should be updated to match the new team name - await expect(this.page).toHaveURL( - `http://localhost:3000/home/${slug}/settings`, - ); + const response = this.page.waitForURL(`**/home/${slug}/settings`); + + return Promise.all([click, response]); }).toPass(); } @@ -94,9 +107,13 @@ export class TeamAccountsPageObject { teamName, ); - await this.page.click('[data-test="delete-team-form-confirm-button"]'); + const click = this.page.click( + '[data-test="delete-team-form-confirm-button"]', + ); - await this.page.waitForURL('http://localhost:3000/home'); + const response = this.page.waitForURL('**/home'); + + return Promise.all([click, response]); }).toPass(); } diff --git a/apps/e2e/tests/team-accounts/team-accounts.spec.ts b/apps/e2e/tests/team-accounts/team-accounts.spec.ts index 4c6c5e158..dd8f91d7a 100644 --- a/apps/e2e/tests/team-accounts/team-accounts.spec.ts +++ b/apps/e2e/tests/team-accounts/team-accounts.spec.ts @@ -17,10 +17,13 @@ test.describe('Team Accounts', () => { const { teamName, slug } = teamAccounts.createTeamName(); await teamAccounts.goToSettings(); - await teamAccounts.updateName(teamName, slug); + + const request = teamAccounts.updateName(teamName, slug); // the slug should be updated to match the new team name - await page.waitForURL(`http://localhost:3000/home/${slug}/settings`); + const newUrl = page.waitForURL(`**/home/${slug}/settings`); + + await Promise.all([request, newUrl]); await teamAccounts.openAccountsSelector();