From 229391b745404876e63e7492ba74dbfdca0dbd00 Mon Sep 17 00:00:00 2001 From: n3c777 Date: Wed, 12 Nov 2025 00:56:03 -0800 Subject: [PATCH 1/7] Add basic test for login and auth state --- .gitignore | 1 + playwright.config.ts | 16 ++++++++-- tests/e2e/web/.auth/.keep | 0 tests/e2e/web/config.ts | 4 +++ tests/e2e/web/pageManager/.keep | 0 tests/e2e/web/pages/.keep | 0 tests/e2e/web/pages/login-page.ts | 41 +++++++++++++++++++++++++ tests/e2e/web/specs/.keep | 0 tests/e2e/web/specs/login.setup.spec.ts | 36 ++++++++++++++++++++++ tests/e2e/web/specs/some.test.ts | 9 ------ tests/e2e/web/specs/test.spec.ts | 6 ++++ 11 files changed, 101 insertions(+), 12 deletions(-) delete mode 100644 tests/e2e/web/.auth/.keep create mode 100644 tests/e2e/web/config.ts delete mode 100644 tests/e2e/web/pageManager/.keep delete mode 100644 tests/e2e/web/pages/.keep create mode 100644 tests/e2e/web/pages/login-page.ts delete mode 100644 tests/e2e/web/specs/.keep create mode 100644 tests/e2e/web/specs/login.setup.spec.ts delete mode 100644 tests/e2e/web/specs/some.test.ts create mode 100644 tests/e2e/web/specs/test.spec.ts diff --git a/.gitignore b/.gitignore index 29d68d4d..43825ce1 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ # Playwright /tests/reports/playwright-report +/tests/e2e/web/.auth/ # next.js /.next/ diff --git a/playwright.config.ts b/playwright.config.ts index 88f48476..7fe315bd 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,4 +1,5 @@ import { defineConfig, devices } from '@playwright/test'; +import path from 'path'; export default defineConfig({ testDir: './tests/e2e', @@ -6,15 +7,23 @@ export default defineConfig({ forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, - reporter: [['html', {outputFolder: `tests/reports/playwright-report`, open: 'on-falure'}]], + reporter: [['html', { outputFolder: `tests/reports/playwright-report`, open: 'on-failure' }]], use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry', }, projects: [ + { + name: 'setup', + testMatch: /.*login\.spec\.ts/, + }, { name: 'chromium', - use: { ...devices['Desktop Chrome'] }, + use: { + ...devices['Desktop Chrome'], + storageState: path.resolve(__dirname, 'tests/e2e/web/.auth/user.json'), + }, + dependencies: ['setup'], }, // { // name: 'firefox', @@ -25,4 +34,5 @@ export default defineConfig({ // use: { ...devices['Desktop Safari'] }, // }, ], -}); \ No newline at end of file + +}); diff --git a/tests/e2e/web/.auth/.keep b/tests/e2e/web/.auth/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/e2e/web/config.ts b/tests/e2e/web/config.ts new file mode 100644 index 00000000..5b26e2a1 --- /dev/null +++ b/tests/e2e/web/config.ts @@ -0,0 +1,4 @@ +export const config = { + BASE_URL: 'http://localhost:3000', + DEFAULT_LOGIN: 'defaultUser@dev.com', + DEFAULT_PASSWORD: 'defaultPassword',}; \ No newline at end of file diff --git a/tests/e2e/web/pageManager/.keep b/tests/e2e/web/pageManager/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/e2e/web/pages/.keep b/tests/e2e/web/pages/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/e2e/web/pages/login-page.ts b/tests/e2e/web/pages/login-page.ts new file mode 100644 index 00000000..f46e64b0 --- /dev/null +++ b/tests/e2e/web/pages/login-page.ts @@ -0,0 +1,41 @@ +import { expect, Locator, Page } from '@playwright/test'; + +export class LoginPage{ +private readonly signInLink: Locator; +private readonly emailField: Locator; +private readonly passwordField: Locator; +private readonly signInWithEmailButton: Locator; +private readonly signInWithGoogleButton: Locator; + +constructor(public readonly page: Page) { + this.signInLink=page.getByRole('link', { name: 'Sign in' }); + this.emailField=page.getByLabel('Email'); + this.passwordField=page.getByLabel('Password'); + this.signInWithEmailButton=page.getByRole('button',{name: 'Sign in With Email'}); + this.signInWithGoogleButton=page.getByRole('button',{name: 'Google'}); +} + +async clickSignInText() { + await this.signInLink.click(); +} + +async clickSignInWithEmailButton() { + await this.signInWithEmailButton.click(); +} + +async clickSignInWithEGoogleButton() { + await this.signInWithGoogleButton.click(); +} + +async fillEmailField(email: string) { + await expect(this.emailField).toBeVisible(); + await this.emailField.fill(email); +} + +async fillPasswprdField(password: string) { + await expect(this.passwordField).toBeVisible(); + await this.passwordField.fill(password); +} + +} + diff --git a/tests/e2e/web/specs/.keep b/tests/e2e/web/specs/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/e2e/web/specs/login.setup.spec.ts b/tests/e2e/web/specs/login.setup.spec.ts new file mode 100644 index 00000000..efcda823 --- /dev/null +++ b/tests/e2e/web/specs/login.setup.spec.ts @@ -0,0 +1,36 @@ +import { test as base, expect } from '@playwright/test'; +import path from 'path'; +import { LoginPage } from '../pages/login-page'; +import { config } from '../config'; + +const test = base.extend<{ loginPage: LoginPage }>({ + loginPage: async ({ page }, use) => { + const loginPage = new LoginPage(page); + await use(loginPage); + }, +}); + +test('Login test', async ({ loginPage, page }) => { + await test.step('Navigated to login page', async () => { + await page.goto('/'); + }); + await test.step( + 'Logging in '.concat(page.url(), ' as ', config.DEFAULT_LOGIN), + async () => { + await page.waitForLoadState('networkidle'); + await loginPage.clickSignInText(); + await loginPage.fillEmailField(config.DEFAULT_LOGIN); + await loginPage.fillPasswprdField(config.DEFAULT_PASSWORD); + await page.waitForLoadState('networkidle'); + await loginPage.clickSignInWithEmailButton(); + await expect(page.getByText(/Sign in to your account/)).not.toBeVisible(); + }, + ); + +await test.step('Saved auth state', async () => { + await page.context().storageState({ + path: path.resolve(__dirname, '..', '.auth', 'user.json'), + }); +}); + +}); diff --git a/tests/e2e/web/specs/some.test.ts b/tests/e2e/web/specs/some.test.ts deleted file mode 100644 index 1e7e2c40..00000000 --- a/tests/e2e/web/specs/some.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {expect, test} from '@playwright/test'; - -test('shows', async ({page}) => { - await page.goto('/'); // Adjust this to your route - expect(await page.title()).toBe('Compass'); - // - // const spinner = page.locator('[data-testid="spinner"]'); - // await expect(spinner).toBeVisible(); -}); diff --git a/tests/e2e/web/specs/test.spec.ts b/tests/e2e/web/specs/test.spec.ts new file mode 100644 index 00000000..e5b9e844 --- /dev/null +++ b/tests/e2e/web/specs/test.spec.ts @@ -0,0 +1,6 @@ +import { test, expect } from '@playwright/test'; + +test('should be logged in and see the dashboard', async ({ page }) => { + await page.goto('/Organization'); + await expect(page.getByRole('link', {name: 'Organization'} )).toBeVisible(); +}); \ No newline at end of file From d0c0bd1a5efea5d7b61c5f708f77db9c62054716 Mon Sep 17 00:00:00 2001 From: n3c777 Date: Wed, 12 Nov 2025 00:59:13 -0800 Subject: [PATCH 2/7] Remove test file --- tests/e2e/web/specs/test.spec.ts | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 tests/e2e/web/specs/test.spec.ts diff --git a/tests/e2e/web/specs/test.spec.ts b/tests/e2e/web/specs/test.spec.ts deleted file mode 100644 index e5b9e844..00000000 --- a/tests/e2e/web/specs/test.spec.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { test, expect } from '@playwright/test'; - -test('should be logged in and see the dashboard', async ({ page }) => { - await page.goto('/Organization'); - await expect(page.getByRole('link', {name: 'Organization'} )).toBeVisible(); -}); \ No newline at end of file From 39b7a302b061c1dcbdf55a77cf70d7ec504d20ef Mon Sep 17 00:00:00 2001 From: n3c777 Date: Wed, 12 Nov 2025 22:29:16 -0800 Subject: [PATCH 3/7] Change login setup --- playwright.config.ts | 9 +++- tests/e2e/web/TESTING_CONFIG.ts | 10 ++++ tests/e2e/web/config.ts | 4 -- .../pages/{login-page.ts => signInPage.ts} | 3 +- tests/e2e/web/specs/login.setup.spec.ts | 36 ------------- tests/e2e/web/specs/postSetup.spec.ts | 8 +++ tests/e2e/web/specs/setup.ts | 51 +++++++++++++++++++ tests/e2e/web/specs/signIn.preSetup.spec.ts | 31 +++++++++++ 8 files changed, 109 insertions(+), 43 deletions(-) create mode 100644 tests/e2e/web/TESTING_CONFIG.ts delete mode 100644 tests/e2e/web/config.ts rename tests/e2e/web/pages/{login-page.ts => signInPage.ts} (93%) delete mode 100644 tests/e2e/web/specs/login.setup.spec.ts create mode 100644 tests/e2e/web/specs/postSetup.spec.ts create mode 100644 tests/e2e/web/specs/setup.ts create mode 100644 tests/e2e/web/specs/signIn.preSetup.spec.ts diff --git a/playwright.config.ts b/playwright.config.ts index 7fe315bd..2fb7fbb5 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -13,16 +13,21 @@ export default defineConfig({ trace: 'on-first-retry', }, projects: [ + { + name: 'preSetup', + testMatch: /.*preSetup\.ts/, + }, { name: 'setup', - testMatch: /.*login\.spec\.ts/, + testMatch: /.*setup\.ts/, }, { - name: 'chromium', + name: 'postSetup', use: { ...devices['Desktop Chrome'], storageState: path.resolve(__dirname, 'tests/e2e/web/.auth/user.json'), }, + testIgnore: [/.*preSetup\.ts/, /.*setup\.ts/], dependencies: ['setup'], }, // { diff --git a/tests/e2e/web/TESTING_CONFIG.ts b/tests/e2e/web/TESTING_CONFIG.ts new file mode 100644 index 00000000..2fccb801 --- /dev/null +++ b/tests/e2e/web/TESTING_CONFIG.ts @@ -0,0 +1,10 @@ +import { DEV_CONFIG } from '../../../common/src/envs/dev'; + +const FIREBASE_API_KEY = DEV_CONFIG.firebaseConfig.apiKey; + +export const config = { + BASE_URL: 'http://localhost:3000', + DEFAULT_LOGIN: 'defaultUser@dev.com', + DEFAULT_PASSWORD: 'defaultPassword', + FIREBASE_AUTH_URL: `https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${FIREBASE_API_KEY}`, +}; \ No newline at end of file diff --git a/tests/e2e/web/config.ts b/tests/e2e/web/config.ts deleted file mode 100644 index 5b26e2a1..00000000 --- a/tests/e2e/web/config.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const config = { - BASE_URL: 'http://localhost:3000', - DEFAULT_LOGIN: 'defaultUser@dev.com', - DEFAULT_PASSWORD: 'defaultPassword',}; \ No newline at end of file diff --git a/tests/e2e/web/pages/login-page.ts b/tests/e2e/web/pages/signInPage.ts similarity index 93% rename from tests/e2e/web/pages/login-page.ts rename to tests/e2e/web/pages/signInPage.ts index f46e64b0..623fe6eb 100644 --- a/tests/e2e/web/pages/login-page.ts +++ b/tests/e2e/web/pages/signInPage.ts @@ -1,6 +1,7 @@ import { expect, Locator, Page } from '@playwright/test'; -export class LoginPage{ +//sets up of all the functions that signin tests will use. +export class SignInPage{ private readonly signInLink: Locator; private readonly emailField: Locator; private readonly passwordField: Locator; diff --git a/tests/e2e/web/specs/login.setup.spec.ts b/tests/e2e/web/specs/login.setup.spec.ts deleted file mode 100644 index efcda823..00000000 --- a/tests/e2e/web/specs/login.setup.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { test as base, expect } from '@playwright/test'; -import path from 'path'; -import { LoginPage } from '../pages/login-page'; -import { config } from '../config'; - -const test = base.extend<{ loginPage: LoginPage }>({ - loginPage: async ({ page }, use) => { - const loginPage = new LoginPage(page); - await use(loginPage); - }, -}); - -test('Login test', async ({ loginPage, page }) => { - await test.step('Navigated to login page', async () => { - await page.goto('/'); - }); - await test.step( - 'Logging in '.concat(page.url(), ' as ', config.DEFAULT_LOGIN), - async () => { - await page.waitForLoadState('networkidle'); - await loginPage.clickSignInText(); - await loginPage.fillEmailField(config.DEFAULT_LOGIN); - await loginPage.fillPasswprdField(config.DEFAULT_PASSWORD); - await page.waitForLoadState('networkidle'); - await loginPage.clickSignInWithEmailButton(); - await expect(page.getByText(/Sign in to your account/)).not.toBeVisible(); - }, - ); - -await test.step('Saved auth state', async () => { - await page.context().storageState({ - path: path.resolve(__dirname, '..', '.auth', 'user.json'), - }); -}); - -}); diff --git a/tests/e2e/web/specs/postSetup.spec.ts b/tests/e2e/web/specs/postSetup.spec.ts new file mode 100644 index 00000000..7c42f23e --- /dev/null +++ b/tests/e2e/web/specs/postSetup.spec.ts @@ -0,0 +1,8 @@ +import { test, expect } from '@playwright/test'; + +//the first test is to confirm setup.ts works + +test('should be logged and see organization link', async ({ page }) => { + await page.goto('/Organization'); + await expect(page.getByRole('link', {name: 'Organization'} )).toBeVisible(); +}); diff --git a/tests/e2e/web/specs/setup.ts b/tests/e2e/web/specs/setup.ts new file mode 100644 index 00000000..d119bf47 --- /dev/null +++ b/tests/e2e/web/specs/setup.ts @@ -0,0 +1,51 @@ +import { test as base, expect } from '@playwright/test'; +import path from 'path'; +import { config } from '../TESTING_CONFIG'; + +/* +Preforms login by directly contacting firebase using credentials from TESTING_CONFIG file. +Saves the resulting authenticated session state to a JSON file for reuse in later tests. +This was done to decrease flakiness and to avoid re-logging in every test. +*/ + +const test = base; + +test('API Signin test', async ({ browser }) => { + const email = config.DEFAULT_LOGIN; + const password = config.DEFAULT_PASSWORD; + const authUrl = config.FIREBASE_AUTH_URL; + const baseUrl =config.BASE_URL; + + const response = await fetch(authUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + email, + password, + returnSecureToken: true, + }), + }); + + if (!response.ok) throw new Error(`Firebase login failed: ${response.statusText}`); + + const data = await response.json(); + const { idToken, refreshToken, localId } = data; + + console.log('Logged in as:', localId); + + const context = await browser.newContext(); + const page = await context.newPage(); + + await page.goto(baseUrl); + + await page.evaluate(([token, refresh]) => { + localStorage.setItem('firebase_id_token', token); + localStorage.setItem('firebase_refresh_token', refresh); + }, [idToken, refreshToken]); + + await context.storageState({ + path: path.resolve(__dirname, '..', '.auth', 'user.json'), + }); + + await context.close(); +}); diff --git a/tests/e2e/web/specs/signIn.preSetup.spec.ts b/tests/e2e/web/specs/signIn.preSetup.spec.ts new file mode 100644 index 00000000..111dc280 --- /dev/null +++ b/tests/e2e/web/specs/signIn.preSetup.spec.ts @@ -0,0 +1,31 @@ +import { test as base, expect } from '@playwright/test'; +import { SignInPage } from '../pages/signInPage'; +import { config } from '../TESTING_CONFIG'; + +//Baisc login using fixture created from signInPage + +const test = base.extend<{ signInPage: SignInPage }>({ + signInPage: async ({ page }, use) => { + const signInPage = new SignInPage(page); + await use(signInPage); + }, +}); + +test('Signin test', async ({ signInPage, page }) => { + await test.step('Navigated to login page', async () => { + await page.goto('/'); + }); + await test.step( + 'Logging in '.concat(page.url(), ' as ', config.DEFAULT_LOGIN), + async () => { + await page.waitForLoadState('networkidle'); + await signInPage.clickSignInText(); + await signInPage.fillEmailField(config.DEFAULT_LOGIN); + await signInPage.fillPasswprdField(config.DEFAULT_PASSWORD); + await page.waitForLoadState('networkidle'); + await signInPage.clickSignInWithEmailButton(); + await expect(page.getByText(/Sign in to your account/)).not.toBeVisible(); + }, + ); + +}); From 6ac737eba5aa3fa63f578eca1190dc64f047a76d Mon Sep 17 00:00:00 2001 From: Nicholas Chamberlain <97712961+n3c777@users.noreply.github.com> Date: Thu, 13 Nov 2025 11:55:55 -0800 Subject: [PATCH 4/7] Apply suggestions from code review Co-authored-by: Martin Braquet --- tests/e2e/web/specs/postSetup.spec.ts | 6 +++--- tests/e2e/web/specs/setup.ts | 2 +- tests/e2e/web/specs/signIn.preSetup.spec.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/e2e/web/specs/postSetup.spec.ts b/tests/e2e/web/specs/postSetup.spec.ts index 7c42f23e..a981820c 100644 --- a/tests/e2e/web/specs/postSetup.spec.ts +++ b/tests/e2e/web/specs/postSetup.spec.ts @@ -2,7 +2,7 @@ import { test, expect } from '@playwright/test'; //the first test is to confirm setup.ts works -test('should be logged and see organization link', async ({ page }) => { - await page.goto('/Organization'); - await expect(page.getByRole('link', {name: 'Organization'} )).toBeVisible(); +test('should be logged and see settings page', async ({ page }) => { + await page.goto('/settings'); + await expect(page.getByRole('heading', {name: 'Theme'} )).toBeVisible(); }); diff --git a/tests/e2e/web/specs/setup.ts b/tests/e2e/web/specs/setup.ts index d119bf47..a8f87816 100644 --- a/tests/e2e/web/specs/setup.ts +++ b/tests/e2e/web/specs/setup.ts @@ -3,7 +3,7 @@ import path from 'path'; import { config } from '../TESTING_CONFIG'; /* -Preforms login by directly contacting firebase using credentials from TESTING_CONFIG file. +Performs login by directly contacting firebase using credentials from TESTING_CONFIG file. Saves the resulting authenticated session state to a JSON file for reuse in later tests. This was done to decrease flakiness and to avoid re-logging in every test. */ diff --git a/tests/e2e/web/specs/signIn.preSetup.spec.ts b/tests/e2e/web/specs/signIn.preSetup.spec.ts index 111dc280..58747152 100644 --- a/tests/e2e/web/specs/signIn.preSetup.spec.ts +++ b/tests/e2e/web/specs/signIn.preSetup.spec.ts @@ -2,7 +2,7 @@ import { test as base, expect } from '@playwright/test'; import { SignInPage } from '../pages/signInPage'; import { config } from '../TESTING_CONFIG'; -//Baisc login using fixture created from signInPage +// Basic login using fixture created from signInPage const test = base.extend<{ signInPage: SignInPage }>({ signInPage: async ({ page }, use) => { From 7487a8c1d72d8630b1151fe1f938a172a1c651cf Mon Sep 17 00:00:00 2001 From: n3c777 Date: Mon, 17 Nov 2025 14:28:41 -0800 Subject: [PATCH 5/7] Change signin structure to use UI --- playwright.config.ts | 16 +------ tests/e2e/web/TESTING_CONFIG.ts | 5 -- tests/e2e/web/fixtures/signInFixture.ts | 20 ++++++++ tests/e2e/web/specs/postSetup.spec.ts | 8 ---- tests/e2e/web/specs/postSignIn.spec.ts | 10 ++++ tests/e2e/web/specs/setup.ts | 51 --------------------- tests/e2e/web/specs/signIn.preSetup.spec.ts | 31 ------------- 7 files changed, 32 insertions(+), 109 deletions(-) create mode 100644 tests/e2e/web/fixtures/signInFixture.ts delete mode 100644 tests/e2e/web/specs/postSetup.spec.ts create mode 100644 tests/e2e/web/specs/postSignIn.spec.ts delete mode 100644 tests/e2e/web/specs/setup.ts delete mode 100644 tests/e2e/web/specs/signIn.preSetup.spec.ts diff --git a/playwright.config.ts b/playwright.config.ts index 2fb7fbb5..2c6346ad 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -14,21 +14,9 @@ export default defineConfig({ }, projects: [ { - name: 'preSetup', - testMatch: /.*preSetup\.ts/, - }, - { - name: 'setup', - testMatch: /.*setup\.ts/, - }, - { - name: 'postSetup', + name: 'main', use: { - ...devices['Desktop Chrome'], - storageState: path.resolve(__dirname, 'tests/e2e/web/.auth/user.json'), - }, - testIgnore: [/.*preSetup\.ts/, /.*setup\.ts/], - dependencies: ['setup'], + ...devices['Desktop Chrome'], }, }, // { // name: 'firefox', diff --git a/tests/e2e/web/TESTING_CONFIG.ts b/tests/e2e/web/TESTING_CONFIG.ts index 2fccb801..5b9ba6a2 100644 --- a/tests/e2e/web/TESTING_CONFIG.ts +++ b/tests/e2e/web/TESTING_CONFIG.ts @@ -1,10 +1,5 @@ -import { DEV_CONFIG } from '../../../common/src/envs/dev'; - -const FIREBASE_API_KEY = DEV_CONFIG.firebaseConfig.apiKey; - export const config = { BASE_URL: 'http://localhost:3000', DEFAULT_LOGIN: 'defaultUser@dev.com', DEFAULT_PASSWORD: 'defaultPassword', - FIREBASE_AUTH_URL: `https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${FIREBASE_API_KEY}`, }; \ No newline at end of file diff --git a/tests/e2e/web/fixtures/signInFixture.ts b/tests/e2e/web/fixtures/signInFixture.ts new file mode 100644 index 00000000..36bc6717 --- /dev/null +++ b/tests/e2e/web/fixtures/signInFixture.ts @@ -0,0 +1,20 @@ +import { test as base, Page } from '@playwright/test'; +import { SignInPage } from '../pages/signInPage'; +import { config } from '../TESTING_CONFIG'; + +export const test = base.extend<{ + authenticatedPage: Page; +}>({ + authenticatedPage: async ({ page }, use) => { + const signInPage = new SignInPage(page); + + await page.goto('/signin'); + await signInPage.fillEmailField(config.DEFAULT_LOGIN); + await signInPage.fillPasswprdField(config.DEFAULT_PASSWORD); + await signInPage.clickSignInWithEmailButton(); + + await page.waitForLoadState('networkidle'); + + await use(page); + }, +}); diff --git a/tests/e2e/web/specs/postSetup.spec.ts b/tests/e2e/web/specs/postSetup.spec.ts deleted file mode 100644 index a981820c..00000000 --- a/tests/e2e/web/specs/postSetup.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { test, expect } from '@playwright/test'; - -//the first test is to confirm setup.ts works - -test('should be logged and see settings page', async ({ page }) => { - await page.goto('/settings'); - await expect(page.getByRole('heading', {name: 'Theme'} )).toBeVisible(); -}); diff --git a/tests/e2e/web/specs/postSignIn.spec.ts b/tests/e2e/web/specs/postSignIn.spec.ts new file mode 100644 index 00000000..5afce38f --- /dev/null +++ b/tests/e2e/web/specs/postSignIn.spec.ts @@ -0,0 +1,10 @@ +import { expect } from '@playwright/test'; +import { test } from '../fixtures/signInFixture'; + +test('should be logged in and see settings page', async ({ authenticatedPage }) => { + await authenticatedPage.goto('/settings'); + + await expect( + authenticatedPage.getByRole('heading', { name: 'Theme' }) + ).toBeVisible(); +}); \ No newline at end of file diff --git a/tests/e2e/web/specs/setup.ts b/tests/e2e/web/specs/setup.ts deleted file mode 100644 index a8f87816..00000000 --- a/tests/e2e/web/specs/setup.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { test as base, expect } from '@playwright/test'; -import path from 'path'; -import { config } from '../TESTING_CONFIG'; - -/* -Performs login by directly contacting firebase using credentials from TESTING_CONFIG file. -Saves the resulting authenticated session state to a JSON file for reuse in later tests. -This was done to decrease flakiness and to avoid re-logging in every test. -*/ - -const test = base; - -test('API Signin test', async ({ browser }) => { - const email = config.DEFAULT_LOGIN; - const password = config.DEFAULT_PASSWORD; - const authUrl = config.FIREBASE_AUTH_URL; - const baseUrl =config.BASE_URL; - - const response = await fetch(authUrl, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - email, - password, - returnSecureToken: true, - }), - }); - - if (!response.ok) throw new Error(`Firebase login failed: ${response.statusText}`); - - const data = await response.json(); - const { idToken, refreshToken, localId } = data; - - console.log('Logged in as:', localId); - - const context = await browser.newContext(); - const page = await context.newPage(); - - await page.goto(baseUrl); - - await page.evaluate(([token, refresh]) => { - localStorage.setItem('firebase_id_token', token); - localStorage.setItem('firebase_refresh_token', refresh); - }, [idToken, refreshToken]); - - await context.storageState({ - path: path.resolve(__dirname, '..', '.auth', 'user.json'), - }); - - await context.close(); -}); diff --git a/tests/e2e/web/specs/signIn.preSetup.spec.ts b/tests/e2e/web/specs/signIn.preSetup.spec.ts deleted file mode 100644 index 58747152..00000000 --- a/tests/e2e/web/specs/signIn.preSetup.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { test as base, expect } from '@playwright/test'; -import { SignInPage } from '../pages/signInPage'; -import { config } from '../TESTING_CONFIG'; - -// Basic login using fixture created from signInPage - -const test = base.extend<{ signInPage: SignInPage }>({ - signInPage: async ({ page }, use) => { - const signInPage = new SignInPage(page); - await use(signInPage); - }, -}); - -test('Signin test', async ({ signInPage, page }) => { - await test.step('Navigated to login page', async () => { - await page.goto('/'); - }); - await test.step( - 'Logging in '.concat(page.url(), ' as ', config.DEFAULT_LOGIN), - async () => { - await page.waitForLoadState('networkidle'); - await signInPage.clickSignInText(); - await signInPage.fillEmailField(config.DEFAULT_LOGIN); - await signInPage.fillPasswprdField(config.DEFAULT_PASSWORD); - await page.waitForLoadState('networkidle'); - await signInPage.clickSignInWithEmailButton(); - await expect(page.getByText(/Sign in to your account/)).not.toBeVisible(); - }, - ); - -}); From b4d19ba0ed5188e9f2c2c14f34d6bd7580db3783 Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Tue, 18 Nov 2025 23:00:18 +0100 Subject: [PATCH 6/7] Fix URL loading --- tests/e2e/web/fixtures/signInFixture.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/e2e/web/fixtures/signInFixture.ts b/tests/e2e/web/fixtures/signInFixture.ts index 36bc6717..f9a476be 100644 --- a/tests/e2e/web/fixtures/signInFixture.ts +++ b/tests/e2e/web/fixtures/signInFixture.ts @@ -1,4 +1,4 @@ -import { test as base, Page } from '@playwright/test'; +import { test as base, Page, expect } from '@playwright/test'; import { SignInPage } from '../pages/signInPage'; import { config } from '../TESTING_CONFIG'; @@ -15,6 +15,10 @@ export const test = base.extend<{ await page.waitForLoadState('networkidle'); + await page.waitForURL('/'); + + expect(page.url()).not.toContain('/signin') + await use(page); }, }); From 5c051f69a463ddaae723a49b287d3b1d7545032a Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Tue, 18 Nov 2025 23:04:41 +0100 Subject: [PATCH 7/7] Spin up backend server as well for E2E --- .github/workflows/ci.yml | 4 ++++ package.json | 1 + scripts/e2e.sh | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f143a9c..578ce3bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,11 +67,15 @@ jobs: NEXT_PUBLIC_SUPABASE_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_KEY }} run: | npx nyc --reporter=lcov yarn --cwd=web serve & + npx nyc --reporter=lcov yarn --cwd=backend/api dev & npx wait-on http://localhost:3000 npx playwright test tests/e2e SERVER_PID=$(fuser -k 3000/tcp) echo $SERVER_PID kill $SERVER_PID + SERVER_PID=$(fuser -k 8088/tcp) + echo $SERVER_PID + kill $SERVER_PID - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 diff --git a/package.json b/package.json index a58b7b5e..b6313c9c 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "test:coverage": "yarn workspaces run test --coverage", "test:watch": "yarn workspaces run test --watch", "test:update": "yarn workspaces run test --updateSnapshot", + "test:e2e": "./scripts/e2e.sh", "playwright": "playwright test", "playwright:ui": "playwright test --ui", "playwright:debug": "playwright test --debug", diff --git a/scripts/e2e.sh b/scripts/e2e.sh index 13d5c117..821d1603 100755 --- a/scripts/e2e.sh +++ b/scripts/e2e.sh @@ -10,9 +10,13 @@ export NEXT_PUBLIC_API_URL=localhost:8088 export NEXT_PUBLIC_FIREBASE_ENV=DEV npx nyc --reporter=lcov yarn --cwd=web serve & +npx nyc --reporter=lcov yarn --cwd=backend/api dev & npx wait-on http://localhost:3000 npx playwright test tests/e2e SERVER_PID=$(fuser -k 3000/tcp) echo $SERVER_PID kill $SERVER_PID +SERVER_PID=$(fuser -k 8088/tcp) +echo $SERVER_PID +kill $SERVER_PID \ No newline at end of file