Add aria-current="page" to clickable last breadcrumb (a11y fix per WAI-ARIA)

This commit is contained in:
2026-04-21 18:34:16 +03:00
parent 8f573c15b8
commit b910fd058c
2 changed files with 75 additions and 1 deletions
+68
View File
@@ -0,0 +1,68 @@
// @vitest-environment jsdom
import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import { Breadcrumbs } from "./Breadcrumbs.js";
vi.mock("@/i18n/provider.js", () => ({
useTranslation: () => ({ t: (k: string) => k }),
}));
// Suppress SCSS import errors in jsdom
vi.mock("./Breadcrumbs.scss", () => ({}));
describe("Breadcrumbs", () => {
it("renders the nav with data-testid breadcrumbs", () => {
render(<Breadcrumbs items={[{ label: "Flights" }]} />);
expect(screen.getByTestId("breadcrumbs")).toBeTruthy();
});
it("last crumb rendered as <span> has aria-current='page'", () => {
render(<Breadcrumbs items={[{ label: "Flights" }]} />);
const span = screen.getByText("Flights");
expect(span.tagName.toLowerCase()).toBe("span");
expect(span.getAttribute("aria-current")).toBe("page");
});
it("last crumb rendered as <a> (with url) has aria-current='page'", () => {
render(
<Breadcrumbs
items={[
{ label: "Online Board", url: "/ru/onlineboard" },
{ label: "Results", url: "/ru/onlineboard/route/MOW-LED" },
]}
/>,
);
const link = screen.getByText("Results");
expect(link.tagName.toLowerCase()).toBe("a");
expect(link.getAttribute("aria-current")).toBe("page");
});
it("non-last crumb rendered as <a> does NOT have aria-current", () => {
render(
<Breadcrumbs
items={[
{ label: "Online Board", url: "/ru/onlineboard" },
{ label: "Results" },
]}
/>,
);
const link = screen.getByText("Online Board");
expect(link.tagName.toLowerCase()).toBe("a");
expect(link.getAttribute("aria-current")).toBeNull();
});
it("non-last crumb rendered as <span> does NOT have aria-current", () => {
// The home crumb (index 0) has url so it won't be a span, but we can
// check an intermediate span by using items without url at non-last position
render(
<Breadcrumbs
items={[
{ label: "Intermediate" },
{ label: "Last" },
]}
/>,
);
const intermediate = screen.getByText("Intermediate");
expect(intermediate.getAttribute("aria-current")).toBeNull();
});
});
+7 -1
View File
@@ -46,7 +46,13 @@ export const Breadcrumbs: FC<BreadcrumbsProps> = ({ items = [] }) => {
className={`breadcrumbs__item${isLast ? " breadcrumbs__item--active" : ""}`}
>
{showAsLink ? (
<a href={item.url} className="breadcrumbs__link">{item.label}</a>
<a
href={item.url}
className="breadcrumbs__link"
{...(isLast ? { "aria-current": "page" } : {})}
>
{item.label}
</a>
) : (
<span
className="breadcrumbs__text"