segmentedControl.spec.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  2. import {SegmentedControl} from 'sentry/components/segmentedControl';
  3. describe('SegmentedControl', function () {
  4. it('renders with uncontrolled value', async function () {
  5. const onChange = jest.fn();
  6. render(
  7. <SegmentedControl aria-label="Test" defaultValue="1" onChange={onChange}>
  8. <SegmentedControl.Item key="1">Option 1</SegmentedControl.Item>
  9. <SegmentedControl.Item key="2">Option 2</SegmentedControl.Item>
  10. <SegmentedControl.Item key="3">Option 3</SegmentedControl.Item>
  11. </SegmentedControl>
  12. );
  13. // Radio group (wrapper) has the correct aria-label and aria-orientation
  14. expect(screen.getByRole('radiogroup')).toHaveAccessibleName('Test');
  15. expect(screen.getByRole('radiogroup')).toHaveAttribute(
  16. 'aria-orientation',
  17. 'horizontal'
  18. );
  19. // All 3 radio options are rendered
  20. expect(screen.getByRole('radio', {name: 'Option 1'})).toBeInTheDocument();
  21. expect(screen.getByRole('radio', {name: 'Option 2'})).toBeInTheDocument();
  22. expect(screen.getByRole('radio', {name: 'Option 3'})).toBeInTheDocument();
  23. // First option is selected by default
  24. expect(screen.getByRole('radio', {name: 'Option 1'})).toBeChecked();
  25. // Click on second option
  26. await userEvent.click(screen.getByRole('radio', {name: 'Option 2'}));
  27. // onChange function is called with the new key
  28. expect(onChange).toHaveBeenCalledWith('2');
  29. });
  30. it('renders with controlled value', function () {
  31. const {rerender} = render(
  32. <SegmentedControl aria-label="Test" value="2">
  33. <SegmentedControl.Item key="1">Option 1</SegmentedControl.Item>
  34. <SegmentedControl.Item key="2">Option 2</SegmentedControl.Item>
  35. <SegmentedControl.Item key="3">Option 3</SegmentedControl.Item>
  36. </SegmentedControl>
  37. );
  38. // Second option is selected
  39. expect(screen.getByRole('radio', {name: 'Option 2'})).toBeChecked();
  40. rerender(
  41. <SegmentedControl aria-label="Test" value="3">
  42. <SegmentedControl.Item key="1">Option 1</SegmentedControl.Item>
  43. <SegmentedControl.Item key="2">Option 2</SegmentedControl.Item>
  44. <SegmentedControl.Item key="3">Option 3</SegmentedControl.Item>
  45. </SegmentedControl>
  46. );
  47. // Third option is selected upon rerender
  48. expect(screen.getByRole('radio', {name: 'Option 3'})).toBeChecked();
  49. });
  50. it('responds to mouse and keyboard events', async function () {
  51. const onChange = jest.fn();
  52. render(
  53. <SegmentedControl aria-label="Test" defaultValue="1" onChange={onChange}>
  54. <SegmentedControl.Item key="1">Option 1</SegmentedControl.Item>
  55. <SegmentedControl.Item key="2">Option 2</SegmentedControl.Item>
  56. <SegmentedControl.Item key="3">Option 3</SegmentedControl.Item>
  57. </SegmentedControl>
  58. );
  59. // Clicking on Option 2 selects it
  60. await userEvent.click(screen.getByRole('radio', {name: 'Option 2'}));
  61. expect(screen.getByRole('radio', {name: 'Option 2'})).toBeChecked();
  62. // onChange function is called with the new key
  63. expect(onChange).toHaveBeenCalledWith('2');
  64. // Pressing arrow left/right selects the previous/next option
  65. await userEvent.keyboard('{ArrowLeft}');
  66. expect(screen.getByRole('radio', {name: 'Option 1'})).toBeChecked();
  67. await userEvent.keyboard('{ArrowRight}');
  68. expect(screen.getByRole('radio', {name: 'Option 2'})).toBeChecked();
  69. // Pressing arrow up/down selects the previous/next option
  70. await userEvent.keyboard('{ArrowUp}');
  71. expect(screen.getByRole('radio', {name: 'Option 1'})).toBeChecked();
  72. await userEvent.keyboard('{ArrowDown}');
  73. expect(screen.getByRole('radio', {name: 'Option 2'})).toBeChecked();
  74. // When the selection state reaches the end of the list, it circles back to the
  75. // first option
  76. await userEvent.keyboard('{ArrowRight>2}');
  77. expect(screen.getByRole('radio', {name: 'Option 1'})).toBeChecked();
  78. });
  79. it('works with disabled options', async function () {
  80. render(
  81. <SegmentedControl aria-label="Test">
  82. <SegmentedControl.Item key="1">Option 1</SegmentedControl.Item>
  83. <SegmentedControl.Item key="2" disabled>
  84. Option 2
  85. </SegmentedControl.Item>
  86. <SegmentedControl.Item key="3">Option 3</SegmentedControl.Item>
  87. </SegmentedControl>
  88. );
  89. expect(screen.getByRole('radio', {name: 'Option 2'})).toBeDisabled();
  90. // Clicking on the disabled option does not select it
  91. await userEvent.click(screen.getByRole('radio', {name: 'Option 2'}));
  92. expect(screen.getByRole('radio', {name: 'Option 2'})).not.toBeChecked();
  93. // The disabled option is skipped when using keyboard navigation
  94. await userEvent.click(screen.getByRole('radio', {name: 'Option 1'}));
  95. expect(screen.getByRole('radio', {name: 'Option 1'})).toBeChecked();
  96. await userEvent.keyboard('{ArrowRight}');
  97. expect(screen.getByRole('radio', {name: 'Option 3'})).toBeChecked();
  98. });
  99. });