Skip to content

Commit 5f42a64

Browse files
committed
refactor: enhance accessibility and structure of login and signup pages
- Removed deprecated admin route from a11y_routes.json. - Updated LoginPage to include aria-labelledby for better accessibility. - Added a test for naming the login form region in LoginPage accessibility tests. - Refactored SignUpPage to improve link structure and accessibility. - Introduced mobile viewport tests for login and signup pages in a11y tests.
1 parent ef6f5e0 commit 5f42a64

6 files changed

Lines changed: 60 additions & 19 deletions

File tree

scripts/a11y/a11y_routes.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,6 @@
124124
}
125125
],
126126
"gated": [
127-
{
128-
"path": "/admin",
129-
"surface": "Admin page",
130-
"currentBehavior": "Redirects to /flows for current user/session. Scan with an admin user."
131-
},
132127
{
133128
"path": "/login",
134129
"surface": "Login page",

src/frontend/src/pages/LoginPage/__tests__/LoginPage.a11y.test.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,14 @@ describe("LoginPage accessibility", () => {
137137
).toBeInTheDocument();
138138
});
139139

140+
it("names_the_login_form_region", () => {
141+
renderLoginPage();
142+
143+
expect(
144+
screen.getByRole("region", { name: /sign in to langflow/i }),
145+
).toBeInTheDocument();
146+
});
147+
140148
it("adds_actionable_suggestion_to_server_login_errors", () => {
141149
mockLoginMutate.mockImplementation((_user, options) => {
142150
options.onError({

src/frontend/src/pages/LoginPage/index.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,13 @@ export default function LoginPage(): JSX.Element {
122122
<CustomLoginBrandTitle />
123123
</h1>
124124
</div>
125-
<section className="w-full rounded-xl border border-border bg-card p-8 shadow-2xl shadow-black/10 dark:shadow-black/40 sm:p-10">
125+
<section
126+
aria-labelledby="login-form-title"
127+
className="w-full rounded-xl border border-border bg-card p-8 shadow-2xl shadow-black/10 dark:shadow-black/40 sm:p-10"
128+
>
129+
<h2 id="login-form-title" className="sr-only">
130+
{t("auth.loginTitle")}
131+
</h2>
126132
<div className="flex flex-col gap-5">
127133
<CustomLoginFormGate>
128134
<Form.Field name="username" className="pb-3">

src/frontend/src/pages/SignUpPage/__tests__/SignUpPage.a11y.test.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ describe("SignUpPage accessibility", () => {
102102
).toBeInTheDocument();
103103
});
104104

105+
it("renders_sign_in_navigation_as_one_link", () => {
106+
renderSignUpPage();
107+
108+
const signInLink = screen.getByRole("link", {
109+
name: /already have an account.*sign in/i,
110+
});
111+
expect(signInLink).toHaveAttribute("href", "/login");
112+
expect(signInLink.querySelector("button")).not.toBeInTheDocument();
113+
});
114+
105115
it("announces_actionable_password_mismatch_suggestion_after_confirm_blur", () => {
106116
const { container } = renderSignUpPage();
107117

src/frontend/src/pages/SignUpPage/index.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -309,23 +309,23 @@ export default function SignUp(): JSX.Element {
309309
</Button>
310310
</Form.Submit>
311311

312-
<CustomLink className="block w-full" to="/login">
313-
<ShadTooltip
314-
content={`${t("auth.haveAccount")} ${t("auth.signInLink")}`}
315-
styleClasses="z-50"
312+
<ShadTooltip
313+
content={`${t("auth.haveAccount")} ${t("auth.signInLink")}`}
314+
styleClasses="z-50"
315+
>
316+
<Button
317+
asChild
318+
className="h-11 w-full overflow-hidden rounded-lg"
319+
variant="outline"
316320
>
317-
<Button
318-
className="h-11 w-full overflow-hidden rounded-lg"
319-
variant="outline"
320-
type="button"
321-
>
321+
<CustomLink to="/login">
322322
<span className="truncate">
323323
{t("auth.haveAccount")}&nbsp;
324324
<b>{t("auth.signInLink")}</b>
325325
</span>
326-
</Button>
327-
</ShadTooltip>
328-
</CustomLink>
326+
</CustomLink>
327+
</Button>
328+
</ShadTooltip>
329329
</div>
330330
</section>
331331
</div>

src/frontend/tests/a11y/auth-pages.a11y.spec.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,20 @@ async function driveLoginEmpty(page: LangflowPage) {
7474
await expect(page.getByRole("button", { name: /sign in/i })).toBeVisible();
7575
}
7676

77+
async function expectPageToReflow(page: LangflowPage) {
78+
const dimensions = await page.evaluate(() => ({
79+
clientWidth: document.documentElement.clientWidth,
80+
scrollWidth: document.documentElement.scrollWidth,
81+
}));
82+
expect(dimensions.scrollWidth).toBeLessThanOrEqual(dimensions.clientWidth);
83+
}
84+
85+
async function driveLoginMobile(page: LangflowPage) {
86+
await page.setViewportSize({ width: 320, height: 800 });
87+
await driveLoginEmpty(page);
88+
await expectPageToReflow(page);
89+
}
90+
7791
async function driveLoginValidation(page: LangflowPage) {
7892
await disableAutoLogin(page);
7993
await page.goto("/login");
@@ -107,6 +121,12 @@ async function driveSignupEmpty(page: LangflowPage) {
107121
await expect(page.getByRole("button", { name: /sign up/i })).toBeVisible();
108122
}
109123

124+
async function driveSignupMobile(page: LangflowPage) {
125+
await page.setViewportSize({ width: 320, height: 800 });
126+
await driveSignupEmpty(page);
127+
await expectPageToReflow(page);
128+
}
129+
110130
async function driveSignupMismatch(page: LangflowPage) {
111131
await disableAutoLogin(page);
112132
await page.goto("/signup");
@@ -163,9 +183,11 @@ const AUTH_STATES: Array<{
163183
drive: (page: LangflowPage) => Promise<void>;
164184
}> = [
165185
{ label: "auth-login-empty", drive: driveLoginEmpty },
186+
{ label: "auth-login-mobile", drive: driveLoginMobile },
166187
{ label: "auth-login-validation", drive: driveLoginValidation },
167188
{ label: "auth-login-error-toast", drive: driveLoginErrorToast },
168189
{ label: "auth-signup-empty", drive: driveSignupEmpty },
190+
{ label: "auth-signup-mobile", drive: driveSignupMobile },
169191
{ label: "auth-signup-mismatch", drive: driveSignupMismatch },
170192
{ label: "auth-signup-error-toast", drive: driveSignupErrorToast },
171193
{ label: "auth-admin-login-empty", drive: driveAdminLoginEmpty },
@@ -192,7 +214,7 @@ test.describe("auth page accessibility", () => {
192214
for (const state of AUTH_STATES) {
193215
test(
194216
`scans ${state.label} (${theme.name})`,
195-
{ tag: ["@release"] },
217+
{ tag: ["@release", "@workspace"] },
196218
async ({ page }) => {
197219
await theme.force(page);
198220
await state.drive(page);

0 commit comments

Comments
 (0)