106 lines
3.2 KiB
TypeScript
106 lines
3.2 KiB
TypeScript
import { describe, expect, it, afterEach } from "vitest"
|
|
import { render, screen, cleanup } from "@testing-library/react"
|
|
import userEvent from "@testing-library/user-event"
|
|
|
|
import { LinkChips } from "./LinkChips"
|
|
import type { LinkChipsProps } from "./types"
|
|
|
|
afterEach(() => {
|
|
cleanup()
|
|
})
|
|
|
|
const defaultChips: LinkChipsProps["chips"] = [
|
|
{ title: "Hotels in Stockholm", url: "/hotels/stockholm" },
|
|
{ title: "Hotels in Copenhagen", url: "/hotels/copenhagen" },
|
|
{ title: "Hotels in Oslo", url: "/hotels/oslo" },
|
|
]
|
|
|
|
describe("LinkChips accessibility", () => {
|
|
describe("semantic HTML", () => {
|
|
it("uses proper link elements for navigation", () => {
|
|
render(<LinkChips chips={defaultChips} />)
|
|
const links = screen.getAllByRole("link")
|
|
expect(links.length).toBe(3)
|
|
links.forEach((link) => {
|
|
expect(link.tagName).toBe("A")
|
|
})
|
|
})
|
|
|
|
it("has accessible link text", () => {
|
|
render(<LinkChips chips={defaultChips} />)
|
|
expect(
|
|
screen.getByRole("link", { name: "Hotels in Stockholm" })
|
|
).toBeTruthy()
|
|
expect(
|
|
screen.getByRole("link", { name: "Hotels in Copenhagen" })
|
|
).toBeTruthy()
|
|
expect(screen.getByRole("link", { name: "Hotels in Oslo" })).toBeTruthy()
|
|
})
|
|
|
|
it("links have descriptive href attributes", () => {
|
|
render(<LinkChips chips={defaultChips} />)
|
|
const stockholmLink = screen.getByRole("link", {
|
|
name: "Hotels in Stockholm",
|
|
})
|
|
expect(stockholmLink.getAttribute("href")).toBe("/hotels/stockholm")
|
|
})
|
|
})
|
|
|
|
describe("keyboard navigation", () => {
|
|
it("all links are keyboard accessible", async () => {
|
|
const user = userEvent.setup()
|
|
render(<LinkChips chips={defaultChips} />)
|
|
|
|
const links = screen.getAllByRole("link")
|
|
expect(links.length).toBeGreaterThan(0)
|
|
|
|
// Tab through all links
|
|
for (const link of links) {
|
|
await user.tab()
|
|
expect(document.activeElement).toBe(link)
|
|
}
|
|
})
|
|
|
|
it("maintains logical focus order", async () => {
|
|
const user = userEvent.setup()
|
|
render(<LinkChips chips={defaultChips} />)
|
|
|
|
const firstLink = screen.getByRole("link", {
|
|
name: "Hotels in Stockholm",
|
|
})
|
|
const secondLink = screen.getByRole("link", {
|
|
name: "Hotels in Copenhagen",
|
|
})
|
|
const thirdLink = screen.getByRole("link", { name: "Hotels in Oslo" })
|
|
|
|
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("links have accessible names", () => {
|
|
render(<LinkChips chips={defaultChips} />)
|
|
const links = screen.getAllByRole("link")
|
|
links.forEach((link) => {
|
|
// Check that link has text content (accessible name)
|
|
expect(link.textContent?.trim().length).toBeGreaterThan(0)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("empty state", () => {
|
|
it("does not render anything when chips array is empty", () => {
|
|
const { container } = render(<LinkChips chips={[]} />)
|
|
expect(container.firstChild).toBeNull()
|
|
expect(screen.queryAllByRole("link")).toHaveLength(0)
|
|
})
|
|
})
|
|
})
|