@1doc/1ds-react 2.7.2 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/CHANGELOG.md +1280 -0
  2. package/dist/components/AIContent/AIContent.d.ts +10 -0
  3. package/dist/components/AIContent/AIContent.js +1 -1
  4. package/dist/components/AILabel/AILabel.d.ts +4 -0
  5. package/dist/components/AILabel/AILabel.js +2 -2
  6. package/dist/components/Accordion/Accordion.d.ts +6 -2
  7. package/dist/components/Alert/Alert.css +2 -0
  8. package/dist/components/Alert/Alert.d.ts +3 -1
  9. package/dist/components/Alert/Alert.js +7 -1
  10. package/dist/components/AppHeader/AppHeader.css +82 -8
  11. package/dist/components/AppHeader/AppHeader.d.ts +12 -1
  12. package/dist/components/AppHeader/AppHeader.js +186 -1
  13. package/dist/components/AppNavItem/AppNavItem.css +11 -3
  14. package/dist/components/AppShell/AppShell.css +9 -0
  15. package/dist/components/AppShell/AppShell.d.ts +8 -0
  16. package/dist/components/AppShell/AppShell.js +4 -1
  17. package/dist/components/AppSidebar/AppSidebar.css +1 -1
  18. package/dist/components/AppSidebar/AppSidebar.d.ts +4 -0
  19. package/dist/components/AppSidebar/AppSidebar.js +3 -1
  20. package/dist/components/AttachmentCard/AttachmentCard.css +17 -1
  21. package/dist/components/AttachmentCard/AttachmentCard.d.ts +29 -2
  22. package/dist/components/AttachmentCard/AttachmentCard.js +88 -20
  23. package/dist/components/Avatar/Avatar.css +7 -2
  24. package/dist/components/Avatar/AvatarGroup.d.ts +27 -0
  25. package/dist/components/Avatar/AvatarGroup.js +28 -4
  26. package/dist/components/Badge/Badge.css +61 -3
  27. package/dist/components/Badge/Badge.d.ts +14 -4
  28. package/dist/components/Badge/Badge.js +1 -0
  29. package/dist/components/BottomSheet/BottomSheet.css +1 -0
  30. package/dist/components/BottomSheet/BottomSheet.d.ts +8 -0
  31. package/dist/components/BottomSheet/BottomSheet.js +14 -2
  32. package/dist/components/Box/Box.css +83 -0
  33. package/dist/components/Box/Box.d.ts +82 -2
  34. package/dist/components/Box/Box.js +42 -2
  35. package/dist/components/Button/Button.css +29 -0
  36. package/dist/components/Button/Button.d.ts +4 -4
  37. package/dist/components/Button/Button.js +4 -1
  38. package/dist/components/Calendar/Calendar.css +245 -0
  39. package/dist/components/Calendar/Calendar.d.ts +125 -0
  40. package/dist/components/Calendar/Calendar.js +320 -0
  41. package/dist/components/Chart/BarChart.d.ts +6 -0
  42. package/dist/components/Chart/BarChart.js +3 -1
  43. package/dist/components/Chart/LineChart.d.ts +6 -0
  44. package/dist/components/Chart/LineChart.js +3 -1
  45. package/dist/components/Checkbox/Checkbox.css +4 -1
  46. package/dist/components/Chips/Chips.css +39 -0
  47. package/dist/components/Chips/Chips.d.ts +7 -2
  48. package/dist/components/Chips/Chips.js +6 -2
  49. package/dist/components/Coachmark/Coachmark.css +118 -0
  50. package/dist/components/Coachmark/Coachmark.d.ts +75 -0
  51. package/dist/components/Coachmark/Coachmark.js +321 -0
  52. package/dist/components/CodeBlock/CodeBlock.css +96 -0
  53. package/dist/components/CodeBlock/CodeBlock.d.ts +47 -0
  54. package/dist/components/CodeBlock/CodeBlock.js +103 -0
  55. package/dist/components/ColorPicker/ColorPicker.css +133 -0
  56. package/dist/components/ColorPicker/ColorPicker.d.ts +73 -0
  57. package/dist/components/ColorPicker/ColorPicker.js +219 -0
  58. package/dist/components/Combobox/Combobox.css +11 -3
  59. package/dist/components/ConfirmAIAction/ConfirmAIAction.d.ts +11 -1
  60. package/dist/components/ConfirmAIAction/ConfirmAIAction.js +6 -1
  61. package/dist/components/ConfirmDialog/ConfirmDialog.css +3 -0
  62. package/dist/components/ConfirmDialog/ConfirmDialog.d.ts +14 -0
  63. package/dist/components/ConfirmDialog/ConfirmDialog.js +2 -2
  64. package/dist/components/DataTable/DataTable.css +80 -0
  65. package/dist/components/DataTable/DataTable.d.ts +23 -4
  66. package/dist/components/DataTable/DataTable.js +61 -15
  67. package/dist/components/DatePicker/DatePicker.css +8 -0
  68. package/dist/components/DatePicker/DatePicker.d.ts +4 -0
  69. package/dist/components/DatePicker/DatePicker.js +14 -1
  70. package/dist/components/DescriptionList/DescriptionList.css +113 -0
  71. package/dist/components/DescriptionList/DescriptionList.d.ts +59 -0
  72. package/dist/components/DescriptionList/DescriptionList.js +51 -0
  73. package/dist/components/Drawer/Drawer.css +1 -0
  74. package/dist/components/Dropdown/Dropdown.js +47 -29
  75. package/dist/components/FileInput/FileInput.css +24 -4
  76. package/dist/components/FileInput/FileInput.d.ts +22 -2
  77. package/dist/components/FileInput/FileInput.js +23 -2
  78. package/dist/components/Grid/Grid.js +5 -5
  79. package/dist/components/IconPicker/IconPicker.css +107 -0
  80. package/dist/components/IconPicker/IconPicker.d.ts +74 -0
  81. package/dist/components/IconPicker/IconPicker.js +194 -0
  82. package/dist/components/Input/Input.css +41 -3
  83. package/dist/components/Input/Input.d.ts +14 -1
  84. package/dist/components/Input/Input.js +72 -6
  85. package/dist/components/Kanban/Kanban.css +5 -0
  86. package/dist/components/Kanban/Kanban.d.ts +41 -0
  87. package/dist/components/Kanban/Kanban.js +59 -27
  88. package/dist/components/Kanban/KanbanCard.d.ts +2 -0
  89. package/dist/components/Kanban/KanbanCard.js +1 -1
  90. package/dist/components/Kanban/KanbanColumn.d.ts +2 -0
  91. package/dist/components/Kanban/KanbanColumn.js +3 -0
  92. package/dist/components/Kbd/Kbd.css +66 -0
  93. package/dist/components/Kbd/Kbd.d.ts +32 -0
  94. package/dist/components/Kbd/Kbd.js +40 -0
  95. package/dist/components/Link/Link.css +1 -1
  96. package/dist/components/List/List.css +136 -0
  97. package/dist/components/List/List.d.ts +82 -0
  98. package/dist/components/List/List.js +53 -0
  99. package/dist/components/List/ListItem.d.ts +85 -0
  100. package/dist/components/List/ListItem.js +81 -0
  101. package/dist/components/Modal/Modal.css +93 -8
  102. package/dist/components/Modal/Modal.d.ts +45 -7
  103. package/dist/components/Modal/Modal.js +106 -6
  104. package/dist/components/MultiSelect/MultiSelect.css +9 -1
  105. package/dist/components/MultiSelect/MultiSelect.js +45 -8
  106. package/dist/components/OrgChart/OrgChart.css +149 -0
  107. package/dist/components/OrgChart/OrgChart.d.ts +83 -0
  108. package/dist/components/OrgChart/OrgChart.js +297 -0
  109. package/dist/components/OtpInput/OtpInput.css +93 -0
  110. package/dist/components/OtpInput/OtpInput.d.ts +60 -0
  111. package/dist/components/OtpInput/OtpInput.js +215 -0
  112. package/dist/components/Pagination/Pagination.d.ts +6 -0
  113. package/dist/components/Pagination/Pagination.js +9 -1
  114. package/dist/components/PhoneInput/PhoneInput.css +9 -1
  115. package/dist/components/PhoneInput/PhoneInput.d.ts +10 -0
  116. package/dist/components/PhoneInput/PhoneInput.js +20 -3
  117. package/dist/components/Popover/Popover.d.ts +7 -0
  118. package/dist/components/Popover/Popover.js +11 -1
  119. package/dist/components/RichTextEditor/RichTextEditor.css +203 -0
  120. package/dist/components/RichTextEditor/RichTextEditor.d.ts +83 -0
  121. package/dist/components/RichTextEditor/RichTextEditor.js +494 -0
  122. package/dist/components/SegmentedControl/SegmentedControl.d.ts +2 -0
  123. package/dist/components/SegmentedControl/SegmentedControl.js +21 -8
  124. package/dist/components/Select/Select.css +71 -1
  125. package/dist/components/Select/Select.d.ts +12 -0
  126. package/dist/components/Select/Select.js +93 -10
  127. package/dist/components/SidePanel/SidePanel.css +4 -4
  128. package/dist/components/SidePanelItem/SidePanelItem.css +7 -5
  129. package/dist/components/SidePanelSearch/SidePanelSearch.css +2 -2
  130. package/dist/components/SidePanelSection/SidePanelSection.css +7 -5
  131. package/dist/components/Stack/Stack.css +49 -0
  132. package/dist/components/Stack/Stack.d.ts +65 -7
  133. package/dist/components/Stack/Stack.js +30 -2
  134. package/dist/components/StatCard/StatCard.css +73 -0
  135. package/dist/components/StatCard/StatCard.d.ts +17 -0
  136. package/dist/components/StatCard/StatCard.js +4 -1
  137. package/dist/components/Stepper/Stepper.css +4 -1
  138. package/dist/components/Stepper/Stepper.d.ts +8 -0
  139. package/dist/components/Stepper/Stepper.js +4 -4
  140. package/dist/components/Switch/Switch.css +1 -0
  141. package/dist/components/Tabs/Tab.d.ts +15 -0
  142. package/dist/components/Tabs/Tab.js +30 -1
  143. package/dist/components/Tabs/Tabs.css +132 -0
  144. package/dist/components/Tabs/Tabs.d.ts +7 -0
  145. package/dist/components/Tabs/Tabs.js +13 -2
  146. package/dist/components/Tag/Tag.css +85 -2
  147. package/dist/components/Tag/Tag.d.ts +13 -6
  148. package/dist/components/Tag/Tag.js +1 -0
  149. package/dist/components/Text/Text.d.ts +9 -1
  150. package/dist/components/Text/Text.js +2 -2
  151. package/dist/components/Textarea/Textarea.css +11 -3
  152. package/dist/components/TimePicker/TimePicker.css +8 -0
  153. package/dist/components/TimePicker/TimePicker.d.ts +6 -0
  154. package/dist/components/TimePicker/TimePicker.js +1 -1
  155. package/dist/components/Tooltip/Tooltip.css +40 -0
  156. package/dist/components/Tooltip/Tooltip.d.ts +11 -0
  157. package/dist/components/Tooltip/Tooltip.js +114 -11
  158. package/dist/index.d.ts +25 -0
  159. package/dist/index.js +14 -0
  160. package/dist/teste/AILabel.test.d.ts +1 -0
  161. package/dist/teste/AILabel.test.js +33 -0
  162. package/dist/teste/AccordionConteudoLivre.test.d.ts +1 -0
  163. package/dist/teste/AccordionConteudoLivre.test.js +29 -0
  164. package/dist/teste/Alert.test.d.ts +1 -0
  165. package/dist/teste/Alert.test.js +27 -0
  166. package/dist/teste/AtributosRepassados.test.d.ts +1 -0
  167. package/dist/teste/AtributosRepassados.test.js +52 -0
  168. package/dist/teste/AttachmentCardIA.test.d.ts +1 -0
  169. package/dist/teste/AttachmentCardIA.test.js +89 -0
  170. package/dist/teste/AvatarGroupOverlap.test.d.ts +1 -0
  171. package/dist/teste/AvatarGroupOverlap.test.js +56 -0
  172. package/dist/teste/BadgeTag.test.d.ts +1 -0
  173. package/dist/teste/BadgeTag.test.js +42 -0
  174. package/dist/teste/BottomSheet.test.d.ts +1 -0
  175. package/dist/teste/BottomSheet.test.js +23 -0
  176. package/dist/teste/BoxItemFlex.test.d.ts +1 -0
  177. package/dist/teste/BoxItemFlex.test.js +54 -0
  178. package/dist/teste/BoxLayout.test.d.ts +1 -0
  179. package/dist/teste/BoxLayout.test.js +35 -0
  180. package/dist/teste/Button.test.d.ts +1 -0
  181. package/dist/teste/Button.test.js +27 -0
  182. package/dist/teste/Calendar.test.d.ts +1 -0
  183. package/dist/teste/Calendar.test.js +221 -0
  184. package/dist/teste/ChipsXs.test.d.ts +1 -0
  185. package/dist/teste/ChipsXs.test.js +31 -0
  186. package/dist/teste/Coachmark.test.d.ts +1 -0
  187. package/dist/teste/Coachmark.test.js +149 -0
  188. package/dist/teste/ColorPicker.test.d.ts +1 -0
  189. package/dist/teste/ColorPicker.test.js +132 -0
  190. package/dist/teste/ConfirmAIAction.test.d.ts +1 -0
  191. package/dist/teste/ConfirmAIAction.test.js +33 -0
  192. package/dist/teste/DataTableCelulaLivre.test.d.ts +1 -0
  193. package/dist/teste/DataTableCelulaLivre.test.js +76 -0
  194. package/dist/teste/DataTableDocumento.test.d.ts +1 -0
  195. package/dist/teste/DataTableDocumento.test.js +92 -0
  196. package/dist/teste/DatePicker.test.js +23 -0
  197. package/dist/teste/Dropdown.test.js +111 -0
  198. package/dist/teste/FileInputTrigger.test.d.ts +1 -0
  199. package/dist/teste/FileInputTrigger.test.js +53 -0
  200. package/dist/teste/IconPicker.test.d.ts +1 -0
  201. package/dist/teste/IconPicker.test.js +130 -0
  202. package/dist/teste/InputMascaraEAfins.test.d.ts +1 -0
  203. package/dist/teste/InputMascaraEAfins.test.js +99 -0
  204. package/dist/teste/KbdCodeBlock.test.d.ts +1 -0
  205. package/dist/teste/KbdCodeBlock.test.js +95 -0
  206. package/dist/teste/List.test.d.ts +1 -0
  207. package/dist/teste/List.test.js +153 -0
  208. package/dist/teste/Modal.test.d.ts +1 -0
  209. package/dist/teste/Modal.test.js +26 -0
  210. package/dist/teste/ModalVariantes.test.d.ts +1 -0
  211. package/dist/teste/ModalVariantes.test.js +151 -0
  212. package/dist/teste/MultiSelectErro.test.d.ts +1 -0
  213. package/dist/teste/MultiSelectErro.test.js +62 -0
  214. package/dist/teste/NomeAcessivelSsr.test.d.ts +1 -0
  215. package/dist/teste/NomeAcessivelSsr.test.js +88 -0
  216. package/dist/teste/OrgChart.test.d.ts +1 -0
  217. package/dist/teste/OrgChart.test.js +162 -0
  218. package/dist/teste/OtpInput.test.d.ts +1 -0
  219. package/dist/teste/OtpInput.test.js +143 -0
  220. package/dist/teste/PopoverMaxHeight.test.d.ts +1 -0
  221. package/dist/teste/PopoverMaxHeight.test.js +38 -0
  222. package/dist/teste/RichTextEditor.test.d.ts +1 -0
  223. package/dist/teste/RichTextEditor.test.js +287 -0
  224. package/dist/teste/RotulosTraduziveis.test.d.ts +1 -0
  225. package/dist/teste/RotulosTraduziveis.test.js +405 -0
  226. package/dist/teste/SegmentedControl.test.js +33 -0
  227. package/dist/teste/Select.test.d.ts +1 -0
  228. package/dist/teste/Select.test.js +62 -0
  229. package/dist/teste/SelectPlacementFiltro.test.d.ts +1 -0
  230. package/dist/teste/SelectPlacementFiltro.test.js +88 -0
  231. package/dist/teste/Stack.test.d.ts +1 -0
  232. package/dist/teste/Stack.test.js +57 -0
  233. package/dist/teste/StatCardRotuloTopo.test.d.ts +1 -0
  234. package/dist/teste/StatCardRotuloTopo.test.js +34 -0
  235. package/dist/teste/TabsContadorFechavel.test.d.ts +1 -0
  236. package/dist/teste/TabsContadorFechavel.test.js +79 -0
  237. package/dist/teste/Tooltip.test.d.ts +1 -0
  238. package/dist/teste/Tooltip.test.js +109 -0
  239. package/dist/teste/TooltipDark.test.d.ts +1 -0
  240. package/dist/teste/TooltipDark.test.js +31 -0
  241. package/dist/utils/calendario.d.ts +28 -0
  242. package/dist/utils/calendario.js +73 -0
  243. package/dist/utils/chart.d.ts +4 -0
  244. package/dist/utils/chart.js +3 -2
  245. package/dist/utils/html-seguro.d.ts +27 -0
  246. package/dist/utils/html-seguro.js +97 -0
  247. package/dist/utils/id.d.ts +2 -0
  248. package/dist/utils/id.js +23 -0
  249. package/dist/utils/paleta-de-cores.d.ts +26 -0
  250. package/dist/utils/paleta-de-cores.js +10 -0
  251. package/dist/utils/texto.d.ts +5 -0
  252. package/dist/utils/texto.js +5 -0
  253. package/package.json +3 -3
  254. package/src/index.ts +26 -0
  255. package/src/teste/AILabel.test.tsx +41 -0
  256. package/src/teste/AccordionConteudoLivre.test.tsx +39 -0
  257. package/src/teste/Alert.test.tsx +32 -0
  258. package/src/teste/AtributosRepassados.test.tsx +73 -0
  259. package/src/teste/AttachmentCardIA.test.tsx +126 -0
  260. package/src/teste/AvatarGroupOverlap.test.tsx +74 -0
  261. package/src/teste/BadgeTag.test.tsx +64 -0
  262. package/src/teste/BottomSheet.test.tsx +25 -0
  263. package/src/teste/BoxItemFlex.test.tsx +81 -0
  264. package/src/teste/BoxLayout.test.tsx +50 -0
  265. package/src/teste/Button.test.tsx +39 -0
  266. package/src/teste/Calendar.test.tsx +282 -0
  267. package/src/teste/ChipsXs.test.tsx +41 -0
  268. package/src/teste/Coachmark.test.tsx +198 -0
  269. package/src/teste/ColorPicker.test.tsx +153 -0
  270. package/src/teste/ConfirmAIAction.test.tsx +41 -0
  271. package/src/teste/DataTableCelulaLivre.test.tsx +103 -0
  272. package/src/teste/DataTableDocumento.test.tsx +102 -0
  273. package/src/teste/DatePicker.test.tsx +38 -0
  274. package/src/teste/Dropdown.test.tsx +146 -0
  275. package/src/teste/FileInputTrigger.test.tsx +89 -0
  276. package/src/teste/IconPicker.test.tsx +145 -0
  277. package/src/teste/InputMascaraEAfins.test.tsx +124 -0
  278. package/src/teste/KbdCodeBlock.test.tsx +106 -0
  279. package/src/teste/List.test.tsx +269 -0
  280. package/src/teste/Modal.test.tsx +28 -0
  281. package/src/teste/ModalVariantes.test.tsx +173 -0
  282. package/src/teste/MultiSelectErro.test.tsx +97 -0
  283. package/src/teste/NomeAcessivelSsr.test.tsx +110 -0
  284. package/src/teste/OrgChart.test.tsx +183 -0
  285. package/src/teste/OtpInput.test.tsx +163 -0
  286. package/src/teste/PopoverMaxHeight.test.tsx +47 -0
  287. package/src/teste/RichTextEditor.test.tsx +329 -0
  288. package/src/teste/RotulosTraduziveis.test.tsx +545 -0
  289. package/src/teste/SegmentedControl.test.tsx +57 -0
  290. package/src/teste/Select.test.tsx +97 -0
  291. package/src/teste/SelectPlacementFiltro.test.tsx +110 -0
  292. package/src/teste/Stack.test.tsx +80 -0
  293. package/src/teste/StatCardRotuloTopo.test.tsx +44 -0
  294. package/src/teste/TabsContadorFechavel.test.tsx +144 -0
  295. package/src/teste/Tooltip.test.tsx +219 -0
  296. package/src/teste/TooltipDark.test.tsx +51 -0
  297. package/src/utils/calendario.ts +78 -0
  298. package/src/utils/chart.ts +7 -2
  299. package/src/utils/html-seguro.ts +94 -0
  300. package/src/utils/id.ts +24 -0
  301. package/src/utils/paleta-de-cores.ts +34 -0
  302. package/src/utils/texto.ts +5 -0
