@1doc/1ds-react 2.8.0 → 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 (213) hide show
  1. package/CHANGELOG.md +1106 -0
  2. package/dist/components/AILabel/AILabel.js +1 -1
  3. package/dist/components/Accordion/Accordion.d.ts +6 -2
  4. package/dist/components/AttachmentCard/AttachmentCard.css +16 -0
  5. package/dist/components/AttachmentCard/AttachmentCard.d.ts +19 -2
  6. package/dist/components/AttachmentCard/AttachmentCard.js +40 -3
  7. package/dist/components/Avatar/Avatar.css +7 -2
  8. package/dist/components/Avatar/AvatarGroup.d.ts +17 -0
  9. package/dist/components/Avatar/AvatarGroup.js +22 -8
  10. package/dist/components/Badge/Badge.css +54 -2
  11. package/dist/components/Badge/Badge.d.ts +14 -4
  12. package/dist/components/Badge/Badge.js +1 -0
  13. package/dist/components/Box/Box.css +83 -0
  14. package/dist/components/Box/Box.d.ts +82 -2
  15. package/dist/components/Box/Box.js +42 -2
  16. package/dist/components/Button/Button.css +29 -0
  17. package/dist/components/Button/Button.d.ts +4 -4
  18. package/dist/components/Button/Button.js +4 -1
  19. package/dist/components/Calendar/Calendar.css +245 -0
  20. package/dist/components/Calendar/Calendar.d.ts +125 -0
  21. package/dist/components/Calendar/Calendar.js +320 -0
  22. package/dist/components/Chips/Chips.css +38 -0
  23. package/dist/components/Chips/Chips.d.ts +5 -2
  24. package/dist/components/Chips/Chips.js +2 -1
  25. package/dist/components/Coachmark/Coachmark.css +118 -0
  26. package/dist/components/Coachmark/Coachmark.d.ts +75 -0
  27. package/dist/components/Coachmark/Coachmark.js +321 -0
  28. package/dist/components/CodeBlock/CodeBlock.css +96 -0
  29. package/dist/components/CodeBlock/CodeBlock.d.ts +47 -0
  30. package/dist/components/CodeBlock/CodeBlock.js +103 -0
  31. package/dist/components/ColorPicker/ColorPicker.css +133 -0
  32. package/dist/components/ColorPicker/ColorPicker.d.ts +73 -0
  33. package/dist/components/ColorPicker/ColorPicker.js +219 -0
  34. package/dist/components/Combobox/Combobox.css +8 -0
  35. package/dist/components/DataTable/DataTable.css +80 -0
  36. package/dist/components/DataTable/DataTable.d.ts +19 -4
  37. package/dist/components/DataTable/DataTable.js +59 -15
  38. package/dist/components/DatePicker/DatePicker.css +8 -0
  39. package/dist/components/DatePicker/DatePicker.js +10 -1
  40. package/dist/components/DescriptionList/DescriptionList.css +113 -0
  41. package/dist/components/DescriptionList/DescriptionList.d.ts +59 -0
  42. package/dist/components/DescriptionList/DescriptionList.js +51 -0
  43. package/dist/components/FileInput/FileInput.css +16 -0
  44. package/dist/components/FileInput/FileInput.d.ts +4 -2
  45. package/dist/components/FileInput/FileInput.js +8 -2
  46. package/dist/components/Grid/Grid.js +5 -5
  47. package/dist/components/IconPicker/IconPicker.css +107 -0
  48. package/dist/components/IconPicker/IconPicker.d.ts +74 -0
  49. package/dist/components/IconPicker/IconPicker.js +194 -0
  50. package/dist/components/Input/Input.css +38 -0
  51. package/dist/components/Input/Input.d.ts +10 -1
  52. package/dist/components/Input/Input.js +66 -5
  53. package/dist/components/Kanban/Kanban.css +4 -0
  54. package/dist/components/Kbd/Kbd.css +66 -0
  55. package/dist/components/Kbd/Kbd.d.ts +32 -0
  56. package/dist/components/Kbd/Kbd.js +40 -0
  57. package/dist/components/List/List.css +136 -0
  58. package/dist/components/List/List.d.ts +82 -0
  59. package/dist/components/List/List.js +53 -0
  60. package/dist/components/List/ListItem.d.ts +85 -0
  61. package/dist/components/List/ListItem.js +81 -0
  62. package/dist/components/Modal/Modal.css +80 -0
  63. package/dist/components/Modal/Modal.d.ts +33 -6
  64. package/dist/components/Modal/Modal.js +101 -6
  65. package/dist/components/MultiSelect/MultiSelect.css +8 -0
  66. package/dist/components/MultiSelect/MultiSelect.js +10 -1
  67. package/dist/components/OrgChart/OrgChart.css +149 -0
  68. package/dist/components/OrgChart/OrgChart.d.ts +83 -0
  69. package/dist/components/OrgChart/OrgChart.js +297 -0
  70. package/dist/components/OtpInput/OtpInput.css +93 -0
  71. package/dist/components/OtpInput/OtpInput.d.ts +60 -0
  72. package/dist/components/OtpInput/OtpInput.js +215 -0
  73. package/dist/components/PhoneInput/PhoneInput.css +8 -0
  74. package/dist/components/Popover/Popover.d.ts +7 -0
  75. package/dist/components/Popover/Popover.js +11 -1
  76. package/dist/components/RichTextEditor/RichTextEditor.css +203 -0
  77. package/dist/components/RichTextEditor/RichTextEditor.d.ts +83 -0
  78. package/dist/components/RichTextEditor/RichTextEditor.js +494 -0
  79. package/dist/components/SegmentedControl/SegmentedControl.js +7 -2
  80. package/dist/components/Select/Select.css +70 -0
  81. package/dist/components/Select/Select.d.ts +12 -0
  82. package/dist/components/Select/Select.js +59 -4
  83. package/dist/components/Stack/Stack.css +49 -0
  84. package/dist/components/Stack/Stack.d.ts +65 -7
  85. package/dist/components/Stack/Stack.js +30 -2
  86. package/dist/components/StatCard/StatCard.css +73 -0
  87. package/dist/components/StatCard/StatCard.d.ts +17 -0
  88. package/dist/components/StatCard/StatCard.js +4 -1
  89. package/dist/components/Tabs/Tab.d.ts +15 -0
  90. package/dist/components/Tabs/Tab.js +30 -1
  91. package/dist/components/Tabs/Tabs.css +132 -0
  92. package/dist/components/Tabs/Tabs.d.ts +7 -0
  93. package/dist/components/Tabs/Tabs.js +13 -2
  94. package/dist/components/Tag/Tag.css +85 -2
  95. package/dist/components/Tag/Tag.d.ts +13 -6
  96. package/dist/components/Tag/Tag.js +1 -0
  97. package/dist/components/Text/Text.js +2 -2
  98. package/dist/components/Textarea/Textarea.css +8 -0
  99. package/dist/components/TimePicker/TimePicker.css +8 -0
  100. package/dist/components/Tooltip/Tooltip.css +25 -0
  101. package/dist/components/Tooltip/Tooltip.d.ts +11 -0
  102. package/dist/components/Tooltip/Tooltip.js +18 -3
  103. package/dist/index.d.ts +25 -0
  104. package/dist/index.js +14 -0
  105. package/dist/teste/AILabel.test.d.ts +1 -0
  106. package/dist/teste/AILabel.test.js +33 -0
  107. package/dist/teste/AccordionConteudoLivre.test.d.ts +1 -0
  108. package/dist/teste/AccordionConteudoLivre.test.js +29 -0
  109. package/dist/teste/AtributosRepassados.test.d.ts +1 -0
  110. package/dist/teste/AtributosRepassados.test.js +52 -0
  111. package/dist/teste/AttachmentCardIA.test.d.ts +1 -0
  112. package/dist/teste/AttachmentCardIA.test.js +89 -0
  113. package/dist/teste/AvatarGroupOverlap.test.d.ts +1 -0
  114. package/dist/teste/AvatarGroupOverlap.test.js +56 -0
  115. package/dist/teste/BadgeTag.test.d.ts +1 -0
  116. package/dist/teste/BadgeTag.test.js +42 -0
  117. package/dist/teste/BoxItemFlex.test.d.ts +1 -0
  118. package/dist/teste/BoxItemFlex.test.js +54 -0
  119. package/dist/teste/BoxLayout.test.d.ts +1 -0
  120. package/dist/teste/BoxLayout.test.js +35 -0
  121. package/dist/teste/Button.test.d.ts +1 -0
  122. package/dist/teste/Button.test.js +27 -0
  123. package/dist/teste/Calendar.test.d.ts +1 -0
  124. package/dist/teste/Calendar.test.js +221 -0
  125. package/dist/teste/ChipsXs.test.d.ts +1 -0
  126. package/dist/teste/ChipsXs.test.js +31 -0
  127. package/dist/teste/Coachmark.test.d.ts +1 -0
  128. package/dist/teste/Coachmark.test.js +149 -0
  129. package/dist/teste/ColorPicker.test.d.ts +1 -0
  130. package/dist/teste/ColorPicker.test.js +132 -0
  131. package/dist/teste/DataTableCelulaLivre.test.d.ts +1 -0
  132. package/dist/teste/DataTableCelulaLivre.test.js +76 -0
  133. package/dist/teste/DataTableDocumento.test.d.ts +1 -0
  134. package/dist/teste/DataTableDocumento.test.js +92 -0
  135. package/dist/teste/DatePicker.test.js +23 -0
  136. package/dist/teste/FileInputTrigger.test.d.ts +1 -0
  137. package/dist/teste/FileInputTrigger.test.js +53 -0
  138. package/dist/teste/IconPicker.test.d.ts +1 -0
  139. package/dist/teste/IconPicker.test.js +130 -0
  140. package/dist/teste/InputMascaraEAfins.test.d.ts +1 -0
  141. package/dist/teste/InputMascaraEAfins.test.js +99 -0
  142. package/dist/teste/KbdCodeBlock.test.d.ts +1 -0
  143. package/dist/teste/KbdCodeBlock.test.js +95 -0
  144. package/dist/teste/List.test.d.ts +1 -0
  145. package/dist/teste/List.test.js +153 -0
  146. package/dist/teste/ModalVariantes.test.d.ts +1 -0
  147. package/dist/teste/ModalVariantes.test.js +151 -0
  148. package/dist/teste/NomeAcessivelSsr.test.d.ts +1 -0
  149. package/dist/teste/NomeAcessivelSsr.test.js +88 -0
  150. package/dist/teste/OrgChart.test.d.ts +1 -0
  151. package/dist/teste/OrgChart.test.js +162 -0
  152. package/dist/teste/OtpInput.test.d.ts +1 -0
  153. package/dist/teste/OtpInput.test.js +143 -0
  154. package/dist/teste/PopoverMaxHeight.test.d.ts +1 -0
  155. package/dist/teste/PopoverMaxHeight.test.js +38 -0
  156. package/dist/teste/RichTextEditor.test.d.ts +1 -0
  157. package/dist/teste/RichTextEditor.test.js +287 -0
  158. package/dist/teste/SelectPlacementFiltro.test.d.ts +1 -0
  159. package/dist/teste/SelectPlacementFiltro.test.js +88 -0
  160. package/dist/teste/Stack.test.d.ts +1 -0
  161. package/dist/teste/Stack.test.js +57 -0
  162. package/dist/teste/StatCardRotuloTopo.test.d.ts +1 -0
  163. package/dist/teste/StatCardRotuloTopo.test.js +34 -0
  164. package/dist/teste/TabsContadorFechavel.test.d.ts +1 -0
  165. package/dist/teste/TabsContadorFechavel.test.js +79 -0
  166. package/dist/teste/TooltipDark.test.d.ts +1 -0
  167. package/dist/teste/TooltipDark.test.js +31 -0
  168. package/dist/utils/calendario.d.ts +28 -0
  169. package/dist/utils/calendario.js +73 -0
  170. package/dist/utils/html-seguro.d.ts +27 -0
  171. package/dist/utils/html-seguro.js +97 -0
  172. package/dist/utils/paleta-de-cores.d.ts +26 -0
  173. package/dist/utils/paleta-de-cores.js +10 -0
  174. package/dist/utils/texto.d.ts +5 -0
  175. package/dist/utils/texto.js +5 -0
  176. package/package.json +3 -3
  177. package/src/index.ts +26 -0
  178. package/src/teste/AILabel.test.tsx +41 -0
  179. package/src/teste/AccordionConteudoLivre.test.tsx +39 -0
  180. package/src/teste/AtributosRepassados.test.tsx +73 -0
  181. package/src/teste/AttachmentCardIA.test.tsx +126 -0
  182. package/src/teste/AvatarGroupOverlap.test.tsx +74 -0
  183. package/src/teste/BadgeTag.test.tsx +64 -0
  184. package/src/teste/BoxItemFlex.test.tsx +81 -0
  185. package/src/teste/BoxLayout.test.tsx +50 -0
  186. package/src/teste/Button.test.tsx +39 -0
  187. package/src/teste/Calendar.test.tsx +282 -0
  188. package/src/teste/ChipsXs.test.tsx +41 -0
  189. package/src/teste/Coachmark.test.tsx +198 -0
  190. package/src/teste/ColorPicker.test.tsx +153 -0
  191. package/src/teste/DataTableCelulaLivre.test.tsx +103 -0
  192. package/src/teste/DataTableDocumento.test.tsx +102 -0
  193. package/src/teste/DatePicker.test.tsx +38 -0
  194. package/src/teste/FileInputTrigger.test.tsx +89 -0
  195. package/src/teste/IconPicker.test.tsx +145 -0
  196. package/src/teste/InputMascaraEAfins.test.tsx +124 -0
  197. package/src/teste/KbdCodeBlock.test.tsx +106 -0
  198. package/src/teste/List.test.tsx +269 -0
  199. package/src/teste/ModalVariantes.test.tsx +173 -0
  200. package/src/teste/NomeAcessivelSsr.test.tsx +110 -0
  201. package/src/teste/OrgChart.test.tsx +183 -0
  202. package/src/teste/OtpInput.test.tsx +163 -0
  203. package/src/teste/PopoverMaxHeight.test.tsx +47 -0
  204. package/src/teste/RichTextEditor.test.tsx +329 -0
  205. package/src/teste/SelectPlacementFiltro.test.tsx +110 -0
  206. package/src/teste/Stack.test.tsx +80 -0
  207. package/src/teste/StatCardRotuloTopo.test.tsx +44 -0
  208. package/src/teste/TabsContadorFechavel.test.tsx +144 -0
  209. package/src/teste/TooltipDark.test.tsx +51 -0
  210. package/src/utils/calendario.ts +78 -0
  211. package/src/utils/html-seguro.ts +94 -0
  212. package/src/utils/paleta-de-cores.ts +34 -0
  213. package/src/utils/texto.ts +5 -0
