@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,405 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, expect, it } from "vitest";
3
+ import { render, screen, waitFor, within } from "@testing-library/react";
4
+ import userEvent from "@testing-library/user-event";
5
+ import AIContent from "../components/AIContent/AIContent";
6
+ import AILabel from "../components/AILabel/AILabel";
7
+ import AppSidebar from "../components/AppSidebar/AppSidebar";
8
+ import AttachmentCard from "../components/AttachmentCard/AttachmentCard";
9
+ import AvatarGroup from "../components/Avatar/AvatarGroup";
10
+ import BarChart from "../components/Chart/BarChart";
11
+ import LineChart from "../components/Chart/LineChart";
12
+ import BottomSheet from "../components/BottomSheet/BottomSheet";
13
+ import Chips from "../components/Chips/Chips";
14
+ import ConfirmAIAction from "../components/ConfirmAIAction/ConfirmAIAction";
15
+ import ConfirmDialog from "../components/ConfirmDialog/ConfirmDialog";
16
+ import DataTable from "../components/DataTable/DataTable";
17
+ import DatePicker from "../components/DatePicker/DatePicker";
18
+ import FileInput from "../components/FileInput/FileInput";
19
+ import Input from "../components/Input/Input";
20
+ import Kanban from "../components/Kanban/Kanban";
21
+ import KanbanCard from "../components/Kanban/KanbanCard";
22
+ import KanbanColumn from "../components/Kanban/KanbanColumn";
23
+ import Pagination from "../components/Pagination/Pagination";
24
+ import PhoneInput from "../components/PhoneInput/PhoneInput";
25
+ import Stepper from "../components/Stepper/Stepper";
26
+ import TimePicker from "../components/TimePicker/TimePicker";
27
+ /**
28
+ * Rótulos traduzíveis. Cada componente tinha texto em português fixo no código
29
+ * (visível ou lido pelo leitor de tela), sem prop para trocar. Duas garantias
30
+ * por componente: SEM a prop, sai exatamente o português de antes; COM a prop,
31
+ * sai o texto passado. A primeira é a que protege quem já usa o DS.
32
+ */
33
+ describe("Chips · removeAriaLabel", () => {
34
+ it("padrão em português", () => {
35
+ render(_jsx(Chips, { label: "Financeiro", removable: true }));
36
+ expect(screen.getByRole("button", { name: "Remover Financeiro" })).toBeInTheDocument();
37
+ });
38
+ it("prefixo customizado", () => {
39
+ render(_jsx(Chips, { label: "Finance", removable: true, removeAriaLabel: "Remove" }));
40
+ expect(screen.getByRole("button", { name: "Remove Finance" })).toBeInTheDocument();
41
+ });
42
+ });
43
+ describe("Stepper · estados lidos", () => {
44
+ const passos = [
45
+ { title: "A", status: "completed" },
46
+ { title: "B", status: "active" },
47
+ { title: "C", status: "error" },
48
+ { title: "D", status: "pending" },
49
+ ];
50
+ it("padrão em português", () => {
51
+ render(_jsx(Stepper, { steps: passos }));
52
+ for (const nome of ["A, concluído", "B, atual", "C, erro", "D, pendente"]) {
53
+ expect(screen.getByRole("listitem", { name: nome })).toBeInTheDocument();
54
+ }
55
+ });
56
+ it("rótulos customizados", () => {
57
+ render(_jsx(Stepper, { steps: passos, completedLabel: "completed", activeLabel: "current", errorLabel: "failed", pendingLabel: "pending" }));
58
+ for (const nome of ["A, completed", "B, current", "C, failed", "D, pending"]) {
59
+ expect(screen.getByRole("listitem", { name: nome })).toBeInTheDocument();
60
+ }
61
+ });
62
+ });
63
+ describe("FileInput · textos", () => {
64
+ const arquivos = [
65
+ { name: "a.pdf", size: 2048, status: "completed" },
66
+ { name: "b.pdf", size: 2048, status: "uploading", progress: 40 },
67
+ ];
68
+ it("padrão em português (base e card)", () => {
69
+ const { container, unmount } = render(_jsx(FileInput, { files: arquivos, maxSize: 1048576 }));
70
+ expect(screen.getByRole("button", { name: "Remover a.pdf" })).toBeInTheDocument();
71
+ expect(screen.getByRole("progressbar", { name: "Enviando b.pdf" })).toBeInTheDocument();
72
+ expect(screen.getByLabelText("Selecionar arquivo")).toBeInTheDocument();
73
+ const gatilho = container.querySelector(".umds-file-input__trigger-text");
74
+ expect(gatilho.textContent).toBe("Clique para selecionar ou arraste aqui");
75
+ expect(screen.getByText("Máximo 1.0 MB")).toBeInTheDocument();
76
+ unmount();
77
+ const card = render(_jsx(FileInput, { variant: "card" }));
78
+ const texto = card.container.querySelector(".umds-file-input__card-text");
79
+ expect(texto.textContent).toBe("Arraste e solte ou clique para escolher");
80
+ });
81
+ it("rótulos customizados", () => {
82
+ const { container, unmount } = render(_jsx(FileInput, { files: arquivos, maxSize: 1048576, selectFileLabel: "Select file", triggerLabel: "Click to select", triggerHint: "or drag here", maxSizeLabel: "Max", removeAriaLabel: "Remove", uploadingAriaLabel: "Uploading" }));
83
+ expect(screen.getByRole("button", { name: "Remove a.pdf" })).toBeInTheDocument();
84
+ expect(screen.getByRole("progressbar", { name: "Uploading b.pdf" })).toBeInTheDocument();
85
+ expect(screen.getByLabelText("Select file")).toBeInTheDocument();
86
+ const gatilho = container.querySelector(".umds-file-input__trigger-text");
87
+ expect(gatilho.textContent).toBe("Click to select or drag here");
88
+ expect(screen.getByText("Max 1.0 MB")).toBeInTheDocument();
89
+ unmount();
90
+ const card = render(_jsx(FileInput, { variant: "card", dropLabel: "Drag and drop", orLabel: "or", browseLabel: "click to choose" }));
91
+ const texto = card.container.querySelector(".umds-file-input__card-text");
92
+ expect(texto.textContent).toBe("Drag and drop or click to choose");
93
+ });
94
+ });
95
+ describe("AILabel · painel", () => {
96
+ const props = { sources: ["Fonte"], notIncluded: "Fora" };
97
+ it("padrão em português", () => {
98
+ render(_jsx(AILabel, { ...props, open: true }));
99
+ expect(screen.getByRole("button", { name: "Conteúdo gerado por IA" })).toBeInTheDocument();
100
+ expect(screen.getByText("Baseado em")).toBeInTheDocument();
101
+ expect(screen.getByText("Não considerado")).toBeInTheDocument();
102
+ });
103
+ it("rótulos customizados", () => {
104
+ render(_jsx(AILabel, { ...props, open: true, sourcesLabel: "Based on", notIncludedLabel: "Not considered" }));
105
+ expect(screen.getByText("Based on")).toBeInTheDocument();
106
+ expect(screen.getByText("Not considered")).toBeInTheDocument();
107
+ });
108
+ });
109
+ describe("AIContent · repasse ao selo", () => {
110
+ it("padrão em português", async () => {
111
+ const usuario = userEvent.setup();
112
+ render(_jsx(AIContent, { sources: ["Fonte"], notIncluded: "Fora", children: "Texto" }));
113
+ const selo = screen.getByRole("button", { name: "Conteúdo gerado por IA" });
114
+ expect(selo).toHaveTextContent("IA");
115
+ await usuario.click(selo);
116
+ expect(screen.getByText("Como isto foi gerado")).toBeInTheDocument();
117
+ expect(screen.getByText("Baseado em")).toBeInTheDocument();
118
+ expect(screen.getByText("Não considerado")).toBeInTheDocument();
119
+ });
120
+ it("rótulos customizados chegam ao AILabel", async () => {
121
+ const usuario = userEvent.setup();
122
+ render(_jsx(AIContent, { sources: ["Source"], notIncluded: "Out", label: "AI", ariaLabel: "AI-generated content", explanationTitle: "How this was generated", sourcesLabel: "Based on", notIncludedLabel: "Not considered", children: "Text" }));
123
+ const selo = screen.getByRole("button", { name: "AI-generated content" });
124
+ expect(selo).toHaveTextContent("AI");
125
+ await usuario.click(selo);
126
+ expect(screen.getByText("How this was generated")).toBeInTheDocument();
127
+ expect(screen.getByText("Based on")).toBeInTheDocument();
128
+ expect(screen.getByText("Not considered")).toBeInTheDocument();
129
+ });
130
+ });
131
+ describe("Pagination · textos", () => {
132
+ it("padrão em português", () => {
133
+ const { unmount } = render(_jsx(Pagination, { page: 1, totalPages: 5 }));
134
+ expect(screen.getByText("de")).toBeInTheDocument();
135
+ unmount();
136
+ const resumida = render(_jsx(Pagination, { variant: "resumed", page: 2, totalPages: 5, pageSize: 10, totalItems: 45 }));
137
+ expect(screen.getByText("11-20 de 45")).toBeInTheDocument();
138
+ resumida.unmount();
139
+ render(_jsx(Pagination, { variant: "full-width", page: 1, totalPages: 3 }));
140
+ expect(screen.getByRole("button", { name: "Página 2" })).toBeInTheDocument();
141
+ });
142
+ it("rótulos customizados", () => {
143
+ const rotulos = {
144
+ ofLabel: "of",
145
+ itemRangeLabel: (a, b, t) => `${a}–${b} of ${t}`,
146
+ pageLabel: (n) => `Page ${n}`,
147
+ };
148
+ const { unmount } = render(_jsx(Pagination, { ...rotulos, page: 1, totalPages: 5 }));
149
+ expect(screen.getByText("of")).toBeInTheDocument();
150
+ unmount();
151
+ const resumida = render(_jsx(Pagination, { ...rotulos, variant: "resumed", page: 2, totalPages: 5, pageSize: 10, totalItems: 45 }));
152
+ expect(screen.getByText("11–20 of 45")).toBeInTheDocument();
153
+ resumida.unmount();
154
+ render(_jsx(Pagination, { ...rotulos, variant: "bordered", page: 1, totalPages: 3 }));
155
+ expect(screen.getByRole("button", { name: "Page 2" })).toBeInTheDocument();
156
+ });
157
+ });
158
+ describe("DataTable · seleção", () => {
159
+ const colunas = [{ key: "nome", label: "Nome" }];
160
+ const dados = [{ nome: "Ana" }, { nome: "Bia" }];
161
+ it("padrão em português", () => {
162
+ render(_jsx(DataTable, { columns: colunas, data: dados, selectable: true }));
163
+ expect(screen.getByRole("checkbox", { name: "Selecionar todas as linhas" })).toBeInTheDocument();
164
+ expect(screen.getByRole("checkbox", { name: "Selecionar linha 2" })).toBeInTheDocument();
165
+ });
166
+ it("rótulos customizados (a função recebe o número da linha a partir de 1)", () => {
167
+ render(_jsx(DataTable, { columns: colunas, data: dados, selectable: true, selectAllLabel: "Select all rows", selectRowLabel: (n) => `Select row ${n}` }));
168
+ expect(screen.getByRole("checkbox", { name: "Select all rows" })).toBeInTheDocument();
169
+ expect(screen.getByRole("checkbox", { name: "Select row 1" })).toBeInTheDocument();
170
+ });
171
+ });
172
+ describe("Input · senha", () => {
173
+ it("padrão em português", async () => {
174
+ const usuario = userEvent.setup();
175
+ render(_jsx(Input, { label: "Senha", type: "password" }));
176
+ await usuario.click(screen.getByRole("button", { name: "Mostrar senha" }));
177
+ expect(screen.getByRole("button", { name: "Ocultar senha" })).toBeInTheDocument();
178
+ });
179
+ it("rótulos customizados", async () => {
180
+ const usuario = userEvent.setup();
181
+ render(_jsx(Input, { label: "Password", type: "password", showPasswordLabel: "Show password", hidePasswordLabel: "Hide password" }));
182
+ await usuario.click(screen.getByRole("button", { name: "Show password" }));
183
+ expect(screen.getByRole("button", { name: "Hide password" })).toBeInTheDocument();
184
+ });
185
+ });
186
+ describe("AvatarGroup · excedente", () => {
187
+ const pessoas = ["Ana", "Bia", "Caio", "Davi", "Edu", "Fábio"].map((name) => ({ name }));
188
+ it("padrão em português", () => {
189
+ render(_jsx(AvatarGroup, { avatars: pessoas, max: 4 }));
190
+ const excedente = screen.getByLabelText("Mais 2 avatares");
191
+ expect(excedente).toHaveAttribute("title", "2 outros");
192
+ });
193
+ it("rótulos customizados", () => {
194
+ render(_jsx(AvatarGroup, { avatars: pessoas, max: 4, overflowAriaLabel: (n) => `${n} more avatars`, overflowTitle: (n) => `${n} others` }));
195
+ const excedente = screen.getByLabelText("2 more avatars");
196
+ expect(excedente).toHaveAttribute("title", "2 others");
197
+ });
198
+ });
199
+ describe("AppSidebar · abrir/fechar", () => {
200
+ const itens = [{ id: "a", label: "Início" }];
201
+ it("padrão em português", () => {
202
+ const { rerender } = render(_jsx(AppSidebar, { items: itens }));
203
+ expect(screen.getByRole("button", { name: "Fechar a navegação" })).toBeInTheDocument();
204
+ rerender(_jsx(AppSidebar, { items: itens, collapsed: true }));
205
+ expect(screen.getByRole("button", { name: "Abrir a navegação" })).toBeInTheDocument();
206
+ });
207
+ it("rótulos customizados", () => {
208
+ const rotulos = { expandLabel: "Open navigation", collapseLabel: "Close navigation" };
209
+ const { rerender } = render(_jsx(AppSidebar, { items: itens, ...rotulos }));
210
+ expect(screen.getByRole("button", { name: "Close navigation" })).toBeInTheDocument();
211
+ rerender(_jsx(AppSidebar, { items: itens, collapsed: true, ...rotulos }));
212
+ expect(screen.getByRole("button", { name: "Open navigation" })).toBeInTheDocument();
213
+ });
214
+ });
215
+ describe("AttachmentCard · complementos", () => {
216
+ const base = {
217
+ fileName: "cnh.pdf",
218
+ documentType: "CNH",
219
+ required: true,
220
+ status: "positive",
221
+ statusLabel: "Pré-aprovado",
222
+ statusDetails: { description: "Ok" },
223
+ };
224
+ it("padrão em português", () => {
225
+ render(_jsx(AttachmentCard, { ...base }));
226
+ expect(screen.getByRole("button", { name: /^Pré-aprovado.*: conferência de CNH$/ })).toBeInTheDocument();
227
+ expect(screen.getByText("(obrigatório)")).toBeInTheDocument();
228
+ });
229
+ it("rótulos customizados", () => {
230
+ render(_jsx(AttachmentCard, { ...base, statusLabel: "Pre-approved", statusContextLabel: (s) => `review of ${s}`, requiredLabel: "(required)" }));
231
+ expect(screen.getByRole("button", { name: /^Pre-approved.*: review of CNH$/ })).toBeInTheDocument();
232
+ expect(screen.getByText("(required)")).toBeInTheDocument();
233
+ });
234
+ });
235
+ describe("BarChart e LineChart · tabela oculta", () => {
236
+ const dados = [
237
+ { label: "A", value: 1 },
238
+ { label: "B", value: 2 },
239
+ ];
240
+ it("padrão em português", () => {
241
+ render(_jsx(BarChart, { data: dados }));
242
+ expect(screen.getByRole("columnheader", { name: "Categoria" })).toBeInTheDocument();
243
+ expect(screen.getByRole("list", { name: "Valores por categoria" })).toBeInTheDocument();
244
+ expect(screen.getByRole("table", { name: "Gráfico de barras" })).toBeInTheDocument();
245
+ });
246
+ it("rótulos customizados", () => {
247
+ render(_jsx(LineChart, { data: dados, title: "Cases", categoryLabel: "Category", valuesListLabel: "Values by category", typeLabel: "Line chart" }));
248
+ expect(screen.getByRole("columnheader", { name: "Category" })).toBeInTheDocument();
249
+ expect(screen.getByRole("list", { name: "Values by category — Cases" })).toBeInTheDocument();
250
+ });
251
+ });
252
+ describe("BottomSheet · alça", () => {
253
+ it("padrão em português", () => {
254
+ render(_jsx(BottomSheet, { open: true, title: "Filtros", snapPoints: [0.3, 0.6] }));
255
+ expect(screen.getByRole("slider", { name: "Altura do painel" })).toBeInTheDocument();
256
+ });
257
+ it("rótulo customizado", () => {
258
+ render(_jsx(BottomSheet, { open: true, title: "Filters", snapPoints: [0.3, 0.6], grabberLabel: "Sheet height" }));
259
+ expect(screen.getByRole("slider", { name: "Sheet height" })).toBeInTheDocument();
260
+ });
261
+ });
262
+ describe("ConfirmDialog · carregando", () => {
263
+ it("padrão em português", () => {
264
+ render(_jsx(ConfirmDialog, { open: true, inline: true, title: "Excluir?", confirmLoading: true }));
265
+ expect(screen.getByRole("button", { name: /Aguarde\.\.\./ })).toBeInTheDocument();
266
+ });
267
+ it("rótulo customizado", () => {
268
+ render(_jsx(ConfirmDialog, { open: true, inline: true, title: "Delete?", confirmLoading: true, loadingLabel: "Please wait..." }));
269
+ expect(screen.getByRole("button", { name: /Please wait\.\.\./ })).toBeInTheDocument();
270
+ });
271
+ });
272
+ describe("ConfirmAIAction · risco alto", () => {
273
+ it("padrão em português", () => {
274
+ render(_jsx(ConfirmAIAction, { open: true, risk: "alto", title: "Arquivar", affected: ["Processo 1"], typedValue: "" }));
275
+ expect(screen.getByText("O que será afetado")).toBeInTheDocument();
276
+ expect(screen.getByText("Esta ação não pode ser desfeita.")).toBeInTheDocument();
277
+ expect(screen.getByText("O botão de confirmar fica desabilitado até o texto conferir.")).toBeInTheDocument();
278
+ const rotulo = document.querySelector(".umds-confirmai__label");
279
+ expect(rotulo.textContent).toBe("Para confirmar, digite CONFIRMAR");
280
+ });
281
+ it("rótulos customizados", () => {
282
+ const rotulos = {
283
+ impactLabel: "What will be affected",
284
+ irreversibleLabel: "This action cannot be undone.",
285
+ typePhraseLabel: "To confirm, type",
286
+ phraseMatchedLabel: "Text matches.",
287
+ phrasePendingLabel: "Waiting for the text.",
288
+ };
289
+ const { rerender } = render(_jsx(ConfirmAIAction, { open: true, risk: "alto", title: "Archive", affected: ["Case 1"], confirmPhrase: "CONFIRM", typedValue: "", ...rotulos }));
290
+ expect(screen.getByText("What will be affected")).toBeInTheDocument();
291
+ expect(screen.getByRole("list", { name: "What will be affected" })).toBeInTheDocument();
292
+ expect(screen.getByText("This action cannot be undone.")).toBeInTheDocument();
293
+ expect(screen.getByText("Waiting for the text.")).toBeInTheDocument();
294
+ expect(document.querySelector(".umds-confirmai__label").textContent).toBe("To confirm, type CONFIRM");
295
+ rerender(_jsx(ConfirmAIAction, { open: true, risk: "alto", title: "Archive", affected: ["Case 1"], confirmPhrase: "CONFIRM", typedValue: "confirm", ...rotulos }));
296
+ expect(screen.getByText("Text matches.")).toBeInTheDocument();
297
+ });
298
+ });
299
+ describe("DatePicker · painel e dias", () => {
300
+ it("padrão em português", async () => {
301
+ const usuario = userEvent.setup();
302
+ render(_jsx(DatePicker, { label: "Data", value: "2026-07-10" }));
303
+ await usuario.click(screen.getByRole("combobox"));
304
+ const painel = await screen.findByRole("dialog", { name: "Selecionar data" });
305
+ expect(within(painel).getAllByRole("button", { name: /^20 de [a-zç]+ de 2026$/ }).length).toBeGreaterThan(0);
306
+ });
307
+ it("rótulos customizados", async () => {
308
+ const usuario = userEvent.setup();
309
+ render(_jsx(DatePicker, { label: "Date", value: "2026-07-10", dialogLabel: "Pick a date", dayLabel: (iso) => `day ${iso}` }));
310
+ await usuario.click(screen.getByRole("combobox"));
311
+ const painel = await screen.findByRole("dialog", { name: "Pick a date" });
312
+ expect(within(painel).getAllByRole("button", { name: /^day 2026-\d{2}-20$/ }).length).toBeGreaterThan(0);
313
+ });
314
+ });
315
+ describe("Kanban · textos", () => {
316
+ const colunas = [
317
+ {
318
+ id: "a",
319
+ title: "A fazer",
320
+ wipLimit: 2,
321
+ cards: [{ id: "1", title: "Cartão 1", assignee: "Ana Lima", tags: [{ label: "RH" }] }],
322
+ },
323
+ { id: "b", title: "Feito", cards: [] },
324
+ ];
325
+ it("padrão em português", async () => {
326
+ const usuario = userEvent.setup();
327
+ const { container } = render(_jsx(Kanban, { columns: colunas }));
328
+ const cartao = screen.getByRole("button", { name: "Cartão 1" });
329
+ expect(cartao).toHaveAttribute("aria-roledescription", "cartão arrastável");
330
+ expect(screen.getByText("Responsável: Ana Lima. Etiquetas: RH")).toBeInTheDocument();
331
+ expect(screen.getByText("1 de 2 cartões")).toBeInTheDocument();
332
+ cartao.focus();
333
+ await usuario.keyboard(" ");
334
+ const regiao = container.querySelector('[aria-live="assertive"]');
335
+ await waitFor(() => expect(regiao).toHaveTextContent("Cartão Cartão 1 pego. Coluna A fazer, posição 1 de 1."));
336
+ await usuario.keyboard("{ArrowUp}");
337
+ await waitFor(() => expect(regiao).toHaveTextContent("Início da coluna."));
338
+ await usuario.keyboard("{Escape}");
339
+ await waitFor(() => expect(regiao).toHaveTextContent("Movimento cancelado. Cartão Cartão 1 voltou."));
340
+ });
341
+ it("rótulos customizados", async () => {
342
+ const usuario = userEvent.setup();
343
+ const { container } = render(_jsx(Kanban, { columns: colunas, assigneeLabel: "Assignee", tagsLabel: "Tags", cardRoleDescription: "draggable card", columnCountLabel: (n, limite) => `${n}/${limite ?? "-"} cards`, announcements: {
344
+ position: (coluna, pos, total) => `Column ${coluna}, ${pos} of ${total}.`,
345
+ grabbed: (c, pos) => `Grabbed ${c}. ${pos}`,
346
+ columnStart: "Top of column.",
347
+ cancelled: (c) => `Cancelled ${c}.`,
348
+ } }));
349
+ const cartao = screen.getByRole("button", { name: "Cartão 1" });
350
+ expect(cartao).toHaveAttribute("aria-roledescription", "draggable card");
351
+ expect(screen.getByText("Assignee: Ana Lima. Tags: RH")).toBeInTheDocument();
352
+ expect(screen.getByText("1/2 cards")).toBeInTheDocument();
353
+ expect(screen.getByText("0/- cards")).toBeInTheDocument();
354
+ cartao.focus();
355
+ await usuario.keyboard(" ");
356
+ const regiao = container.querySelector('[aria-live="assertive"]');
357
+ await waitFor(() => expect(regiao).toHaveTextContent("Grabbed Cartão 1. Column A fazer, 1 of 1."));
358
+ await usuario.keyboard("{ArrowUp}");
359
+ await waitFor(() => expect(regiao).toHaveTextContent("Top of column. Column A fazer, 1 of 1."));
360
+ await usuario.keyboard("{Escape}");
361
+ await waitFor(() => expect(regiao).toHaveTextContent("Cancelled Cartão 1."));
362
+ });
363
+ });
364
+ describe("KanbanCard e KanbanColumn · avulsos", () => {
365
+ it("padrão em português", () => {
366
+ render(_jsx(KanbanColumn, { title: "Coluna", count: 1, children: _jsx(KanbanCard, { title: "T", assignee: "Ana Lima" }) }));
367
+ expect(screen.getByLabelText("Responsável: Ana Lima")).toBeInTheDocument();
368
+ expect(screen.getByText("1 cartão")).toBeInTheDocument();
369
+ });
370
+ it("rótulos customizados", () => {
371
+ render(_jsx(KanbanColumn, { title: "Column", count: 3, countLabel: (n) => `${n} cards`, children: _jsx(KanbanCard, { title: "T", assignee: "Ana Lima", assigneeLabel: "Assignee" }) }));
372
+ expect(screen.getByLabelText("Assignee: Ana Lima")).toBeInTheDocument();
373
+ expect(screen.getByText("3 cards")).toBeInTheDocument();
374
+ });
375
+ });
376
+ describe("PhoneInput · copiar e países", () => {
377
+ it("padrão em português", () => {
378
+ render(_jsx(PhoneInput, { value: "11 99999-0000", country: "ES" }));
379
+ expect(screen.getByRole("button", { name: "Copiar número" })).toHaveAttribute("title", "Copiar");
380
+ expect(screen.getAllByAltText("Espanha").length).toBeGreaterThan(0);
381
+ });
382
+ it("rótulos customizados", () => {
383
+ render(_jsx(PhoneInput, { value: "11 99999-0000", country: "ES", copyLabel: "Copy number", copyTitle: "Copy", copiedLabel: "Copied!", countryNames: { ES: "Spain" } }));
384
+ expect(screen.getByRole("button", { name: "Copy number" })).toHaveAttribute("title", "Copy");
385
+ expect(screen.getAllByAltText("Spain").length).toBeGreaterThan(0);
386
+ });
387
+ });
388
+ describe("TimePicker · unidades", () => {
389
+ it("padrão em português", async () => {
390
+ const usuario = userEvent.setup();
391
+ render(_jsx(TimePicker, { label: "Hora", format: "HH:mm:ss" }));
392
+ await usuario.click(screen.getByRole("combobox"));
393
+ await waitFor(() => expect(screen.getByText("seg")).toBeInTheDocument());
394
+ expect(screen.getByText("min")).toBeInTheDocument();
395
+ expect(screen.getByText("h")).toBeInTheDocument();
396
+ });
397
+ it("rótulos customizados", async () => {
398
+ const usuario = userEvent.setup();
399
+ render(_jsx(TimePicker, { label: "Time", format: "HH:mm:ss", hourUnitLabel: "hr", minuteUnitLabel: "mins", secondUnitLabel: "sec" }));
400
+ await usuario.click(screen.getByRole("combobox"));
401
+ await waitFor(() => expect(screen.getByText("sec")).toBeInTheDocument());
402
+ expect(screen.getByText("mins")).toBeInTheDocument();
403
+ expect(screen.getByText("hr")).toBeInTheDocument();
404
+ });
405
+ });
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { describe, expect, it, vi } from "vitest";
3
3
  import { render, screen, waitFor } from "@testing-library/react";