@@ -0,0 +1,153 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import { render, screen } from "@testing-library/react";
4
+ import userEvent from "@testing-library/user-event";
5
+ import { faInbox } from "@fortawesome/free-solid-svg-icons";
6
+ import List from "../components/List/List";
7
+ import ListItem from "../components/List/ListItem";
8
+ describe("ListItem", () => {
9
+ it("sem as nem href é um button dentro de um li", () => {
10
+ const { container } = render(_jsx("ul", { children: _jsx(ListItem, { title: "Memorando 114/2025" }) }));
11
+ const botao = screen.getByRole("button", { name: /Memorando 114\/2025/ });
12
+ expect(botao.tagName).toBe("BUTTON");
13
+ expect(botao).toHaveAttribute("type", "button");
14
+ expect(botao.parentElement?.tagName).toBe("LI");
15
+ expect(container.querySelectorAll("li")).toHaveLength(1);
16
+ });
17
+ it("com href vira link; target _blank ganha rel seguro", () => {
18
+ render(_jsx("ul", { children: _jsx(ListItem, { title: "Of\u00EDcio", href: "/oficios/31", target: "_blank" }) }));
19
+ const link = screen.getByRole("link", { name: /Ofício/ });
20
+ expect(link).toHaveAttribute("href", "/oficios/31");
21
+ expect(link).toHaveAttribute("rel", "noopener noreferrer");
22
+ });
23
+ it("as='div' sem onClick é só leitura: sem role nem tabindex", () => {
24
+ const { container } = render(_jsx("ul", { children: _jsx(ListItem, { as: "div", title: "Somente leitura" }) }));
25
+ const linha = container.querySelector(".umds-list-item");
26
+ expect(linha.tagName).toBe("DIV");
27
+ expect(linha).not.toHaveAttribute("role");
28
+ expect(linha).not.toHaveAttribute("tabindex");
29
+ expect(linha).not.toHaveClass("umds-list-item--interactive");
30
+ });
31
+ it("as='div' com onClick é acionável por Enter e Espaço", async () => {
32
+ const usuario = userEvent.setup();
33
+ const aoClicar = vi.fn();
34
+ render(_jsx("ul", { children: _jsx(ListItem, { as: "div", title: "Acion\u00E1vel", onClick: aoClicar }) }));
35
+ const linha = screen.getByRole("button", { name: /Acionável/ });
36
+ linha.focus();
37
+ await usuario.keyboard("{Enter}");
38
+ await usuario.keyboard(" ");
39
+ expect(aoClicar).toHaveBeenCalledTimes(2);
40
+ });
41
+ it("monta título, subtítulo, meta, início e fim nos lugares certos", () => {
42
+ const { container } = render(_jsx("ul", { children: _jsx(ListItem, { title: "Memorando 114/2025", subtitle: "Novo contrato - Governo", meta: "23 de agosto de 2025", start: _jsx("span", { "data-testid": "inicio", children: "AV" }), end: _jsx("span", { "data-testid": "fim", children: "novo" }), children: _jsx("span", { "data-testid": "livre", children: "conte\u00FAdo livre" }) }) }));
43
+ expect(container.querySelector(".umds-list-item__title")).toHaveTextContent("Memorando 114/2025");
44
+ expect(container.querySelector(".umds-list-item__subtitle")).toHaveTextContent("Novo contrato - Governo");
45
+ expect(container.querySelector(".umds-list-item__meta")).toHaveTextContent("23 de agosto de 2025");
46
+ expect(container.querySelector(".umds-list-item__start")).toContainElement(screen.getByTestId("inicio"));
47
+ expect(container.querySelector(".umds-list-item__end")).toContainElement(screen.getByTestId("fim"));
48
+ expect(container.querySelector(".umds-list-item__body")).toContainElement(screen.getByTestId("livre"));
49
+ });
50
+ it("title aceita nó e não vira o atributo title do HTML", () => {
51
+ const { container } = render(_jsx("ul", { children: _jsx(ListItem, { title: _jsx("b", { "data-testid": "rico", children: "Rico" }) }) }));
52
+ expect(screen.getByTestId("rico")).toBeInTheDocument();
53
+ expect(container.querySelector("[title]")).toBeNull();
54
+ });
55
+ it("sem start, end e textos, não desenha as regiões vazias", () => {
56
+ const { container } = render(_jsx("ul", { children: _jsx(ListItem, { title: "S\u00F3 t\u00EDtulo" }) }));
57
+ expect(container.querySelector(".umds-list-item__start")).toBeNull();
58
+ expect(container.querySelector(".umds-list-item__end")).toBeNull();
59
+ expect(container.querySelector(".umds-list-item__subtitle")).toBeNull();
60
+ expect(container.querySelector(".umds-list-item__meta")).toBeNull();
61
+ });
62
+ it("selected marca aria-current e a classe de seleção", () => {
63
+ render(_jsx("ul", { children: _jsx(ListItem, { title: "Atual", selected: true }) }));
64
+ const botao = screen.getByRole("button", { name: /Atual/ });
65
+ expect(botao).toHaveAttribute("aria-current", "true");
66
+ expect(botao).toHaveClass("umds-list-item--selected");
67
+ });
68
+ it("disabled bloqueia o clique e o foco do botão", async () => {
69
+ const usuario = userEvent.setup();
70
+ const aoClicar = vi.fn();
71
+ render(_jsx("ul", { children: _jsx(ListItem, { title: "Bloqueada", disabled: true, onClick: aoClicar }) }));
72
+ const botao = screen.getByRole("button", { name: /Bloqueada/ });
73
+ expect(botao).toBeDisabled();
74
+ await usuario.click(botao);
75
+ expect(aoClicar).not.toHaveBeenCalled();
76
+ });
77
+ it("link disabled perde o href e declara aria-disabled", () => {
78
+ render(_jsx("ul", { children: _jsx(ListItem, { title: "Link bloqueado", href: "/x", disabled: true }) }));
79
+ const link = screen.getByText("Link bloqueado").closest("a");
80
+ expect(link).not.toHaveAttribute("href");
81
+ expect(link).toHaveAttribute("aria-disabled", "true");
82
+ });
83
+ it("clique chama onClick com o evento", async () => {
84
+ const usuario = userEvent.setup();
85
+ const aoClicar = vi.fn();
86
+ render(_jsx("ul", { children: _jsx(ListItem, { title: "Abrir", onClick: aoClicar }) }));
87
+ await usuario.click(screen.getByRole("button", { name: /Abrir/ }));
88
+ expect(aoClicar).toHaveBeenCalledTimes(1);
89
+ });
90
+ it("repassa aria-label, id, data-* e style ao elemento interativo", () => {
91
+ render(_jsx("ul", { children: _jsx(ListItem, { "aria-label": "Abrir memorando", id: "item-1", "data-origem": "home", style: { marginTop: 4 } }) }));
92
+ const botao = screen.getByRole("button", { name: "Abrir memorando" });
93
+ expect(botao).toHaveAttribute("id", "item-1");
94
+ expect(botao).toHaveAttribute("data-origem", "home");
95
+ expect(botao).toHaveStyle({ marginTop: "4px" });
96
+ });
97
+ });
98
+ describe("List", () => {
99
+ it("é uma ul com role list, nome acessível e gap padrão", () => {
100
+ render(_jsxs(List, { ariaLabel: "Documentos n\u00E3o lidos", children: [_jsx(ListItem, { title: "A" }), _jsx(ListItem, { title: "B" })] }));
101
+ const lista = screen.getByRole("list", { name: "Documentos não lidos" });
102
+ expect(lista.tagName).toBe("UL");
103
+ expect(lista).toHaveClass("umds-list--gap-quarck");
104
+ expect(screen.getAllByRole("listitem")).toHaveLength(2);
105
+ });
106
+ it("as='ol' e gap trocam o elemento e a classe", () => {
107
+ render(_jsx(List, { as: "ol", gap: "nano", ariaLabel: "Passos", children: _jsx(ListItem, { title: "A" }) }));
108
+ const lista = screen.getByRole("list", { name: "Passos" });
109
+ expect(lista.tagName).toBe("OL");
110
+ expect(lista).toHaveClass("umds-list--gap-nano");
111
+ });
112
+ it("ariaLabelledby aponta para o título visível", () => {
113
+ render(_jsxs(_Fragment, { children: [_jsx("h2", { id: "titulo", children: "Prazos a vencer" }), _jsx(List, { ariaLabelledby: "titulo", children: _jsx(ListItem, { title: "A" }) })] }));
114
+ expect(screen.getByRole("list", { name: "Prazos a vencer" })).toBeInTheDocument();
115
+ });
116
+ it("sem isEmpty mostra os itens e nunca o estado vazio", () => {
117
+ render(_jsx(List, { ariaLabel: "Lista", emptyTitle: "Nada aqui", children: _jsx(ListItem, { title: "A" }) }));
118
+ expect(screen.queryByText("Nada aqui")).toBeNull();
119
+ });
120
+ it("isEmpty troca os itens pelo EmptyState dentro da própria lista", () => {
121
+ const aoAgir = vi.fn();
122
+ const { container } = render(_jsx(List, { ariaLabel: "Lista", isEmpty: true, emptyTitle: "Nenhum documento", emptyDescription: "Tudo em dia.", emptyIcon: faInbox, emptyActionLabel: "Atualizar", onEmptyAction: aoAgir, children: _jsx(ListItem, { title: "N\u00E3o aparece" }) }));
123
+ expect(screen.queryByRole("list")).toBeNull();
124
+ expect(screen.queryByText("Não aparece")).toBeNull();
125
+ const raiz = container.firstElementChild;
126
+ expect(raiz).toHaveAttribute("role", "status");
127
+ expect(raiz).toHaveClass("umds-list--empty");
128
+ expect(raiz.querySelector(".umds-empty-state")).not.toBeNull();
129
+ expect(screen.getByText("Nenhum documento")).toBeInTheDocument();
130
+ expect(screen.getByText("Tudo em dia.")).toBeInTheDocument();
131
+ expect(raiz.querySelector(".umds-empty-state--sm")).not.toBeNull();
132
+ screen.getByRole("button", { name: "Atualizar" }).click();
133
+ expect(aoAgir).toHaveBeenCalledTimes(1);
134
+ });
135
+ it("isEmpty sem título usa o texto padrão", () => {
136
+ render(_jsx(List, { ariaLabel: "Lista", isEmpty: true }));
137
+ expect(screen.getByText("Nenhum item encontrado")).toBeInTheDocument();
138
+ });
139
+ it("o conteúdo ao redor da lista não é desmontado ao esvaziar", () => {
140
+ const Tela = ({ vazia }) => (_jsxs("section", { children: [_jsx("h2", { children: "Documentos" }), _jsx("input", { "aria-label": "Buscar" }), _jsx(List, { ariaLabel: "Documentos", isEmpty: vazia, children: _jsx(ListItem, { title: "A" }) }), _jsx("nav", { "aria-label": "Pagina\u00E7\u00E3o", children: "p\u00E1g. 1" })] }));
141
+ const { rerender } = render(_jsx(Tela, { vazia: false }));
142
+ const busca = screen.getByLabelText("Buscar");
143
+ rerender(_jsx(Tela, { vazia: true }));
144
+ expect(screen.getByLabelText("Buscar")).toBe(busca);
145
+ expect(screen.getByRole("heading", { name: "Documentos" })).toBeInTheDocument();
146
+ expect(screen.getByRole("navigation", { name: "Paginação" })).toBeInTheDocument();
147
+ });
148
+ it("slot empty (prop empty no React) substitui o EmptyState", () => {
149
+ render(_jsx(List, { ariaLabel: "Lista", isEmpty: true, empty: _jsx("p", { "data-testid": "vazio", children: "Nada por aqui" }) }));
150
+ expect(screen.getByTestId("vazio")).toBeInTheDocument();
151
+ expect(document.querySelector(".umds-empty-state")).toBeNull();
152
+ });
153
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, expect, it } from "vitest";
3
+ import { render, screen } from "@testing-library/react";
4
+ import Modal from "../components/Modal/Modal";
5
+ /**
6
+ * Modal sem `title` saía com `role="dialog"` anônimo: o leitor de tela dizia
7
+ * só "diálogo". Com título, quem nomeia é o `aria-labelledby`; sem título,
8
+ * `ariaLabel`; sem nenhum dos dois, o genérico "Diálogo".
9
+ */
10
+ describe("Modal · nome acessível", () => {
11
+ it("com title, é nomeado pelo título e ignora ariaLabel", () => {
12
+ render(_jsx(Modal, { open: true, inline: true, title: "Admitir colaborador", ariaLabel: "Outro nome" }));
13
+ const dialogo = screen.getByRole("dialog", { name: "Admitir colaborador" });
14
+ expect(dialogo).toHaveAttribute("aria-labelledby");
15
+ expect(dialogo).not.toHaveAttribute("aria-label");
16
+ });
17
+ it("sem title, usa ariaLabel", () => {
18
+ render(_jsx(Modal, { open: true, inline: true, ariaLabel: "Pr\u00E9-visualiza\u00E7\u00E3o do documento" }));
19
+ const dialogo = screen.getByRole("dialog", { name: "Pré-visualização do documento" });
20
+ expect(dialogo).not.toHaveAttribute("aria-labelledby");
21
+ });
22
+ it("sem title e sem ariaLabel, nunca sai anônimo", () => {
23
+ render(_jsx(Modal, { open: true, inline: true }));
24
+ expect(screen.getByRole("dialog", { name: "Diálogo" })).toBeInTheDocument();
25
+ });
26
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,151 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { act, fireEvent, render, screen } from "@testing-library/react";
4
+ import Modal from "../components/Modal/Modal";
5
+ import Select from "../components/Select/Select";
6
+ afterEach(() => {
7
+ vi.unstubAllGlobals();
8
+ });
9
+ /** Troca `window.matchMedia` por um que responde `matches` e deixa disparar `change`. */
10
+ function simularTela(matches) {
11
+ const ouvintes = new Set();
12
+ vi.stubGlobal("matchMedia", (consulta) => ({
13
+ matches,
14
+ media: consulta,
15
+ addEventListener: (_, fn) => ouvintes.add(fn),
16
+ removeEventListener: (_, fn) => ouvintes.delete(fn),
17
+ }));
18
+ return (novo) => ouvintes.forEach((fn) => fn({ matches: novo }));
19
+ }
20
+ describe("Modal · variant primary", () => {
21
+ it("fica no modal base (três faixas), com a classe do cabeçalho cheio", () => {
22
+ render(_jsx(Modal, { open: true, inline: true, variant: "primary", title: "Resolver tarefa" }));
23
+ const dialogo = screen.getByRole("dialog", { name: "Resolver tarefa" });
24
+ expect(dialogo).toHaveClass("umds-modal--primary", "umds-modal--base");
25
+ expect(dialogo).not.toHaveClass("umds-modal--feedback");
26
+ expect(dialogo.querySelector(".umds-modal__header")).not.toBeNull();
27
+ expect(dialogo.querySelector(".umds-modal__icon")).toBeNull();
28
+ });
29
+ it("positive continua sendo diálogo de feedback", () => {
30
+ render(_jsx(Modal, { open: true, inline: true, variant: "positive", title: "Pronto" }));
31
+ expect(screen.getByRole("dialog")).toHaveClass("umds-modal--feedback");
32
+ });
33
+ });
34
+ describe("Modal · width e maxWidth", () => {
35
+ it("escreve a largura e, sem maxWidth, solta o teto do size", () => {
36
+ render(_jsx(Modal, { open: true, inline: true, title: "x", width: "600px" }));
37
+ const dialogo = screen.getByRole("dialog");
38
+ expect(dialogo.style.width).toBe("600px");
39
+ expect(dialogo.style.maxWidth).toBe("100%");
40
+ });
41
+ it("maxWidth explícito vale", () => {
42
+ render(_jsx(Modal, { open: true, inline: true, title: "x", width: "90%", maxWidth: "720px" }));
43
+ expect(screen.getByRole("dialog").style.maxWidth).toBe("720px");
44
+ });
45
+ it("sem width nem maxWidth não escreve style", () => {
46
+ render(_jsx(Modal, { open: true, inline: true, title: "x" }));
47
+ expect(screen.getByRole("dialog").getAttribute("style")).toBeNull();
48
+ });
49
+ });
50
+ describe("Modal · Escape", () => {
51
+ it("fecha com Escape no borbulho", () => {
52
+ const aoFechar = vi.fn();
53
+ render(_jsx(Modal, { open: true, inline: true, title: "x", onClose: aoFechar }));
54
+ fireEvent.keyDown(document.body, { key: "Escape" });
55
+ expect(aoFechar).toHaveBeenCalledTimes(1);
56
+ });
57
+ it("não fecha quando outro componente já consumiu a tecla (defaultPrevented)", () => {
58
+ const aoFechar = vi.fn();
59
+ render(_jsx(Modal, { open: true, inline: true, title: "x", onClose: aoFechar }));
60
+ const consumidor = document.createElement("div");
61
+ consumidor.addEventListener("keydown", (e) => e.preventDefault());
62
+ document.body.appendChild(consumidor);
63
+ fireEvent.keyDown(consumidor, { key: "Escape" });
64
+ expect(aoFechar).not.toHaveBeenCalled();
65
+ consumidor.remove();
66
+ });
67
+ it("Select aberto dentro do modal fecha só a lista, e o modal fica", () => {
68
+ const aoFechar = vi.fn();
69
+ render(_jsx(Modal, { open: true, inline: true, title: "x", onClose: aoFechar, children: _jsx(Select, { label: "Categoria", options: [{ label: "Administrativa", value: "adm" }] }) }));
70
+ const gatilho = screen.getByRole("combobox");
71
+ fireEvent.click(gatilho);
72
+ expect(gatilho).toHaveAttribute("aria-expanded", "true");
73
+ fireEvent.keyDown(gatilho, { key: "Escape" });
74
+ expect(gatilho).toHaveAttribute("aria-expanded", "false");
75
+ expect(aoFechar).not.toHaveBeenCalled();
76
+ // Com o Select fechado, o Esc seguinte é do modal.
77
+ fireEvent.keyDown(gatilho, { key: "Escape" });
78
+ expect(aoFechar).toHaveBeenCalledTimes(1);
79
+ });
80
+ });
81
+ describe("Modal · controles de janela escolhidos um a um", () => {
82
+ it("true liga os quatro, como antes", () => {
83
+ render(_jsx(Modal, { open: true, inline: true, title: "x", windowControls: true }));
84
+ for (const nome of ["Modo normal", "Expandir", "Tela cheia", "Minimizar"]) {
85
+ expect(screen.getByRole("button", { name: nome })).toBeInTheDocument();
86
+ }
87
+ });
88
+ it("lista escolhe só os pedidos, sem minimizar", () => {
89
+ render(_jsx(Modal, { open: true, inline: true, title: "x", windowControls: ["expand", "fullscreen"] }));
90
+ expect(screen.getByRole("button", { name: "Expandir" })).toBeInTheDocument();
91
+ expect(screen.getByRole("button", { name: "Tela cheia" })).toBeInTheDocument();
92
+ expect(screen.queryByRole("button", { name: "Minimizar" })).toBeNull();
93
+ expect(screen.queryByRole("button", { name: "Modo normal" })).toBeNull();
94
+ expect(screen.getByRole("button", { name: "Fechar" })).toBeInTheDocument();
95
+ });
96
+ it("sem windowControls só há o ×", () => {
97
+ render(_jsx(Modal, { open: true, inline: true, title: "x" }));
98
+ expect(screen.queryByRole("button", { name: "Expandir" })).toBeNull();
99
+ expect(screen.getByRole("button", { name: "Fechar" })).toBeInTheDocument();
100
+ });
101
+ it("sem o botão normal, clicar de novo no modo ativo volta ao normal; e o normal usa o tamanho do modal", () => {
102
+ render(_jsx(Modal, { open: true, inline: true, title: "x", width: "600px", windowControls: ["expand"] }));
103
+ const dialogo = screen.getByRole("dialog");
104
+ const expandir = screen.getByRole("button", { name: "Expandir" });
105
+ expect(dialogo).not.toHaveClass("umds-modal--janela-normal");
106
+ expect(dialogo.style.width).toBe("600px");
107
+ fireEvent.click(expandir);
108
+ expect(dialogo).toHaveClass("umds-modal--janela-expanded");
109
+ expect(dialogo.style.width).toBe("");
110
+ fireEvent.click(expandir);
111
+ expect(dialogo).not.toHaveClass("umds-modal--janela-expanded");
112
+ expect(dialogo.style.width).toBe("600px");
113
+ });
114
+ it("minimizar chama onMinimize", () => {
115
+ const aoMinimizar = vi.fn();
116
+ render(_jsx(Modal, { open: true, inline: true, title: "x", windowControls: ["minimize"], onMinimize: aoMinimizar }));
117
+ fireEvent.click(screen.getByRole("button", { name: "Minimizar" }));
118
+ expect(aoMinimizar).toHaveBeenCalledTimes(1);
119
+ });
120
+ });
121
+ describe("Modal · responsive", () => {
122
+ it("em tela larga continua centralizado", () => {
123
+ simularTela(false);
124
+ render(_jsx(Modal, { open: true, inline: true, title: "x", responsive: true }));
125
+ expect(screen.getByRole("dialog")).not.toHaveClass("umds-modal--sheet");
126
+ });
127
+ it("em tela estreita vira painel de baixo, sem controles de janela e sem a largura livre", () => {
128
+ simularTela(true);
129
+ render(_jsx(Modal, { open: true, inline: true, title: "x", responsive: true, width: "600px", windowControls: true }));
130
+ const dialogo = screen.getByRole("dialog");
131
+ expect(dialogo).toHaveClass("umds-modal--sheet");
132
+ expect(dialogo.style.width).toBe("");
133
+ expect(screen.queryByRole("button", { name: "Expandir" })).toBeNull();
134
+ expect(dialogo.querySelector(".umds-modal__grabber")).not.toBeNull();
135
+ });
136
+ it("acompanha a mudança de tamanho da tela", () => {
137
+ const mudar = simularTela(false);
138
+ render(_jsx(Modal, { open: true, inline: true, title: "x", responsive: true }));
139
+ const dialogo = screen.getByRole("dialog");
140
+ expect(dialogo).not.toHaveClass("umds-modal--sheet");
141
+ act(() => mudar(true));
142
+ expect(screen.getByRole("dialog")).toHaveClass("umds-modal--sheet");
143
+ act(() => mudar(false));
144
+ expect(screen.getByRole("dialog")).not.toHaveClass("umds-modal--sheet");
145
+ });
146
+ it("sem responsive nunca vira painel", () => {
147
+ simularTela(true);
148
+ render(_jsx(Modal, { open: true, inline: true, title: "x" }));
149
+ expect(screen.getByRole("dialog")).not.toHaveClass("umds-modal--sheet");
150
+ });
151
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,62 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, expect, it } from "vitest";
3
+ import { render, screen } from "@testing-library/react";
4
+ import { renderToString } from "react-dom/server";
5
+ import MultiSelect from "../components/MultiSelect/MultiSelect";
6
+ /**
7
+ * O foco do MultiSelect cai no trigger `role="combobox"`, não num `<select>`
8
+ * nativo. Então nada liga a mensagem de erro ao campo de graça: se o
9
+ * `aria-describedby` não estiver no combobox, o leitor de tela anuncia
10
+ * "Setor, caixa de combinação" e a pessoa nunca ouve POR QUE o campo está
11
+ * vermelho.
12
+ */
13
+ const OPCOES = [
14
+ { label: "Recursos Humanos", value: "rh" },
15
+ { label: "Financeiro", value: "fin" },
16
+ ];
17
+ describe("MultiSelect · erro e apoio ligados ao campo", () => {
18
+ it("a mensagem de erro descreve o combobox e o marca inválido", () => {
19
+ render(_jsx(MultiSelect, { label: "Setor", options: OPCOES, errorMessage: "Escolha um setor" }));
20
+ const campo = screen.getByRole("combobox", { name: "Setor" });
21
+ expect(campo).toHaveAccessibleDescription("Escolha um setor");
22
+ expect(campo).toHaveAttribute("aria-invalid", "true");
23
+ });
24
+ it("erro e texto de apoio entram os dois, erro primeiro", () => {
25
+ render(_jsx(MultiSelect, { label: "Setor", options: OPCOES, errorMessage: "Obrigat\u00F3rio", helperText: "Onde a pessoa trabalha" }));
26
+ expect(screen.getByRole("combobox")).toHaveAccessibleDescription("Obrigatório Onde a pessoa trabalha");
27
+ });
28
+ it("o apelido antigo `description` também é ligado", () => {
29
+ render(_jsx(MultiSelect, { label: "Setor", options: OPCOES, description: "Opcional" }));
30
+ expect(screen.getByRole("combobox")).toHaveAccessibleDescription("Opcional");
31
+ });
32
+ it("sem erro nem apoio, nada de aria-describedby ou aria-invalid", () => {
33
+ render(_jsx(MultiSelect, { label: "Setor", options: OPCOES }));
34
+ const campo = screen.getByRole("combobox");
35
+ expect(campo).not.toHaveAttribute("aria-describedby");
36
+ expect(campo).not.toHaveAttribute("aria-invalid");
37
+ });
38
+ it("`invalid` sem mensagem também marca aria-invalid", () => {
39
+ render(_jsx(MultiSelect, { label: "Setor", options: OPCOES, invalid: true }));
40
+ expect(screen.getByRole("combobox")).toHaveAttribute("aria-invalid", "true");
41
+ });
42
+ it("com `id`, os ids internos derivam dele", () => {
43
+ render(_jsx(MultiSelect, { id: "setor", label: "Setor", options: OPCOES, errorMessage: "Erro" }));
44
+ expect(screen.getByRole("combobox")).toHaveAttribute("aria-describedby", "setor-error");
45
+ });
46
+ });
47
+ describe("MultiSelect · ids na renderização do servidor", () => {
48
+ /**
49
+ * Id sorteado no render sai diferente no servidor e no cliente: a
50
+ * hidratação diverge e o describedby do HTML aponta para o nada. Duas
51
+ * renderizações de servidor têm de sair byte a byte iguais.
52
+ */
53
+ it("o HTML do servidor é determinístico", () => {
54
+ const html = () => renderToString(_jsx(MultiSelect, { label: "Setor", options: OPCOES, errorMessage: "Erro" }));
55
+ expect(html()).toBe(html());
56
+ });
57
+ it("com `id`, o servidor já manda o describedby", () => {
58
+ const html = renderToString(_jsx(MultiSelect, { id: "setor", label: "Setor", options: OPCOES, errorMessage: "Erro" }));
59
+ expect(html).toContain('aria-describedby="setor-error"');
60
+ expect(html).toContain('id="setor-error"');
61
+ });
62
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,88 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { act, screen } from "@testing-library/react";
4
+ import { renderToString } from "react-dom/server";
5
+ import { hydrateRoot } from "react-dom/client";
6
+ import Select from "../components/Select/Select";
7
+ import MultiSelect from "../components/MultiSelect/MultiSelect";
8
+ import SegmentedControl from "../components/SegmentedControl/SegmentedControl";
9
+ /**
10
+ * Select, MultiSelect e SegmentedControl nascem SEM id automático (utils/id):
11
+ * o id só é gerado no onMount, para o servidor e a primeira renderização do
12
+ * cliente saírem idênticos. Só que o nome acessível deles vinha de
13
+ * `aria-labelledby` apontando para esse id — no HTML do servidor, e até a
14
+ * hidratação, o combobox ficava sem nome (axe `aria-input-field-name`, visto
15
+ * no portal Astro com `client:visible`).
16
+ *
17
+ * Aqui o HTML sai do `renderToString`, que não dispara o onMount, e vai para
18
+ * o DOM do jsdom como o navegador receberia. O nome é conferido pelo cálculo
19
+ * do Testing Library, o mesmo algoritmo de nome acessível que o axe usa.
20
+ */
21
+ const OPCOES = [
22
+ { label: "Recursos Humanos", value: "rh" },
23
+ { label: "Financeiro", value: "fin" },
24
+ ];
25
+ const POR_PAGINA = [
26
+ { label: "10", value: "10" },
27
+ { label: "25", value: "25" },
28
+ ];
29
+ function comoDoServidor(html) {
30
+ const raiz = document.createElement("div");
31
+ raiz.innerHTML = html;
32
+ document.body.appendChild(raiz);
33
+ return raiz;
34
+ }
35
+ describe("Nome acessível no HTML do servidor", () => {
36
+ // As raízes são montadas à mão (fora do render), e o cleanup global não as vê.
37
+ afterEach(() => {
38
+ document.body.innerHTML = "";
39
+ });
40
+ it("Select: o combobox tem o nome do label antes do mount", () => {
41
+ comoDoServidor(renderToString(_jsx(Select, { label: "Setor", options: OPCOES })));
42
+ const campo = screen.getByRole("combobox", { name: "Setor" });
43
+ expect(campo).not.toHaveAttribute("aria-labelledby");
44
+ expect(campo).toHaveAttribute("aria-label", "Setor");
45
+ });
46
+ it("Select: `ariaLabel` continua valendo sobre o label", () => {
47
+ comoDoServidor(renderToString(_jsx(Select, { label: "Setor", ariaLabel: "Setor do servidor", options: OPCOES })));
48
+ expect(screen.getByRole("combobox", { name: "Setor do servidor" })).toBeInTheDocument();
49
+ });
50
+ it("Select com `id`: o servidor já liga pelo aria-labelledby", () => {
51
+ const html = renderToString(_jsx(Select, { id: "setor", label: "Setor", options: OPCOES }));
52
+ expect(html).toContain('aria-labelledby="setor-label"');
53
+ expect(html).not.toContain('aria-label="Setor"');
54
+ });
55
+ it("MultiSelect: o combobox tem o nome do label antes do mount", () => {
56
+ comoDoServidor(renderToString(_jsx(MultiSelect, { label: "Setores", options: OPCOES })));
57
+ expect(screen.getByRole("combobox", { name: "Setores" })).toBeInTheDocument();
58
+ });
59
+ it("SegmentedControl: grupo e segmentos têm nome antes do mount", () => {
60
+ comoDoServidor(renderToString(_jsx(SegmentedControl, { label: "Itens", options: POR_PAGINA })));
61
+ expect(screen.getByRole("radiogroup", { name: "Itens" })).toBeInTheDocument();
62
+ expect(screen.getByRole("radio", { name: "10" })).toBeInTheDocument();
63
+ expect(screen.getByRole("radio", { name: "25" })).toBeInTheDocument();
64
+ });
65
+ it("hidrata sem divergência e, montado, volta ao aria-labelledby", async () => {
66
+ const arvore = (_jsxs("div", { children: [_jsx(Select, { label: "Setor", options: OPCOES }), _jsx(MultiSelect, { label: "Setores", options: OPCOES }), _jsx(SegmentedControl, { label: "Itens", options: POR_PAGINA })] }));
67
+ const raiz = comoDoServidor(renderToString(arvore));
68
+ const erro = vi.spyOn(console, "error").mockImplementation(() => { });
69
+ const avisosDeHidratacao = [];
70
+ await act(async () => {
71
+ hydrateRoot(raiz, arvore, {
72
+ onRecoverableError: (e) => avisosDeHidratacao.push(e),
73
+ });
74
+ });
75
+ const chamadas = erro.mock.calls.map((c) => String(c[0]));
76
+ erro.mockRestore();
77
+ expect(avisosDeHidratacao).toEqual([]);
78
+ expect(chamadas.filter((c) => /hydrat|did not match/i.test(c))).toEqual([]);
79
+ const select = screen.getByRole("combobox", { name: "Setor" });
80
+ expect(select).toHaveAttribute("aria-labelledby");
81
+ expect(select).not.toHaveAttribute("aria-label");
82
+ const multi = screen.getByRole("combobox", { name: "Setores" });
83
+ expect(multi).toHaveAttribute("aria-labelledby");
84
+ const grupo = screen.getByRole("radiogroup", { name: "Itens" });
85
+ expect(grupo).toHaveAttribute("aria-labelledby");
86
+ expect(screen.getByRole("radio", { name: "10" })).not.toHaveAttribute("aria-label");
87
+ });
88
+ });
@@ -0,0 +1 @@
1
+ export {};