// @vitest-environment jsdom /** * What the Link page claims, pinned: it is a real anchor with a real address; * `external` opens a new tab that cannot reach back; a router app takes the * click through `onClick` and the address survives it; each look is its own * class list and `plain` carries none; a ref reaches the anchor. */ import { createRef } from 'react' import { afterEach, describe, expect, it, vi } from 'vitest' import { cleanup, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { Link } from './Link' afterEach(cleanup) const classesOf = (el: Element) => el.getAttribute('class')?.split(' ').filter(Boolean) ?? [] describe('Link', () => { it('is an anchor with its address', () => { render(Documents) const link = screen.getByRole('link', { name: 'Documents' }) expect(link.tagName).toBe('A') expect(link.getAttribute('href')).toBe('/documents') }) it('stays in the same tab unless it is external', () => { render(Documents) const link = screen.getByRole('link', { name: 'Documents' }) expect(link.getAttribute('target')).toBeNull() expect(link.getAttribute('rel')).toBeNull() }) it('external opens a new tab that cannot reach back into this page', () => { render( Example , ) const link = screen.getByRole('link', { name: 'Example' }) expect(link.getAttribute('target')).toBe('_blank') expect(link.getAttribute('rel')).toBe('noopener noreferrer') }) it('a router app takes the click through onClick, and the href stays a real address', async () => { const onClick = vi.fn((event: { preventDefault: () => void }) => event.preventDefault()) render( Documents , ) await userEvent.click(screen.getByRole('link', { name: 'Documents' })) expect(onClick).toHaveBeenCalledTimes(1) expect(screen.getByRole('link', { name: 'Documents' }).getAttribute('href')).toBe('/documents') }) it('text is the link colour, always underlined, and is the default', () => { render(Label) const classes = classesOf(screen.getByRole('link')) expect(classes).toContain('text-text-interactive') expect(classes).toContain('underline') expect(classes).toContain('underline-offset-2') }) it('quiet sets no colour and no size of its own, and underlines on hover', () => { render( Label , ) expect(classesOf(screen.getByRole('link'))).toEqual(['hover:underline']) }) it('underlined sets no colour at rest, is always underlined, and brightens on hover', () => { render( Label , ) expect(classesOf(screen.getByRole('link'))).toEqual(['underline', 'underline-offset-2', 'hover:text-text-primary']) }) it('plain carries no class at all, so what it wraps draws itself', () => { render( Label , ) expect(classesOf(screen.getByRole('link'))).toEqual([]) }) it('cover lays a layer over the row and moves the ring onto it; without it, nothing of the kind', () => { render( <> Row Words , ) expect(classesOf(screen.getByRole('link', { name: 'Row' }))).toEqual(['after:absolute', 'after:inset-0', 'after:rounded-md', 'focus-visible:outline-none', 'focus-visible:after:[outline-style:auto]']) expect(classesOf(screen.getByRole('link', { name: 'Words' }))).toEqual([]) }) it('a ref reaches the anchor', () => { const ref = createRef() render( Label , ) expect(ref.current?.tagName).toBe('A') }) })