import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useContextSelector } from 'use-context-selector'
// Group.test.tsx
import { describe, expect, it, vi } from 'vitest'
import RadioGroupContext from '../../context'
import Group from './index'
// small consumer that uses the same context as your component
function ContextConsumer({ showButton = true }: { showButton?: boolean }) {
// eslint-disable-next-line ts/no-explicit-any
const ctx = useContextSelector(RadioGroupContext, (v: any) => v)
const value = ctx?.value
const onChange = ctx?.onChange
return (
{String(value)}
{showButton && (
)}
)
}
describe('Group component', () => {
it('renders children and exposes provided value through context', () => {
render(
,
)
const valueNode = screen.getByTestId('radio-value')
expect(valueNode).toBeInTheDocument()
expect(valueNode).toHaveTextContent('initial-value')
})
it('merges custom className with existing classes on root element', () => {
const { container } = render(
,
)
const root = container.firstChild as HTMLElement
expect(root).toBeInTheDocument()
expect(root.className).toContain('my-extra-class')
// ensure it still has other classes (from cn + css module)
expect(root.className.length).toBeGreaterThan('my-extra-class'.length)
})
it('calls onChange from context when consumer triggers it', async () => {
const user = userEvent.setup()
const handleChange = vi.fn()
render(
,
)
const btn = screen.getByTestId('radio-change-btn')
await user.click(btn)
expect(handleChange).toHaveBeenCalledTimes(1)
expect(handleChange).toHaveBeenCalledWith('clicked-from-test')
})
it('does not throw if onChange is not provided and consumer calls it', async () => {
const user = userEvent.setup()
render(
{/* the consumer will call onChange which is undefined */}
,
)
const btn = screen.getByTestId('radio-change-btn')
// clicking should not throw (if it threw the test would fail)
await user.click(btn)
// value still rendered correctly (verifies consumer reads numeric/false-y values too)
expect(screen.getByTestId('radio-value')).toHaveTextContent('0')
})
it('correctly passes boolean and numeric values through context', () => {
render(
<>
>,
)
const nodes = screen.getAllByTestId('radio-value')
// first should be "false", second "123"
expect(nodes[0]).toHaveTextContent('false')
expect(nodes[1]).toHaveTextContent('123')
})
})