@1doc/1ds-react 2.8.0 → 2.10.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 (287) hide show
  1. package/CHANGELOG.md +1540 -0
  2. package/dist/components/AILabel/AILabel.js +1 -1
  3. package/dist/components/Accordion/Accordion.css +13 -0
  4. package/dist/components/Accordion/Accordion.d.ts +9 -2
  5. package/dist/components/Accordion/Accordion.js +1 -0
  6. package/dist/components/AppSubheader/AppSubheader.css +10 -1
  7. package/dist/components/AttachmentCard/AttachmentCard.css +26 -8
  8. package/dist/components/AttachmentCard/AttachmentCard.d.ts +22 -2
  9. package/dist/components/AttachmentCard/AttachmentCard.js +47 -3
  10. package/dist/components/Avatar/Avatar.css +7 -2
  11. package/dist/components/Avatar/AvatarGroup.d.ts +17 -0
  12. package/dist/components/Avatar/AvatarGroup.js +22 -8
  13. package/dist/components/Badge/Badge.css +67 -2
  14. package/dist/components/Badge/Badge.d.ts +23 -4
  15. package/dist/components/Badge/Badge.js +4 -0
  16. package/dist/components/Box/Box.css +83 -0
  17. package/dist/components/Box/Box.d.ts +82 -2
  18. package/dist/components/Box/Box.js +42 -2
  19. package/dist/components/Button/Button.css +29 -0
  20. package/dist/components/Button/Button.d.ts +4 -4
  21. package/dist/components/Button/Button.js +4 -1
  22. package/dist/components/Calendar/Calendar.css +245 -0
  23. package/dist/components/Calendar/Calendar.d.ts +126 -0
  24. package/dist/components/Calendar/Calendar.js +320 -0
  25. package/dist/components/Chips/Chips.css +38 -0
  26. package/dist/components/Chips/Chips.d.ts +5 -2
  27. package/dist/components/Chips/Chips.js +2 -1
  28. package/dist/components/Coachmark/Coachmark.css +128 -0
  29. package/dist/components/Coachmark/Coachmark.d.ts +87 -0
  30. package/dist/components/Coachmark/Coachmark.js +362 -0
  31. package/dist/components/CodeBlock/CodeBlock.css +96 -0
  32. package/dist/components/CodeBlock/CodeBlock.d.ts +47 -0
  33. package/dist/components/CodeBlock/CodeBlock.js +103 -0
  34. package/dist/components/ColorPicker/ColorPicker.css +140 -0
  35. package/dist/components/ColorPicker/ColorPicker.d.ts +73 -0
  36. package/dist/components/ColorPicker/ColorPicker.js +219 -0
  37. package/dist/components/Combobox/Combobox.css +8 -0
  38. package/dist/components/DataTable/DataTable.css +254 -0
  39. package/dist/components/DataTable/DataTable.d.ts +81 -5
  40. package/dist/components/DataTable/DataTable.js +335 -19
  41. package/dist/components/DatePicker/DatePicker.css +8 -0
  42. package/dist/components/DatePicker/DatePicker.js +10 -1
  43. package/dist/components/DescriptionList/DescriptionList.css +127 -0
  44. package/dist/components/DescriptionList/DescriptionList.d.ts +62 -0
  45. package/dist/components/DescriptionList/DescriptionList.js +52 -0
  46. package/dist/components/EmptyState/EmptyState.d.ts +4 -2
  47. package/dist/components/EmptyState/EmptyState.js +2 -2
  48. package/dist/components/FileInput/FileInput.css +16 -0
  49. package/dist/components/FileInput/FileInput.d.ts +4 -2
  50. package/dist/components/FileInput/FileInput.js +8 -2
  51. package/dist/components/Grid/Grid.js +5 -5
  52. package/dist/components/IconPicker/IconPicker.css +107 -0
  53. package/dist/components/IconPicker/IconPicker.d.ts +74 -0
  54. package/dist/components/IconPicker/IconPicker.js +194 -0
  55. package/dist/components/Input/Input.css +59 -0
  56. package/dist/components/Input/Input.d.ts +17 -1
  57. package/dist/components/Input/Input.js +67 -5
  58. package/dist/components/Kanban/Kanban.css +4 -0
  59. package/dist/components/Kbd/Kbd.css +66 -0
  60. package/dist/components/Kbd/Kbd.d.ts +32 -0
  61. package/dist/components/Kbd/Kbd.js +40 -0
  62. package/dist/components/List/List.css +136 -0
  63. package/dist/components/List/List.d.ts +82 -0
  64. package/dist/components/List/List.js +53 -0
  65. package/dist/components/List/ListItem.d.ts +97 -0
  66. package/dist/components/List/ListItem.js +82 -0
  67. package/dist/components/Modal/Modal.css +80 -0
  68. package/dist/components/Modal/Modal.d.ts +33 -6
  69. package/dist/components/Modal/Modal.js +101 -6
  70. package/dist/components/MultiSelect/MultiSelect.css +8 -0
  71. package/dist/components/MultiSelect/MultiSelect.js +10 -1
  72. package/dist/components/OrgChart/OrgChart.css +149 -0
  73. package/dist/components/OrgChart/OrgChart.d.ts +83 -0
  74. package/dist/components/OrgChart/OrgChart.js +297 -0
  75. package/dist/components/OtpInput/OtpInput.css +93 -0
  76. package/dist/components/OtpInput/OtpInput.d.ts +60 -0
  77. package/dist/components/OtpInput/OtpInput.js +215 -0
  78. package/dist/components/PhoneInput/PhoneInput.css +8 -0
  79. package/dist/components/Popover/Popover.d.ts +7 -0
  80. package/dist/components/Popover/Popover.js +11 -1
  81. package/dist/components/RichTextEditor/RichTextEditor.css +250 -0
  82. package/dist/components/RichTextEditor/RichTextEditor.d.ts +97 -0
  83. package/dist/components/RichTextEditor/RichTextEditor.js +951 -0
  84. package/dist/components/SegmentedControl/SegmentedControl.css +24 -0
  85. package/dist/components/SegmentedControl/SegmentedControl.d.ts +2 -0
  86. package/dist/components/SegmentedControl/SegmentedControl.js +10 -2
  87. package/dist/components/Select/Select.css +164 -0
  88. package/dist/components/Select/Select.d.ts +34 -0
  89. package/dist/components/Select/Select.js +258 -28
  90. package/dist/components/Stack/Stack.css +49 -0
  91. package/dist/components/Stack/Stack.d.ts +65 -7
  92. package/dist/components/Stack/Stack.js +30 -2
  93. package/dist/components/StatCard/StatCard.css +138 -0
  94. package/dist/components/StatCard/StatCard.d.ts +26 -0
  95. package/dist/components/StatCard/StatCard.js +13 -1
  96. package/dist/components/Tabs/Tab.d.ts +15 -0
  97. package/dist/components/Tabs/Tab.js +30 -1
  98. package/dist/components/Tabs/Tabs.css +132 -0
  99. package/dist/components/Tabs/Tabs.d.ts +7 -0
  100. package/dist/components/Tabs/Tabs.js +13 -2
  101. package/dist/components/Tag/Tag.css +85 -2
  102. package/dist/components/Tag/Tag.d.ts +13 -6
  103. package/dist/components/Tag/Tag.js +1 -0
  104. package/dist/components/Text/Text.js +2 -2
  105. package/dist/components/Textarea/Textarea.css +8 -0
  106. package/dist/components/TimePicker/TimePicker.css +8 -0
  107. package/dist/components/Toast/Toast.css +32 -0
  108. package/dist/components/Toast/Toast.d.ts +18 -0
  109. package/dist/components/Toast/Toast.js +14 -1
  110. package/dist/components/Toast/ToastStack.js +8 -1
  111. package/dist/components/Tooltip/Tooltip.css +25 -0
  112. package/dist/components/Tooltip/Tooltip.d.ts +11 -0
  113. package/dist/components/Tooltip/Tooltip.js +18 -3
  114. package/dist/index.d.ts +25 -0
  115. package/dist/index.js +14 -0
  116. package/dist/teste/AILabel.test.d.ts +1 -0
  117. package/dist/teste/AILabel.test.js +33 -0
  118. package/dist/teste/AccordionConteudoLivre.test.d.ts +1 -0
  119. package/dist/teste/AccordionConteudoLivre.test.js +29 -0
  120. package/dist/teste/AccordionTituloNeutro.test.d.ts +1 -0
  121. package/dist/teste/AccordionTituloNeutro.test.js +23 -0
  122. package/dist/teste/AppSubheaderRegiao.test.d.ts +1 -0
  123. package/dist/teste/AppSubheaderRegiao.test.js +13 -0
  124. package/dist/teste/AtributosRepassados.test.d.ts +1 -0
  125. package/dist/teste/AtributosRepassados.test.js +52 -0
  126. package/dist/teste/AttachmentCardIA.test.d.ts +1 -0
  127. package/dist/teste/AttachmentCardIA.test.js +89 -0
  128. package/dist/teste/AttachmentCardLista.test.d.ts +1 -0
  129. package/dist/teste/AttachmentCardLista.test.js +49 -0
  130. package/dist/teste/AttachmentCardSm.test.d.ts +1 -0
  131. package/dist/teste/AttachmentCardSm.test.js +26 -0
  132. package/dist/teste/AvatarGroupOverlap.test.d.ts +1 -0
  133. package/dist/teste/AvatarGroupOverlap.test.js +56 -0
  134. package/dist/teste/BadgeNeutroColado.test.d.ts +1 -0
  135. package/dist/teste/BadgeNeutroColado.test.js +11 -0
  136. package/dist/teste/BadgeTag.test.d.ts +1 -0
  137. package/dist/teste/BadgeTag.test.js +55 -0
  138. package/dist/teste/BoxItemFlex.test.d.ts +1 -0
  139. package/dist/teste/BoxItemFlex.test.js +54 -0
  140. package/dist/teste/BoxLayout.test.d.ts +1 -0
  141. package/dist/teste/BoxLayout.test.js +35 -0
  142. package/dist/teste/Button.test.d.ts +1 -0
  143. package/dist/teste/Button.test.js +27 -0
  144. package/dist/teste/Calendar.test.d.ts +1 -0
  145. package/dist/teste/Calendar.test.js +221 -0
  146. package/dist/teste/CalendarCabecalho.test.d.ts +1 -0
  147. package/dist/teste/CalendarCabecalho.test.js +11 -0
  148. package/dist/teste/ChipsXs.test.d.ts +1 -0
  149. package/dist/teste/ChipsXs.test.js +31 -0
  150. package/dist/teste/Coachmark.test.d.ts +1 -0
  151. package/dist/teste/Coachmark.test.js +149 -0
  152. package/dist/teste/CoachmarkSemVeu.test.d.ts +1 -0
  153. package/dist/teste/CoachmarkSemVeu.test.js +85 -0
  154. package/dist/teste/ColorPicker.test.d.ts +1 -0
  155. package/dist/teste/ColorPicker.test.js +132 -0
  156. package/dist/teste/ColorPickerXs.test.d.ts +1 -0
  157. package/dist/teste/ColorPickerXs.test.js +21 -0
  158. package/dist/teste/DataTableArvoreEVariantes.test.d.ts +1 -0
  159. package/dist/teste/DataTableArvoreEVariantes.test.js +190 -0
  160. package/dist/teste/DataTableCelulaLivre.test.d.ts +1 -0
  161. package/dist/teste/DataTableCelulaLivre.test.js +76 -0
  162. package/dist/teste/DataTableDocumento.test.d.ts +1 -0
  163. package/dist/teste/DataTableDocumento.test.js +92 -0
  164. package/dist/teste/DatePicker.test.js +23 -0
  165. package/dist/teste/DescriptionListCompacta.test.d.ts +1 -0
  166. package/dist/teste/DescriptionListCompacta.test.js +22 -0
  167. package/dist/teste/EmptyStateTituloRico.test.d.ts +1 -0
  168. package/dist/teste/EmptyStateTituloRico.test.js +23 -0
  169. package/dist/teste/FileInputTrigger.test.d.ts +1 -0
  170. package/dist/teste/FileInputTrigger.test.js +53 -0
  171. package/dist/teste/IconPicker.test.d.ts +1 -0
  172. package/dist/teste/IconPicker.test.js +130 -0
  173. package/dist/teste/InputAgrupado.test.d.ts +1 -0
  174. package/dist/teste/InputAgrupado.test.js +24 -0
  175. package/dist/teste/InputMascaraEAfins.test.d.ts +1 -0
  176. package/dist/teste/InputMascaraEAfins.test.js +99 -0
  177. package/dist/teste/KbdCodeBlock.test.d.ts +1 -0
  178. package/dist/teste/KbdCodeBlock.test.js +95 -0
  179. package/dist/teste/List.test.d.ts +1 -0
  180. package/dist/teste/List.test.js +153 -0
  181. package/dist/teste/ListItemTooltipStandalone.test.d.ts +1 -0
  182. package/dist/teste/ListItemTooltipStandalone.test.js +39 -0
  183. package/dist/teste/ModalVariantes.test.d.ts +1 -0
  184. package/dist/teste/ModalVariantes.test.js +151 -0
  185. package/dist/teste/NomeAcessivelSsr.test.d.ts +1 -0
  186. package/dist/teste/NomeAcessivelSsr.test.js +88 -0
  187. package/dist/teste/OrgChart.test.d.ts +1 -0
  188. package/dist/teste/OrgChart.test.js +162 -0
  189. package/dist/teste/OtpInput.test.d.ts +1 -0
  190. package/dist/teste/OtpInput.test.js +143 -0
  191. package/dist/teste/PopoverMaxHeight.test.d.ts +1 -0
  192. package/dist/teste/PopoverMaxHeight.test.js +38 -0
  193. package/dist/teste/RichTextEditor.test.d.ts +1 -0
  194. package/dist/teste/RichTextEditor.test.js +287 -0
  195. package/dist/teste/RichTextEditorAlinhaImagemTabela.test.d.ts +1 -0
  196. package/dist/teste/RichTextEditorAlinhaImagemTabela.test.js +212 -0
  197. package/dist/teste/RichTextEditorEstiloDeTexto.test.d.ts +1 -0
  198. package/dist/teste/RichTextEditorEstiloDeTexto.test.js +120 -0
  199. package/dist/teste/SegmentedControlContador.test.d.ts +1 -0
  200. package/dist/teste/SegmentedControlContador.test.js +39 -0
  201. package/dist/teste/SelectAbertoControladoEFlutuante.test.d.ts +1 -0
  202. package/dist/teste/SelectAbertoControladoEFlutuante.test.js +145 -0
  203. package/dist/teste/SelectFiltroCorETamanho.test.d.ts +1 -0
  204. package/dist/teste/SelectFiltroCorETamanho.test.js +77 -0
  205. package/dist/teste/SelectPlacementFiltro.test.d.ts +1 -0
  206. package/dist/teste/SelectPlacementFiltro.test.js +88 -0
  207. package/dist/teste/Stack.test.d.ts +1 -0
  208. package/dist/teste/Stack.test.js +57 -0
  209. package/dist/teste/StatCardRotuloTopo.test.d.ts +1 -0
  210. package/dist/teste/StatCardRotuloTopo.test.js +34 -0
  211. package/dist/teste/StatCardSecundariaETom.test.d.ts +1 -0
  212. package/dist/teste/StatCardSecundariaETom.test.js +45 -0
  213. package/dist/teste/TabsContadorFechavel.test.d.ts +1 -0
  214. package/dist/teste/TabsContadorFechavel.test.js +79 -0
  215. package/dist/teste/ToastAcaoEDetalhes.test.d.ts +1 -0
  216. package/dist/teste/ToastAcaoEDetalhes.test.js +94 -0
  217. package/dist/teste/TooltipDark.test.d.ts +1 -0
  218. package/dist/teste/TooltipDark.test.js +31 -0
  219. package/dist/utils/calendario.d.ts +28 -0
  220. package/dist/utils/calendario.js +73 -0
  221. package/dist/utils/html-seguro.d.ts +45 -0
  222. package/dist/utils/html-seguro.js +208 -0
  223. package/dist/utils/paleta-de-cores.d.ts +26 -0
  224. package/dist/utils/paleta-de-cores.js +10 -0
  225. package/dist/utils/texto.d.ts +5 -0
  226. package/dist/utils/texto.js +5 -0
  227. package/dist/utils/toast.d.ts +10 -1
  228. package/dist/utils/toast.js +2 -1
  229. package/package.json +3 -3
  230. package/src/index.ts +26 -0
  231. package/src/teste/AILabel.test.tsx +41 -0
  232. package/src/teste/AccordionConteudoLivre.test.tsx +39 -0
  233. package/src/teste/AccordionTituloNeutro.test.tsx +25 -0
  234. package/src/teste/AppSubheaderRegiao.test.tsx +17 -0
  235. package/src/teste/AtributosRepassados.test.tsx +73 -0
  236. package/src/teste/AttachmentCardIA.test.tsx +126 -0
  237. package/src/teste/AttachmentCardLista.test.tsx +53 -0
  238. package/src/teste/AttachmentCardSm.test.tsx +29 -0
  239. package/src/teste/AvatarGroupOverlap.test.tsx +74 -0
  240. package/src/teste/BadgeNeutroColado.test.tsx +15 -0
  241. package/src/teste/BadgeTag.test.tsx +85 -0
  242. package/src/teste/BoxItemFlex.test.tsx +81 -0
  243. package/src/teste/BoxLayout.test.tsx +50 -0
  244. package/src/teste/Button.test.tsx +39 -0
  245. package/src/teste/Calendar.test.tsx +282 -0
  246. package/src/teste/CalendarCabecalho.test.tsx +11 -0
  247. package/src/teste/ChipsXs.test.tsx +41 -0
  248. package/src/teste/Coachmark.test.tsx +198 -0
  249. package/src/teste/CoachmarkSemVeu.test.tsx +101 -0
  250. package/src/teste/ColorPicker.test.tsx +153 -0
  251. package/src/teste/ColorPickerXs.test.tsx +22 -0
  252. package/src/teste/DataTableArvoreEVariantes.test.tsx +240 -0
  253. package/src/teste/DataTableCelulaLivre.test.tsx +103 -0
  254. package/src/teste/DataTableDocumento.test.tsx +102 -0
  255. package/src/teste/DatePicker.test.tsx +38 -0
  256. package/src/teste/DescriptionListCompacta.test.tsx +24 -0
  257. package/src/teste/EmptyStateTituloRico.test.tsx +34 -0
  258. package/src/teste/FileInputTrigger.test.tsx +89 -0
  259. package/src/teste/IconPicker.test.tsx +145 -0
  260. package/src/teste/InputAgrupado.test.tsx +26 -0
  261. package/src/teste/InputMascaraEAfins.test.tsx +124 -0
  262. package/src/teste/KbdCodeBlock.test.tsx +106 -0
  263. package/src/teste/List.test.tsx +269 -0
  264. package/src/teste/ListItemTooltipStandalone.test.tsx +64 -0
  265. package/src/teste/ModalVariantes.test.tsx +173 -0
  266. package/src/teste/NomeAcessivelSsr.test.tsx +110 -0
  267. package/src/teste/OrgChart.test.tsx +183 -0
  268. package/src/teste/OtpInput.test.tsx +163 -0
  269. package/src/teste/PopoverMaxHeight.test.tsx +47 -0
  270. package/src/teste/RichTextEditor.test.tsx +329 -0
  271. package/src/teste/RichTextEditorAlinhaImagemTabela.test.tsx +238 -0
  272. package/src/teste/RichTextEditorEstiloDeTexto.test.tsx +137 -0
  273. package/src/teste/SegmentedControlContador.test.tsx +43 -0
  274. package/src/teste/SelectAbertoControladoEFlutuante.test.tsx +180 -0
  275. package/src/teste/SelectFiltroCorETamanho.test.tsx +90 -0
  276. package/src/teste/SelectPlacementFiltro.test.tsx +110 -0
  277. package/src/teste/Stack.test.tsx +80 -0
  278. package/src/teste/StatCardRotuloTopo.test.tsx +44 -0
  279. package/src/teste/StatCardSecundariaETom.test.tsx +51 -0
  280. package/src/teste/TabsContadorFechavel.test.tsx +144 -0
  281. package/src/teste/ToastAcaoEDetalhes.test.tsx +109 -0
  282. package/src/teste/TooltipDark.test.tsx +51 -0
  283. package/src/utils/calendario.ts +78 -0
  284. package/src/utils/html-seguro.ts +197 -0
  285. package/src/utils/paleta-de-cores.ts +34 -0
  286. package/src/utils/texto.ts +5 -0
  287. package/src/utils/toast.ts +12 -2
