element, not a heading this.logo = page.locator('svg[width="300"]'); - - // Error messages - this.errorMessages = page.locator('[role="alert"], .error-message, [data-testid="error"]'); - - // SAML specific elements - this.samlModeTitle = page.getByRole("heading", { name: "Sign in with SAML SSO" }); + // Use text matching with exact=true to avoid matching other elements + this.pageTitle = page.getByText("Sign in", { exact: true }); + + // Error messages - form validation errors appear as
with specific classes
+ this.errorMessages = page.locator(
+ "p.text-destructive, p.text-sm.text-destructive",
+ );
+
+ // SAML specific elements - use text matching
+ this.samlModeTitle = page.getByText("Sign in with SAML SSO", {
+ exact: true,
+ });
this.samlEmailInput = page.getByRole("textbox", { name: "Email" });
}
@@ -75,6 +89,14 @@ export class SignInPage extends BasePage {
await super.goto("/sign-in");
}
+ /**
+ * Navigate to sign-in page with an error query parameter
+ * Used for testing error message display (e.g., session expiry)
+ */
+ async gotoWithError(errorType: string): Promise elements with destructive styling
+ await expect(this.page.getByText(errorMessage).first()).toBeVisible();
await expect(this.page).toHaveURL("/sign-in");
}
@@ -177,22 +215,24 @@ export class SignInPage extends BasePage {
}
async verifyNormalModeActive(): Promise elements
+ 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();
+ await expect(emailError.or(passwordError).first()).toBeVisible();
}
// Accessibility methods
@@ -211,9 +251,15 @@ export class SignInPage extends BasePage {
}
async verifyAriaLabels(): Promise