@1doc/1ds-react 2.9.0 → 2.11.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.
- package/CHANGELOG.md +653 -0
- package/dist/components/Accordion/Accordion.css +13 -0
- package/dist/components/Accordion/Accordion.d.ts +9 -0
- package/dist/components/Accordion/Accordion.js +18 -5
- package/dist/components/AppSubheader/AppSubheader.css +10 -1
- package/dist/components/AttachmentCard/AttachmentCard.css +10 -8
- package/dist/components/AttachmentCard/AttachmentCard.d.ts +3 -0
- package/dist/components/AttachmentCard/AttachmentCard.js +8 -1
- package/dist/components/Badge/Badge.css +27 -5
- package/dist/components/Badge/Badge.d.ts +20 -4
- package/dist/components/Badge/Badge.js +6 -0
- package/dist/components/Button/Button.css +5 -0
- package/dist/components/Button/Button.d.ts +3 -0
- package/dist/components/Button/Button.js +1 -0
- package/dist/components/Calendar/Calendar.css +10 -0
- package/dist/components/Calendar/Calendar.d.ts +10 -6
- package/dist/components/Calendar/Calendar.js +6 -1
- package/dist/components/Coachmark/Coachmark.css +10 -0
- package/dist/components/Coachmark/Coachmark.d.ts +14 -1
- package/dist/components/Coachmark/Coachmark.js +51 -5
- package/dist/components/ColorPicker/ColorPicker.css +8 -1
- package/dist/components/ColorPicker/ColorPicker.d.ts +2 -2
- package/dist/components/DataTable/DataTable.css +216 -0
- package/dist/components/DataTable/DataTable.d.ts +70 -2
- package/dist/components/DataTable/DataTable.js +293 -6
- package/dist/components/DescriptionList/DescriptionList.css +14 -0
- package/dist/components/DescriptionList/DescriptionList.d.ts +3 -0
- package/dist/components/DescriptionList/DescriptionList.js +1 -0
- package/dist/components/EmptyState/EmptyState.d.ts +4 -2
- package/dist/components/EmptyState/EmptyState.js +2 -2
- package/dist/components/Input/Input.css +30 -0
- package/dist/components/Input/Input.d.ts +10 -0
- package/dist/components/Input/Input.js +3 -1
- package/dist/components/List/ListItem.d.ts +14 -2
- package/dist/components/List/ListItem.js +3 -2
- package/dist/components/Modal/Modal.css +19 -0
- package/dist/components/Modal/Modal.d.ts +7 -0
- package/dist/components/Modal/Modal.js +1 -0
- package/dist/components/RichTextEditor/RichTextEditor.css +47 -0
- package/dist/components/RichTextEditor/RichTextEditor.d.ts +22 -8
- package/dist/components/RichTextEditor/RichTextEditor.js +460 -3
- package/dist/components/SegmentedControl/SegmentedControl.css +70 -0
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +5 -0
- package/dist/components/SegmentedControl/SegmentedControl.js +5 -1
- package/dist/components/Select/Select.css +122 -2
- package/dist/components/Select/Select.d.ts +33 -4
- package/dist/components/Select/Select.js +256 -35
- package/dist/components/StatCard/StatCard.css +73 -0
- package/dist/components/StatCard/StatCard.d.ts +12 -0
- package/dist/components/StatCard/StatCard.js +11 -1
- package/dist/components/Tabs/Tabs.css +11 -0
- package/dist/components/Tabs/Tabs.d.ts +7 -0
- package/dist/components/Tabs/Tabs.js +7 -1
- package/dist/components/Tag/Tag.css +3 -1
- package/dist/components/Toast/Toast.css +32 -0
- package/dist/components/Toast/Toast.d.ts +18 -0
- package/dist/components/Toast/Toast.js +14 -1
- package/dist/components/Toast/ToastStack.js +8 -1
- package/dist/teste/AccordionControlado.test.d.ts +1 -0
- package/dist/teste/AccordionControlado.test.js +73 -0
- package/dist/teste/AccordionTituloNeutro.test.d.ts +1 -0
- package/dist/teste/AccordionTituloNeutro.test.js +23 -0
- package/dist/teste/AppSubheaderRegiao.test.d.ts +1 -0
- package/dist/teste/AppSubheaderRegiao.test.js +13 -0
- package/dist/teste/AttachmentCardLista.test.d.ts +1 -0
- package/dist/teste/AttachmentCardLista.test.js +49 -0
- package/dist/teste/AttachmentCardSm.test.d.ts +1 -0
- package/dist/teste/AttachmentCardSm.test.js +26 -0
- package/dist/teste/BadgeAttachedTomEPadding.test.d.ts +1 -0
- package/dist/teste/BadgeAttachedTomEPadding.test.js +43 -0
- package/dist/teste/BadgeNeutroColado.test.d.ts +1 -0
- package/dist/teste/BadgeNeutroColado.test.js +11 -0
- package/dist/teste/BadgeTag.test.js +13 -0
- package/dist/teste/ButtonDensidade.test.d.ts +1 -0
- package/dist/teste/ButtonDensidade.test.js +28 -0
- package/dist/teste/CalendarCabecalho.test.d.ts +1 -0
- package/dist/teste/CalendarCabecalho.test.js +11 -0
- package/dist/teste/CalendarCompacto.test.d.ts +1 -0
- package/dist/teste/CalendarCompacto.test.js +29 -0
- package/dist/teste/CoachmarkSemVeu.test.d.ts +1 -0
- package/dist/teste/CoachmarkSemVeu.test.js +85 -0
- package/dist/teste/CoachmarkUmPasso.test.d.ts +1 -0
- package/dist/teste/CoachmarkUmPasso.test.js +34 -0
- package/dist/teste/ColorPickerXs.test.d.ts +1 -0
- package/dist/teste/ColorPickerXs.test.js +21 -0
- package/dist/teste/DataTableArvoreEVariantes.test.d.ts +1 -0
- package/dist/teste/DataTableArvoreEVariantes.test.js +190 -0
- package/dist/teste/DataTableCompactaETom.test.d.ts +1 -0
- package/dist/teste/DataTableCompactaETom.test.js +69 -0
- package/dist/teste/DescriptionListCompacta.test.d.ts +1 -0
- package/dist/teste/DescriptionListCompacta.test.js +22 -0
- package/dist/teste/EmptyStateTituloRico.test.d.ts +1 -0
- package/dist/teste/EmptyStateTituloRico.test.js +23 -0
- package/dist/teste/InputAgrupado.test.d.ts +1 -0
- package/dist/teste/InputAgrupado.test.js +24 -0
- package/dist/teste/InputGhost.test.d.ts +1 -0
- package/dist/teste/InputGhost.test.js +32 -0
- package/dist/teste/ListItemTooltipStandalone.test.d.ts +1 -0
- package/dist/teste/ListItemTooltipStandalone.test.js +39 -0
- package/dist/teste/ModalProporcoes1Doc.test.d.ts +1 -0
- package/dist/teste/ModalProporcoes1Doc.test.js +32 -0
- package/dist/teste/RichTextEditorAlinhaImagemTabela.test.d.ts +1 -0
- package/dist/teste/RichTextEditorAlinhaImagemTabela.test.js +212 -0
- package/dist/teste/RichTextEditorEstiloDeTexto.test.d.ts +1 -0
- package/dist/teste/RichTextEditorEstiloDeTexto.test.js +120 -0
- package/dist/teste/SegmentedControlContador.test.d.ts +1 -0
- package/dist/teste/SegmentedControlContador.test.js +39 -0
- package/dist/teste/SegmentedControlSuperficie.test.d.ts +1 -0
- package/dist/teste/SegmentedControlSuperficie.test.js +39 -0
- package/dist/teste/SelectAbertoControladoEFlutuante.test.d.ts +1 -0
- package/dist/teste/SelectAbertoControladoEFlutuante.test.js +145 -0
- package/dist/teste/SelectFiltroCorETamanho.test.d.ts +1 -0
- package/dist/teste/SelectFiltroCorETamanho.test.js +77 -0
- package/dist/teste/SelectItemComEscopo.test.d.ts +1 -0
- package/dist/teste/SelectItemComEscopo.test.js +54 -0
- package/dist/teste/SelectListaFiltro.test.d.ts +1 -0
- package/dist/teste/SelectListaFiltro.test.js +102 -0
- package/dist/teste/StatCardSecundariaETom.test.d.ts +1 -0
- package/dist/teste/StatCardSecundariaETom.test.js +45 -0
- package/dist/teste/StatCardTamanhoSm.test.d.ts +1 -0
- package/dist/teste/StatCardTamanhoSm.test.js +32 -0
- package/dist/teste/TabsCompacta.test.d.ts +1 -0
- package/dist/teste/TabsCompacta.test.js +35 -0
- package/dist/teste/TagPositivoTingido.test.d.ts +1 -0
- package/dist/teste/TagPositivoTingido.test.js +54 -0
- package/dist/teste/ToastAcaoEDetalhes.test.d.ts +1 -0
- package/dist/teste/ToastAcaoEDetalhes.test.js +94 -0
- package/dist/teste/lerArquivo.d.ts +1 -0
- package/dist/teste/lerArquivo.js +12 -0
- package/dist/utils/html-seguro.d.ts +19 -1
- package/dist/utils/html-seguro.js +113 -2
- package/dist/utils/toast.d.ts +10 -1
- package/dist/utils/toast.js +2 -1
- package/package.json +3 -3
- package/src/teste/AccordionControlado.test.tsx +87 -0
- package/src/teste/AccordionTituloNeutro.test.tsx +25 -0
- package/src/teste/AppSubheaderRegiao.test.tsx +17 -0
- package/src/teste/AttachmentCardLista.test.tsx +53 -0
- package/src/teste/AttachmentCardSm.test.tsx +29 -0
- package/src/teste/BadgeAttachedTomEPadding.test.tsx +60 -0
- package/src/teste/BadgeNeutroColado.test.tsx +15 -0
- package/src/teste/BadgeTag.test.tsx +21 -0
- package/src/teste/ButtonDensidade.test.tsx +40 -0
- package/src/teste/CalendarCabecalho.test.tsx +11 -0
- package/src/teste/CalendarCompacto.test.tsx +37 -0
- package/src/teste/CoachmarkSemVeu.test.tsx +101 -0
- package/src/teste/CoachmarkUmPasso.test.tsx +45 -0
- package/src/teste/ColorPickerXs.test.tsx +22 -0
- package/src/teste/DataTableArvoreEVariantes.test.tsx +240 -0
- package/src/teste/DataTableCompactaETom.test.tsx +85 -0
- package/src/teste/DescriptionListCompacta.test.tsx +24 -0
- package/src/teste/EmptyStateTituloRico.test.tsx +34 -0
- package/src/teste/InputAgrupado.test.tsx +26 -0
- package/src/teste/InputGhost.test.tsx +42 -0
- package/src/teste/ListItemTooltipStandalone.test.tsx +64 -0
- package/src/teste/ModalProporcoes1Doc.test.tsx +36 -0
- package/src/teste/RichTextEditorAlinhaImagemTabela.test.tsx +238 -0
- package/src/teste/RichTextEditorEstiloDeTexto.test.tsx +137 -0
- package/src/teste/SegmentedControlContador.test.tsx +43 -0
- package/src/teste/SegmentedControlSuperficie.test.tsx +52 -0
- package/src/teste/SelectAbertoControladoEFlutuante.test.tsx +180 -0
- package/src/teste/SelectFiltroCorETamanho.test.tsx +90 -0
- package/src/teste/SelectItemComEscopo.test.tsx +69 -0
- package/src/teste/SelectListaFiltro.test.tsx +120 -0
- package/src/teste/StatCardSecundariaETom.test.tsx +51 -0
- package/src/teste/StatCardTamanhoSm.test.tsx +42 -0
- package/src/teste/TabsCompacta.test.tsx +45 -0
- package/src/teste/TagPositivoTingido.test.tsx +60 -0
- package/src/teste/ToastAcaoEDetalhes.test.tsx +109 -0
- package/src/teste/lerArquivo.ts +13 -0
- package/src/utils/html-seguro.ts +105 -2
- package/src/utils/toast.ts +12 -2
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
3
|
+
import Coachmark from "../components/Coachmark/Coachmark";
|
|
4
|
+
|
|
5
|
+
const PASSOS = [{ target: "#alvo-a", title: "Novo: arrastar", content: "Arraste a linha para trocar a ordem." }];
|
|
6
|
+
|
|
7
|
+
function Pagina(props: any) {
|
|
8
|
+
return (
|
|
9
|
+
<div>
|
|
10
|
+
<button id="alvo-a">A</button>
|
|
11
|
+
<button id="fora">Fora</button>
|
|
12
|
+
<Coachmark steps={PASSOS} open {...props} />
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe("Coachmark · modal={false}", () => {
|
|
18
|
+
it("sem véu nem recorte; o cartão é um diálogo não modal e a raiz deixa o ponteiro passar", () => {
|
|
19
|
+
const { baseElement } = render(<Pagina modal={false} />);
|
|
20
|
+
expect(baseElement.querySelector(".umds-coachmark__veil")).toBeNull();
|
|
21
|
+
expect(baseElement.querySelector(".umds-coachmark__cutout")).toBeNull();
|
|
22
|
+
expect(baseElement.querySelector(".umds-coachmark")).toHaveClass("umds-coachmark--modeless");
|
|
23
|
+
expect(screen.getByRole("dialog", { name: "Novo: arrastar" })).toHaveAttribute("aria-modal", "false");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("o padrão continua modal: véu, recorte e aria-modal verdadeiro", () => {
|
|
27
|
+
const { baseElement } = render(<Pagina />);
|
|
28
|
+
expect(baseElement.querySelector(".umds-coachmark__veil")).not.toBeNull();
|
|
29
|
+
expect(baseElement.querySelector(".umds-coachmark__cutout")).not.toBeNull();
|
|
30
|
+
expect(baseElement.querySelector(".umds-coachmark")).not.toHaveClass("umds-coachmark--modeless");
|
|
31
|
+
expect(screen.getByRole("dialog")).toHaveAttribute("aria-modal", "true");
|
|
32
|
+
const { unmount } = render(<Pagina modal />);
|
|
33
|
+
unmount();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("o foco entra no cartão, mas o Tab não fica preso", async () => {
|
|
37
|
+
render(<Pagina modal={false} />);
|
|
38
|
+
const cartao = screen.getByRole("dialog");
|
|
39
|
+
await waitFor(() => expect(cartao).toHaveFocus());
|
|
40
|
+
const concluir = screen.getByRole("button", { name: "Concluir" });
|
|
41
|
+
concluir.focus();
|
|
42
|
+
const evento = new KeyboardEvent("keydown", { key: "Tab", bubbles: true, cancelable: true });
|
|
43
|
+
concluir.dispatchEvent(evento);
|
|
44
|
+
expect(evento.defaultPrevented).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("no modal o Tab continua preso (o último volta ao primeiro)", () => {
|
|
48
|
+
render(<Pagina />);
|
|
49
|
+
const concluir = screen.getByRole("button", { name: "Concluir" });
|
|
50
|
+
concluir.focus();
|
|
51
|
+
const evento = new KeyboardEvent("keydown", { key: "Tab", bubbles: true, cancelable: true });
|
|
52
|
+
concluir.dispatchEvent(evento);
|
|
53
|
+
expect(evento.defaultPrevented).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("a página segue clicável: o clique fora não é capturado e o tour não fecha sozinho", () => {
|
|
57
|
+
const aoFechar = vi.fn();
|
|
58
|
+
render(<Pagina modal={false} onClose={aoFechar} />);
|
|
59
|
+
fireEvent.click(screen.getByRole("button", { name: "Fora" }));
|
|
60
|
+
expect(aoFechar).not.toHaveBeenCalled();
|
|
61
|
+
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("o Esc fecha de qualquer lugar da página, uma vez só", () => {
|
|
65
|
+
const aoFechar = vi.fn();
|
|
66
|
+
render(<Pagina modal={false} onClose={aoFechar} />);
|
|
67
|
+
const fora = screen.getByRole("button", { name: "Fora" });
|
|
68
|
+
fora.focus();
|
|
69
|
+
fireEvent.keyDown(fora, { key: "Escape" });
|
|
70
|
+
expect(aoFechar).toHaveBeenCalledTimes(1);
|
|
71
|
+
expect(aoFechar).toHaveBeenCalledWith("escape");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("o Esc dentro do cartão também fecha uma vez só", async () => {
|
|
75
|
+
const aoFechar = vi.fn();
|
|
76
|
+
render(<Pagina modal={false} onClose={aoFechar} />);
|
|
77
|
+
await waitFor(() => expect(screen.getByRole("dialog")).toHaveFocus());
|
|
78
|
+
fireEvent.keyDown(screen.getByRole("dialog"), { key: "Escape" });
|
|
79
|
+
expect(aoFechar).toHaveBeenCalledTimes(1);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("depois de fechar, o ouvinte do Esc sai do documento", () => {
|
|
83
|
+
const aoFechar = vi.fn();
|
|
84
|
+
const { rerender } = render(<Pagina modal={false} onClose={aoFechar} />);
|
|
85
|
+
rerender(<Pagina modal={false} open={false} onClose={aoFechar} />);
|
|
86
|
+
fireEvent.keyDown(document, { key: "Escape" });
|
|
87
|
+
expect(aoFechar).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("ao fechar, o foco volta ao elemento de antes, se a pessoa não foi a outro lugar", async () => {
|
|
91
|
+
const { rerender } = render(<Pagina modal={false} open={false} />);
|
|
92
|
+
const gatilho = screen.getByRole("button", { name: "Fora" });
|
|
93
|
+
gatilho.focus();
|
|
94
|
+
expect(gatilho).toHaveFocus();
|
|
95
|
+
rerender(<Pagina modal={false} open />);
|
|
96
|
+
// O foco entra no cartão depois da montagem (um quadro de animação).
|
|
97
|
+
await waitFor(() => expect(screen.getByRole("dialog")).toHaveFocus());
|
|
98
|
+
rerender(<Pagina modal={false} open={false} />);
|
|
99
|
+
await waitFor(() => expect(gatilho).toHaveFocus());
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import Coachmark from "../components/Coachmark/Coachmark";
|
|
4
|
+
|
|
5
|
+
const UM = [{ target: "#alvo-a", title: "Novo: arrastar", content: "Arraste a linha para trocar a ordem." }];
|
|
6
|
+
const DOIS = [...UM, { title: "Pronto", content: "Sem alvo." }];
|
|
7
|
+
|
|
8
|
+
function Pagina({ passos, ...resto }: any) {
|
|
9
|
+
return (
|
|
10
|
+
<div>
|
|
11
|
+
<button id="alvo-a">A</button>
|
|
12
|
+
<Coachmark steps={passos} open {...resto} />
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe("Coachmark · contador", () => {
|
|
18
|
+
it("com um passo só não há contador, nem visível nem na região aria-live", () => {
|
|
19
|
+
const { baseElement } = render(<Pagina passos={UM} />);
|
|
20
|
+
expect(screen.queryByText("1 de 1")).toBeNull();
|
|
21
|
+
expect(baseElement.textContent).not.toContain("1 de 1");
|
|
22
|
+
expect(baseElement.querySelector(".umds-coachmark__sr")?.textContent).toBe("Novo: arrastar");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("com um passo e modal={false} também não (a dica pontual)", () => {
|
|
26
|
+
const { baseElement } = render(<Pagina passos={UM} modal={false} />);
|
|
27
|
+
expect(baseElement.textContent).not.toContain("1 de 1");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("com dois passos o contador aparece e o leitor de tela o ouve", () => {
|
|
31
|
+
const { baseElement } = render(<Pagina passos={DOIS} />);
|
|
32
|
+
expect(screen.getByText("1 de 2")).toBeInTheDocument();
|
|
33
|
+
expect(baseElement.querySelector(".umds-coachmark__sr")?.textContent).toBe("1 de 2: Novo: arrastar");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("counterLabel segue valendo com mais de um passo", () => {
|
|
37
|
+
render(<Pagina passos={DOIS} counterLabel="Step {current} of {total}" />);
|
|
38
|
+
expect(screen.getByText("Step 1 of 2")).toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("o botão do último passo continua sendo Concluir", () => {
|
|
42
|
+
render(<Pagina passos={UM} />);
|
|
43
|
+
expect(screen.getByRole("button", { name: "Concluir" })).toBeInTheDocument();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import ColorPicker from "../components/ColorPicker/ColorPicker";
|
|
4
|
+
|
|
5
|
+
describe("ColorPicker · size xs", () => {
|
|
6
|
+
it("xs escreve a classe do tamanho; sm e md seguem como eram", () => {
|
|
7
|
+
const { container, rerender } = render(<ColorPicker ariaLabel="Cor" size="xs" />);
|
|
8
|
+
const raiz = () => container.firstElementChild as HTMLElement;
|
|
9
|
+
expect(raiz()).toHaveClass("umds-color-picker--xs");
|
|
10
|
+
rerender(<ColorPicker ariaLabel="Cor" size="sm" />);
|
|
11
|
+
expect(raiz()).toHaveClass("umds-color-picker--sm");
|
|
12
|
+
expect(raiz()).not.toHaveClass("umds-color-picker--xs");
|
|
13
|
+
rerender(<ColorPicker ariaLabel="Cor" />);
|
|
14
|
+
expect(raiz()).toHaveClass("umds-color-picker--md");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("no xs a amostra escolhida mantém a marcação e o aria-checked", () => {
|
|
18
|
+
const { container } = render(<ColorPicker ariaLabel="Cor" size="xs" defaultValue="--umds-primitive-red-pure" />);
|
|
19
|
+
expect(screen.getByRole("radio", { name: "Vermelho" })).toHaveAttribute("aria-checked", "true");
|
|
20
|
+
expect(container.querySelectorAll(".umds-color-picker__swatch--selected")).toHaveLength(1);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { render, screen, fireEvent } from "@testing-library/react";
|
|
3
|
+
import { faBoxOpen } from "@fortawesome/free-solid-svg-icons";
|
|
4
|
+
import DataTable from "../components/DataTable/DataTable";
|
|
5
|
+
|
|
6
|
+
const COLUNAS = [
|
|
7
|
+
{ key: "nome", label: "Nome" },
|
|
8
|
+
{ key: "sigla", label: "Sigla" },
|
|
9
|
+
];
|
|
10
|
+
const DADOS = [
|
|
11
|
+
{ id: "a", nome: "Ana", sigla: "SADM" },
|
|
12
|
+
{ id: "b", nome: "Bruno", sigla: "SOBR" },
|
|
13
|
+
{ id: "c", nome: "Carla", sigla: "SEFIN" },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
describe("DataTable: cabeçalho, zebra e destaque", () => {
|
|
17
|
+
it("headerVariant dark e headerUppercase ligam as classes; sem as props, nada muda", () => {
|
|
18
|
+
const { container, rerender } = render(<DataTable columns={COLUNAS} data={DADOS} />);
|
|
19
|
+
const raiz = () => container.querySelector(".umds-datatable") as HTMLElement;
|
|
20
|
+
expect(raiz().className).not.toMatch(/header-dark|header-uppercase|striped|header-hidden/);
|
|
21
|
+
rerender(<DataTable columns={COLUNAS} data={DADOS} headerVariant="dark" headerUppercase striped hideHeader />);
|
|
22
|
+
expect(raiz()).toHaveClass("umds-datatable--header-dark");
|
|
23
|
+
expect(raiz()).toHaveClass("umds-datatable--header-uppercase");
|
|
24
|
+
expect(raiz()).toHaveClass("umds-datatable--striped");
|
|
25
|
+
expect(raiz()).toHaveClass("umds-datatable--header-hidden");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("hideHeader não remove o cabeçalho: as colunas continuam nomeadas", () => {
|
|
29
|
+
render(<DataTable columns={COLUNAS} data={DADOS} hideHeader />);
|
|
30
|
+
expect(screen.getAllByRole("columnheader")).toHaveLength(2);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("striped marca as linhas ímpares", () => {
|
|
34
|
+
const { container } = render(<DataTable columns={COLUNAS} data={DADOS} striped />);
|
|
35
|
+
const linhas = [...container.querySelectorAll("tbody tr")];
|
|
36
|
+
expect(linhas.map((l) => l.classList.contains("umds-datatable__row--striped"))).toEqual([false, true, false]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("selectedRowKeys destaca a linha sem checkbox e marca aria-selected", () => {
|
|
40
|
+
const { container } = render(<DataTable columns={COLUNAS} data={DADOS} rowKey="id" selectedRowKeys={["b"]} />);
|
|
41
|
+
const linhas = [...container.querySelectorAll("tbody tr")];
|
|
42
|
+
expect(linhas[1]).toHaveClass("umds-datatable__row--selected");
|
|
43
|
+
expect(linhas[1]).toHaveClass("umds-datatable__row--highlighted");
|
|
44
|
+
expect(linhas[1]).toHaveAttribute("aria-selected", "true");
|
|
45
|
+
expect(linhas[0]).not.toHaveClass("umds-datatable__row--selected");
|
|
46
|
+
expect(linhas[0]).not.toHaveAttribute("aria-selected");
|
|
47
|
+
expect(screen.queryByRole("checkbox")).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("isRowSelected destaca por função", () => {
|
|
51
|
+
const { container } = render(
|
|
52
|
+
<DataTable columns={COLUNAS} data={DADOS} isRowSelected={(row) => row.sigla === "SEFIN"} />
|
|
53
|
+
);
|
|
54
|
+
const linhas = [...container.querySelectorAll("tbody tr")];
|
|
55
|
+
expect(linhas[2]).toHaveClass("umds-datatable__row--selected");
|
|
56
|
+
expect(linhas[0]).not.toHaveClass("umds-datatable__row--selected");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("emptyIcon e emptyDescription entram no estado vazio", () => {
|
|
60
|
+
const { container } = render(
|
|
61
|
+
<DataTable
|
|
62
|
+
columns={COLUNAS}
|
|
63
|
+
data={[]}
|
|
64
|
+
emptyMessage="Nada por aqui"
|
|
65
|
+
emptyDescription="Ajuste o filtro de setor."
|
|
66
|
+
emptyIcon={faBoxOpen}
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
expect(screen.getByText("Nada por aqui")).toBeInTheDocument();
|
|
70
|
+
expect(screen.getByText("Ajuste o filtro de setor.")).toBeInTheDocument();
|
|
71
|
+
expect(container.querySelector(".umds-datatable__empty-icon svg")).toHaveAttribute("data-icon", "box-open");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("o ícone padrão do estado vazio continua o inbox", () => {
|
|
75
|
+
const { container } = render(<DataTable columns={COLUNAS} data={[]} />);
|
|
76
|
+
expect(container.querySelector(".umds-datatable__empty-icon svg")).toHaveAttribute("data-icon", "inbox");
|
|
77
|
+
expect(container.querySelector(".umds-datatable__empty-desc")).toBeNull();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("compact na tabela de documento soma as duas classes", () => {
|
|
81
|
+
const { container } = render(<DataTable variant="document" density="compact" columns={COLUNAS} data={DADOS} />);
|
|
82
|
+
const raiz = container.querySelector(".umds-datatable") as HTMLElement;
|
|
83
|
+
expect(raiz).toHaveClass("umds-datatable--document");
|
|
84
|
+
expect(raiz).toHaveClass("umds-datatable--compact");
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const ARVORE = [
|
|
89
|
+
{
|
|
90
|
+
id: "gab",
|
|
91
|
+
nome: "Gabinete",
|
|
92
|
+
sigla: "GAB",
|
|
93
|
+
children: [
|
|
94
|
+
{ id: "sadm", nome: "Administração", sigla: "SADM", children: [{ id: "rh", nome: "Recursos Humanos", sigla: "RH" }] },
|
|
95
|
+
{ id: "sobr", nome: "Obras", sigla: "SOBR" },
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
{ id: "sefin", nome: "Finanças", sigla: "SEFIN" },
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
const linhas = (c: HTMLElement) => [...c.querySelectorAll("tbody tr")] as HTMLElement[];
|
|
102
|
+
const nomes = (c: HTMLElement) => linhas(c).map((l) => l.querySelectorAll("td")[0].textContent);
|
|
103
|
+
|
|
104
|
+
describe("DataTable treeData", () => {
|
|
105
|
+
it("vira treegrid; fechada, mostra só as raízes, com aria-level, posinset, setsize e expanded", () => {
|
|
106
|
+
const { container } = render(<DataTable columns={COLUNAS} data={ARVORE} treeData rowKey="id" />);
|
|
107
|
+
expect(screen.getByRole("treegrid")).toBeInTheDocument();
|
|
108
|
+
expect(nomes(container)).toEqual(["Gabinete", "Finanças"]);
|
|
109
|
+
const [gab, fin] = linhas(container);
|
|
110
|
+
expect(gab).toHaveAttribute("aria-level", "1");
|
|
111
|
+
expect(gab).toHaveAttribute("aria-posinset", "1");
|
|
112
|
+
expect(gab).toHaveAttribute("aria-setsize", "2");
|
|
113
|
+
expect(gab).toHaveAttribute("aria-expanded", "false");
|
|
114
|
+
expect(fin).not.toHaveAttribute("aria-expanded");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("o botão expande e recolhe, com nome acessível e onExpand", () => {
|
|
118
|
+
const aoExpandir = vi.fn();
|
|
119
|
+
const { container } = render(<DataTable columns={COLUNAS} data={ARVORE} treeData rowKey="id" onExpand={aoExpandir} />);
|
|
120
|
+
fireEvent.click(screen.getByRole("button", { name: "Expandir" }));
|
|
121
|
+
expect(nomes(container)).toEqual(["Gabinete", "Administração", "Obras", "Finanças"]);
|
|
122
|
+
expect(aoExpandir).toHaveBeenCalledWith(["gab"], ARVORE[0], true);
|
|
123
|
+
const filha = linhas(container)[1];
|
|
124
|
+
expect(filha).toHaveAttribute("aria-level", "2");
|
|
125
|
+
expect(filha).toHaveAttribute("aria-expanded", "false");
|
|
126
|
+
fireEvent.click(screen.getAllByRole("button", { name: "Recolher" })[0]);
|
|
127
|
+
expect(nomes(container)).toEqual(["Gabinete", "Finanças"]);
|
|
128
|
+
expect(aoExpandir).toHaveBeenLastCalledWith([], ARVORE[0], false);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("expandLabel e collapseLabel traduzem os botões", () => {
|
|
132
|
+
render(
|
|
133
|
+
<DataTable
|
|
134
|
+
columns={COLUNAS}
|
|
135
|
+
data={ARVORE}
|
|
136
|
+
treeData
|
|
137
|
+
rowKey="id"
|
|
138
|
+
defaultExpandedKeys={["gab"]}
|
|
139
|
+
expandLabel="Expand"
|
|
140
|
+
collapseLabel="Collapse"
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
expect(screen.getByRole("button", { name: "Collapse" })).toBeInTheDocument();
|
|
144
|
+
expect(screen.getByRole("button", { name: "Expand" })).toBeInTheDocument();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("defaultExpandAll abre tudo, e o primeiro recolher parte da árvore aberta", () => {
|
|
148
|
+
const { container } = render(<DataTable columns={COLUNAS} data={ARVORE} treeData rowKey="id" defaultExpandAll />);
|
|
149
|
+
expect(nomes(container)).toEqual(["Gabinete", "Administração", "Recursos Humanos", "Obras", "Finanças"]);
|
|
150
|
+
expect(linhas(container)[2]).toHaveAttribute("aria-level", "3");
|
|
151
|
+
fireEvent.click(screen.getAllByRole("button", { name: "Recolher" })[1]);
|
|
152
|
+
expect(nomes(container)).toEqual(["Gabinete", "Administração", "Obras", "Finanças"]);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("expandedKeys controla: o clique avisa, mas só muda quando o pai muda a prop", () => {
|
|
156
|
+
const aoExpandir = vi.fn();
|
|
157
|
+
const { container, rerender } = render(
|
|
158
|
+
<DataTable columns={COLUNAS} data={ARVORE} treeData rowKey="id" expandedKeys={[]} onExpand={aoExpandir} />
|
|
159
|
+
);
|
|
160
|
+
fireEvent.click(screen.getByRole("button", { name: "Expandir" }));
|
|
161
|
+
expect(aoExpandir).toHaveBeenCalledWith(["gab"], ARVORE[0], true);
|
|
162
|
+
expect(nomes(container)).toEqual(["Gabinete", "Finanças"]);
|
|
163
|
+
rerender(<DataTable columns={COLUNAS} data={ARVORE} treeData rowKey="id" expandedKeys={["gab"]} onExpand={aoExpandir} />);
|
|
164
|
+
expect(nomes(container)).toEqual(["Gabinete", "Administração", "Obras", "Finanças"]);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("sem rowKey, a chave é o caminho de índices", () => {
|
|
168
|
+
const aoExpandir = vi.fn();
|
|
169
|
+
render(<DataTable columns={COLUNAS} data={ARVORE} treeData onExpand={aoExpandir} />);
|
|
170
|
+
fireEvent.click(screen.getByRole("button", { name: "Expandir" }));
|
|
171
|
+
expect(aoExpandir.mock.calls[0][0]).toEqual(["0"]);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("desenha os fios: tee para quem tem irmã depois, elbow para a última, line para o que continua", () => {
|
|
175
|
+
const { container } = render(<DataTable columns={COLUNAS} data={ARVORE} treeData rowKey="id" defaultExpandAll />);
|
|
176
|
+
const guias = (l: HTMLElement) => [...l.querySelectorAll(".umds-datatable__guide")].map((g) => g.className.replace("umds-datatable__guide umds-datatable__guide--", ""));
|
|
177
|
+
const [gab, sadm, rh, sobr] = linhas(container);
|
|
178
|
+
expect(guias(gab)).toEqual([]);
|
|
179
|
+
expect(guias(sadm)).toEqual(["tee"]);
|
|
180
|
+
expect(guias(rh)).toEqual(["line", "elbow"]);
|
|
181
|
+
expect(guias(sobr)).toEqual(["elbow"]);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("o recuo cresce por nível", () => {
|
|
185
|
+
const { container } = render(<DataTable columns={COLUNAS} data={ARVORE} treeData rowKey="id" defaultExpandAll />);
|
|
186
|
+
const recuo = (l: HTMLElement) => (l.querySelector(".umds-datatable__tree-content") as HTMLElement).style.paddingLeft;
|
|
187
|
+
expect(recuo(linhas(container)[0])).toContain("calc(0 *");
|
|
188
|
+
expect(recuo(linhas(container)[2])).toContain("calc(2 *");
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("teclado: ↓ ↑ andam, → expande e desce, ← recolhe e sobe, Home e End", () => {
|
|
192
|
+
const { container } = render(<DataTable columns={COLUNAS} data={ARVORE} treeData rowKey="id" />);
|
|
193
|
+
const gab = linhas(container)[0];
|
|
194
|
+
gab.focus();
|
|
195
|
+
expect(gab).toHaveAttribute("tabindex", "0");
|
|
196
|
+
expect(linhas(container)[1]).toHaveAttribute("tabindex", "-1");
|
|
197
|
+
|
|
198
|
+
fireEvent.keyDown(gab, { key: "ArrowRight" });
|
|
199
|
+
expect(nomes(container)).toEqual(["Gabinete", "Administração", "Obras", "Finanças"]);
|
|
200
|
+
expect(document.activeElement).toBe(gab);
|
|
201
|
+
|
|
202
|
+
fireEvent.keyDown(gab, { key: "ArrowRight" });
|
|
203
|
+
expect(document.activeElement).toBe(linhas(container)[1]);
|
|
204
|
+
|
|
205
|
+
fireEvent.keyDown(document.activeElement as Element, { key: "ArrowDown" });
|
|
206
|
+
expect(document.activeElement).toBe(linhas(container)[2]);
|
|
207
|
+
expect(linhas(container)[2]).toHaveAttribute("tabindex", "0");
|
|
208
|
+
|
|
209
|
+
fireEvent.keyDown(document.activeElement as Element, { key: "ArrowLeft" });
|
|
210
|
+
expect(document.activeElement).toBe(linhas(container)[0]);
|
|
211
|
+
|
|
212
|
+
fireEvent.keyDown(document.activeElement as Element, { key: "End" });
|
|
213
|
+
expect(document.activeElement).toBe(linhas(container)[3]);
|
|
214
|
+
fireEvent.keyDown(document.activeElement as Element, { key: "Home" });
|
|
215
|
+
expect(document.activeElement).toBe(linhas(container)[0]);
|
|
216
|
+
|
|
217
|
+
fireEvent.keyDown(document.activeElement as Element, { key: "ArrowLeft" });
|
|
218
|
+
expect(nomes(container)).toEqual(["Gabinete", "Finanças"]);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("clicar no botão não aciona o onRowClick da linha", () => {
|
|
222
|
+
const aoClicar = vi.fn();
|
|
223
|
+
render(<DataTable columns={COLUNAS} data={ARVORE} treeData rowKey="id" onRowClick={aoClicar} />);
|
|
224
|
+
fireEvent.click(screen.getByRole("button", { name: "Expandir" }));
|
|
225
|
+
expect(aoClicar).not.toHaveBeenCalled();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("sem treeData, a tabela é a de sempre: sem role, sem aria-level", () => {
|
|
229
|
+
const { container } = render(<DataTable columns={COLUNAS} data={ARVORE} />);
|
|
230
|
+
expect(screen.queryByRole("treegrid")).toBeNull();
|
|
231
|
+
expect(container.querySelector("[aria-level]")).toBeNull();
|
|
232
|
+
expect(container.querySelector(".umds-datatable__tree-toggle")).toBeNull();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("childrenKey troca o campo das filhas", () => {
|
|
236
|
+
const dados = [{ id: 1, nome: "Pai", sigla: "P", itens: [{ id: 2, nome: "Filho", sigla: "F" }] }];
|
|
237
|
+
const { container } = render(<DataTable columns={COLUNAS} data={dados} treeData childrenKey="itens" rowKey="id" defaultExpandAll />);
|
|
238
|
+
expect(nomes(container)).toEqual(["Pai", "Filho"]);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { render } from "@testing-library/react";
|
|
3
|
+
import DataTable from "../components/DataTable/DataTable";
|
|
4
|
+
import { lerArquivo } from "./lerArquivo";
|
|
5
|
+
|
|
6
|
+
const cssDataTable = await lerArquivo("../core/src/components/DataTable/DataTable.css");
|
|
7
|
+
|
|
8
|
+
const COLUNAS = [
|
|
9
|
+
{ key: "nome", label: "Nome" },
|
|
10
|
+
{ key: "situacao", label: "Situação" },
|
|
11
|
+
];
|
|
12
|
+
const DADOS = [
|
|
13
|
+
{ nome: "Ana Souza", situacao: "Ativa", tom: "positive" },
|
|
14
|
+
{ nome: "Carlos Lima", situacao: "Bloqueado", tom: "negative" },
|
|
15
|
+
{ nome: "Marina Alves", situacao: "Licença", tom: "info" },
|
|
16
|
+
{ nome: "Rafael Pereira", situacao: "Desligado", tom: "muted" },
|
|
17
|
+
{ nome: "Beatriz Lima", situacao: "Ativa" },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const linhas = (c: HTMLElement) => [...c.querySelectorAll("tbody tr")] as HTMLElement[];
|
|
21
|
+
|
|
22
|
+
describe("DataTable · rowTone", () => {
|
|
23
|
+
it("o nome de um campo da linha traz o tom", () => {
|
|
24
|
+
const { container } = render(<DataTable columns={COLUNAS} data={DADOS} rowTone="tom" />);
|
|
25
|
+
const l = linhas(container);
|
|
26
|
+
expect(l[0]).toHaveClass("umds-datatable__row--positive");
|
|
27
|
+
expect(l[1]).toHaveClass("umds-datatable__row--negative");
|
|
28
|
+
expect(l[2]).toHaveClass("umds-datatable__row--info");
|
|
29
|
+
expect(l[3]).toHaveClass("umds-datatable__row--muted");
|
|
30
|
+
expect(l[4].className).toBe("umds-datatable__row");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("uma função (row, rowIndex) devolve o tom", () => {
|
|
34
|
+
const { container } = render(
|
|
35
|
+
<DataTable columns={COLUNAS} data={DADOS} rowTone={(row, i) => (row.situacao === "Bloqueado" || i === 4 ? "negative" : undefined)} />,
|
|
36
|
+
);
|
|
37
|
+
const l = linhas(container);
|
|
38
|
+
expect(l[1]).toHaveClass("umds-datatable__row--negative");
|
|
39
|
+
expect(l[4]).toHaveClass("umds-datatable__row--negative");
|
|
40
|
+
expect(l[0].className).toBe("umds-datatable__row");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("tom desconhecido ou vazio não vira classe", () => {
|
|
44
|
+
const { container } = render(
|
|
45
|
+
<DataTable columns={COLUNAS} data={[{ nome: "A", situacao: "x", tom: "rosa" }, { nome: "B", situacao: "y", tom: "" }]} rowTone="tom" />,
|
|
46
|
+
);
|
|
47
|
+
for (const l of linhas(container)) expect(l.className).toBe("umds-datatable__row");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("sem rowTone nada muda", () => {
|
|
51
|
+
const { container } = render(<DataTable columns={COLUNAS} data={DADOS} />);
|
|
52
|
+
for (const l of linhas(container)) expect(l.className).toBe("umds-datatable__row");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("o tom convive com a linha selecionada e a zebra (as classes ficam; o CSS faz a selecionada vencer)", () => {
|
|
56
|
+
const { container } = render(
|
|
57
|
+
<DataTable columns={COLUNAS} data={DADOS} rowTone="tom" striped rowKey="nome" selectedRowKeys={["Carlos Lima"]} />,
|
|
58
|
+
);
|
|
59
|
+
const l = linhas(container);
|
|
60
|
+
expect(l[1]).toHaveClass("umds-datatable__row--negative", "umds-datatable__row--selected", "umds-datatable__row--striped");
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("DataTable · compacta, 44px e CSS do tom", () => {
|
|
65
|
+
const css = cssDataTable.replace(/\r\n/g, "\n");
|
|
66
|
+
const bloco = (seletor: string) => {
|
|
67
|
+
const inicio = css.indexOf(seletor + " {");
|
|
68
|
+
return css.slice(inicio, css.indexOf("}", inicio));
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
it("a densidade compacta fixa cabeçalho e linha na altura de campo (44px); o documento fica de fora", () => {
|
|
72
|
+
expect(bloco(".umds-datatable--compact:not(.umds-datatable--document) .umds-datatable__td")).toMatch(
|
|
73
|
+
/height:\s*var\(--umds-semantic-field-height\)/,
|
|
74
|
+
);
|
|
75
|
+
expect(css).toContain(".umds-datatable--compact:not(.umds-datatable--document) .umds-datatable__th,");
|
|
76
|
+
const { container } = render(<DataTable density="compact" columns={COLUNAS} data={DADOS} />);
|
|
77
|
+
expect(container.querySelector(".umds-datatable--compact")).not.toBeNull();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("a linha selecionada vence o tom (o :not) e o tom vence a zebra", () => {
|
|
81
|
+
expect(css).toMatch(/\.umds-datatable__row--negative:not\(\.umds-datatable__row--selected\)/);
|
|
82
|
+
expect(css).toMatch(/\.umds-datatable__row--negative:not\(\.umds-datatable__row--selected\)\.umds-datatable__row--striped/);
|
|
83
|
+
expect(bloco(".umds-datatable__row--muted .umds-datatable__td")).toMatch(/neutral-dark-down/);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { render } from "@testing-library/react";
|
|
3
|
+
import DescriptionList from "../components/DescriptionList/DescriptionList";
|
|
4
|
+
|
|
5
|
+
const ITENS = [{ label: "Dotação", value: "02.031.0001" }];
|
|
6
|
+
|
|
7
|
+
describe("DescriptionList · density", () => {
|
|
8
|
+
it("compact escreve a classe; o padrão não", () => {
|
|
9
|
+
const { container, rerender } = render(<DescriptionList items={ITENS} density="compact" />);
|
|
10
|
+
const dl = () => container.querySelector("dl") as HTMLElement;
|
|
11
|
+
expect(dl()).toHaveClass("umds-description-list--compact");
|
|
12
|
+
rerender(<DescriptionList items={ITENS} density="default" />);
|
|
13
|
+
expect(dl()).not.toHaveClass("umds-description-list--compact");
|
|
14
|
+
rerender(<DescriptionList items={ITENS} />);
|
|
15
|
+
expect(dl()).not.toHaveClass("umds-description-list--compact");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("compact vale nos dois desenhos", () => {
|
|
19
|
+
const { container, rerender } = render(<DescriptionList items={ITENS} density="compact" layout="stacked" bordered />);
|
|
20
|
+
expect(container.querySelector("dl")).toHaveClass("umds-description-list--stacked", "umds-description-list--compact");
|
|
21
|
+
rerender(<DescriptionList items={ITENS} density="compact" fit />);
|
|
22
|
+
expect(container.querySelector("dl")).toHaveClass("umds-description-list--inline", "umds-description-list--compact");
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import { faInbox } from "@fortawesome/free-solid-svg-icons";
|
|
4
|
+
import EmptyState from "../components/EmptyState/EmptyState";
|
|
5
|
+
|
|
6
|
+
describe("EmptyState · título rico", () => {
|
|
7
|
+
it("título em texto continua igual", () => {
|
|
8
|
+
const { container } = render(<EmptyState icon={faInbox} title="Nenhuma mensagem" description="Tudo em dia." />);
|
|
9
|
+
expect(container.querySelector(".umds-empty-state__title")).toHaveTextContent("Nenhuma mensagem");
|
|
10
|
+
expect(screen.getByText("Tudo em dia.")).toBeInTheDocument();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("título aceita conteúdo rico: negrito, link", () => {
|
|
14
|
+
const { container } = render(
|
|
15
|
+
<EmptyState
|
|
16
|
+
title={
|
|
17
|
+
<>
|
|
18
|
+
Nenhum processo para <strong data-testid="termo">SOBR</strong>{" "}
|
|
19
|
+
<a href="#limpar">Limpar filtro</a>
|
|
20
|
+
</>
|
|
21
|
+
}
|
|
22
|
+
/>,
|
|
23
|
+
);
|
|
24
|
+
const titulo = container.querySelector(".umds-empty-state__title") as HTMLElement;
|
|
25
|
+
expect(titulo).toContainElement(screen.getByTestId("termo"));
|
|
26
|
+
expect(titulo.querySelector("a")).toHaveAttribute("href", "#limpar");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("o título é um div (conteúdo de bloco não vira HTML inválido dentro de p)", () => {
|
|
30
|
+
const { container } = render(<EmptyState title={<div data-testid="bloco">Bloco</div>} />);
|
|
31
|
+
expect(container.querySelector(".umds-empty-state__title")!.tagName).toBe("DIV");
|
|
32
|
+
expect(screen.getByTestId("bloco").parentElement).toHaveClass("umds-empty-state__title");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { render } from "@testing-library/react";
|
|
3
|
+
import Input from "../components/Input/Input";
|
|
4
|
+
|
|
5
|
+
describe("Input · grouped", () => {
|
|
6
|
+
it("grouped liga a classe própria e a do borderless; sem a prop, nenhuma das duas", () => {
|
|
7
|
+
const { container, rerender } = render(<Input ariaLabel="Adicionar setor" grouped />);
|
|
8
|
+
const raiz = () => container.firstElementChild as HTMLElement;
|
|
9
|
+
expect(raiz()).toHaveClass("umds-input--grouped");
|
|
10
|
+
expect(raiz()).toHaveClass("umds-input--borderless");
|
|
11
|
+
rerender(<Input ariaLabel="Adicionar setor" />);
|
|
12
|
+
expect(raiz()).not.toHaveClass("umds-input--grouped");
|
|
13
|
+
expect(raiz()).not.toHaveClass("umds-input--borderless");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("borderless sozinho não ganha a classe do grupo (segue com altura de campo e foco próprio)", () => {
|
|
17
|
+
const { container } = render(<Input ariaLabel="x" borderless />);
|
|
18
|
+
expect(container.firstElementChild).toHaveClass("umds-input--borderless");
|
|
19
|
+
expect(container.firstElementChild).not.toHaveClass("umds-input--grouped");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("o campo continua digitável dentro do grupo", () => {
|
|
23
|
+
const { container } = render(<Input ariaLabel="Adicionar setor" grouped placeholder="SADM, SOBR..." />);
|
|
24
|
+
expect(container.querySelector("input")).toHaveAttribute("placeholder", "SADM, SOBR...");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import Input from "../components/Input/Input";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import { lerArquivo } from "./lerArquivo";
|
|
5
|
+
|
|
6
|
+
const cssInput = await lerArquivo("../core/src/components/Input/Input.css");
|
|
7
|
+
|
|
8
|
+
const CSS: Record<string, string> = { Input: cssInput };
|
|
9
|
+
const css = (componente: string) => CSS[componente].replace(/\r\n/g, "\n");
|
|
10
|
+
const bloco = (texto: string, seletor: string) => {
|
|
11
|
+
const inicio = texto.indexOf(seletor + " {");
|
|
12
|
+
expect(inicio, seletor).toBeGreaterThanOrEqual(0);
|
|
13
|
+
return texto.slice(inicio, texto.indexOf("}", inicio));
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
describe("Input · variant ghost", () => {
|
|
17
|
+
it("ghost escreve a classe; sem a prop e com default, não", () => {
|
|
18
|
+
const { container } = render(
|
|
19
|
+
<>
|
|
20
|
+
<Input ariaLabel="a" variant="ghost" />
|
|
21
|
+
<Input ariaLabel="b" />
|
|
22
|
+
<Input ariaLabel="c" variant="default" />
|
|
23
|
+
</>,
|
|
24
|
+
);
|
|
25
|
+
expect(container.children[0]).toHaveClass("umds-input--ghost");
|
|
26
|
+
expect(container.children[1]).not.toHaveClass("umds-input--ghost");
|
|
27
|
+
expect(container.children[2]).not.toHaveClass("umds-input--ghost");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("CSS: só o repouso muda (fundo claro, borda clara) e com baixa especificidade, para o hover e o foco vencerem", () => {
|
|
31
|
+
const t = css("Input");
|
|
32
|
+
const ghost = bloco(t, ".umds-input--ghost:where(:not(.umds-input--error):not(.umds-input--disabled):not(.umds-input--readonly)) .umds-input__container");
|
|
33
|
+
expect(ghost).toMatch(/background-color:\s*var\(--umds-semantic-color-background-light\)/);
|
|
34
|
+
expect(ghost).toMatch(/border-color:\s*var\(--umds-semantic-color-neutral-light-medium\)/);
|
|
35
|
+
expect(t.indexOf(".umds-input__container:focus-within:not(")).toBeGreaterThanOrEqual(0);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("o foco, o erro e o desabilitado do campo ghost seguem as classes do padrão", () => {
|
|
39
|
+
const { container } = render(<Input ariaLabel="d" variant="ghost" errorMessage="Obrigatório" />);
|
|
40
|
+
expect(container.firstElementChild).toHaveClass("umds-input--ghost", "umds-input--error");
|
|
41
|
+
});
|
|
42
|
+
});
|