import { describe, it, expect, vi } from 'vitest'
import { render, screen, within } from '@testing-library/react'
import { userEvent } from '@testing-library/user-event'
import { axe, toHaveNoViolations } from 'jest-axe'
expect.extend(toHaveNoViolations)
/**
* Example component test demonstrating RTL best practices
* with accessibility testing via axe-core
*/
// Example component
interface EntityCardProps {
entity: {
id: string
name: string
type: string
description?: string
}
onEdit?: (id: string) => void
onDelete?: (id: string) => void
}
function EntityCard({ entity, onEdit, onDelete }: EntityCardProps) {
return (
{entity.name}
{entity.type}
{entity.description && {entity.description}
}
)
}
describe('EntityCard', () => {
const mockEntity = {
id: '1',
name: 'Test Character',
type: 'character',
description: 'A brave adventurer'
}
it('renders entity information', () => {
render()
expect(screen.getByRole('heading', { name: 'Test Character' })).toBeInTheDocument()
expect(screen.getByText('character')).toBeInTheDocument()
expect(screen.getByText('A brave adventurer')).toBeInTheDocument()
})
it('does not render description when not provided', () => {
const entityWithoutDesc = { ...mockEntity, description: undefined }
render()
expect(screen.queryByText('A brave adventurer')).not.toBeInTheDocument()
})
it('calls onEdit when edit button is clicked', async () => {
const user = userEvent.setup()
const onEdit = vi.fn()
render()
await user.click(screen.getByRole('button', { name: /edit test character/i }))
expect(onEdit).toHaveBeenCalledTimes(1)
expect(onEdit).toHaveBeenCalledWith('1')
})
it('calls onDelete when delete button is clicked', async () => {
const user = userEvent.setup()
const onDelete = vi.fn()
render()
await user.click(screen.getByRole('button', { name: /delete test character/i }))
expect(onDelete).toHaveBeenCalledTimes(1)
expect(onDelete).toHaveBeenCalledWith('1')
})
it('does not render action buttons when handlers not provided', () => {
render()
expect(screen.queryByRole('button', { name: /edit/i })).not.toBeInTheDocument()
expect(screen.queryByRole('button', { name: /delete/i })).not.toBeInTheDocument()
})
it('has accessible structure', () => {
render()
const article = screen.getByRole('article', { name: /entity: test character/i })
expect(article).toBeInTheDocument()
// Check heading hierarchy
const heading = within(article).getByRole('heading', { level: 2 })
expect(heading).toHaveTextContent('Test Character')
// Check buttons have accessible names
const editButton = within(article).getByRole('button', { name: /edit test character/i })
const deleteButton = within(article).getByRole('button', { name: /delete test character/i })
expect(editButton).toBeInTheDocument()
expect(deleteButton).toBeInTheDocument()
})
it('has no accessibility violations', async () => {
const { container } = render(
)
const results = await axe(container)
expect(results).toHaveNoViolations()
})
})