@@ -0,0 +1,90 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+ import Select from "../components/Select/Select";
4
+
5
+ const MARCADORES = [
6
+ { label: "Urgente", value: "urgente", color: "var(--umds-semantic-color-feedback-negative-pure)" },
7
+ { label: "Revisão", value: "revisao", color: "var(--umds-semantic-color-primary-pure)" },
8
+ { label: "Sem marcador", value: "nenhum" },
9
+ ];
10
+
11
+ describe("Select filtro · tamanho e fundo", () => {
12
+ it("as variantes de filtro nascem no tamanho sm; size explícito manda; o padrão segue md", () => {
13
+ const { container, rerender } = render(<Select ariaLabel="x" options={MARCADORES} variant="filter" />);
14
+ const raiz = () => container.firstElementChild as HTMLElement;
15
+ expect(raiz()).toHaveClass("umds-select--sm");
16
+ rerender(<Select ariaLabel="x" options={MARCADORES} variant="search" />);
17
+ expect(raiz()).toHaveClass("umds-select--sm");
18
+ rerender(<Select ariaLabel="x" options={MARCADORES} variant="combo" />);
19
+ expect(raiz()).toHaveClass("umds-select--sm");
20
+ rerender(<Select ariaLabel="x" options={MARCADORES} variant="filter" size="md" />);
21
+ expect(raiz()).toHaveClass("umds-select--md");
22
+ rerender(<Select ariaLabel="x" options={MARCADORES} />);
23
+ expect(raiz()).toHaveClass("umds-select--md");
24
+ expect(raiz()).not.toHaveClass("umds-select--sm");
25
+ });
26
+
27
+ it("o azul-claro do gatilho só vem com valor escolhido (--has-value); sem valor, não", () => {
28
+ const { container, rerender } = render(<Select ariaLabel="x" options={MARCADORES} variant="filter" placeholder="Marcadores" />);
29
+ const raiz = () => container.firstElementChild as HTMLElement;
30
+ expect(raiz()).not.toHaveClass("umds-select--has-value");
31
+ rerender(<Select ariaLabel="x" options={MARCADORES} variant="filter" placeholder="Marcadores" value="urgente" />);
32
+ expect(raiz()).toHaveClass("umds-select--has-value");
33
+ rerender(<Select ariaLabel="x" options={MARCADORES} placeholder="Marcadores" value="urgente" />);
34
+ expect(raiz()).not.toHaveClass("umds-select--has-value");
35
+ });
36
+
37
+ it("o valor vazio do emptyOptionLabel volta ao estado sem valor", () => {
38
+ const { container } = render(
39
+ <Select ariaLabel="x" options={MARCADORES} variant="filter" placeholder="Marcadores" emptyOptionLabel="Todos" value="" />,
40
+ );
41
+ expect(container.firstElementChild).not.toHaveClass("umds-select--has-value");
42
+ });
43
+ });
44
+
45
+ describe("Select · cor por opção", () => {
46
+ it("a lista mostra uma amostra por opção com color; sem color, não", () => {
47
+ const { container } = render(<Select ariaLabel="x" options={MARCADORES} variant="filter" />);
48
+ fireEvent.click(screen.getByRole("combobox"));
49
+ const opcoes = [...container.querySelectorAll('[role="option"]')];
50
+ expect(opcoes[0].querySelector(".umds-select__swatch")).toHaveAttribute("aria-hidden", "true");
51
+ expect((opcoes[0].querySelector(".umds-select__swatch") as HTMLElement).style.background).toContain("--umds-semantic-color-feedback-negative-pure");
52
+ expect(opcoes[1].querySelector(".umds-select__swatch")).not.toBeNull();
53
+ expect(opcoes[2].querySelector(".umds-select__swatch")).toBeNull();
54
+ });
55
+
56
+ it("o gatilho ganha a cor da opção escolhida (seleção única)", () => {
57
+ const { container } = render(<Select ariaLabel="x" options={MARCADORES} variant="filter" placeholder="Marcadores" value="revisao" />);
58
+ const amostra = container.querySelector(".umds-select__trigger .umds-select__swatch") as HTMLElement;
59
+ expect(amostra.style.background).toContain("--umds-semantic-color-primary-pure");
60
+ });
61
+
62
+ it("opção escolhida sem color e estado sem valor: o gatilho não tem amostra", () => {
63
+ const { container, rerender } = render(<Select ariaLabel="x" options={MARCADORES} placeholder="Marcadores" value="nenhum" />);
64
+ expect(container.querySelector(".umds-select__trigger .umds-select__swatch")).toBeNull();
65
+ rerender(<Select ariaLabel="x" options={MARCADORES} placeholder="Marcadores" />);
66
+ expect(container.querySelector(".umds-select__trigger .umds-select__swatch")).toBeNull();
67
+ });
68
+
69
+ it("triggerSwatch explícito manda sobre a cor da opção", () => {
70
+ const { container } = render(
71
+ <Select ariaLabel="x" options={MARCADORES} value="urgente" triggerSwatch="var(--umds-semantic-color-feedback-positive-pure)" />,
72
+ );
73
+ const amostras = container.querySelectorAll(".umds-select__trigger .umds-select__swatch");
74
+ expect(amostras).toHaveLength(1);
75
+ expect((amostras[0] as HTMLElement).style.background).toContain("--umds-semantic-color-feedback-positive-pure");
76
+ });
77
+
78
+ it("na seleção múltipla o gatilho não pinta amostra (são várias), mas a lista mostra as cores", () => {
79
+ const { container } = render(<Select ariaLabel="x" options={MARCADORES} multiple value={["urgente", "revisao"]} />);
80
+ expect(container.querySelector(".umds-select__trigger .umds-select__swatch")).toBeNull();
81
+ fireEvent.click(screen.getByRole("combobox"));
82
+ expect(container.querySelectorAll('[role="option"] .umds-select__swatch')).toHaveLength(2);
83
+ });
84
+
85
+ it("a cor não vira texto nem entra no nome acessível da opção", () => {
86
+ render(<Select ariaLabel="x" options={MARCADORES} />);
87
+ fireEvent.click(screen.getByRole("combobox"));
88
+ expect(screen.getByRole("option", { name: "Urgente" })).toBeInTheDocument();
89
+ });
90
+ });
@@ -0,0 +1,110 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+ import Select from "../components/Select/Select";
4
+
5
+ const OPCOES = [
6
+ { label: "Urgente", value: "urgente" },
7
+ { label: "Revisão", value: "revisao" },
8
+ ];
9
+
10
+ afterEach(() => vi.restoreAllMocks());
11
+
12
+ /** jsdom não tem layout: o gatilho "mede" o que o teste mandar. */
13
+ function medirGatilho(topo: number, base: number, alturaDaTela: number) {
14
+ vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(
15
+ () => ({ top: topo, bottom: base, left: 0, right: 0, width: 0, height: base - topo, x: 0, y: topo, toJSON() {} }) as any,
16
+ );
17
+ Object.defineProperty(window, "innerHeight", { value: alturaDaTela, configurable: true });
18
+ }
19
+
20
+ describe("Select · placement", () => {
21
+ it("padrão abre para baixo", () => {
22
+ const { container } = render(<Select ariaLabel="x" options={OPCOES} />);
23
+ fireEvent.click(screen.getByRole("combobox"));
24
+ expect(container.querySelector(".umds-select--placement-top")).toBeNull();
25
+ });
26
+
27
+ it("top abre para cima", () => {
28
+ const { container } = render(<Select ariaLabel="x" options={OPCOES} placement="top" />);
29
+ fireEvent.click(screen.getByRole("combobox"));
30
+ expect(container.querySelector(".umds-select--placement-top")).not.toBeNull();
31
+ });
32
+
33
+ it("auto abre para cima quando falta espaço embaixo e há mais em cima", () => {
34
+ medirGatilho(500, 544, 600);
35
+ const { container } = render(<Select ariaLabel="x" options={OPCOES} placement="auto" />);
36
+ fireEvent.click(screen.getByRole("combobox"));
37
+ expect(container.querySelector(".umds-select--placement-top")).not.toBeNull();
38
+ });
39
+
40
+ it("auto abre para baixo quando cabe", () => {
41
+ medirGatilho(20, 64, 900);
42
+ const { container } = render(<Select ariaLabel="x" options={OPCOES} placement="auto" />);
43
+ fireEvent.click(screen.getByRole("combobox"));
44
+ expect(container.querySelector(".umds-select--placement-top")).toBeNull();
45
+ });
46
+
47
+ it("auto abre para baixo quando falta espaço dos dois lados e embaixo é maior", () => {
48
+ medirGatilho(60, 104, 220);
49
+ const { container } = render(<Select ariaLabel="x" options={OPCOES} placement="auto" />);
50
+ fireEvent.click(screen.getByRole("combobox"));
51
+ expect(container.querySelector(".umds-select--placement-top")).toBeNull();
52
+ });
53
+ });
54
+
55
+ describe("Select · variant filter", () => {
56
+ it("escreve a classe do filtro; sem variant não escreve", () => {
57
+ const { container, rerender } = render(<Select ariaLabel="x" options={OPCOES} variant="filter" />);
58
+ expect(container.querySelector(".umds-select--filter")).not.toBeNull();
59
+ rerender(<Select ariaLabel="x" options={OPCOES} />);
60
+ expect(container.querySelector(".umds-select--filter")).toBeNull();
61
+ });
62
+
63
+ it("emptyOptionLabel vem no topo, marcada sem seleção; escolher chama onChange com vazio e volta ao placeholder", () => {
64
+ const aoMudar = vi.fn();
65
+ const { rerender } = render(
66
+ <Select ariaLabel="Marcadores" placeholder="Marcadores" options={OPCOES} emptyOptionLabel="Todos os marcadores" onChange={aoMudar} />,
67
+ );
68
+ fireEvent.click(screen.getByRole("combobox"));
69
+ const opcoes = screen.getAllByRole("option");
70
+ expect(opcoes[0]).toHaveTextContent("Todos os marcadores");
71
+ expect(opcoes[0]).toHaveAttribute("aria-selected", "true");
72
+ fireEvent.click(opcoes[1]);
73
+ expect(aoMudar).toHaveBeenLastCalledWith("urgente");
74
+
75
+ rerender(
76
+ <Select ariaLabel="Marcadores" placeholder="Marcadores" options={OPCOES} emptyOptionLabel="Todos os marcadores" value="urgente" onChange={aoMudar} />,
77
+ );
78
+ expect(screen.getByRole("combobox")).toHaveTextContent("Urgente");
79
+ fireEvent.click(screen.getByRole("combobox"));
80
+ fireEvent.click(screen.getAllByRole("option")[0]);
81
+ expect(aoMudar).toHaveBeenLastCalledWith("");
82
+
83
+ rerender(
84
+ <Select ariaLabel="Marcadores" placeholder="Marcadores" options={OPCOES} emptyOptionLabel="Todos os marcadores" value="" onChange={aoMudar} />,
85
+ );
86
+ expect(screen.getByRole("combobox")).toHaveTextContent("Marcadores");
87
+ });
88
+
89
+ it("sem emptyOptionLabel não há opção extra", () => {
90
+ render(<Select ariaLabel="x" options={OPCOES} />);
91
+ fireEvent.click(screen.getByRole("combobox"));
92
+ expect(screen.getAllByRole("option")).toHaveLength(2);
93
+ });
94
+
95
+ it("footer aparece dentro da lista aberta, e não fecha ao clicar nele", () => {
96
+ render(<Select ariaLabel="x" options={OPCOES} footer={<button>Gerenciar marcadores</button>} />);
97
+ expect(screen.queryByText("Gerenciar marcadores")).toBeNull();
98
+ fireEvent.click(screen.getByRole("combobox"));
99
+ const acao = screen.getByText("Gerenciar marcadores");
100
+ expect(acao.closest(".umds-select__footer")).not.toBeNull();
101
+ fireEvent.mouseDown(acao);
102
+ expect(screen.getByRole("combobox")).toHaveAttribute("aria-expanded", "true");
103
+ });
104
+
105
+ it("sem footer não há rodapé", () => {
106
+ const { container } = render(<Select ariaLabel="x" options={OPCOES} />);
107
+ fireEvent.click(screen.getByRole("combobox"));
108
+ expect(container.querySelector(".umds-select__footer")).toBeNull();
109
+ });
110
+ });
@@ -0,0 +1,80 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+ import Stack from "../components/Stack/Stack";
4
+
5
+ const TAGS = ["div", "span", "ul", "ol", "li", "section", "nav", "header", "footer", "form"] as const;
6
+
7
+ describe("Stack", () => {
8
+ it("sem props continua um div vertical com gap xxxs", () => {
9
+ const { container } = render(<Stack>x</Stack>);
10
+ const el = container.firstElementChild as HTMLElement;
11
+ expect(el.tagName).toBe("DIV");
12
+ expect(el.className).toBe("umds-stack umds-stack--vertical umds-stack--gap-xxxs");
13
+ });
14
+
15
+ it("aceita gap none", () => {
16
+ const { container } = render(<Stack gap="none">x</Stack>);
17
+ expect(container.firstElementChild).toHaveClass("umds-stack--gap-none");
18
+ });
19
+
20
+ it.each(TAGS)("as=%s renderiza o elemento certo", (tag) => {
21
+ const { container } = render(<Stack as={tag}>x</Stack>);
22
+ expect(container.firstElementChild?.tagName.toLowerCase()).toBe(tag);
23
+ });
24
+
25
+ it("ul e ol mantêm a semântica de lista", () => {
26
+ const { container } = render(
27
+ <Stack as="ul" aria-label="Itens">
28
+ <Stack as="li">um</Stack>
29
+ </Stack>,
30
+ );
31
+ expect(screen.getByRole("list", { name: "Itens" })).toBeInTheDocument();
32
+ expect(container.querySelectorAll("li")).toHaveLength(1);
33
+ });
34
+
35
+ it("repassa id, aria-label, title e style ao elemento raiz", () => {
36
+ const { container } = render(
37
+ <Stack as="nav" id="menu" aria-label="Principal" title="Dica" style={{ marginTop: 4 }}>
38
+ x
39
+ </Stack>,
40
+ );
41
+ const el = container.firstElementChild as HTMLElement;
42
+ expect(el.id).toBe("menu");
43
+ expect(el.getAttribute("aria-label")).toBe("Principal");
44
+ expect(el.getAttribute("title")).toBe("Dica");
45
+ expect(el.style.marginTop).toBe("4px");
46
+ expect(screen.getByRole("navigation", { name: "Principal" })).toBe(el);
47
+ });
48
+
49
+ it("as=form chama onSubmit", () => {
50
+ const aoEnviar = vi.fn((e: Event) => e.preventDefault());
51
+ const { container } = render(
52
+ <Stack as="form" onSubmit={aoEnviar}>
53
+ <button type="submit">Enviar</button>
54
+ </Stack>,
55
+ );
56
+ fireEvent.submit(container.querySelector("form") as HTMLFormElement);
57
+ expect(aoEnviar).toHaveBeenCalledTimes(1);
58
+ });
59
+
60
+ it("escreve as classes de item flex", () => {
61
+ const { container } = render(
62
+ <Stack grow shrink="0" basis="50" minWidth="auto" overflow="hidden" overflowY="auto" fullHeight>
63
+ x
64
+ </Stack>,
65
+ );
66
+ const el = container.firstElementChild as HTMLElement;
67
+ for (const c of [
68
+ "umds-stack--grow",
69
+ "umds-stack--shrink-0",
70
+ "umds-stack--basis-50",
71
+ "umds-stack--min-w-auto",
72
+ "umds-stack--overflow-hidden",
73
+ "umds-stack--overflow-y-auto",
74
+ "umds-stack--full-height",
75
+ ]) {
76
+ expect(el).toHaveClass(c);
77
+ }
78
+ expect(el).not.toHaveClass("umds-stack--full-width");
79
+ });
80
+ });
@@ -0,0 +1,44 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { render, screen } from "@testing-library/react";
3
+ import StatCard from "../components/StatCard/StatCard";
4
+
5
+ const raiz = (c: HTMLElement) => c.firstElementChild as HTMLElement;
6
+
7
+ describe("StatCard · labelPosition", () => {
8
+ it("top escreve a classe; sem a prop o cartão é o de antes", () => {
9
+ const { container } = render(
10
+ <>
11
+ <StatCard value={44} label="Não lidos" labelPosition="top" />
12
+ <StatCard value={44} label="Não lidos" />
13
+ </>,
14
+ );
15
+ expect(container.children[0]).toHaveClass("umds-stat-card--rotulo-topo");
16
+ expect(container.children[1]).not.toHaveClass("umds-stat-card--rotulo-topo");
17
+ });
18
+
19
+ it("o número continua antes do rótulo no HTML (ordem do leitor de tela)", () => {
20
+ const { container } = render(<StatCard value={44} label="Não lidos" labelPosition="top" />);
21
+ const valor = container.querySelector(".umds-stat-card__valor") as HTMLElement;
22
+ const rotulo = container.querySelector(".umds-stat-card__rotulo") as HTMLElement;
23
+ expect(valor.compareDocumentPosition(rotulo) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
24
+ });
25
+ });
26
+
27
+ describe("StatCard · infoTooltip", () => {
28
+ it("mostra o ⓘ como botão nomeado, dentro do rótulo, descrito pelo texto de ajuda", () => {
29
+ const { container } = render(<StatCard value={44} label="Não lidos" infoTooltip="Ainda não abertos por você." />);
30
+ const info = screen.getByRole("button", { name: "Mais informações" });
31
+ expect(container.querySelector(".umds-stat-card__rotulo")?.contains(info)).toBe(true);
32
+ expect(info).toHaveAccessibleDescription("Ainda não abertos por você.");
33
+ });
34
+
35
+ it("infoLabel traduz o nome do ⓘ", () => {
36
+ render(<StatCard value={1} label="Unread" infoTooltip="Not opened yet." infoLabel="More info" />);
37
+ expect(screen.getByRole("button", { name: "More info" })).toBeInTheDocument();
38
+ });
39
+
40
+ it("sem infoTooltip não há botão", () => {
41
+ render(<StatCard value={1} label="x" />);
42
+ expect(screen.queryByRole("button")).toBeNull();
43
+ });
44
+ });
@@ -0,0 +1,51 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { render } from "@testing-library/react";
3
+ import StatCard from "../components/StatCard/StatCard";
4
+
5
+ describe("StatCard · segunda medida e valueTone", () => {
6
+ it("secondaryValue e secondaryLabel vêm depois do corpo, e o número principal segue antes do rótulo", () => {
7
+ const { container } = render(
8
+ <StatCard value="22,31%" label="Eficiência" description="Meu Setor" secondaryValue="14,11%" secondaryLabel="Geral" labelPosition="top" />,
9
+ );
10
+ const filhos = [...(container.firstElementChild as HTMLElement).children].map((e) => e.className);
11
+ expect(filhos[filhos.length - 1]).toBe("umds-stat-card__secundaria");
12
+ const secundaria = container.querySelector(".umds-stat-card__secundaria") as HTMLElement;
13
+ expect(secundaria.querySelector(".umds-stat-card__valor-secundario")).toHaveTextContent("14,11%");
14
+ expect(secundaria.querySelector(".umds-stat-card__rotulo-secundario")).toHaveTextContent("Geral");
15
+ expect(container.firstElementChild).toHaveClass("umds-stat-card--com-secundaria");
16
+ const texto = (container.firstElementChild as HTMLElement).textContent as string;
17
+ expect(texto.indexOf("22,31%")).toBeLessThan(texto.indexOf("Eficiência"));
18
+ expect(texto.indexOf("Eficiência")).toBeLessThan(texto.indexOf("14,11%"));
19
+ });
20
+
21
+ it("secondaryValue 0 aparece; vazio e ausente não", () => {
22
+ const { container, rerender } = render(<StatCard value="5" label="x" secondaryValue={0} />);
23
+ expect(container.querySelector(".umds-stat-card__valor-secundario")).toHaveTextContent("0");
24
+ rerender(<StatCard value="5" label="x" secondaryValue="" />);
25
+ expect(container.querySelector(".umds-stat-card__secundaria")).toBeNull();
26
+ rerender(<StatCard value="5" label="x" />);
27
+ expect(container.querySelector(".umds-stat-card__secundaria")).toBeNull();
28
+ expect(container.firstElementChild).not.toHaveClass("umds-stat-card--com-secundaria");
29
+ });
30
+
31
+ it("secondaryValue sem secondaryLabel não desenha o rótulo", () => {
32
+ const { container } = render(<StatCard value="5" label="x" secondaryValue="9" />);
33
+ expect(container.querySelector(".umds-stat-card__rotulo-secundario")).toBeNull();
34
+ });
35
+
36
+ it("valueTone escreve a classe do tom; default e ausente não", () => {
37
+ const { container, rerender } = render(<StatCard value="5" label="x" valueTone="negative" />);
38
+ expect(container.firstElementChild).toHaveClass("umds-stat-card--valor-negative");
39
+ rerender(<StatCard value="5" label="x" valueTone="primary" />);
40
+ expect(container.firstElementChild).toHaveClass("umds-stat-card--valor-primary");
41
+ rerender(<StatCard value="5" label="x" valueTone="default" />);
42
+ expect(container.firstElementChild!.className).not.toMatch(/valor-/);
43
+ rerender(<StatCard value="5" label="x" />);
44
+ expect(container.firstElementChild!.className).not.toMatch(/valor-/);
45
+ });
46
+
47
+ it("valueTone não mexe na variant do ícone", () => {
48
+ const { container } = render(<StatCard value="5" label="x" variant="positive" valueTone="negative" />);
49
+ expect(container.firstElementChild).toHaveClass("umds-stat-card--positive", "umds-stat-card--valor-negative");
50
+ });
51
+ });
@@ -0,0 +1,144 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+ import Tabs from "../components/Tabs/Tabs";
4
+ import Tab from "../components/Tabs/Tab";
5
+
6
+ describe("Tab · count", () => {
7
+ it("mostra o contador em pílula e ele entra no nome da aba", () => {
8
+ render(
9
+ <Tabs value="0" ariaLabel="Tarefas">
10
+ <Tab label="Todas" index="0" count={31} />
11
+ <Tab label="Atribuídas" index="1" count={9} />
12
+ </Tabs>,
13
+ );
14
+ expect(screen.getByRole("tab", { name: "Todas 31" })).toBeInTheDocument();
15
+ expect(screen.getByRole("tab", { name: "Atribuídas 9" })).toBeInTheDocument();
16
+ });
17
+
18
+ it("o 0 aparece; sem count, não há pílula", () => {
19
+ const { container } = render(
20
+ <Tabs value="0">
21
+ <Tab label="Concluídas" index="0" count={0} />
22
+ <Tab label="Sem contador" index="1" />
23
+ </Tabs>,
24
+ );
25
+ const pilulas = container.querySelectorAll(".umds-tabs__count");
26
+ expect(pilulas).toHaveLength(1);
27
+ expect(pilulas[0].textContent).toBe("0");
28
+ });
29
+
30
+ it("a pílula fica dentro da aba selecionada (que a pinta de azul pelo CSS)", () => {
31
+ const { container } = render(
32
+ <Tabs value="1">
33
+ <Tab label="A" index="0" count={1} />
34
+ <Tab label="B" index="1" count={2} />
35
+ </Tabs>,
36
+ );
37
+ const selecionada = container.querySelector(".umds-tabs__tab--selected");
38
+ expect(selecionada?.querySelector(".umds-tabs__count")?.textContent).toBe("2");
39
+ });
40
+ });
41
+
42
+ describe("Tab · closable", () => {
43
+ it("o × é um botão irmão da aba, com o nome 'Fechar <aba>'", () => {
44
+ render(
45
+ <Tabs value="0">
46
+ <Tab label="Documento 1" index="0" closable />
47
+ </Tabs>,
48
+ );
49
+ const fechar = screen.getByRole("button", { name: "Fechar Documento 1" });
50
+ const aba = screen.getByRole("tab");
51
+ expect(aba.contains(fechar)).toBe(false);
52
+ expect(fechar.parentElement).toBe(aba.parentElement);
53
+ });
54
+
55
+ it("o rótulo do × vem por prop", () => {
56
+ render(
57
+ <Tabs value="0">
58
+ <Tab label="Doc 1" index="0" closable closeLabel="Close" />
59
+ </Tabs>,
60
+ );
61
+ expect(screen.getByRole("button", { name: "Close Doc 1" })).toBeInTheDocument();
62
+ });
63
+
64
+ it("clicar no × chama onClose com o index e não troca de aba", () => {
65
+ const aoFechar = vi.fn();
66
+ const aoTrocar = vi.fn();
67
+ render(
68
+ <Tabs value="0" onChange={aoTrocar}>
69
+ <Tab label="Um" index="0" />
70
+ <Tab label="Dois" index="1" closable onClose={aoFechar} />
71
+ </Tabs>,
72
+ );
73
+ fireEvent.click(screen.getByRole("button", { name: "Fechar Dois" }));
74
+ expect(aoFechar).toHaveBeenCalledTimes(1);
75
+ expect(aoFechar.mock.calls[0][0]).toBe("1");
76
+ expect(aoTrocar).not.toHaveBeenCalled();
77
+ });
78
+
79
+ it("Delete na aba focada fecha; sem closable, não", () => {
80
+ const aoFechar = vi.fn();
81
+ render(
82
+ <Tabs value="0">
83
+ <Tab label="Fechável" index="0" closable onClose={aoFechar} />
84
+ <Tab label="Fixa" index="1" onClose={aoFechar} />
85
+ </Tabs>,
86
+ );
87
+ fireEvent.keyDown(screen.getByRole("tab", { name: "Fechável" }), { key: "Delete" });
88
+ expect(aoFechar).toHaveBeenCalledTimes(1);
89
+ fireEvent.keyDown(screen.getByRole("tab", { name: "Fixa" }), { key: "Delete" });
90
+ expect(aoFechar).toHaveBeenCalledTimes(1);
91
+ });
92
+
93
+ it("sem closable não há ×", () => {
94
+ render(
95
+ <Tabs value="0">
96
+ <Tab label="Fixa" index="0" />
97
+ </Tabs>,
98
+ );
99
+ expect(screen.queryByRole("button")).toBeNull();
100
+ });
101
+
102
+ it("o tablist só tem abas como filhas de papel (o × não é tab)", () => {
103
+ render(
104
+ <Tabs value="0">
105
+ <Tab label="A" index="0" closable />
106
+ <Tab label="B" index="1" closable />
107
+ </Tabs>,
108
+ );
109
+ expect(screen.getAllByRole("tab")).toHaveLength(2);
110
+ });
111
+ });
112
+
113
+ describe("Tabs · onAdd", () => {
114
+ it("mostra o + fora do tablist e chama onAdd", () => {
115
+ const aoAdicionar = vi.fn();
116
+ render(
117
+ <Tabs value="0" onAdd={aoAdicionar}>
118
+ <Tab label="A" index="0" />
119
+ </Tabs>,
120
+ );
121
+ const mais = screen.getByRole("button", { name: "Adicionar aba" });
122
+ expect(screen.getByRole("tablist").contains(mais)).toBe(false);
123
+ fireEvent.click(mais);
124
+ expect(aoAdicionar).toHaveBeenCalledTimes(1);
125
+ });
126
+
127
+ it("o rótulo do + vem por prop", () => {
128
+ render(
129
+ <Tabs value="0" onAdd={() => {}} addLabel="New tab">
130
+ <Tab label="A" index="0" />
131
+ </Tabs>,
132
+ );
133
+ expect(screen.getByRole("button", { name: "New tab" })).toBeInTheDocument();
134
+ });
135
+
136
+ it("sem onAdd não há botão", () => {
137
+ render(
138
+ <Tabs value="0">
139
+ <Tab label="A" index="0" />
140
+ </Tabs>,
141
+ );
142
+ expect(screen.queryByRole("button")).toBeNull();
143
+ });
144
+ });
@@ -0,0 +1,109 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { act, fireEvent, render, screen } from "@testing-library/react";
3
+ import Toast from "../components/Toast/Toast";
4
+ import ToastStack from "../components/Toast/ToastStack";
5
+ import { dismissAllToasts, toast } from "../utils/toast";
6
+
7
+ afterEach(() => {
8
+ act(() => dismissAllToasts());
9
+ });
10
+
11
+ describe("Toast · ação e detalhes", () => {
12
+ it("actionLabel com onAction desenha o botão; acionar chama onAction e fecha", () => {
13
+ const aoAgir = vi.fn();
14
+ const aoFechar = vi.fn();
15
+ render(<Toast open message="Despacho enviado" actionLabel="Desfazer" onAction={aoAgir} onClose={aoFechar} />);
16
+ fireEvent.click(screen.getByRole("button", { name: "Desfazer" }));
17
+ expect(aoAgir).toHaveBeenCalledTimes(1);
18
+ expect(aoFechar).toHaveBeenCalledTimes(1);
19
+ });
20
+
21
+ it("a ação roda antes de fechar", () => {
22
+ const ordem: string[] = [];
23
+ render(
24
+ <Toast
25
+ open
26
+ message="x"
27
+ actionLabel="Ver processo"
28
+ onAction={() => ordem.push("acao")}
29
+ onClose={() => ordem.push("fechar")}
30
+ />,
31
+ );
32
+ fireEvent.click(screen.getByRole("button", { name: "Ver processo" }));
33
+ expect(ordem).toEqual(["acao", "fechar"]);
34
+ });
35
+
36
+ it("actionLabel sem onAction, ou onAction sem actionLabel, não desenha botão de ação", () => {
37
+ const { rerender } = render(<Toast open message="x" actionLabel="Desfazer" />);
38
+ expect(screen.queryByRole("button", { name: "Desfazer" })).toBeNull();
39
+ rerender(<Toast open message="x" onAction={() => {}} />);
40
+ expect(document.querySelector(".umds-toast__action")).toBeNull();
41
+ });
42
+
43
+ it("details vira uma lista de linhas abaixo da descrição", () => {
44
+ render(<Toast open message="3 anexos não enviados" description="Corrija e envie de novo." details={["Anexo 1 acima de 10 MB", "Anexo 2 sem assunto"]} />);
45
+ const itens = screen.getAllByRole("listitem");
46
+ expect(itens.map((i) => i.textContent)).toEqual(["Anexo 1 acima de 10 MB", "Anexo 2 sem assunto"]);
47
+ });
48
+
49
+ it("sem details não há lista", () => {
50
+ render(<Toast open message="Salvo" />);
51
+ expect(document.querySelector(".umds-toast__details")).toBeNull();
52
+ });
53
+
54
+ it("o botão de fechar continua ao lado da ação", () => {
55
+ render(<Toast open message="x" actionLabel="Desfazer" onAction={() => {}} />);
56
+ expect(screen.getByRole("button", { name: "Fechar notificação" })).toBeInTheDocument();
57
+ });
58
+ });
59
+
60
+ describe("toast() imperativo com ação e detalhes", () => {
61
+ it("passa ação e detalhes ao ToastStack, e acionar a ação fecha o toast", () => {
62
+ const aoAgir = vi.fn();
63
+ render(<ToastStack />);
64
+ act(() => {
65
+ toast({ message: "Despacho enviado", details: ["SADM", "SOBR"], actionLabel: "Desfazer", onAction: aoAgir });
66
+ });
67
+ expect(screen.getByText("Despacho enviado")).toBeInTheDocument();
68
+ expect(screen.getAllByRole("listitem")).toHaveLength(2);
69
+ fireEvent.click(screen.getByRole("button", { name: "Desfazer" }));
70
+ expect(aoAgir).toHaveBeenCalledTimes(1);
71
+ expect(screen.queryByText("Despacho enviado")).toBeNull();
72
+ });
73
+
74
+ it("toast com ação não some sozinho (duration 0); sem ação continua em 5000", () => {
75
+ vi.useFakeTimers();
76
+ try {
77
+ render(<ToastStack />);
78
+ act(() => {
79
+ toast({ message: "Com ação", actionLabel: "Desfazer", onAction: () => {} });
80
+ toast({ message: "Sem ação" });
81
+ });
82
+ expect(screen.getByText("Com ação")).toBeInTheDocument();
83
+ expect(screen.getByText("Sem ação")).toBeInTheDocument();
84
+ act(() => {
85
+ vi.advanceTimersByTime(5100);
86
+ });
87
+ expect(screen.queryByText("Sem ação")).toBeNull();
88
+ expect(screen.getByText("Com ação")).toBeInTheDocument();
89
+ } finally {
90
+ vi.useRealTimers();
91
+ }
92
+ });
93
+
94
+ it("um duration explícito vale também com ação", () => {
95
+ vi.useFakeTimers();
96
+ try {
97
+ render(<ToastStack />);
98
+ act(() => {
99
+ toast({ message: "Curto", actionLabel: "Desfazer", onAction: () => {}, duration: 1000 });
100
+ });
101
+ act(() => {
102
+ vi.advanceTimersByTime(1100);
103
+ });
104
+ expect(screen.queryByText("Curto")).toBeNull();
105
+ } finally {
106
+ vi.useRealTimers();
107
+ }
108
+ });
109
+ });