Move LinkChips and add unit + a11y tests for chips components
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
/* eslint-disable formatjs/no-literal-string-in-jsx */
|
||||
import { describe, expect, it, afterEach } from "vitest"
|
||||
import { render, screen, cleanup } from "@testing-library/react"
|
||||
import userEvent from "@testing-library/user-event"
|
||||
|
||||
import { ChipLink } from "./ChipLink"
|
||||
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
})
|
||||
|
||||
describe("ChipLink accessibility", () => {
|
||||
describe("semantic HTML", () => {
|
||||
it("uses proper link element for navigation", () => {
|
||||
render(<ChipLink href="/test">Test Link</ChipLink>)
|
||||
const link = screen.getByRole("link")
|
||||
expect(link.tagName).toBe("A")
|
||||
})
|
||||
|
||||
it("has accessible link text", () => {
|
||||
render(<ChipLink href="/hotels">View Hotels</ChipLink>)
|
||||
expect(screen.getByRole("link", { name: "View Hotels" })).toBeTruthy()
|
||||
})
|
||||
|
||||
it("link has descriptive href attribute", () => {
|
||||
render(<ChipLink href="/hotels/stockholm">Stockholm Hotels</ChipLink>)
|
||||
const link = screen.getByRole("link", { name: "Stockholm Hotels" })
|
||||
expect(link.getAttribute("href")).toBe("/hotels/stockholm")
|
||||
})
|
||||
})
|
||||
|
||||
describe("keyboard navigation", () => {
|
||||
it("link is keyboard accessible", async () => {
|
||||
const user = userEvent.setup()
|
||||
render(<ChipLink href="/test">Accessible Link</ChipLink>)
|
||||
|
||||
const link = screen.getByRole("link")
|
||||
await user.tab()
|
||||
expect(document.activeElement).toBe(link)
|
||||
})
|
||||
|
||||
it("multiple links maintain logical focus order", async () => {
|
||||
const user = userEvent.setup()
|
||||
render(
|
||||
<div>
|
||||
<ChipLink href="/first">First Link</ChipLink>
|
||||
<ChipLink href="/second">Second Link</ChipLink>
|
||||
<ChipLink href="/third">Third Link</ChipLink>
|
||||
</div>
|
||||
)
|
||||
|
||||
const firstLink = screen.getByRole("link", { name: "First Link" })
|
||||
const secondLink = screen.getByRole("link", { name: "Second Link" })
|
||||
const thirdLink = screen.getByRole("link", { name: "Third Link" })
|
||||
|
||||
await user.tab()
|
||||
expect(document.activeElement).toBe(firstLink)
|
||||
|
||||
await user.tab()
|
||||
expect(document.activeElement).toBe(secondLink)
|
||||
|
||||
await user.tab()
|
||||
expect(document.activeElement).toBe(thirdLink)
|
||||
})
|
||||
})
|
||||
|
||||
describe("screen reader support", () => {
|
||||
it("link has accessible name from content", () => {
|
||||
render(<ChipLink href="/test">Descriptive Link Text</ChipLink>)
|
||||
const link = screen.getByRole("link")
|
||||
expect(link.textContent?.trim().length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it("link with icon and text has accessible name", () => {
|
||||
render(
|
||||
<ChipLink href="/test">
|
||||
<span aria-hidden="true">→</span>
|
||||
Next Page
|
||||
</ChipLink>
|
||||
)
|
||||
const link = screen.getByRole("link")
|
||||
expect(link.textContent).toContain("Next Page")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,86 @@
|
||||
/* eslint-disable formatjs/no-literal-string-in-jsx */
|
||||
import { describe, expect, it, afterEach } from "vitest"
|
||||
import { render, screen, cleanup } from "@testing-library/react"
|
||||
import userEvent from "@testing-library/user-event"
|
||||
|
||||
import { ChipLink } from "./ChipLink"
|
||||
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
})
|
||||
|
||||
describe("ChipLink", () => {
|
||||
describe("rendering", () => {
|
||||
it("renders as a link element", () => {
|
||||
render(<ChipLink href="/test">Test Link</ChipLink>)
|
||||
const link = screen.getByRole("link", { name: "Test Link" })
|
||||
expect(link).toBeTruthy()
|
||||
expect(link.tagName).toBe("A")
|
||||
})
|
||||
|
||||
it("renders children content", () => {
|
||||
render(<ChipLink href="/test">Link Content</ChipLink>)
|
||||
expect(screen.getByText("Link Content")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("applies correct href attribute", () => {
|
||||
render(<ChipLink href="/destination">Go somewhere</ChipLink>)
|
||||
const link = screen.getByRole("link", { name: "Go somewhere" })
|
||||
expect(link.getAttribute("href")).toBe("/destination")
|
||||
})
|
||||
|
||||
it("renders with multiple children", () => {
|
||||
render(
|
||||
<ChipLink href="/test">
|
||||
<span>Icon</span>
|
||||
Text
|
||||
</ChipLink>
|
||||
)
|
||||
expect(screen.getByText("Icon")).toBeTruthy()
|
||||
expect(screen.getByText("Text")).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe("props", () => {
|
||||
it("applies custom className", () => {
|
||||
render(
|
||||
<ChipLink href="/test" className="custom-class">
|
||||
Link
|
||||
</ChipLink>
|
||||
)
|
||||
const link = screen.getByRole("link", { name: "Link" })
|
||||
expect(link.className).toContain("custom-class")
|
||||
})
|
||||
|
||||
it("supports target attribute", () => {
|
||||
render(
|
||||
<ChipLink href="/external" target="_blank">
|
||||
External Link
|
||||
</ChipLink>
|
||||
)
|
||||
const link = screen.getByRole("link", { name: "External Link" })
|
||||
expect(link.getAttribute("target")).toBe("_blank")
|
||||
})
|
||||
|
||||
it("supports rel attribute", () => {
|
||||
render(
|
||||
<ChipLink href="/external" rel="noopener noreferrer">
|
||||
External Link
|
||||
</ChipLink>
|
||||
)
|
||||
const link = screen.getByRole("link", { name: "External Link" })
|
||||
expect(link.getAttribute("rel")).toBe("noopener noreferrer")
|
||||
})
|
||||
})
|
||||
|
||||
describe("keyboard navigation", () => {
|
||||
it("is focusable via keyboard", async () => {
|
||||
const user = userEvent.setup()
|
||||
render(<ChipLink href="/test">Focusable Link</ChipLink>)
|
||||
|
||||
const link = screen.getByRole("link", { name: "Focusable Link" })
|
||||
await user.tab()
|
||||
expect(document.activeElement).toBe(link)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user