import React from 'react'
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import Tag from './tag'
import type { TagVariant } from './tag.types'
describe('Tag Component', () => {
describe('Rendering', () => {
it('should render with default props', () => {
render(Default Tag)
const tag = screen.getByText('Default Tag')
expect(tag).toBeInTheDocument()
expect(tag.tagName).toBe('SPAN')
})
it('should render children correctly', () => {
render(Test Content)
expect(screen.getByText('Test Content')).toBeInTheDocument()
})
it('should render as span element by default', () => {
render(Span Tag)
const tag = screen.getByText('Span Tag')
expect(tag.tagName).toBe('SPAN')
})
it('should render as p element when elm prop is "p"', () => {
render(Paragraph Tag)
const tag = screen.getByText('Paragraph Tag')
expect(tag.tagName).toBe('P')
})
})
describe('Accessibility (ARIA Roles)', () => {
it('should have role="note" by default', () => {
render(Note Tag)
const tag = screen.getByRole('note')
expect(tag).toBeInTheDocument()
})
it('should apply role="status" when specified', () => {
render(Status Tag)
const tag = screen.getByRole('status')
expect(tag).toBeInTheDocument()
})
it('should support aria-label for additional context', () => {
render(Beta)
const tag = screen.getByLabelText('Beta version indicator')
expect(tag).toBeInTheDocument()
})
it('should support aria-describedby for extended descriptions', () => {
render(
<>
This is a beta feature
Beta
>
)
const tag = screen.getByRole('note')
expect(tag).toHaveAttribute('aria-describedby', 'beta-desc')
})
})
describe('Variants', () => {
const variants: TagVariant[] = ['alpha', 'beta', 'stable', 'production']
variants.forEach((variant) => {
it(`should apply data-tag="${variant}" attribute for ${variant} variant`, () => {
render({variant})
const tag = screen.getByText(variant)
expect(tag).toHaveAttribute('data-tag', variant)
})
})
it('should not apply data-tag attribute when variant is undefined', () => {
render(No Variant)
const tag = screen.getByText('No Variant')
expect(tag).not.toHaveAttribute('data-tag')
})
})
describe('Custom Styling', () => {
it('should apply custom inline styles via styles prop', () => {
render(
Styled Tag
)
const tag = screen.getByText('Styled Tag')
expect(tag).toHaveStyle({ fontSize: '1rem' })
expect(tag.style.backgroundColor).toBeTruthy()
expect(tag.style.color).toBeTruthy()
})
it('should apply CSS classes via classes prop', () => {
render(Classed Tag)
const tag = screen.getByText('Classed Tag')
expect(tag).toHaveClass('custom-class', 'another-class')
})
it('should apply id attribute', () => {
render(ID Tag)
const tag = screen.getByText('ID Tag')
expect(tag).toHaveAttribute('id', 'unique-tag')
})
})
describe('Component Composition', () => {
it('should render with both variant and custom styles', () => {
render(
Combined
)
const tag = screen.getByText('Combined')
expect(tag).toHaveAttribute('data-tag', 'beta')
expect(tag).toHaveStyle({ fontSize: '1rem' })
})
it('should render with all props combined', () => {
render(
Production
)
const tag = screen.getByRole('status')
expect(tag.tagName).toBe('P')
expect(tag).toHaveAttribute('data-tag', 'production')
expect(tag).toHaveAttribute('id', 'prod-tag')
expect(tag).toHaveAttribute('aria-label', 'Production environment')
expect(tag).toHaveClass('production-tag')
expect(tag).toHaveStyle({ fontWeight: 'bold' })
})
})
describe('Type Safety', () => {
it('should accept valid TagVariant values', () => {
// These should compile without TypeScript errors
const validVariants: TagVariant[] = ['alpha', 'beta', 'stable', 'production']
validVariants.forEach((variant) => {
const { unmount } = render({variant})
expect(screen.getByText(variant)).toBeInTheDocument()
unmount()
})
})
it('should accept valid elm prop values', () => {
const { rerender } = render(Span)
expect(screen.getByText('Span').tagName).toBe('SPAN')
rerender(Paragraph)
expect(screen.getByText('Paragraph').tagName).toBe('P')
})
it('should accept valid role prop values', () => {
const { rerender } = render(Note)
expect(screen.getByRole('note')).toBeInTheDocument()
rerender(Status)
expect(screen.getByRole('status')).toBeInTheDocument()
})
})
describe('Edge Cases', () => {
it('should require children for accessibility', () => {
// TypeScript should enforce children as required
// This test verifies meaningful content is provided
render(Required Content)
const tag = screen.getByLabelText('Tag with content')
expect(tag).toBeInTheDocument()
expect(tag).toHaveTextContent('Required Content')
})
it('should handle multiple children', () => {
render(
Part 1
Part 2
)
expect(screen.getByText('Part 1')).toBeInTheDocument()
expect(screen.getByText('Part 2')).toBeInTheDocument()
})
it('should handle complex children with React elements', () => {
render(
Beta v2.0
)
expect(screen.getByText('Beta')).toBeInTheDocument()
expect(screen.getByText('v2.0')).toBeInTheDocument()
})
})
describe('Display Name', () => {
it('should have correct displayName for debugging', () => {
expect(Tag.displayName).toBe('Tag')
})
})
})