@@ -0,0 +1,183 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { useState } from "react";
3
+ import { fireEvent, render, screen, within } from "@testing-library/react";
4
+ import userEvent from "@testing-library/user-event";
5
+ import OrgChart from "../components/OrgChart/OrgChart";
6
+
7
+ const ARVORE = [
8
+ {
9
+ id: "copirn",
10
+ title: "COPIRN",
11
+ subtitle: "Companhia Potiguar de Infraestrutura",
12
+ children: [
13
+ { id: "aj", title: "AJ", subtitle: "Assessoria Jurídica" },
14
+ {
15
+ id: "sadm",
16
+ title: "SADM",
17
+ subtitle: "Secretaria de Administração",
18
+ children: [
19
+ { id: "al", title: "AL", subtitle: "Almoxarifado" },
20
+ { id: "ssa", title: "SSA", subtitle: "Subsetor do Almoxarifado" },
21
+ ],
22
+ },
23
+ { id: "sfin", title: "SFIN", subtitle: "Secretaria de Finanças" },
24
+ ],
25
+ },
26
+ ];
27
+
28
+ const item = (id: string) => document.querySelector(`[data-node-id="${id}"]`) as HTMLElement;
29
+ const esquerda = (id: string) => parseFloat(item(id).style.left);
30
+
31
+ describe("OrgChart", () => {
32
+ it("é uma tree nomeada, com um treeitem por nó visível e níveis ARIA", () => {
33
+ render(<OrgChart nodes={ARVORE} ariaLabel="Setores" />);
34
+ expect(screen.getByRole("tree", { name: "Setores" })).toBeInTheDocument();
35
+ expect(screen.getAllByRole("treeitem")).toHaveLength(6);
36
+ expect(item("copirn")).toHaveAttribute("aria-level", "1");
37
+ expect(item("al")).toHaveAttribute("aria-level", "3");
38
+ expect(item("sadm")).toHaveAttribute("aria-posinset", "2");
39
+ expect(item("sadm")).toHaveAttribute("aria-setsize", "3");
40
+ expect(item("sadm")).toHaveAttribute("aria-expanded", "true");
41
+ expect(item("aj")).not.toHaveAttribute("aria-expanded");
42
+ });
43
+
44
+ it("o nome padrão é Organograma; título e subtítulo aparecem", () => {
45
+ render(<OrgChart nodes={ARVORE} />);
46
+ expect(screen.getByRole("tree", { name: "Organograma" })).toBeInTheDocument();
47
+ expect(within(item("aj")).getByText("AJ")).toBeInTheDocument();
48
+ expect(within(item("aj")).getByText("Assessoria Jurídica")).toBeInTheDocument();
49
+ });
50
+
51
+ it("o pai se centra sobre os filhos e os irmãos andam lado a lado", () => {
52
+ render(<OrgChart nodes={ARVORE} nodeWidth={100} gapX={20} />);
53
+ expect(esquerda("aj")).toBe(0);
54
+ expect(esquerda("al")).toBe(120);
55
+ expect(esquerda("ssa")).toBe(240);
56
+ expect(esquerda("sadm")).toBe(180);
57
+ expect(esquerda("sfin")).toBe(360);
58
+ expect(esquerda("copirn")).toBe((0 + 360) / 2);
59
+ expect(parseFloat(item("sadm").style.top)).toBeGreaterThan(parseFloat(item("copirn").style.top));
60
+ });
61
+
62
+ it("desenha um conector por pai expandido", () => {
63
+ const { container } = render(<OrgChart nodes={ARVORE} />);
64
+ expect(container.querySelectorAll(".umds-org-chart__line")).toHaveLength(2);
65
+ });
66
+
67
+ it("a raiz é cheia e o nó marcado leva aria-selected", () => {
68
+ render(<OrgChart nodes={ARVORE} selectedId="aj" />);
69
+ expect(item("copirn")).toHaveClass("umds-org-chart__node--root");
70
+ expect(item("aj")).toHaveAttribute("aria-selected", "true");
71
+ expect(item("sfin")).not.toHaveAttribute("aria-selected");
72
+ });
73
+
74
+ it("recolher esconde os filhos e avisa; expandir volta", async () => {
75
+ const usuario = userEvent.setup();
76
+ const aoMudar = vi.fn();
77
+ render(<OrgChart nodes={ARVORE} onCollapsedChange={aoMudar} />);
78
+ item("sadm").focus();
79
+ await usuario.keyboard(" ");
80
+ expect(aoMudar).toHaveBeenLastCalledWith(["sadm"]);
81
+ expect(screen.getAllByRole("treeitem")).toHaveLength(4);
82
+ expect(item("sadm")).toHaveAttribute("aria-expanded", "false");
83
+ await usuario.keyboard(" ");
84
+ expect(aoMudar).toHaveBeenLastCalledWith([]);
85
+ expect(screen.getAllByRole("treeitem")).toHaveLength(6);
86
+ });
87
+
88
+ it("o botão de expandir do mouse faz o mesmo e não aciona o nó", async () => {
89
+ const usuario = userEvent.setup();
90
+ const aoClicar = vi.fn();
91
+ const { container } = render(<OrgChart nodes={ARVORE} onNodeClick={aoClicar} />);
92
+ const botoes = container.querySelectorAll(".umds-org-chart__toggle");
93
+ expect(botoes).toHaveLength(2);
94
+ await usuario.click(botoes[1] as HTMLElement);
95
+ expect(screen.getAllByRole("treeitem")).toHaveLength(4);
96
+ expect(aoClicar).not.toHaveBeenCalled();
97
+ });
98
+
99
+ it("defaultCollapsedIds começa recolhido; collapsedIds controla", () => {
100
+ const { rerender } = render(<OrgChart nodes={ARVORE} defaultCollapsedIds={["sadm"]} />);
101
+ expect(screen.getAllByRole("treeitem")).toHaveLength(4);
102
+ rerender(<OrgChart nodes={ARVORE} collapsedIds={["copirn"]} />);
103
+ expect(screen.getAllByRole("treeitem")).toHaveLength(1);
104
+ });
105
+
106
+ it("clicar e Enter acionam o nó com o nó", async () => {
107
+ const usuario = userEvent.setup();
108
+ const aoClicar = vi.fn();
109
+ render(<OrgChart nodes={ARVORE} onNodeClick={aoClicar} />);
110
+ await usuario.click(item("aj"));
111
+ expect(aoClicar).toHaveBeenLastCalledWith(expect.objectContaining({ id: "aj" }));
112
+ item("sfin").focus();
113
+ await usuario.keyboard("{Enter}");
114
+ expect(aoClicar).toHaveBeenLastCalledWith(expect.objectContaining({ id: "sfin" }));
115
+ });
116
+
117
+ it("só um nó entra na ordem de Tab (o primeiro)", () => {
118
+ render(<OrgChart nodes={ARVORE} />);
119
+ const comTab = screen.getAllByRole("treeitem").filter((n) => n.getAttribute("tabindex") === "0");
120
+ expect(comTab).toHaveLength(1);
121
+ expect(comTab[0]).toHaveAttribute("data-node-id", "copirn");
122
+ });
123
+
124
+ it("setas: baixo desce ao primeiro filho, cima sobe ao pai, lados andam entre irmãos, Home e End", async () => {
125
+ const usuario = userEvent.setup();
126
+ render(<OrgChart nodes={ARVORE} />);
127
+ item("copirn").focus();
128
+ await usuario.keyboard("{ArrowDown}");
129
+ expect(item("aj")).toHaveFocus();
130
+ await usuario.keyboard("{ArrowRight}");
131
+ expect(item("sadm")).toHaveFocus();
132
+ await usuario.keyboard("{ArrowDown}");
133
+ expect(item("al")).toHaveFocus();
134
+ await usuario.keyboard("{ArrowRight}");
135
+ expect(item("ssa")).toHaveFocus();
136
+ await usuario.keyboard("{Home}");
137
+ expect(item("al")).toHaveFocus();
138
+ await usuario.keyboard("{ArrowUp}");
139
+ expect(item("sadm")).toHaveFocus();
140
+ await usuario.keyboard("{End}");
141
+ expect(item("sfin")).toHaveFocus();
142
+ await usuario.keyboard("{ArrowLeft}{ArrowLeft}");
143
+ expect(item("aj")).toHaveFocus();
144
+ });
145
+
146
+ it("baixo num nó recolhido abre; o foco desce no seguinte", async () => {
147
+ const usuario = userEvent.setup();
148
+ render(<OrgChart nodes={ARVORE} defaultCollapsedIds={["sadm"]} />);
149
+ item("sadm").focus();
150
+ await usuario.keyboard("{ArrowDown}");
151
+ expect(item("sadm")).toHaveAttribute("aria-expanded", "true");
152
+ await usuario.keyboard("{ArrowDown}");
153
+ expect(item("al")).toHaveFocus();
154
+ });
155
+
156
+ it("renderNode troca o conteúdo do nó", () => {
157
+ render(<OrgChart nodes={ARVORE} renderNode={(no, meta) => <b data-testid={"c-" + no.id}>{no.title + ":" + meta.level}</b>} />);
158
+ expect(screen.getByTestId("c-ssa")).toHaveTextContent("SSA:2");
159
+ expect(item("ssa").querySelector(".umds-org-chart__title")).toBeNull();
160
+ });
161
+
162
+ it("textos do botão por prop; sem nós, não desenha a árvore", () => {
163
+ const { container, rerender } = render(<OrgChart nodes={ARVORE} expandLabel="Expand" collapseLabel="Collapse" />);
164
+ expect(container.querySelector(".umds-org-chart__toggle")).toHaveAttribute("title", "Collapse");
165
+ rerender(<OrgChart nodes={[]} />);
166
+ expect(screen.queryByRole("tree")).toBeNull();
167
+ });
168
+
169
+ it("controlado por pai", () => {
170
+ function Pai() {
171
+ const [fechados, setFechados] = useState<string[]>([]);
172
+ return (
173
+ <>
174
+ <OrgChart nodes={ARVORE} collapsedIds={fechados} onCollapsedChange={setFechados} />
175
+ <button onClick={() => setFechados(["sadm"])}>fechar</button>
176
+ </>
177
+ );
178
+ }
179
+ render(<Pai />);
180
+ fireEvent.click(screen.getByText("fechar"));
181
+ expect(screen.getAllByRole("treeitem")).toHaveLength(4);
182
+ });
183
+ });
@@ -0,0 +1,163 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { useState } from "react";
3
+ import { render, screen } from "@testing-library/react";
4
+ import userEvent from "@testing-library/user-event";
5
+ import OtpInput from "../components/OtpInput/OtpInput";
6
+
7
+ const caixas = () => screen.getAllByRole("textbox") as HTMLInputElement[];
8
+
9
+ describe("OtpInput", () => {
10
+ it("tem 6 caixas por padrão, cada uma com nome próprio, num grupo nomeado", () => {
11
+ render(<OtpInput ariaLabel="Código de verificação" />);
12
+ expect(screen.getByRole("group", { name: "Código de verificação" })).toBeInTheDocument();
13
+ expect(caixas()).toHaveLength(6);
14
+ expect(screen.getByRole("textbox", { name: "Dígito 3 de 6" })).toBeInTheDocument();
15
+ });
16
+
17
+ it("length muda a quantidade e digitLabel traduz o nome", () => {
18
+ render(<OtpInput ariaLabel="Code" length={4} digitLabel="Digit {n} of {total}" />);
19
+ expect(caixas()).toHaveLength(4);
20
+ expect(screen.getByRole("textbox", { name: "Digit 2 of 4" })).toBeInTheDocument();
21
+ });
22
+
23
+ it("a primeira caixa leva autocomplete one-time-code e teclado numérico", () => {
24
+ render(<OtpInput ariaLabel="Código" />);
25
+ expect(caixas()[0]).toHaveAttribute("autocomplete", "one-time-code");
26
+ expect(caixas()[1]).toHaveAttribute("autocomplete", "off");
27
+ expect(caixas()[0]).toHaveAttribute("inputmode", "numeric");
28
+ });
29
+
30
+ it("digitar avança o foco e entrega o código em onChange", async () => {
31
+ const usuario = userEvent.setup();
32
+ const aoMudar = vi.fn();
33
+ render(<OtpInput ariaLabel="Código" onChange={aoMudar} />);
34
+ caixas()[0].focus();
35
+ await usuario.keyboard("482");
36
+ expect(aoMudar).toHaveBeenLastCalledWith("482");
37
+ expect(caixas().map((c) => c.value).join("")).toBe("482");
38
+ expect(caixas()[3]).toHaveFocus();
39
+ });
40
+
41
+ it("rejeita o que não é dígito (numeric)", async () => {
42
+ const usuario = userEvent.setup();
43
+ const aoMudar = vi.fn();
44
+ render(<OtpInput ariaLabel="Código" onChange={aoMudar} />);
45
+ caixas()[0].focus();
46
+ await usuario.keyboard("a-b");
47
+ expect(aoMudar).not.toHaveBeenCalled();
48
+ expect(caixas()[0].value).toBe("");
49
+ expect(caixas()[0]).toHaveFocus();
50
+ });
51
+
52
+ it("alphanumeric aceita letras e sai em maiúsculas", async () => {
53
+ const usuario = userEvent.setup();
54
+ const aoMudar = vi.fn();
55
+ render(<OtpInput ariaLabel="Código" type="alphanumeric" length={4} onChange={aoMudar} />);
56
+ caixas()[0].focus();
57
+ await usuario.keyboard("a9z");
58
+ expect(aoMudar).toHaveBeenLastCalledWith("A9Z");
59
+ expect(caixas()[0]).toHaveAttribute("inputmode", "text");
60
+ });
61
+
62
+ it("colar o código inteiro em qualquer caixa distribui e chama onComplete uma vez", async () => {
63
+ const usuario = userEvent.setup();
64
+ const aoCompletar = vi.fn();
65
+ render(<OtpInput ariaLabel="Código" onComplete={aoCompletar} />);
66
+ caixas()[2].focus();
67
+ await usuario.paste("482 913");
68
+ expect(caixas().map((c) => c.value).join("")).toBe("482913");
69
+ expect(aoCompletar).toHaveBeenCalledTimes(1);
70
+ expect(aoCompletar).toHaveBeenCalledWith("482913");
71
+ expect(caixas()[5]).toHaveFocus();
72
+ });
73
+
74
+ it("colar um pedaço entra a partir da caixa atual", async () => {
75
+ const usuario = userEvent.setup();
76
+ render(<OtpInput ariaLabel="Código" defaultValue="12" />);
77
+ caixas()[2].focus();
78
+ await usuario.paste("345");
79
+ expect(caixas().map((c) => c.value).join("")).toBe("12345");
80
+ });
81
+
82
+ it("onComplete só dispara quando as caixas enchem", async () => {
83
+ const usuario = userEvent.setup();
84
+ const aoCompletar = vi.fn();
85
+ render(<OtpInput ariaLabel="Código" length={3} onComplete={aoCompletar} />);
86
+ caixas()[0].focus();
87
+ await usuario.keyboard("12");
88
+ expect(aoCompletar).not.toHaveBeenCalled();
89
+ await usuario.keyboard("3");
90
+ expect(aoCompletar).toHaveBeenCalledWith("123");
91
+ });
92
+
93
+ it("Backspace apaga o caractere e, em caixa vazia, volta e apaga o anterior", async () => {
94
+ const usuario = userEvent.setup();
95
+ const aoMudar = vi.fn();
96
+ render(<OtpInput ariaLabel="Código" defaultValue="123" onChange={aoMudar} />);
97
+ caixas()[3].focus();
98
+ await usuario.keyboard("{Backspace}");
99
+ expect(aoMudar).toHaveBeenLastCalledWith("12");
100
+ expect(caixas()[2]).toHaveFocus();
101
+ await usuario.keyboard("{Backspace}");
102
+ expect(aoMudar).toHaveBeenLastCalledWith("1");
103
+ });
104
+
105
+ it("setas, Home e End movem o foco", async () => {
106
+ const usuario = userEvent.setup();
107
+ render(<OtpInput ariaLabel="Código" defaultValue="1234" />);
108
+ caixas()[4].focus();
109
+ await usuario.keyboard("{ArrowLeft}");
110
+ expect(caixas()[3]).toHaveFocus();
111
+ await usuario.keyboard("{Home}");
112
+ expect(caixas()[0]).toHaveFocus();
113
+ await usuario.keyboard("{ArrowRight}");
114
+ expect(caixas()[1]).toHaveFocus();
115
+ await usuario.keyboard("{End}");
116
+ expect(caixas()[4]).toHaveFocus();
117
+ });
118
+
119
+ it("focar uma caixa à frente da primeira vazia volta para ela (sem buraco)", async () => {
120
+ const usuario = userEvent.setup();
121
+ render(<OtpInput ariaLabel="Código" defaultValue="12" />);
122
+ await usuario.click(caixas()[5]);
123
+ expect(caixas()[2]).toHaveFocus();
124
+ });
125
+
126
+ it("controlado: reflete o value e escreve no pai", async () => {
127
+ const usuario = userEvent.setup();
128
+ function Pai() {
129
+ const [codigo, setCodigo] = useState("");
130
+ return (
131
+ <>
132
+ <OtpInput ariaLabel="Código" value={codigo} onChange={setCodigo} />
133
+ <output data-testid="codigo">{codigo}</output>
134
+ </>
135
+ );
136
+ }
137
+ render(<Pai />);
138
+ caixas()[0].focus();
139
+ await usuario.keyboard("90");
140
+ expect(screen.getByTestId("codigo")).toHaveTextContent("90");
141
+ expect(caixas()[1].value).toBe("0");
142
+ });
143
+
144
+ it("errorMessage liga o estado de erro e descreve as caixas", () => {
145
+ render(<OtpInput ariaLabel="Código" errorMessage="Código inválido" id="otp" />);
146
+ expect(screen.getByText("Código inválido")).toBeInTheDocument();
147
+ for (const c of caixas()) {
148
+ expect(c).toHaveAttribute("aria-invalid", "true");
149
+ expect(c).toHaveAttribute("aria-describedby", "otp-error");
150
+ }
151
+ });
152
+
153
+ it("disabled desabilita todas as caixas; label visível nomeia o grupo", () => {
154
+ render(<OtpInput label="Código do app" disabled id="o" />);
155
+ for (const c of caixas()) expect(c).toBeDisabled();
156
+ expect(screen.getByRole("group", { name: "Código do app" })).toBeInTheDocument();
157
+ });
158
+
159
+ it("autoFocus foca a primeira caixa vazia", () => {
160
+ render(<OtpInput ariaLabel="Código" autoFocus defaultValue="12" />);
161
+ expect(caixas()[2]).toHaveFocus();
162
+ });
163
+ });
@@ -0,0 +1,47 @@
1
+ import { beforeAll, describe, expect, it } from "vitest";
2
+ import { render, screen } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+ import Popover from "../components/Popover/Popover";
5
+ import Button from "../components/Button/Button";
6
+
7
+ beforeAll(() => {
8
+ if (!(globalThis as any).ResizeObserver) {
9
+ (globalThis as any).ResizeObserver = class {
10
+ observe() {}
11
+ unobserve() {}
12
+ disconnect() {}
13
+ };
14
+ }
15
+ });
16
+
17
+ async function abrirCom(maxHeight?: number | string) {
18
+ const usuario = userEvent.setup();
19
+ render(
20
+ <Popover title="Colunas" maxHeight={maxHeight} content={<p>Corpo do painel</p>}>
21
+ <Button variant="secondary">Abrir</Button>
22
+ </Popover>,
23
+ );
24
+ await usuario.click(screen.getByRole("button", { name: "Abrir" }));
25
+ const corpo = document.querySelector(".umds-popover__body") as HTMLElement;
26
+ expect(corpo).not.toBeNull();
27
+ return corpo;
28
+ }
29
+
30
+ describe("Popover · maxHeight", () => {
31
+ it("sem a prop não escreve style no corpo (o teto de 300px do CSS segue valendo)", async () => {
32
+ const corpo = await abrirCom();
33
+ expect(corpo.getAttribute("style")).toBeNull();
34
+ });
35
+
36
+ it("número vira px", async () => {
37
+ expect((await abrirCom(180)).style.maxHeight).toBe("180px");
38
+ });
39
+
40
+ it("texto vai como CSS", async () => {
41
+ expect((await abrirCom("60vh")).style.maxHeight).toBe("60vh");
42
+ });
43
+
44
+ it("none deixa o corpo crescer", async () => {
45
+ expect((await abrirCom("none")).style.maxHeight).toBe("none");
46
+ });
47
+ });