From 0b82dbfc2017cc2896ccb8a935386cab76498ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Tue, 14 Jul 2026 12:26:50 +0200 Subject: [PATCH 1/3] add SMTP settings helper --- e2e/utils/controllers/mfa/enableEmail.ts | 25 ++------------------ e2e/utils/controllers/settings.ts | 30 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 23 deletions(-) create mode 100644 e2e/utils/controllers/settings.ts diff --git a/e2e/utils/controllers/mfa/enableEmail.ts b/e2e/utils/controllers/mfa/enableEmail.ts index 7feff994fc..77cf7f8f9b 100644 --- a/e2e/utils/controllers/mfa/enableEmail.ts +++ b/e2e/utils/controllers/mfa/enableEmail.ts @@ -1,40 +1,19 @@ import { Browser } from 'playwright'; import { TOTP } from 'totp-generator'; -import { defaultUserAdmin, routes } from '../../../config'; +import { routes } from '../../../config'; import { User } from '../../../types'; import { extractEmailSecret } from '../../db/extractEmailSecret'; import { waitForBase } from '../../waitForBase'; import { acceptRecovery } from '../acceptRecovery'; import { loginBasic } from '../login'; -import { logout } from '../logout'; +import { setupSMTP } from '../settings'; export type EnableEmailResult = { secret: string; recoveryCodes?: string[]; }; -export const setupSMTP = async (browser: Browser) => { - const context = await browser.newContext(); - const page = await context.newPage(); - await waitForBase(page); - await loginBasic(page, defaultUserAdmin); - await page.goto(routes.base + routes.settings.smtp); - await page.getByTestId('smtp-card-basic-configure').click(); - await page.getByTestId('field-smtp_server').waitFor({ state: 'visible' }); - await page.getByTestId('field-smtp_server').fill('testServer.com'); - await page.getByTestId('field-smtp_port').fill('543'); - await page.getByTestId('field-smtp_user').fill('testuser'); - await page.getByTestId('field-smtp_password').fill('test'); - await page.getByTestId('field-smtp_sender').fill('test@test.com'); - const saveButton = await page.getByTestId('submit'); - if (await saveButton.isEnabled()) { - await saveButton.click(); - } - await logout(page); - await context.close(); -}; - export const enableEmailMFA = async ( browser: Browser, user: User, diff --git a/e2e/utils/controllers/settings.ts b/e2e/utils/controllers/settings.ts new file mode 100644 index 0000000000..22a7e98431 --- /dev/null +++ b/e2e/utils/controllers/settings.ts @@ -0,0 +1,30 @@ +import { Browser } from 'playwright'; + +import { defaultUserAdmin, routes } from '../../config'; +import { waitForBase } from '../waitForBase'; +import { loginBasic } from './login'; +import { logout } from './logout'; + +// Configure SMTP in Core settings as an admin. +// Several Edge features (password reset, email MFA) are only exposed once SMTP +// is configured, so tests that exercise them must call this first. +export const setupSMTP = async (browser: Browser) => { + const context = await browser.newContext(); + const page = await context.newPage(); + await waitForBase(page); + await loginBasic(page, defaultUserAdmin); + await page.goto(routes.base + routes.settings.smtp); + await page.getByTestId('smtp-card-basic-configure').click(); + await page.getByTestId('field-smtp_server').waitFor({ state: 'visible' }); + await page.getByTestId('field-smtp_server').fill('testServer.com'); + await page.getByTestId('field-smtp_port').fill('543'); + await page.getByTestId('field-smtp_user').fill('testuser'); + await page.getByTestId('field-smtp_password').fill('test'); + await page.getByTestId('field-smtp_sender').fill('test@test.com'); + const saveButton = await page.getByTestId('submit'); + if (await saveButton.isEnabled()) { + await saveButton.click(); + } + await logout(page); + await context.close(); +}; From 0437e42013a40788ef90d4989a383a62991e31bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Tue, 14 Jul 2026 12:27:01 +0200 Subject: [PATCH 2/3] add e2e command --- justfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/justfile b/justfile index 33a66a0df1..bdb9e27629 100644 --- a/justfile +++ b/justfile @@ -1,3 +1,6 @@ +# default Docker image tag for e2e tests +IMAGE_TAG := "release-2.1" + # build release binary build: cargo build --release @@ -90,3 +93,7 @@ test-ldap *ARGS: status=$? docker compose -p defguard-ldap -f docker-compose.ldap-test.yaml down exit $status + +# run e2e tests (requires Docker, IMAGE_TAG defaults to release-2.1) +e2e-test *ARGS='': + cd e2e && IMAGE_TAG="{{IMAGE_TAG}}" pnpm exec playwright test {{ARGS}} From 9c915d91ae6f8ab918d0c4a99f533d94a74a61df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Tue, 14 Jul 2026 12:27:20 +0200 Subject: [PATCH 3/3] configure SMTP for password reset test --- e2e/tests/passwordReset.spec.ts | 10 +++++++++- e2e/utils/controllers/passwordReset.ts | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/e2e/tests/passwordReset.spec.ts b/e2e/tests/passwordReset.spec.ts index e621f6a276..c2d920522d 100644 --- a/e2e/tests/passwordReset.spec.ts +++ b/e2e/tests/passwordReset.spec.ts @@ -9,7 +9,9 @@ import { selectPasswordReset, setEmail, setPassword, + waitForEdgePasswordResetEnabled, } from '../utils/controllers/passwordReset'; +import { setupSMTP } from '../utils/controllers/settings'; import { disableUser } from '../utils/controllers/toggleUserState'; import { getPasswordResetToken } from '../utils/db/getPasswordResetToken'; import { dockerRestart } from '../utils/docker'; @@ -25,8 +27,11 @@ test.describe('Reset password', () => { await createUser(browser, user); }); - test('Reset user password', async ({ page }) => { + test('Reset user password', async ({ page, browser }) => { await waitForBase(page); + // Password reset is only shown on Edge once SMTP is configured in Core. + await setupSMTP(browser); + await waitForEdgePasswordResetEnabled(page); await page.goto(testsConfig.ENROLLMENT_URL); await selectPasswordReset(page); await setEmail(user.mail, page); @@ -48,6 +53,9 @@ test.describe('Reset password', () => { // TODO: Enable when https://github.com/DefGuard/defguard/issues/2425 is fixed test.skip('Reset disabled user password', async ({ page, browser }) => { await waitForBase(page); + // Password reset is only shown on Edge once SMTP is configured in Core. + await setupSMTP(browser); + await waitForEdgePasswordResetEnabled(page); await page.goto(testsConfig.ENROLLMENT_URL); await selectPasswordReset(page); await setEmail(user.mail, page); diff --git a/e2e/utils/controllers/passwordReset.ts b/e2e/utils/controllers/passwordReset.ts index 7346b8c026..ac8490574b 100644 --- a/e2e/utils/controllers/passwordReset.ts +++ b/e2e/utils/controllers/passwordReset.ts @@ -1,5 +1,26 @@ +import { expect } from '@playwright/test'; import { Page } from 'playwright'; +import { testsConfig } from '../../config'; + +// The Edge home page only shows the password-reset option once Core reports +// display_password_reset === true (which requires SMTP to be configured and the +// setting enabled). Core pushes that value to the proxy asynchronously, so poll +// the proxy's public info endpoint until it is reflected before navigating. +export const waitForEdgePasswordResetEnabled = async (page: Page) => { + await expect + .poll( + async () => { + const res = await page.request.get(`${testsConfig.ENROLLMENT_URL}/api/v1/info`); + if (!res.ok()) return false; + const body = await res.json(); + return body.display_password_reset === true; + }, + { timeout: 30_000 }, + ) + .toBe(true); +}; + export const selectPasswordReset = async (page: Page) => { const selectButton = page.getByTestId('start-password-reset'); await selectButton.waitFor({ state: 'visible' });