Design system.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 

336 Zeilen
7.4 KiB

  1. import * as React from 'react';
  2. import {
  3. cleanup, fireEvent,
  4. render,
  5. screen,
  6. act, waitFor,
  7. } from '@testing-library/react';
  8. import userEvent from '@testing-library/user-event';
  9. import { TextControl } from '@tesseract-design/web-base';
  10. import {
  11. vi,
  12. expect,
  13. describe,
  14. it,
  15. afterEach,
  16. } from 'vitest';
  17. import matchers from '@testing-library/jest-dom/matchers';
  18. import {
  19. MaskedTextInput,
  20. MaskedTextInputDerivedElement,
  21. } from '.';
  22. expect.extend(matchers);
  23. describe('MaskedTextInput', () => {
  24. afterEach(() => {
  25. cleanup();
  26. });
  27. it('renders a password input', () => {
  28. render(
  29. <MaskedTextInput />,
  30. );
  31. const textbox = screen.getByTestId('input');
  32. expect(textbox).toBeInTheDocument();
  33. expect(textbox).toHaveProperty('type', 'password');
  34. });
  35. it('renders a border', () => {
  36. render(
  37. <MaskedTextInput
  38. border
  39. />,
  40. );
  41. const border = screen.getByTestId('border');
  42. expect(border).toBeInTheDocument();
  43. });
  44. it('renders a label', () => {
  45. render(
  46. <MaskedTextInput
  47. label="foo"
  48. />,
  49. );
  50. const textbox = screen.getByLabelText('foo');
  51. expect(textbox).toBeInTheDocument();
  52. const label = screen.getByTestId('label');
  53. expect(label).toHaveTextContent('foo');
  54. });
  55. it('renders a hidden label', () => {
  56. render(
  57. <MaskedTextInput
  58. label="foo"
  59. hiddenLabel
  60. />,
  61. );
  62. const textbox = screen.getByLabelText('foo');
  63. expect(textbox).toBeInTheDocument();
  64. const label = screen.queryByTestId('label');
  65. expect(label).toBeInTheDocument();
  66. expect(label).toHaveClass('sr-only');
  67. });
  68. it('renders a hint', () => {
  69. render(
  70. <MaskedTextInput
  71. hint="foo"
  72. />,
  73. );
  74. const hint = screen.getByTestId('hint');
  75. expect(hint).toBeInTheDocument();
  76. });
  77. it('renders an indicator', () => {
  78. render(
  79. <MaskedTextInput
  80. enhanced
  81. />,
  82. );
  83. const indicator = screen.getByTestId('indicator');
  84. expect(indicator).toBeInTheDocument();
  85. });
  86. it('renders the indicator changing when switching visibility state', async () => {
  87. render(
  88. <MaskedTextInput
  89. enhanced
  90. />,
  91. );
  92. const indicator = screen.getByTestId('indicator');
  93. await userEvent.click(indicator);
  94. expect(indicator).toHaveTextContent('Hide');
  95. await userEvent.click(indicator);
  96. expect(indicator).toHaveTextContent('Show');
  97. });
  98. it('renders the indicator changing when switching visibility state using function ref', async () => {
  99. render(
  100. <MaskedTextInput
  101. enhanced
  102. ref={vi.fn()}
  103. />,
  104. );
  105. const indicator = screen.getByTestId('indicator');
  106. await userEvent.click(indicator);
  107. expect(indicator).toHaveTextContent('Hide');
  108. await userEvent.click(indicator);
  109. expect(indicator).toHaveTextContent('Show');
  110. });
  111. it('highlights the indicator when visibility is toggled via keyboard', async () => {
  112. render(
  113. <MaskedTextInput
  114. enhanced
  115. />,
  116. );
  117. const input = screen.getByTestId('input');
  118. const indicator = screen.getByTestId('indicator');
  119. input.focus();
  120. fireEvent.keyDown(input, { code: 'Space', ctrlKey: true });
  121. expect(indicator).toHaveClass('text-tertiary');
  122. fireEvent.keyUp(input, { code: 'Space', ctrlKey: true });
  123. expect(indicator).toHaveClass('text-primary');
  124. });
  125. it('handles keydown events', async () => {
  126. const onKeyDown = vi.fn();
  127. render(
  128. <MaskedTextInput
  129. enhanced
  130. onKeyDown={onKeyDown}
  131. />,
  132. );
  133. const input = screen.getByTestId('input');
  134. input.focus();
  135. fireEvent.keyDown(input, { code: 'Space', ctrlKey: true });
  136. expect(onKeyDown).toBeCalled();
  137. });
  138. it('handles keyup events', async () => {
  139. const onKeyUp = vi.fn();
  140. render(
  141. <MaskedTextInput
  142. enhanced
  143. onKeyUp={onKeyUp}
  144. />,
  145. );
  146. const input = screen.getByTestId('input');
  147. input.focus();
  148. fireEvent.keyUp(input, { code: 'Space', ctrlKey: true });
  149. expect(onKeyUp).toBeCalled();
  150. });
  151. it('accepts a function ref', () => {
  152. const ref = vi.fn();
  153. render(
  154. <MaskedTextInput
  155. enhanced
  156. ref={ref}
  157. />,
  158. );
  159. expect(ref).toBeCalled();
  160. });
  161. describe.each`
  162. size | inputClassName | hintClassName | indicatorClassName
  163. ${'small'} | ${'h-10'} | ${'pr-10'} | ${'w-10'}
  164. ${'medium'} | ${'h-12'} | ${'pr-12'} | ${'w-12'}
  165. ${'large'} | ${'h-16'} | ${'pr-16'} | ${'w-16'}
  166. `('on $size size', ({
  167. size,
  168. inputClassName,
  169. hintClassName,
  170. indicatorClassName,
  171. }: {
  172. size: TextControl.Size,
  173. inputClassName: string,
  174. hintClassName: string,
  175. indicatorClassName: string,
  176. }) => {
  177. it('renders input styles', () => {
  178. render(
  179. <MaskedTextInput
  180. size={size}
  181. />,
  182. );
  183. const input = screen.getByTestId('input');
  184. expect(input).toHaveClass(inputClassName);
  185. });
  186. it('renders label styles with indicator', () => {
  187. render(
  188. <MaskedTextInput
  189. size={size}
  190. label="foo"
  191. enhanced
  192. />,
  193. );
  194. const label = screen.getByTestId('label');
  195. expect(label).toHaveClass(hintClassName);
  196. });
  197. it('renders hint styles when indicator is present', () => {
  198. render(
  199. <MaskedTextInput
  200. size={size}
  201. hint="hint"
  202. enhanced
  203. />,
  204. );
  205. const hint = screen.getByTestId('hint');
  206. expect(hint).toHaveClass(hintClassName);
  207. });
  208. it('renders indicator styles', () => {
  209. render(
  210. <MaskedTextInput
  211. size={size}
  212. enhanced
  213. />,
  214. );
  215. const indicator = screen.getByTestId('indicator');
  216. expect(indicator).toHaveClass(indicatorClassName);
  217. });
  218. });
  219. it('renders a block textbox', () => {
  220. render(
  221. <MaskedTextInput
  222. block
  223. />,
  224. );
  225. const base = screen.getByTestId('base');
  226. expect(base).toHaveClass('block');
  227. });
  228. describe.each`
  229. variant | inputClassName | hintClassName
  230. ${'default'} | ${'pl-4'} | ${'bottom-0 pl-4 pb-1'}
  231. ${'alternate'} | ${'pl-1.5 pt-4'} | ${'top-0.5'}
  232. `('on $variant style', ({
  233. variant,
  234. inputClassName,
  235. hintClassName,
  236. }: {
  237. variant: TextControl.Variant,
  238. inputClassName: string,
  239. hintClassName: string,
  240. }) => {
  241. it('renders input styles', () => {
  242. render(
  243. <MaskedTextInput
  244. variant={variant}
  245. />,
  246. );
  247. const input = screen.getByTestId('input');
  248. expect(input).toHaveClass(inputClassName);
  249. });
  250. it('renders hint styles', () => {
  251. render(
  252. <MaskedTextInput
  253. variant={variant}
  254. hint="hint"
  255. />,
  256. );
  257. const hint = screen.getByTestId('hint');
  258. expect(hint).toHaveClass(hintClassName);
  259. });
  260. });
  261. it('handles change events', async () => {
  262. const onChange = vi.fn().mockImplementationOnce(
  263. (e: React.ChangeEvent<MaskedTextInputDerivedElement>) => {
  264. e.preventDefault();
  265. },
  266. );
  267. render(
  268. <MaskedTextInput
  269. onChange={onChange}
  270. />,
  271. );
  272. const textbox = screen.getByTestId('input');
  273. await userEvent.type(textbox, 'foobar');
  274. expect(onChange).toBeCalled();
  275. });
  276. it('handles input events', async () => {
  277. const onInput = vi.fn().mockImplementationOnce(
  278. (e: React.SyntheticEvent<MaskedTextInputDerivedElement>) => {
  279. e.preventDefault();
  280. },
  281. );
  282. render(
  283. <MaskedTextInput
  284. onInput={onInput}
  285. />,
  286. );
  287. const textbox = screen.getByTestId('input');
  288. await userEvent.type(textbox, 'foobar');
  289. expect(onInput).toBeCalled();
  290. });
  291. });