Design system.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

255 lines
5.9 KiB

  1. import * as React from 'react';
  2. import {
  3. cleanup,
  4. render,
  5. screen,
  6. } from '@testing-library/react';
  7. import { TextControl } from '@tesseract-design/web-base';
  8. import userEvent from '@testing-library/user-event';
  9. import {
  10. afterEach,
  11. expect,
  12. vi,
  13. describe,
  14. it,
  15. } from 'vitest';
  16. import matchers from '@testing-library/jest-dom/matchers';
  17. import {
  18. MenuSelect,
  19. MenuSelectDerivedElement,
  20. } from '.';
  21. expect.extend(matchers);
  22. describe('MenuSelect', () => {
  23. afterEach(() => {
  24. cleanup();
  25. });
  26. it('renders a listbox', () => {
  27. render(<MenuSelect />);
  28. const listbox = screen.getByRole('listbox');
  29. expect(listbox).toBeInTheDocument();
  30. });
  31. it('renders a border', () => {
  32. render(
  33. <MenuSelect
  34. border
  35. />,
  36. );
  37. const border = screen.getByTestId('border');
  38. expect(border).toBeInTheDocument();
  39. });
  40. it('renders a label', () => {
  41. render(
  42. <MenuSelect
  43. label="foo"
  44. />,
  45. );
  46. const listbox = screen.getByLabelText('foo');
  47. expect(listbox).toBeInTheDocument();
  48. const label = screen.getByTestId('label');
  49. expect(label).toHaveTextContent('foo');
  50. });
  51. it('renders a hidden label', () => {
  52. render(
  53. <MenuSelect
  54. label="foo"
  55. hiddenLabel
  56. />,
  57. );
  58. const listbox = screen.getByLabelText('foo');
  59. expect(listbox).toBeInTheDocument();
  60. const label = screen.getByTestId('label');
  61. expect(label).toHaveClass('sr-only');
  62. });
  63. it('renders a hint', () => {
  64. render(
  65. <MenuSelect
  66. hint="foo"
  67. />,
  68. );
  69. const hint = screen.getByTestId('hint');
  70. expect(hint).toBeInTheDocument();
  71. });
  72. it('render options with implicit values', () => {
  73. render(
  74. <MenuSelect>
  75. <option>foo</option>
  76. <option>bar</option>
  77. </MenuSelect>,
  78. );
  79. const listbox = screen.getByRole('listbox');
  80. expect(listbox.children).toHaveLength(2);
  81. });
  82. it('renders valid options', () => {
  83. render(
  84. <MenuSelect>
  85. <option value="foo">foo</option>
  86. <option value="bar">bar</option>
  87. </MenuSelect>,
  88. );
  89. const listbox = screen.getByRole('listbox');
  90. expect(listbox.children).toHaveLength(2);
  91. });
  92. it('renders option groups', () => {
  93. render(
  94. <MenuSelect>
  95. <optgroup label="foo">
  96. <option value="baz">baz</option>
  97. </optgroup>
  98. <optgroup label="bar">
  99. <option value="quux">quux</option>
  100. <option value="quuux">quuux</option>
  101. </optgroup>
  102. </MenuSelect>,
  103. );
  104. const listbox = screen.getByRole('listbox');
  105. expect(listbox.children).toHaveLength(2);
  106. expect(listbox.children[0].children).toHaveLength(1);
  107. expect(listbox.children[1].children).toHaveLength(2);
  108. });
  109. describe.each`
  110. size | inputClassNames | hintClassNames | indicatorClassNames
  111. ${'small'} | ${'min-h-10'} | ${'pr-10'} | ${'w-10'}
  112. ${'medium'} | ${'min-h-12'} | ${'pr-12'} | ${'w-12'}
  113. ${'large'} | ${'min-h-16'} | ${'pr-16'} | ${'w-16'}
  114. `('on $size size', ({
  115. size,
  116. inputClassNames,
  117. hintClassNames,
  118. indicatorClassNames,
  119. }: {
  120. size: TextControl.Size,
  121. inputClassNames: string,
  122. hintClassNames: string,
  123. indicatorClassNames: string,
  124. }) => {
  125. it('renders input styles', () => {
  126. render(
  127. <MenuSelect
  128. size={size}
  129. />,
  130. );
  131. const listbox = screen.getByRole('listbox');
  132. expect(listbox).toHaveClass(inputClassNames);
  133. });
  134. it('renders hint styles with indicator', () => {
  135. render(
  136. <MenuSelect
  137. size={size}
  138. hint="hint"
  139. indicator="a"
  140. />,
  141. );
  142. const hint = screen.getByTestId('hint');
  143. expect(hint).toHaveClass(hintClassNames);
  144. });
  145. it('renders indicator styles', () => {
  146. render(
  147. <MenuSelect
  148. size={size}
  149. indicator="a"
  150. />,
  151. );
  152. const indicator = screen.getByTestId('indicator');
  153. expect(indicator).toHaveClass(indicatorClassNames);
  154. });
  155. it('renders indicator styles for label', () => {
  156. render(
  157. <MenuSelect
  158. size={size}
  159. label="label"
  160. indicator="a"
  161. />,
  162. );
  163. const label = screen.getByTestId('label');
  164. expect(label).toHaveClass(hintClassNames);
  165. });
  166. });
  167. it('renders a block input', () => {
  168. render(
  169. <MenuSelect
  170. block
  171. />,
  172. );
  173. const base = screen.getByTestId('base');
  174. expect(base).toHaveClass('block');
  175. });
  176. describe.each`
  177. variant | inputClassNames | hintClassNames
  178. ${'default'} | ${'pl-4'} | ${'bottom-0 pl-4 pb-1'}
  179. ${'alternate'} | ${'pl-1.5 pt-5'} | ${'top-0.5'}
  180. `('on $variant variant', ({
  181. variant,
  182. inputClassNames,
  183. hintClassNames,
  184. }: {
  185. variant: TextControl.Variant,
  186. inputClassNames: string,
  187. hintClassNames: string,
  188. }) => {
  189. it('renders input styles', () => {
  190. render(
  191. <MenuSelect
  192. variant={variant}
  193. />,
  194. );
  195. const listbox = screen.getByRole('listbox');
  196. expect(listbox).toHaveClass(inputClassNames);
  197. });
  198. it('renders hint styles', () => {
  199. render(
  200. <MenuSelect
  201. variant={variant}
  202. hint="hint"
  203. />,
  204. );
  205. const hint = screen.getByTestId('hint');
  206. expect(hint).toHaveClass(hintClassNames);
  207. });
  208. });
  209. it('handles change events', async () => {
  210. const onChange = vi.fn().mockImplementationOnce(
  211. (e: React.ChangeEvent<MenuSelectDerivedElement>) => {
  212. e.preventDefault();
  213. },
  214. );
  215. render(
  216. <MenuSelect
  217. onChange={onChange}
  218. >
  219. <option value="foo">foo</option>
  220. <option value="bar">bar</option>
  221. </MenuSelect>,
  222. );
  223. const listbox: HTMLSelectElement = screen.getByRole('listbox');
  224. const [, secondOption] = screen.getAllByRole('option');
  225. await userEvent.selectOptions(listbox, secondOption);
  226. expect(onChange).toBeCalled();
  227. });
  228. });