4
+ import { renderToString } from "react-dom/server";
4
5
  import userEvent from "@testing-library/user-event";
5
6
  import { faList } from "@fortawesome/free-solid-svg-icons";
6
7
  import SegmentedControl from "../components/SegmentedControl/SegmentedControl";
@@ -100,3 +101,35 @@ describe("SegmentedControl · acessibilidade", () => {
100
101
  expect(new Set(nomes).size).toBe(2);
101
102
  });
102
103
  });
104
+ /**
105
+ * O id automático era sorteado na inicialização: um no servidor, outro no
106
+ * cliente, e a hidratação divergia no `for`, no `name` e no
107
+ * `aria-labelledby`. Duas renderizações de servidor têm de sair iguais.
108
+ */
109
+ describe("SegmentedControl · ids estáveis", () => {
110
+ it("o HTML do servidor é determinístico", () => {
111
+ const html = () => renderToString(_jsx(SegmentedControl, { label: "Itens", options: POR_PAGINA, defaultValue: "25" }));
112
+ expect(html()).toBe(html());
113
+ });
114
+ it("com `id`, o servidor já manda os ids e o name derivados dele", () => {
115
+ const html = renderToString(_jsx(SegmentedControl, { id: "por-pagina", label: "Itens", options: POR_PAGINA, errorMessage: "Escolha um" }));
116
+ expect(html).toContain('id="por-pagina-label"');
117
+ expect(html).toContain('for="por-pagina-0"');
118
+ expect(html).toContain('name="por-pagina"');
119
+ expect(html).toContain('aria-describedby="por-pagina-error"');
120
+ });
121
+ it("sem `id` nem `name`, o cliente gera um name único por grupo", () => {
122
+ render(_jsxs(_Fragment, { children: [_jsx(SegmentedControl, { label: "A", options: POR_PAGINA }), _jsx(SegmentedControl, { label: "B", options: POR_PAGINA })] }));
123
+ const [grupoA, grupoB] = screen.getAllByRole("radiogroup");
124
+ const nomeA = grupoA.querySelector("input")?.getAttribute("name");
125
+ const nomeB = grupoB.querySelector("input")?.getAttribute("name");
126
+ expect(nomeA).toBeTruthy();
127
+ expect(nomeB).toBeTruthy();
128
+ expect(nomeA).not.toBe(nomeB);
129
+ expect(screen.getByRole("radiogroup", { name: "A" })).toBe(grupoA);
130
+ });
131
+ it("`name` explícito continua mandando no agrupamento", () => {
132
+ render(_jsx(SegmentedControl, { id: "x", name: "perPage", label: "Itens", options: POR_PAGINA }));
133
+ expect(screen.getByRole("radio", { name: "25" })).toHaveAttribute("name", "perPage");
134
+ });
135
+ });
@@ -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 Select from "../components/Select/Select";
6
+ /**
7
+ * O foco do Select 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("Select · erro e apoio ligados ao campo", () => {
18
+ it("a mensagem de erro descreve o combobox e o marca inválido", () => {
19
+ render(_jsx(Select, { 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(Select, { 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(Select, { 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(Select, { 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(Select, { 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(Select, { id: "setor", label: "Setor", options: OPCOES, errorMessage: "Erro" }));
44
+ expect(screen.getByRole("combobox")).toHaveAttribute("aria-describedby", "setor-error");
45
+ });
46
+ });
47
+ describe("Select · 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(Select, { 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(Select, { 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 } from "react/jsx-runtime";
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { fireEvent, render, screen } from "@testing-library/react";
4
+ import Select from "../components/Select/Select";
5
+ const OPCOES = [
6
+ { label: "Urgente", value: "urgente" },
7
+ { label: "Revisão", value: "revisao" },
8
+ ];
9
+ afterEach(() => vi.restoreAllMocks());
10
+ /** jsdom não tem layout: o gatilho "mede" o que o teste mandar. */
11
+ function medirGatilho(topo, base, alturaDaTela) {
12
+ vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(() => ({ top: topo, bottom: base, left: 0, right: 0, width: 0, height: base - topo, x: 0, y: topo, toJSON() { } }));
13
+ Object.defineProperty(window, "innerHeight", { value: alturaDaTela, configurable: true });
14
+ }
15
+ describe("Select · placement", () => {
16
+ it("padrão abre para baixo", () => {
17
+ const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES }));
18
+ fireEvent.click(screen.getByRole("combobox"));
19
+ expect(container.querySelector(".umds-select--placement-top")).toBeNull();
20
+ });
21
+ it("top abre para cima", () => {
22
+ const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, placement: "top" }));
23
+ fireEvent.click(screen.getByRole("combobox"));
24
+ expect(container.querySelector(".umds-select--placement-top")).not.toBeNull();
25
+ });
26
+ it("auto abre para cima quando falta espaço embaixo e há mais em cima", () => {
27
+ medirGatilho(500, 544, 600);
28
+ const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, placement: "auto" }));
29
+ fireEvent.click(screen.getByRole("combobox"));
30
+ expect(container.querySelector(".umds-select--placement-top")).not.toBeNull();
31
+ });
32
+ it("auto abre para baixo quando cabe", () => {
33
+ medirGatilho(20, 64, 900);
34
+ const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, placement: "auto" }));
35
+ fireEvent.click(screen.getByRole("combobox"));
36
+ expect(container.querySelector(".umds-select--placement-top")).toBeNull();
37
+ });
38
+ it("auto abre para baixo quando falta espaço dos dois lados e embaixo é maior", () => {
39
+ medirGatilho(60, 104, 220);
40
+ const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, placement: "auto" }));
41
+ fireEvent.click(screen.getByRole("combobox"));
42
+ expect(container.querySelector(".umds-select--placement-top")).toBeNull();
43
+ });
44
+ });
45
+ describe("Select · variant filter", () => {
46
+ it("escreve a classe do filtro; sem variant não escreve", () => {
47
+ const { container, rerender } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, variant: "filter" }));
48
+ expect(container.querySelector(".umds-select--filter")).not.toBeNull();
49
+ rerender(_jsx(Select, { ariaLabel: "x", options: OPCOES }));
50
+ expect(container.querySelector(".umds-select--filter")).toBeNull();
51
+ });
52
+ it("emptyOptionLabel vem no topo, marcada sem seleção; escolher chama onChange com vazio e volta ao placeholder", () => {
53
+ const aoMudar = vi.fn();
54
+ const { rerender } = render(_jsx(Select, { ariaLabel: "Marcadores", placeholder: "Marcadores", options: OPCOES, emptyOptionLabel: "Todos os marcadores", onChange: aoMudar }));
55
+ fireEvent.click(screen.getByRole("combobox"));
56
+ const opcoes = screen.getAllByRole("option");
57
+ expect(opcoes[0]).toHaveTextContent("Todos os marcadores");
58
+ expect(opcoes[0]).toHaveAttribute("aria-selected", "true");
59
+ fireEvent.click(opcoes[1]);
60
+ expect(aoMudar).toHaveBeenLastCalledWith("urgente");
61
+ rerender(_jsx(Select, { ariaLabel: "Marcadores", placeholder: "Marcadores", options: OPCOES, emptyOptionLabel: "Todos os marcadores", value: "urgente", onChange: aoMudar }));
62
+ expect(screen.getByRole("combobox")).toHaveTextContent("Urgente");
63
+ fireEvent.click(screen.getByRole("combobox"));
64
+ fireEvent.click(screen.getAllByRole("option")[0]);
65
+ expect(aoMudar).toHaveBeenLastCalledWith("");
66
+ rerender(_jsx(Select, { ariaLabel: "Marcadores", placeholder: "Marcadores", options: OPCOES, emptyOptionLabel: "Todos os marcadores", value: "", onChange: aoMudar }));
67
+ expect(screen.getByRole("combobox")).toHaveTextContent("Marcadores");
68
+ });
69
+ it("sem emptyOptionLabel não há opção extra", () => {
70
+ render(_jsx(Select, { ariaLabel: "x", options: OPCOES }));
71
+ fireEvent.click(screen.getByRole("combobox"));
72
+ expect(screen.getAllByRole("option")).toHaveLength(2);
73
+ });
74
+ it("footer aparece dentro da lista aberta, e não fecha ao clicar nele", () => {
75
+ render(_jsx(Select, { ariaLabel: "x", options: OPCOES, footer: _jsx("button", { children: "Gerenciar marcadores" }) }));
76
+ expect(screen.queryByText("Gerenciar marcadores")).toBeNull();
77
+ fireEvent.click(screen.getByRole("combobox"));
78
+ const acao = screen.getByText("Gerenciar marcadores");
79
+ expect(acao.closest(".umds-select__footer")).not.toBeNull();
80
+ fireEvent.mouseDown(acao);
81
+ expect(screen.getByRole("combobox")).toHaveAttribute("aria-expanded", "true");
82
+ });
83
+ it("sem footer não há rodapé", () => {
84
+ const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES }));
85
+ fireEvent.click(screen.getByRole("combobox"));
86
+ expect(container.querySelector(".umds-select__footer")).toBeNull();
87
+ });
88
+ });
@@ -0,0 +1 @@
1
+ export {};