From 447d754b494aaf88c14557357219f4d3b2c001a1 Mon Sep 17 00:00:00 2001 From: StylusFrost Date: Mon, 20 Oct 2025 10:36:40 +0200 Subject: [PATCH 1/5] test(ui): add page load wait to sign-up page tests - Introduced a call to `waitForPageLoad` in the sign-up page test to ensure the page is fully loaded before proceeding with visibility checks for elements. --- ui/tests/sign-up/sign-up-page.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/tests/sign-up/sign-up-page.ts b/ui/tests/sign-up/sign-up-page.ts index 58e77c8cd6..077f250e86 100644 --- a/ui/tests/sign-up/sign-up-page.ts +++ b/ui/tests/sign-up/sign-up-page.ts @@ -50,6 +50,7 @@ export class SignUpPage extends BasePage { await expect(this.page.getByText("Sign up", { exact: true })).toBeVisible(); await expect(this.emailInput).toBeVisible(); await expect(this.submitButton).toBeVisible(); + await this.waitForPageLoad(); } async fillName(name: string): Promise { From 4920f84d7561837df0ecc639f1216d9aa166a3a1 Mon Sep 17 00:00:00 2001 From: StylusFrost Date: Mon, 20 Oct 2025 17:35:54 +0200 Subject: [PATCH 2/5] test(ui): update sign-up tests to use E2E_NEW_PASSWORD environment variable - Modified the sign-up test to retrieve the password from the E2E_NEW_PASSWORD environment variable. - Updated documentation to specify the requirement for the E2E_NEW_PASSWORD variable before running tests. --- .github/workflows/ui-e2e-tests.yml | 1 + ui/tests/sign-up/sign-up.md | 2 + ui/tests/sign-up/sign-up.spec.ts | 72 +++++++++++++++++------------- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ui-e2e-tests.yml b/.github/workflows/ui-e2e-tests.yml index dea6f1f3e2..81f191765c 100644 --- a/.github/workflows/ui-e2e-tests.yml +++ b/.github/workflows/ui-e2e-tests.yml @@ -18,6 +18,7 @@ jobs: AUTH_TRUST_HOST: true NEXTAUTH_URL: 'http://localhost:3000' NEXT_PUBLIC_API_BASE_URL: 'http://localhost:8080/api/v1' + E2E_NEW_PASSWORD: ${{ secrets.E2E_NEW_PASSWORD }} steps: - name: Checkout repository uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/ui/tests/sign-up/sign-up.md b/ui/tests/sign-up/sign-up.md index 4b0d8b38de..1ebff2a7d9 100644 --- a/ui/tests/sign-up/sign-up.md +++ b/ui/tests/sign-up/sign-up.md @@ -18,6 +18,7 @@ **Preconditions:** - Application is running, email domain & password is acceptable for sign-up. - No existing data in Prowler is required; the test can run on a clean state. +- `E2E_NEW_PASSWORD` environment variable must be set with a valid password for the test. ### Flow Steps: 1. Navigate to the Sign up page. @@ -37,5 +38,6 @@ ### Notes: - Test data uses a random base36 suffix to avoid collisions with email. +- The test requires the `E2E_NEW_PASSWORD` environment variable to be set before running. diff --git a/ui/tests/sign-up/sign-up.spec.ts b/ui/tests/sign-up/sign-up.spec.ts index e0f8f4e462..19d831705c 100644 --- a/ui/tests/sign-up/sign-up.spec.ts +++ b/ui/tests/sign-up/sign-up.spec.ts @@ -4,38 +4,46 @@ import { SignInPage } from "../sign-in/sign-in-page"; import { makeSuffix } from "../helpers"; test.describe("Sign Up Flow", () => { - test("should register a new user successfully", { tag: ['@critical', '@e2e', '@signup', '@SIGNUP-E2E-001'] }, async ({ page }) => { - const signUpPage = new SignUpPage(page); - await signUpPage.goto(); + test( + "should register a new user successfully", + { tag: ["@critical", "@e2e", "@signup", "@SIGNUP-E2E-001"] }, + async ({ page }) => { + const password = process.env.E2E_NEW_PASSWORD; - // Generate unique test data - const suffix = makeSuffix(10); - const uniqueEmail = `e2e+${suffix}@prowler.com`; + if (!password) { + throw new Error("E2E_NEW_PASSWORD environment variable is not set"); + } - // Fill and submit the sign-up form - await signUpPage.signup({ - name: `E2E User ${suffix}`, - company: `Test E2E Co ${suffix}`, - email: uniqueEmail, - password: "Thisisapassword123@", - confirmPassword: "Thisisapassword123@", - acceptTerms: true, - }); - - // Verify no errors occurred during sign-up - await signUpPage.verifyNoErrors(); - - // Verify redirect to login page (OSS environment) - await signUpPage.verifyRedirectToLogin(); - - // Verify the newly created user can log in successfully - const signInPage = new SignInPage(page); - await signInPage.login({ - email: uniqueEmail, - password: "Thisisapassword123@", - }); - await signInPage.verifySuccessfulLogin(); - }); + const signUpPage = new SignUpPage(page); + await signUpPage.goto(); + + // Generate unique test data + const suffix = makeSuffix(10); + const uniqueEmail = `e2e+${suffix}@prowler.com`; + + // Fill and submit the sign-up form + await signUpPage.signup({ + name: `E2E User ${suffix}`, + company: `Test E2E Co ${suffix}`, + email: uniqueEmail, + password: password, + confirmPassword: password, + acceptTerms: true, + }); + + // Verify no errors occurred during sign-up + await signUpPage.verifyNoErrors(); + + // Verify redirect to login page (OSS environment) + await signUpPage.verifyRedirectToLogin(); + + // Verify the newly created user can log in successfully + const signInPage = new SignInPage(page); + await signInPage.login({ + email: uniqueEmail, + password: password, + }); + await signInPage.verifySuccessfulLogin(); + }, + ); }); - - From 94d5322f166a539b09da71cddd05444d4507126a Mon Sep 17 00:00:00 2001 From: StylusFrost Date: Mon, 20 Oct 2025 18:11:29 +0200 Subject: [PATCH 3/5] test(ui): update locators in tests to use role-based queries - Replaced text-based locators with role-based queries in various test files for improved accessibility and consistency. - Removed deprecated HomePage and SignInPage files to streamline the test structure. --- ui/tests/base-page.ts | 2 +- ui/tests/page-objects/home-page.ts | 125 ---------- ui/tests/page-objects/sign-in-page.ts | 316 -------------------------- ui/tests/sign-in/sign-in-page.ts | 26 +-- ui/tests/sign-up/sign-up-page.ts | 4 +- 5 files changed, 16 insertions(+), 457 deletions(-) delete mode 100644 ui/tests/page-objects/home-page.ts delete mode 100644 ui/tests/page-objects/sign-in-page.ts diff --git a/ui/tests/base-page.ts b/ui/tests/base-page.ts index e45da93970..a31f84c7ad 100644 --- a/ui/tests/base-page.ts +++ b/ui/tests/base-page.ts @@ -17,7 +17,7 @@ export abstract class BasePage { // Common locators that most pages share this.title = page.locator("h1, h2, [role='heading']").first(); - this.loadingIndicator = page.getByText("Loading"); + this.loadingIndicator = page.getByRole("status", { name: "Loading" }); this.themeToggle = page.getByLabel("Toggle theme"); } diff --git a/ui/tests/page-objects/home-page.ts b/ui/tests/page-objects/home-page.ts deleted file mode 100644 index 077591eb4e..0000000000 --- a/ui/tests/page-objects/home-page.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { Page, Locator, expect } from "@playwright/test"; - -export class HomePage { - readonly page: Page; - - // Main content elements - readonly mainContent: Locator; - readonly breadcrumbs: Locator; - readonly overviewHeading: Locator; - - // Navigation elements - readonly navigationMenu: Locator; - readonly userMenu: Locator; - readonly signOutButton: Locator; - - // Dashboard elements - readonly dashboardCards: Locator; - readonly overviewSection: Locator; - - // UI elements - readonly themeToggle: Locator; - readonly logo: Locator; - - constructor(page: Page) { - this.page = page; - - // Main content elements - this.mainContent = page.locator("main"); - this.breadcrumbs = page.getByLabel("Breadcrumbs"); - this.overviewHeading = page.getByRole("heading", { name: "Overview", exact: true }); - - // Navigation elements - this.navigationMenu = page.locator("nav"); - this.userMenu = page.getByRole("button", { name: /user menu/i }); - this.signOutButton = page.getByRole("button", { name: "Sign out" }); - - // Dashboard elements - this.dashboardCards = page.locator('[data-testid="dashboard-card"]'); - this.overviewSection = page.locator('[data-testid="overview-section"]'); - - // UI elements - this.themeToggle = page.getByLabel("Toggle theme"); - this.logo = page.locator('svg[width="300"]'); - } - - // Navigation methods - async goto(): Promise { - await this.page.goto("/"); - await this.waitForPageLoad(); - } - - async waitForPageLoad(): Promise { - await this.page.waitForLoadState("networkidle"); - } - - // Verification methods - async verifyPageLoaded(): Promise { - await expect(this.page).toHaveURL("/"); - await expect(this.mainContent).toBeVisible(); - await expect(this.overviewHeading).toBeVisible(); - await this.waitForPageLoad(); - } - - async verifyBreadcrumbs(): Promise { - await expect(this.breadcrumbs).toBeVisible(); - await expect(this.overviewHeading).toBeVisible(); - } - - async verifyMainContent(): Promise { - await expect(this.mainContent).toBeVisible(); - } - - // Navigation methods - async navigateToOverview(): Promise { - await this.overviewHeading.click(); - } - - async openUserMenu(): Promise { - await this.userMenu.click(); - } - - async signOut(): Promise { - await this.openUserMenu(); - await this.signOutButton.click(); - } - - // Dashboard methods - async verifyDashboardCards(): Promise { - await expect(this.dashboardCards.first()).toBeVisible(); - } - - async verifyOverviewSection(): Promise { - await expect(this.overviewSection).toBeVisible(); - } - - // Utility methods - async refresh(): Promise { - await this.page.reload(); - await this.waitForPageLoad(); - } - - async goBack(): Promise { - await this.page.goBack(); - await this.waitForPageLoad(); - } - - // Accessibility methods - async verifyKeyboardNavigation(): Promise { - // Test tab navigation through main elements - await this.page.keyboard.press("Tab"); - await expect(this.themeToggle).toBeFocused(); - } - - // Wait methods - async waitForRedirect(expectedUrl: string): Promise { - await this.page.waitForURL(expectedUrl); - } - - async waitForContentLoad(): Promise { - await this.page.waitForFunction(() => { - const main = document.querySelector("main"); - return main && main.offsetHeight > 0; - }); - } -} diff --git a/ui/tests/page-objects/sign-in-page.ts b/ui/tests/page-objects/sign-in-page.ts deleted file mode 100644 index 2c426606c7..0000000000 --- a/ui/tests/page-objects/sign-in-page.ts +++ /dev/null @@ -1,316 +0,0 @@ -import { Page, Locator, expect } from "@playwright/test"; -import { HomePage } from "./home-page"; - -export interface SignInCredentials { - email: string; - password: string; -} - -export interface SocialAuthConfig { - googleEnabled: boolean; - githubEnabled: boolean; -} - -export class SignInPage { - readonly page: Page; - readonly homePage: HomePage; - - // Form elements - readonly emailInput: Locator; - readonly passwordInput: Locator; - readonly loginButton: Locator; - readonly form: Locator; - - // Social authentication buttons - readonly googleButton: Locator; - readonly githubButton: Locator; - readonly samlButton: Locator; - - // Navigation elements - readonly signUpLink: Locator; - readonly backButton: Locator; - - // UI elements - readonly title: Locator; - readonly logo: Locator; - readonly themeToggle: Locator; - - // Error messages - readonly errorMessages: Locator; - readonly loadingIndicator: Locator; - - // SAML specific elements - readonly samlModeTitle: Locator; - readonly samlEmailInput: Locator; - - constructor(page: Page) { - this.page = page; - this.homePage = new HomePage(page); - - // Form elements - this.emailInput = page.getByLabel("Email"); - this.passwordInput = page.getByLabel("Password"); - this.loginButton = page.getByRole("button", { name: "Log in" }); - this.form = page.locator("form"); - - // Social authentication buttons - this.googleButton = page.getByText("Continue with Google"); - this.githubButton = page.getByText("Continue with Github"); - this.samlButton = page.getByText("Continue with SAML SSO"); - - // Navigation elements - this.signUpLink = page.getByRole("link", { name: "Sign up" }); - this.backButton = page.getByText("Back"); - - // UI elements - this.title = page.getByText("Sign in", { exact: true }); - this.logo = page.locator('svg[width="300"]'); - this.themeToggle = page.getByLabel("Toggle theme"); - - // Error messages - this.errorMessages = page.locator('[role="alert"], .error-message, [data-testid="error"]'); - this.loadingIndicator = page.getByText("Loading"); - - // SAML specific elements - this.samlModeTitle = page.getByText("Sign in with SAML SSO"); - this.samlEmailInput = page.getByLabel("Email"); - } - - // Navigation methods - async goto(): Promise { - await this.page.goto("/sign-in"); - await this.waitForPageLoad(); - } - - async waitForPageLoad(): Promise { - await this.page.waitForLoadState("networkidle"); - } - - // Form interaction methods - async fillEmail(email: string): Promise { - await this.emailInput.fill(email); - } - - async fillPassword(password: string): Promise { - await this.passwordInput.fill(password); - } - - async fillCredentials(credentials: SignInCredentials): Promise { - await this.fillEmail(credentials.email); - await this.fillPassword(credentials.password); - } - - async submitForm(): Promise { - await this.loginButton.click(); - } - - async login(credentials: SignInCredentials): Promise { - await this.fillCredentials(credentials); - await this.submitForm(); - } - - // Social authentication methods - async clickGoogleAuth(): Promise { - await this.googleButton.click(); - } - - async clickGithubAuth(): Promise { - await this.githubButton.click(); - } - - async clickSamlAuth(): Promise { - await this.samlButton.click(); - } - - // SAML SSO methods - async toggleSamlMode(): Promise { - await this.clickSamlAuth(); - } - - async goBackFromSaml(): Promise { - await this.backButton.click(); - } - - async fillSamlEmail(email: string): Promise { - await this.samlEmailInput.fill(email); - } - - async submitSamlForm(): Promise { - await this.submitForm(); - } - - // Navigation methods - async goToSignUp(): Promise { - await this.signUpLink.click(); - } - - // Validation and assertion methods - async verifyPageLoaded(): Promise { - await expect(this.page).toHaveTitle(/Prowler/); - await expect(this.logo).toBeVisible(); - await expect(this.title).toBeVisible(); - await this.waitForPageLoad(); - } - - async verifyFormElements(): Promise { - await expect(this.emailInput).toBeVisible(); - await expect(this.passwordInput).toBeVisible(); - await expect(this.loginButton).toBeVisible(); - } - - async verifySocialButtons(config: SocialAuthConfig): Promise { - if (config.googleEnabled) { - await expect(this.googleButton).toBeVisible(); - } - if (config.githubEnabled) { - await expect(this.githubButton).toBeVisible(); - } - await expect(this.samlButton).toBeVisible(); - } - - async verifyNavigationLinks(): Promise { - await expect(this.page.getByText("Need to create an account?")).toBeVisible(); - await expect(this.signUpLink).toBeVisible(); - } - - async verifySuccessfulLogin(): Promise { - await this.homePage.verifyPageLoaded(); - } - - async verifyLoginError(errorMessage: string = "Invalid email or password"): Promise { - await expect(this.page.getByText(errorMessage).first()).toBeVisible(); - await expect(this.page).toHaveURL("/sign-in"); - } - - async verifySamlModeActive(): Promise { - await expect(this.samlModeTitle).toBeVisible(); - await expect(this.passwordInput).not.toBeVisible(); - await expect(this.backButton).toBeVisible(); - } - - async verifyNormalModeActive(): Promise { - await expect(this.title).toBeVisible(); - await expect(this.passwordInput).toBeVisible(); - } - - async verifyLoadingState(): Promise { - await expect(this.loginButton).toHaveAttribute("aria-disabled", "true"); - await expect(this.loadingIndicator).toBeVisible(); - } - - async verifyFormValidation(): Promise { - // Check for common validation messages - const emailError = this.page.getByText("Please enter a valid email address."); - const passwordError = this.page.getByText("Password is required."); - - // At least one validation error should be visible - await expect(emailError.or(passwordError)).toBeVisible(); - } - - // Accessibility methods - async verifyKeyboardNavigation(): Promise { - // Test tab navigation through form elements - await this.page.keyboard.press("Tab"); // Theme toggle - await this.page.keyboard.press("Tab"); // Email field - await expect(this.emailInput).toBeFocused(); - - await this.page.keyboard.press("Tab"); // Password field - await expect(this.passwordInput).toBeFocused(); - - await this.page.keyboard.press("Tab"); // Show password button - await this.page.keyboard.press("Tab"); // Login button - await expect(this.loginButton).toBeFocused(); - } - - async verifyAriaLabels(): Promise { - await expect(this.page.getByRole("textbox", { name: "Email" })).toBeVisible(); - await expect(this.page.getByRole("textbox", { name: "Password" })).toBeVisible(); - await expect(this.page.getByRole("button", { name: "Log in" })).toBeVisible(); - } - - // Utility methods - async clearForm(): Promise { - await this.emailInput.clear(); - await this.passwordInput.clear(); - } - - async isFormValid(): Promise { - const emailValue = await this.emailInput.inputValue(); - const passwordValue = await this.passwordInput.inputValue(); - return emailValue.length > 0 && passwordValue.length > 0; - } - - async getFormErrors(): Promise { - const errorElements = await this.errorMessages.all(); - const errors: string[] = []; - - for (const element of errorElements) { - const text = await element.textContent(); - if (text) { - errors.push(text.trim()); - } - } - - return errors; - } - - // Browser interaction methods - async refresh(): Promise { - await this.page.reload(); - await this.waitForPageLoad(); - } - - async goBack(): Promise { - await this.page.goBack(); - await this.waitForPageLoad(); - } - - // Session management methods - async logout(): Promise { - await this.homePage.signOut(); - } - - async verifyLogoutSuccess(): Promise { - await expect(this.page).toHaveURL("/sign-in"); - await expect(this.title).toBeVisible(); - } - - // Advanced interaction methods - async fillFormWithValidation(credentials: SignInCredentials): Promise { - // Fill email first and check for validation - await this.fillEmail(credentials.email); - await this.page.keyboard.press("Tab"); // Trigger validation - - // Fill password - await this.fillPassword(credentials.password); - } - - async submitFormWithEnterKey(): Promise { - await this.passwordInput.press("Enter"); - } - - async submitFormWithButtonClick(): Promise { - await this.submitForm(); - } - - // Error handling methods - async handleSamlError(): Promise { - const samlError = this.page.getByText("SAML Authentication Error"); - if (await samlError.isVisible()) { - // Handle SAML error if present - console.log("SAML authentication error detected"); - } - } - - // Wait methods - async waitForFormSubmission(): Promise { - await this.page.waitForFunction(() => { - const button = document.querySelector('button[aria-disabled="true"]'); - return button === null; - }); - } - - async waitForRedirect(expectedUrl: string): Promise { - await this.page.waitForURL(expectedUrl); - } -} diff --git a/ui/tests/sign-in/sign-in-page.ts b/ui/tests/sign-in/sign-in-page.ts index 8fcf1a3a04..5c426779b6 100644 --- a/ui/tests/sign-in/sign-in-page.ts +++ b/ui/tests/sign-in/sign-in-page.ts @@ -51,13 +51,13 @@ export class SignInPage extends BasePage { this.form = page.locator("form"); // Social authentication buttons - this.googleButton = page.getByText("Continue with Google"); - this.githubButton = page.getByText("Continue with Github"); - this.samlButton = page.getByText("Continue with SAML SSO"); + this.googleButton = page.getByRole("button", { name: "Continue with Google" }); + this.githubButton = page.getByRole("button", { name: "Continue with Github" }); + this.samlButton = page.getByRole("button", { name: "Continue with SAML SSO" }); // Navigation elements this.signUpLink = page.getByRole("link", { name: "Sign up" }); - this.backButton = page.getByText("Back"); + this.backButton = page.getByRole("button", { name: "Back" }); // UI elements this.logo = page.locator('svg[width="300"]'); @@ -66,7 +66,7 @@ export class SignInPage extends BasePage { this.errorMessages = page.locator('[role="alert"], .error-message, [data-testid="error"]'); // SAML specific elements - this.samlModeTitle = page.getByText("Sign in with SAML SSO"); + this.samlModeTitle = page.getByRole("heading", { name: "Sign in with SAML SSO" }); this.samlEmailInput = page.getByLabel("Email"); } @@ -137,7 +137,7 @@ export class SignInPage extends BasePage { async verifyPageLoaded(): Promise { await expect(this.page).toHaveTitle(/Prowler/); await expect(this.logo).toBeVisible(); - await expect(this.page.getByText("Sign in", { exact: true })).toBeVisible(); + await expect(this.page.getByRole("heading", { name: "Sign in", exact: true })).toBeVisible(); } async verifyFormElements(): Promise { @@ -157,7 +157,7 @@ export class SignInPage extends BasePage { } async verifyNavigationLinks(): Promise { - await expect(this.page.getByText("Need to create an account?")).toBeVisible(); + await expect(this.page.getByRole('link', { name: /Need to create an account\?/i })).toBeVisible(); await expect(this.signUpLink).toBeVisible(); } @@ -166,7 +166,7 @@ export class SignInPage extends BasePage { } async verifyLoginError(errorMessage: string = "Invalid email or password"): Promise { - await expect(this.page.getByText(errorMessage).first()).toBeVisible(); + await expect(this.page.getByRole("alert", { name: errorMessage })).toBeVisible(); await expect(this.page).toHaveURL("/sign-in"); } @@ -177,7 +177,7 @@ export class SignInPage extends BasePage { } async verifyNormalModeActive(): Promise { - await expect(this.page.getByText("Sign in", { exact: true })).toBeVisible(); + await expect(this.page.getByRole("heading", { name: "Sign in", exact: true })).toBeVisible(); await expect(this.passwordInput).toBeVisible(); } @@ -188,8 +188,8 @@ export class SignInPage extends BasePage { async verifyFormValidation(): Promise { // Check for common validation messages - const emailError = this.page.getByText("Please enter a valid email address."); - const passwordError = this.page.getByText("Password is required."); + const emailError = this.page.getByRole("alert", { name: "Please enter a valid email address." }); + const passwordError = this.page.getByRole("alert", { name: "Password is required." }); // At least one validation error should be visible await expect(emailError.or(passwordError)).toBeVisible(); @@ -237,7 +237,7 @@ export class SignInPage extends BasePage { async verifyLogoutSuccess(): Promise { await expect(this.page).toHaveURL("/sign-in"); - await expect(this.page.getByText("Sign in", { exact: true })).toBeVisible(); + await expect(this.page.getByRole("heading", { name: "Sign in", exact: true })).toBeVisible(); } // Advanced interaction methods @@ -260,7 +260,7 @@ export class SignInPage extends BasePage { // Error handling methods async handleSamlError(): Promise { - const samlError = this.page.getByText("SAML Authentication Error"); + const samlError = this.page.getByRole("alert", { name: "SAML Authentication Error" }); if (await samlError.isVisible()) { // Handle SAML error if present console.log("SAML authentication error detected"); diff --git a/ui/tests/sign-up/sign-up-page.ts b/ui/tests/sign-up/sign-up-page.ts index 077f250e86..52027279d3 100644 --- a/ui/tests/sign-up/sign-up-page.ts +++ b/ui/tests/sign-up/sign-up-page.ts @@ -39,7 +39,7 @@ export class SignUpPage extends BasePage { this.submitButton = page.getByRole("button", { name: "Sign up" }); this.loginLink = page.getByRole("link", { name: "Log in" }); - this.termsCheckbox = page.getByText("I agree with the"); + this.termsCheckbox = page.getByRole("checkbox", { name: /I agree with the/i }); } async goto(): Promise { @@ -47,7 +47,7 @@ export class SignUpPage extends BasePage { } async verifyPageLoaded(): Promise { - await expect(this.page.getByText("Sign up", { exact: true })).toBeVisible(); + await expect(this.page.getByRole("heading", { name: "Sign up" })).toBeVisible(); await expect(this.emailInput).toBeVisible(); await expect(this.submitButton).toBeVisible(); await this.waitForPageLoad(); From d17d519a3e6665576e0f491aa58ef582e6cf8ac9 Mon Sep 17 00:00:00 2001 From: StylusFrost Date: Tue, 21 Oct 2025 11:12:09 +0200 Subject: [PATCH 4/5] test(ui): update locators in tests to use role-based queries - Refactored locators in BasePage, HomePage, SignInPage, and SignUpPage to utilize role-based queries for improved accessibility and consistency across the UI tests. --- ui/tests/base-page.ts | 2 +- ui/tests/home/home-page.ts | 2 +- ui/tests/sign-in/sign-in-page.ts | 6 +++--- ui/tests/sign-up/sign-up-page.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/tests/base-page.ts b/ui/tests/base-page.ts index a31f84c7ad..c9b73f2b1a 100644 --- a/ui/tests/base-page.ts +++ b/ui/tests/base-page.ts @@ -18,7 +18,7 @@ export abstract class BasePage { // Common locators that most pages share this.title = page.locator("h1, h2, [role='heading']").first(); this.loadingIndicator = page.getByRole("status", { name: "Loading" }); - this.themeToggle = page.getByLabel("Toggle theme"); + this.themeToggle = page.getByRole("button", { name: "Toggle theme" }); } // Common navigation methods diff --git a/ui/tests/home/home-page.ts b/ui/tests/home/home-page.ts index 0ae8312481..e696e02ab5 100644 --- a/ui/tests/home/home-page.ts +++ b/ui/tests/home/home-page.ts @@ -25,7 +25,7 @@ export class HomePage extends BasePage { // Main content elements this.mainContent = page.locator("main"); - this.breadcrumbs = page.getByLabel("Breadcrumbs"); + this.breadcrumbs = page.getByRole("navigation", { name: "Breadcrumbs" }); this.overviewHeading = page.getByRole("heading", { name: "Overview", exact: true }); // Navigation elements diff --git a/ui/tests/sign-in/sign-in-page.ts b/ui/tests/sign-in/sign-in-page.ts index 5c426779b6..a694359422 100644 --- a/ui/tests/sign-in/sign-in-page.ts +++ b/ui/tests/sign-in/sign-in-page.ts @@ -45,8 +45,8 @@ export class SignInPage extends BasePage { this.homePage = new HomePage(page); // Form elements - this.emailInput = page.getByLabel("Email"); - this.passwordInput = page.getByLabel("Password"); + this.emailInput = page.getByRole("textbox", { name: "Email" }); + this.passwordInput = page.getByRole("textbox", { name: "Password" }); this.loginButton = page.getByRole("button", { name: "Log in" }); this.form = page.locator("form"); @@ -67,7 +67,7 @@ export class SignInPage extends BasePage { // SAML specific elements this.samlModeTitle = page.getByRole("heading", { name: "Sign in with SAML SSO" }); - this.samlEmailInput = page.getByLabel("Email"); + this.samlEmailInput = page.getByRole("textbox", { name: "Email" }); } // Navigation methods diff --git a/ui/tests/sign-up/sign-up-page.ts b/ui/tests/sign-up/sign-up-page.ts index 52027279d3..30d8f4d50d 100644 --- a/ui/tests/sign-up/sign-up-page.ts +++ b/ui/tests/sign-up/sign-up-page.ts @@ -32,7 +32,7 @@ export class SignUpPage extends BasePage { // Prefer stable name attributes to avoid label ambiguity in composed inputs this.nameInput = page.locator('input[name="name"]'); this.companyInput = page.locator('input[name="company"]'); - this.emailInput = page.getByLabel("Email"); + this.emailInput = page.getByRole("textbox", { name: "Email" }); this.passwordInput = page.locator('input[name="password"]'); this.confirmPasswordInput = page.locator('input[name="confirmPassword"]'); this.invitationTokenInput = page.locator('input[name="invitationToken"]'); From a6121396caddfc04ba2879dd0460b1730924a2f4 Mon Sep 17 00:00:00 2001 From: StylusFrost Date: Tue, 21 Oct 2025 11:13:52 +0200 Subject: [PATCH 5/5] test(ui): remove unnecessary blank line in admin authentication setup test - Cleaned up the admin authentication setup test by removing an unnecessary blank line for improved readability. --- ui/tests/setups/admin.auth.setup.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/tests/setups/admin.auth.setup.ts b/ui/tests/setups/admin.auth.setup.ts index 023428695b..0e24c242c3 100644 --- a/ui/tests/setups/admin.auth.setup.ts +++ b/ui/tests/setups/admin.auth.setup.ts @@ -4,7 +4,6 @@ import { authenticateAndSaveState } from '@/tests/helpers'; const adminUserFile = 'playwright/.auth/admin_user.json'; authAdminSetup('authenticate as admin e2e user', async ({ page }) => { - const adminEmail = process.env.E2E_ADMIN_USER; const adminPassword = process.env.E2E_ADMIN_PASSWORD;