import {describe, expect, it, vi, beforeEach} from 'vitest'
import {render, screen, userEvent} from '../../test-utils'
import {TransitionLink} from './transition-link'
// Mock react-router hooks
const mockNavigate = vi.fn()
vi.mock('react-router', () => ({
useHref: vi.fn((to: string) => to),
}))
// Mock navigation hook
vi.mock('../../hooks/navigation/useNavigateWithTransition', () => ({
useNavigateWithTransition: () => mockNavigate,
}))
describe('TransitionLink', () => {
beforeEach(() => {
vi.clearAllMocks()
// Reset console.warn mock
vi.spyOn(console, 'warn').mockImplementation(() => {})
})
it('renders link with children', () => {
render(Click me)
const link = screen.getByRole('link', {name: /click me/i})
expect(link).toBeInTheDocument()
})
it('sets href attribute for relative paths', () => {
render(Test Link)
const link = screen.getByRole('link')
expect(link).toHaveAttribute('href', '/test-path')
})
it('navigates on click', async () => {
const user = userEvent.setup()
render(Navigate)
const link = screen.getByRole('link')
await user.click(link)
expect(mockNavigate).toHaveBeenCalledWith('/test-path')
})
it('prevents default link behavior on click', async () => {
userEvent.setup()
const preventDefault = vi.fn()
render(Link)
const link = screen.getByRole('link')
// Manually create and dispatch event to test preventDefault
const clickEvent = new MouseEvent('click', {
bubbles: true,
cancelable: true,
})
Object.defineProperty(clickEvent, 'preventDefault', {
value: preventDefault,
})
link.dispatchEvent(clickEvent)
expect(preventDefault).toHaveBeenCalled()
})
it('calls custom onClick handler', async () => {
const user = userEvent.setup()
const handleClick = vi.fn()
render(
Link
)
const link = screen.getByRole('link')
await user.click(link)
expect(handleClick).toHaveBeenCalled()
expect(mockNavigate).toHaveBeenCalled()
})
it('does not navigate if onClick prevents default', async () => {
const user = userEvent.setup()
const handleClick = vi.fn(err => err.preventDefault())
render(
Link
)
const link = screen.getByRole('link')
await user.click(link)
expect(handleClick).toHaveBeenCalled()
expect(mockNavigate).not.toHaveBeenCalled()
})
it('warns about absolute URLs', () => {
const warnSpy = vi.spyOn(console, 'warn')
render(
External Link
)
expect(warnSpy).toHaveBeenCalledWith(
'TransitionLink: absolute URLs are not supported. Please update to a valid relative path.'
)
})
it('does not set href for absolute URLs', () => {
render(
External Link
)
const link = screen.getByText('External Link')
expect(link).not.toHaveAttribute('href')
})
it('forwards ref to anchor element', () => {
const ref = vi.fn()
render(
Link
)
expect(ref).toHaveBeenCalled()
expect(ref.mock.calls[0][0]).toBeInstanceOf(HTMLAnchorElement)
})
it('passes additional props to anchor element', () => {
render(
Link
)
const link = screen.getByRole('link')
expect(link).toHaveClass('custom-class')
expect(link).toHaveAttribute('data-testid', 'custom-link')
})
})