From cfab441fe064d9511d14dba0bef5cbf50934a850 Mon Sep 17 00:00:00 2001 From: lehnerja Date: Fri, 29 May 2026 15:38:26 +0200 Subject: [PATCH 1/9] test: add E2E test for on-prem login redirect (TC-8757) Add a critical flow E2E test to verify the on-premise login redirect behaviour when a user enters an email associated with a claimed domain on the SSO page. Changes included: - Add `onPremLoginRedirect-TC-8757.spec.ts` to test the redirect flow and verify the custom backend dialog. - Implement `CustomBackendPage` POM. - Update `brig.repository.e2e.ts` with `claimDomain` and `deleteDomain` API helpers to handle test setup and guaranteed teardown. - Use FakerJS to ensure domain uniqueness per test run to prevent collisions. Refs: WPB-25319 --- .../e2e_tests/backend/brigRepository.e2e.ts | 27 ++++++++ .../test/e2e_tests/pageManager/index.ts | 2 + .../webapp/pages/customBackend.page.ts | 36 ++++++++++ .../onPremLoginRedirect-TC-8757.spec.ts | 68 +++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 apps/webapp/test/e2e_tests/pageManager/webapp/pages/customBackend.page.ts create mode 100644 apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts diff --git a/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts b/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts index bdd64a9259b..fa19ef61e68 100644 --- a/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts +++ b/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts @@ -251,4 +251,31 @@ export class BrigRepositoryE2E { }, ); } + + public async claimDomain(domain: string) { + await this.axiosInstance.put( + `i/domain-registration/${domain}`, + { + backend: { + config_url: 'https://nginz-https.anta.wire.link/deeplink.json', + webapp_url: 'https://webapp.anta.wire.link', + }, + domain_redirect: 'backend', + team_invite: 'not-allowed', + }, + { + headers: { + Authorization: `Basic ${BASIC_AUTH}`, + }, + }, + ); + } + + public async deleteDomain(domain: string) { + await this.axiosInstance.delete(`i/domain-registration/${domain}`, { + headers: { + Authorization: `Basic ${BASIC_AUTH}`, + }, + }); + } } diff --git a/apps/webapp/test/e2e_tests/pageManager/index.ts b/apps/webapp/test/e2e_tests/pageManager/index.ts index bcd842078eb..e8d3f1bf511 100644 --- a/apps/webapp/test/e2e_tests/pageManager/index.ts +++ b/apps/webapp/test/e2e_tests/pageManager/index.ts @@ -78,6 +78,7 @@ import {ParticipantDeviceDetailsPage} from './webapp/pages/participantDeviceDeta import {ParticipantDevicesPage} from './webapp/pages/participantDevices.page'; import {NewDeviceModal} from './webapp/modals/newDevice.modal'; import {ReadReceiptModal} from './webapp/modals/readReceipt.modal'; +import {CustomBackendPage} from './webapp/pages/customBackend.page'; export const webAppPath = process.env.WEBAPP_URL ?? ''; @@ -201,6 +202,7 @@ export class PageManager { this.getOrCreate('webapp.pages.verification', () => new EmailVerificationPage(this.page)), setUsername: () => this.getOrCreate('webapp.pages.setUsername', () => new SetUsernamePage(this.page)), conversationJoin: () => this.getOrCreate('webapp.pages.conversationJoin', () => ConversationJoinPage(this.page)), + customBackend: () => this.getOrCreate('webapp.pages.customBackend', () => new CustomBackendPage(this.page)), }, modals: { appLock: () => this.getOrCreate('webapp.modals.appLock', () => new AppLockModal(this.page)), diff --git a/apps/webapp/test/e2e_tests/pageManager/webapp/pages/customBackend.page.ts b/apps/webapp/test/e2e_tests/pageManager/webapp/pages/customBackend.page.ts new file mode 100644 index 00000000000..26a008e92d9 --- /dev/null +++ b/apps/webapp/test/e2e_tests/pageManager/webapp/pages/customBackend.page.ts @@ -0,0 +1,36 @@ +/* + * Wire + * Copyright (C) 2025 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {Locator, Page} from '@playwright/test'; + +export class CustomBackendPage { + readonly title: Locator; + readonly redirectWarningText: Locator; + readonly adminInfoText: Locator; + readonly connectButton: Locator; + readonly cancelButton: Locator; + + constructor(page: Page) { + this.title = page.getByText("Connect to your organization's backend?", {exact: true}); + this.redirectWarningText = page.getByText('Your email belongs to another backend.'); + this.adminInfoText = page.getByText('Your IT team administers this Wire backend.'); + this.connectButton = page.getByRole('button', {name: 'Connect'}); + this.cancelButton = page.getByRole('button', {name: 'Cancel'}); + } +} diff --git a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts new file mode 100644 index 00000000000..da40bb6d7f0 --- /dev/null +++ b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts @@ -0,0 +1,68 @@ +/* + * Wire + * Copyright (C) 2025 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {expect, test} from '../../test.fixtures'; +import {PageManager} from '../../pageManager'; +import {faker} from '@faker-js/faker'; + +const ON_PREM_WEBAPP_URL = 'https://webapp.anta.wire.link'; + +test('On Prem Login Redirect', {tag: ['@TC-8757', '@regression']}, async ({context, createPage, api}) => { + const domain = faker.internet.domainName(); + const email = `redirect-user@${domain}`; + + try { + await test.step('Claim domain and configure on-prem redirect', async () => { + await api.brig.claimDomain(domain); + }); + + const page = await createPage(context); + const pageManager = PageManager.from(page); + const {pages} = pageManager.webapp; + + await test.step('Open login page and enter email with claimed domain', async () => { + await pageManager.openSSOPage(); + await pages.singleSignOn().enterEmailOnSSOPage(email); + await pages.singleSignOn().ssoSignInButton.click(); + }); + + await test.step('Verify connect-to-organization backend dialog is shown', async () => { + await expect(pages.customBackend().title).toBeVisible(); + await expect(pages.customBackend().redirectWarningText).toBeVisible(); + await expect(pages.customBackend().adminInfoText).toBeVisible(); + }); + + await test.step('Click connect and verify redirect to on-prem webapp', async () => { + const urlPattern = new RegExp(ON_PREM_WEBAPP_URL.replace(/\./g, '\\.')); + + await Promise.all([ + page.waitForURL(urlPattern, { + timeout: 20_000, + }), + pages.customBackend().connectButton.click(), + ]); + + await expect(page).toHaveURL(urlPattern); + }); + } finally { + await test.step('Delete claimed domain registration', async () => { + await api.brig.deleteDomain(domain); + }); + } +}); From a517a4fb56529109672af3b67f50ddd487ad9097 Mon Sep 17 00:00:00 2001 From: lehnerja Date: Mon, 1 Jun 2026 09:09:59 +0200 Subject: [PATCH 2/9] refactor: rename deleteDomain to deleteDomainClaim for clarity Refs: WPB-25319 --- apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts | 2 +- .../specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts b/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts index fa19ef61e68..88434551f52 100644 --- a/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts +++ b/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts @@ -271,7 +271,7 @@ export class BrigRepositoryE2E { ); } - public async deleteDomain(domain: string) { + public async deleteDomainClaim(domain: string) { await this.axiosInstance.delete(`i/domain-registration/${domain}`, { headers: { Authorization: `Basic ${BASIC_AUTH}`, diff --git a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts index da40bb6d7f0..e1e3a63293d 100644 --- a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts +++ b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts @@ -62,7 +62,7 @@ test('On Prem Login Redirect', {tag: ['@TC-8757', '@regression']}, async ({conte }); } finally { await test.step('Delete claimed domain registration', async () => { - await api.brig.deleteDomain(domain); + await api.brig.deleteDomainClaim(domain); }); } }); From 7c2753daeefb1def9d3da95b2a2c59ea7add51dc Mon Sep 17 00:00:00 2001 From: lehnerja Date: Mon, 1 Jun 2026 09:13:04 +0200 Subject: [PATCH 3/9] refactor: remove button click to avoid undefined behavior Refs: WPB-25319 --- .../specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts index e1e3a63293d..2b6f417374f 100644 --- a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts +++ b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts @@ -39,7 +39,6 @@ test('On Prem Login Redirect', {tag: ['@TC-8757', '@regression']}, async ({conte await test.step('Open login page and enter email with claimed domain', async () => { await pageManager.openSSOPage(); await pages.singleSignOn().enterEmailOnSSOPage(email); - await pages.singleSignOn().ssoSignInButton.click(); }); await test.step('Verify connect-to-organization backend dialog is shown', async () => { From 35a63b31ad87b731998afce4551e019fb0cd7fa5 Mon Sep 17 00:00:00 2001 From: lehnerja Date: Mon, 1 Jun 2026 09:29:34 +0200 Subject: [PATCH 4/9] refactor: simplify assertions with inline locators for headline and backend URL for resilience and reducing maintenance effort Refs: WPB-25319 --- .../specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts index 2b6f417374f..07d9c14ea31 100644 --- a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts +++ b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts @@ -42,9 +42,8 @@ test('On Prem Login Redirect', {tag: ['@TC-8757', '@regression']}, async ({conte }); await test.step('Verify connect-to-organization backend dialog is shown', async () => { - await expect(pages.customBackend().title).toBeVisible(); - await expect(pages.customBackend().redirectWarningText).toBeVisible(); - await expect(pages.customBackend().adminInfoText).toBeVisible(); + await expect(page.getByText("Connect to your organization's backend?")).toBeVisible(); + await expect(page.getByText(ON_PREM_WEBAPP_URL)).toBeVisible(); }); await test.step('Click connect and verify redirect to on-prem webapp', async () => { From 9ff90885178512a4324ed751ad318585b9f8eae1 Mon Sep 17 00:00:00 2001 From: lehnerja Date: Mon, 1 Jun 2026 09:32:53 +0200 Subject: [PATCH 5/9] refactor: inline Connect Button Locator Refs: WPB-25319 --- .../specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts index 07d9c14ea31..fa08f8726da 100644 --- a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts +++ b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts @@ -53,7 +53,7 @@ test('On Prem Login Redirect', {tag: ['@TC-8757', '@regression']}, async ({conte page.waitForURL(urlPattern, { timeout: 20_000, }), - pages.customBackend().connectButton.click(), + page.getByRole('button', {name: 'Connect'}).click(), ]); await expect(page).toHaveURL(urlPattern); From c3b8240a5db1db2cb4e379a70f0304ee1eb54b73 Mon Sep 17 00:00:00 2001 From: lehnerja Date: Mon, 1 Jun 2026 09:34:13 +0200 Subject: [PATCH 6/9] refactor: remove redundant customBackend.page.ts Refs: WPB-25319 --- .../test/e2e_tests/pageManager/index.ts | 2 -- .../webapp/pages/customBackend.page.ts | 36 ------------------- 2 files changed, 38 deletions(-) delete mode 100644 apps/webapp/test/e2e_tests/pageManager/webapp/pages/customBackend.page.ts diff --git a/apps/webapp/test/e2e_tests/pageManager/index.ts b/apps/webapp/test/e2e_tests/pageManager/index.ts index e8d3f1bf511..bcd842078eb 100644 --- a/apps/webapp/test/e2e_tests/pageManager/index.ts +++ b/apps/webapp/test/e2e_tests/pageManager/index.ts @@ -78,7 +78,6 @@ import {ParticipantDeviceDetailsPage} from './webapp/pages/participantDeviceDeta import {ParticipantDevicesPage} from './webapp/pages/participantDevices.page'; import {NewDeviceModal} from './webapp/modals/newDevice.modal'; import {ReadReceiptModal} from './webapp/modals/readReceipt.modal'; -import {CustomBackendPage} from './webapp/pages/customBackend.page'; export const webAppPath = process.env.WEBAPP_URL ?? ''; @@ -202,7 +201,6 @@ export class PageManager { this.getOrCreate('webapp.pages.verification', () => new EmailVerificationPage(this.page)), setUsername: () => this.getOrCreate('webapp.pages.setUsername', () => new SetUsernamePage(this.page)), conversationJoin: () => this.getOrCreate('webapp.pages.conversationJoin', () => ConversationJoinPage(this.page)), - customBackend: () => this.getOrCreate('webapp.pages.customBackend', () => new CustomBackendPage(this.page)), }, modals: { appLock: () => this.getOrCreate('webapp.modals.appLock', () => new AppLockModal(this.page)), diff --git a/apps/webapp/test/e2e_tests/pageManager/webapp/pages/customBackend.page.ts b/apps/webapp/test/e2e_tests/pageManager/webapp/pages/customBackend.page.ts deleted file mode 100644 index 26a008e92d9..00000000000 --- a/apps/webapp/test/e2e_tests/pageManager/webapp/pages/customBackend.page.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Wire - * Copyright (C) 2025 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import {Locator, Page} from '@playwright/test'; - -export class CustomBackendPage { - readonly title: Locator; - readonly redirectWarningText: Locator; - readonly adminInfoText: Locator; - readonly connectButton: Locator; - readonly cancelButton: Locator; - - constructor(page: Page) { - this.title = page.getByText("Connect to your organization's backend?", {exact: true}); - this.redirectWarningText = page.getByText('Your email belongs to another backend.'); - this.adminInfoText = page.getByText('Your IT team administers this Wire backend.'); - this.connectButton = page.getByRole('button', {name: 'Connect'}); - this.cancelButton = page.getByRole('button', {name: 'Cancel'}); - } -} From 7f3af785ea9fcd7870227c212dad00d8827b0c8b Mon Sep 17 00:00:00 2001 From: lehnerja Date: Mon, 1 Jun 2026 09:44:20 +0200 Subject: [PATCH 7/9] refactor: simplify URL assertion and regex escaping Refs: WPB-25319 --- .../CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts index fa08f8726da..8a8615cd2b1 100644 --- a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts +++ b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts @@ -47,16 +47,8 @@ test('On Prem Login Redirect', {tag: ['@TC-8757', '@regression']}, async ({conte }); await test.step('Click connect and verify redirect to on-prem webapp', async () => { - const urlPattern = new RegExp(ON_PREM_WEBAPP_URL.replace(/\./g, '\\.')); - - await Promise.all([ - page.waitForURL(urlPattern, { - timeout: 20_000, - }), - page.getByRole('button', {name: 'Connect'}).click(), - ]); - - await expect(page).toHaveURL(urlPattern); + page.getByRole('button', {name: 'Connect'}).click(); + await expect(page).toHaveURL(new RegExp(String.raw`${ON_PREM_WEBAPP_URL}`), {timeout: 20_000}); }); } finally { await test.step('Delete claimed domain registration', async () => { From 9d16374bc2278f37e1c8bdd36e843f990b6ff067 Mon Sep 17 00:00:00 2001 From: lehnerja Date: Mon, 1 Jun 2026 10:57:20 +0200 Subject: [PATCH 8/9] refactor: move domain claim setup to beforeEach hook and add after each hook to clean up Refs: WPB-25319 --- .../onPremLoginRedirect-TC-8757.spec.ts | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts index 8a8615cd2b1..50ec28a9672 100644 --- a/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts +++ b/apps/webapp/test/e2e_tests/specs/CriticalFlow/onPremLoginRedirect-TC-8757.spec.ts @@ -23,15 +23,20 @@ import {faker} from '@faker-js/faker'; const ON_PREM_WEBAPP_URL = 'https://webapp.anta.wire.link'; -test('On Prem Login Redirect', {tag: ['@TC-8757', '@regression']}, async ({context, createPage, api}) => { - const domain = faker.internet.domainName(); - const email = `redirect-user@${domain}`; +test.describe('On Prem Login Redirect Flow', () => { + let domain: string; + let email: string; + + test.beforeEach(async ({api}) => { + domain = faker.internet.domainName(); + email = `redirect-user@${domain}`; - try { await test.step('Claim domain and configure on-prem redirect', async () => { await api.brig.claimDomain(domain); }); + }); + test('On Prem Login Redirect', {tag: ['@TC-8757', '@regression']}, async ({context, createPage}) => { const page = await createPage(context); const pageManager = PageManager.from(page); const {pages} = pageManager.webapp; @@ -47,12 +52,14 @@ test('On Prem Login Redirect', {tag: ['@TC-8757', '@regression']}, async ({conte }); await test.step('Click connect and verify redirect to on-prem webapp', async () => { - page.getByRole('button', {name: 'Connect'}).click(); + await page.getByRole('button', {name: 'Connect'}).click(); await expect(page).toHaveURL(new RegExp(String.raw`${ON_PREM_WEBAPP_URL}`), {timeout: 20_000}); }); - } finally { + }); + + test.afterEach(async ({api}) => { await test.step('Delete claimed domain registration', async () => { await api.brig.deleteDomainClaim(domain); }); - } + }); }); From bdf66d4c57d0d1acc8e3ae4bf5b77530fc2716d4 Mon Sep 17 00:00:00 2001 From: lehnerja Date: Mon, 1 Jun 2026 11:20:05 +0200 Subject: [PATCH 9/9] refactor: replace hardcoded backend URLs with env vars Refs: WPB-25319 --- apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts b/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts index 88434551f52..4462ce5a27d 100644 --- a/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts +++ b/apps/webapp/test/e2e_tests/backend/brigRepository.e2e.ts @@ -257,8 +257,8 @@ export class BrigRepositoryE2E { `i/domain-registration/${domain}`, { backend: { - config_url: 'https://nginz-https.anta.wire.link/deeplink.json', - webapp_url: 'https://webapp.anta.wire.link', + config_url: new URL('deeplink.json', process.env.FEDERATION_BACKEND_URL), + webapp_url: process.env.FEDERATION_WEBAPP_URL, }, domain_redirect: 'backend', team_invite: 'not-allowed',