import React from 'react' import { render, fireEvent, createEvent } from '../utils/test-utils' import userEvent from '@testing-library/user-event' import { GridEditorRadio } from './radio' import type { CellEditorParams } from '../types' import { GridEditorContext } from '../context/grid-editor-context/context' jest.mock('../context/grid-context', () => ({ useGridColumn: () => ({ data: { label: 'Is Default' } }), })) const baseProps = { rowId: '1', mode: 'editing' as CellEditorParams['mode'], tabIndex: 0, label: '', value: false, columnId: 'isDefault', } describe('GridEditorRadio', () => { let onConfirm: jest.Mock let onCancel: jest.Mock beforeEach(() => { onConfirm = jest.fn() onCancel = jest.fn() }) function renderRadio(props: Partial = {}) { return render( ) } it('should render a radio button', () => { const { getByRole } = renderRadio() expect(getByRole('radio')).toBeInTheDocument() }) it('should reflect value as checked', () => { const { getByRole } = renderRadio({ value: true }) expect(getByRole('radio')).toBeChecked() }) it('should reflect value as unchecked', () => { const { getByRole } = renderRadio({ value: false }) expect(getByRole('radio')).not.toBeChecked() }) it('should call onConfirm(true) on click', async () => { const { getByRole } = renderRadio({ value: false }) await userEvent.click(getByRole('radio')) expect(onConfirm).toHaveBeenCalledWith(true, { continueEditing: 'current', }) }) it('should call onConfirm with continueEditing:next on Tab', async () => { renderRadio() await userEvent.keyboard('{Tab}') expect(onConfirm).toHaveBeenCalledWith(false, { continueEditing: 'next', }) }) it('should call onConfirm with continueEditing:previous on Shift+Tab', async () => { renderRadio() await userEvent.keyboard('{Shift>}{Tab}{/Shift}') expect(onConfirm).toHaveBeenCalledWith(false, { continueEditing: 'previous', }) }) it('should call onCancel on Escape', async () => { renderRadio() await userEvent.keyboard('{Escape}') expect(onConfirm).not.toHaveBeenCalled() expect(onCancel).toHaveBeenCalled() }) it('should not intercept Tab in navigation mode', async () => { renderRadio({ mode: 'navigation' }) await userEvent.keyboard('{Tab}') expect(onConfirm).not.toHaveBeenCalled() expect(onCancel).not.toHaveBeenCalled() }) it.each(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'])( 'should swallow %s key', (key) => { const { getByRole } = renderRadio() const radio = getByRole('radio') const event = createEvent.keyDown(radio, { key, bubbles: true }) fireEvent(radio, event) expect(event.defaultPrevented).toBe(true) } ) describe('disabled state', () => { function renderDisabled(value: boolean) { return render( ) } const getDisabledWrapper = ( container: ReturnType ) => container.getByRole('radio') it('should expose role=radio with aria-disabled on the wrapper', () => { const wrapper = getDisabledWrapper(renderDisabled(false)) expect(wrapper).toBeInTheDocument() expect(wrapper).toHaveAttribute('aria-disabled', 'true') }) it('should expose aria-checked on wrapper matching value', () => { const wrapper = getDisabledWrapper(renderDisabled(true)) expect(wrapper).toHaveAttribute('aria-checked', 'true') }) it('should expose aria-label on the wrapper', () => { const wrapper = getDisabledWrapper(renderDisabled(false)) expect(wrapper).toHaveAttribute('aria-label', 'Is Default') }) }) })