@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,77 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import Select from "../components/Select/Select";
|
|
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
|
+
describe("Select filtro · tamanho e fundo", () => {
|
|
11
|
+
it("as variantes de filtro nascem no tamanho sm; size explícito manda; o padrão segue md", () => {
|
|
12
|
+
const { container, rerender } = render(_jsx(Select, { ariaLabel: "x", options: MARCADORES, variant: "filter" }));
|
|
13
|
+
const raiz = () => container.firstElementChild;
|
|
14
|
+
expect(raiz()).toHaveClass("umds-select--sm");
|
|
15
|
+
rerender(_jsx(Select, { ariaLabel: "x", options: MARCADORES, variant: "search" }));
|
|
16
|
+
expect(raiz()).toHaveClass("umds-select--sm");
|
|
17
|
+
rerender(_jsx(Select, { ariaLabel: "x", options: MARCADORES, variant: "combo" }));
|
|
18
|
+
expect(raiz()).toHaveClass("umds-select--sm");
|
|
19
|
+
rerender(_jsx(Select, { ariaLabel: "x", options: MARCADORES, variant: "filter", size: "md" }));
|
|
20
|
+
expect(raiz()).toHaveClass("umds-select--md");
|
|
21
|
+
rerender(_jsx(Select, { ariaLabel: "x", options: MARCADORES }));
|
|
22
|
+
expect(raiz()).toHaveClass("umds-select--md");
|
|
23
|
+
expect(raiz()).not.toHaveClass("umds-select--sm");
|
|
24
|
+
});
|
|
25
|
+
it("o azul-claro do gatilho só vem com valor escolhido (--has-value); sem valor, não", () => {
|
|
26
|
+
const { container, rerender } = render(_jsx(Select, { ariaLabel: "x", options: MARCADORES, variant: "filter", placeholder: "Marcadores" }));
|
|
27
|
+
const raiz = () => container.firstElementChild;
|
|
28
|
+
expect(raiz()).not.toHaveClass("umds-select--has-value");
|
|
29
|
+
rerender(_jsx(Select, { ariaLabel: "x", options: MARCADORES, variant: "filter", placeholder: "Marcadores", value: "urgente" }));
|
|
30
|
+
expect(raiz()).toHaveClass("umds-select--has-value");
|
|
31
|
+
rerender(_jsx(Select, { ariaLabel: "x", options: MARCADORES, placeholder: "Marcadores", value: "urgente" }));
|
|
32
|
+
expect(raiz()).not.toHaveClass("umds-select--has-value");
|
|
33
|
+
});
|
|
34
|
+
it("o valor vazio do emptyOptionLabel volta ao estado sem valor", () => {
|
|
35
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: MARCADORES, variant: "filter", placeholder: "Marcadores", emptyOptionLabel: "Todos", value: "" }));
|
|
36
|
+
expect(container.firstElementChild).not.toHaveClass("umds-select--has-value");
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe("Select · cor por opção", () => {
|
|
40
|
+
it("a lista mostra uma amostra por opção com color; sem color, não", () => {
|
|
41
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: MARCADORES, variant: "filter" }));
|
|
42
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
43
|
+
const opcoes = [...container.querySelectorAll('[role="option"]')];
|
|
44
|
+
expect(opcoes[0].querySelector(".umds-select__swatch")).toHaveAttribute("aria-hidden", "true");
|
|
45
|
+
expect(opcoes[0].querySelector(".umds-select__swatch").style.background).toContain("--umds-semantic-color-feedback-negative-pure");
|
|
46
|
+
expect(opcoes[1].querySelector(".umds-select__swatch")).not.toBeNull();
|
|
47
|
+
expect(opcoes[2].querySelector(".umds-select__swatch")).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
it("o gatilho ganha a cor da opção escolhida (seleção única)", () => {
|
|
50
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: MARCADORES, variant: "filter", placeholder: "Marcadores", value: "revisao" }));
|
|
51
|
+
const amostra = container.querySelector(".umds-select__trigger .umds-select__swatch");
|
|
52
|
+
expect(amostra.style.background).toContain("--umds-semantic-color-primary-pure");
|
|
53
|
+
});
|
|
54
|
+
it("opção escolhida sem color e estado sem valor: o gatilho não tem amostra", () => {
|
|
55
|
+
const { container, rerender } = render(_jsx(Select, { ariaLabel: "x", options: MARCADORES, placeholder: "Marcadores", value: "nenhum" }));
|
|
56
|
+
expect(container.querySelector(".umds-select__trigger .umds-select__swatch")).toBeNull();
|
|
57
|
+
rerender(_jsx(Select, { ariaLabel: "x", options: MARCADORES, placeholder: "Marcadores" }));
|
|
58
|
+
expect(container.querySelector(".umds-select__trigger .umds-select__swatch")).toBeNull();
|
|
59
|
+
});
|
|
60
|
+
it("triggerSwatch explícito manda sobre a cor da opção", () => {
|
|
61
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: MARCADORES, value: "urgente", triggerSwatch: "var(--umds-semantic-color-feedback-positive-pure)" }));
|
|
62
|
+
const amostras = container.querySelectorAll(".umds-select__trigger .umds-select__swatch");
|
|
63
|
+
expect(amostras).toHaveLength(1);
|
|
64
|
+
expect(amostras[0].style.background).toContain("--umds-semantic-color-feedback-positive-pure");
|
|
65
|
+
});
|
|
66
|
+
it("na seleção múltipla o gatilho não pinta amostra (são várias), mas a lista mostra as cores", () => {
|
|
67
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: MARCADORES, multiple: true, value: ["urgente", "revisao"] }));
|
|
68
|
+
expect(container.querySelector(".umds-select__trigger .umds-select__swatch")).toBeNull();
|
|
69
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
70
|
+
expect(container.querySelectorAll('[role="option"] .umds-select__swatch')).toHaveLength(2);
|
|
71
|
+
});
|
|
72
|
+
it("a cor não vira texto nem entra no nome acessível da opção", () => {
|
|
73
|
+
render(_jsx(Select, { ariaLabel: "x", options: MARCADORES }));
|
|
74
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
75
|
+
expect(screen.getByRole("option", { name: "Urgente" })).toBeInTheDocument();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import Select from "../components/Select/Select";
|
|
5
|
+
const OPCOES = [
|
|
6
|
+
{ label: "Urgente", value: "urgente", etiqueta: "Prazo hoje" },
|
|
7
|
+
{ label: "Rotina", value: "rotina", etiqueta: "Sem prazo" },
|
|
8
|
+
];
|
|
9
|
+
const item = ({ optionData }) => (_jsxs("span", { "data-testid": "item", children: [_jsx("b", { children: optionData.label }), " ", _jsx("i", { children: optionData.etiqueta })] }));
|
|
10
|
+
describe("Select · item com escopo da opção", () => {
|
|
11
|
+
it("a lista mostra o item de cada opção, recebendo a opção (optionData e o apelido option)", () => {
|
|
12
|
+
const vistos = [];
|
|
13
|
+
render(_jsx(Select, { ariaLabel: "Prioridade", options: OPCOES, item: (escopo) => {
|
|
14
|
+
vistos.push(escopo);
|
|
15
|
+
return _jsx("span", { "data-testid": "item", children: escopo.optionData.label });
|
|
16
|
+
} }));
|
|
17
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
18
|
+
expect(screen.getAllByTestId("item").map((n) => n.textContent)).toEqual(["Urgente", "Rotina"]);
|
|
19
|
+
expect(vistos[0].optionData).toBe(OPCOES[0]);
|
|
20
|
+
expect(vistos[0].option).toBe(OPCOES[0]);
|
|
21
|
+
});
|
|
22
|
+
it("o gatilho com a opção escolhida mostra o conteúdo do item, não o texto", () => {
|
|
23
|
+
render(_jsx(Select, { ariaLabel: "Prioridade", options: OPCOES, value: "urgente", item: item }));
|
|
24
|
+
const gatilho = screen.getByRole("combobox");
|
|
25
|
+
expect(gatilho.querySelector(".umds-select__trigger-item")).not.toBeNull();
|
|
26
|
+
expect(gatilho).toHaveTextContent("Urgente");
|
|
27
|
+
expect(gatilho).toHaveTextContent("Prazo hoje");
|
|
28
|
+
expect(gatilho.querySelector(".umds-select__placeholder")).toBeNull();
|
|
29
|
+
});
|
|
30
|
+
it("sem valor o gatilho mostra o placeholder; escolher na lista passa o item para o gatilho", () => {
|
|
31
|
+
function App() {
|
|
32
|
+
return _jsx(Select, { ariaLabel: "Prioridade", placeholder: "Escolha", options: OPCOES, item: item });
|
|
33
|
+
}
|
|
34
|
+
render(_jsx(App, {}));
|
|
35
|
+
const gatilho = screen.getByRole("combobox");
|
|
36
|
+
expect(gatilho).toHaveTextContent("Escolha");
|
|
37
|
+
expect(gatilho.querySelector(".umds-select__trigger-item")).toBeNull();
|
|
38
|
+
fireEvent.click(gatilho);
|
|
39
|
+
fireEvent.click(screen.getAllByRole("option")[1]);
|
|
40
|
+
expect(screen.getByRole("combobox").querySelector(".umds-select__trigger-item")).toHaveTextContent("Rotina");
|
|
41
|
+
});
|
|
42
|
+
it("seleção múltipla segue com o texto no gatilho", () => {
|
|
43
|
+
render(_jsx(Select, { ariaLabel: "Prioridade", multiple: true, options: OPCOES, value: ["urgente"], item: item }));
|
|
44
|
+
expect(screen.getByRole("combobox").querySelector(".umds-select__trigger-item")).toBeNull();
|
|
45
|
+
});
|
|
46
|
+
it("sem item nada muda: o gatilho mostra o rótulo; item como nó solto (legado) não vai ao gatilho", () => {
|
|
47
|
+
const { rerender } = render(_jsx(Select, { ariaLabel: "Prioridade", options: OPCOES, value: "urgente" }));
|
|
48
|
+
expect(screen.getByRole("combobox")).toHaveTextContent("Urgente");
|
|
49
|
+
expect(screen.getByRole("combobox").querySelector(".umds-select__trigger-item")).toBeNull();
|
|
50
|
+
rerender(_jsx(Select, { ariaLabel: "Prioridade", options: OPCOES, value: "urgente", item: _jsx("em", { children: "fixo" }) }));
|
|
51
|
+
expect(screen.getByRole("combobox").querySelector(".umds-select__trigger-item")).toBeNull();
|
|
52
|
+
expect(screen.getByRole("combobox")).toHaveTextContent("Urgente");
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
4
|
+
import Select from "../components/Select/Select";
|
|
5
|
+
import { lerArquivo } from "./lerArquivo";
|
|
6
|
+
const cssSelect = await lerArquivo("../core/src/components/Select/Select.css");
|
|
7
|
+
const OPCOES = [
|
|
8
|
+
{ label: "Urgente", value: "urgente" },
|
|
9
|
+
{ label: "Revisão", value: "revisao" },
|
|
10
|
+
];
|
|
11
|
+
afterEach(() => vi.restoreAllMocks());
|
|
12
|
+
const lista = (container) => container.querySelector(".umds-select__dropdown");
|
|
13
|
+
/** jsdom não tem layout: só a lista "mede" o que o teste mandar. */
|
|
14
|
+
function medirLista(direita, larguraDaJanela) {
|
|
15
|
+
vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(function () {
|
|
16
|
+
const eLista = this.classList.contains("umds-select__dropdown");
|
|
17
|
+
return { top: 0, bottom: 0, left: 0, right: eLista ? direita : 0, width: 0, height: 0, x: 0, y: 0, toJSON() { } };
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(window, "innerWidth", { value: larguraDaJanela, configurable: true });
|
|
20
|
+
}
|
|
21
|
+
describe("Select filtro · listMinWidth", () => {
|
|
22
|
+
it("um número vira px e a lista nunca fica mais estreita que o gatilho", () => {
|
|
23
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, variant: "filter", listMinWidth: 220 }));
|
|
24
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
25
|
+
expect(lista(container).style.minWidth).toBe("max(100%, 220px)");
|
|
26
|
+
});
|
|
27
|
+
it("uma medida CSS vale como veio", () => {
|
|
28
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, variant: "filter", listMinWidth: "18rem" }));
|
|
29
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
30
|
+
expect(lista(container).style.minWidth).toBe("max(100%, 18rem)");
|
|
31
|
+
});
|
|
32
|
+
it("0 é um valor (sem mínimo além do gatilho), não ausência", () => {
|
|
33
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, variant: "filter", listMinWidth: 0 }));
|
|
34
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
35
|
+
expect(lista(container).style.minWidth).toBe("max(100%, 0px)");
|
|
36
|
+
});
|
|
37
|
+
it("sem a prop o mínimo é o do CSS (240px), sem estilo inline", () => {
|
|
38
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, variant: "filter" }));
|
|
39
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
40
|
+
expect(lista(container).style.minWidth).toBe("");
|
|
41
|
+
});
|
|
42
|
+
it("o Select padrão ignora a prop (a lista é a largura do campo)", () => {
|
|
43
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, listMinWidth: 220 }));
|
|
44
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
45
|
+
expect(lista(container).style.minWidth).toBe("");
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe("Select filtro · nunca passa da borda da janela", () => {
|
|
49
|
+
it("a lista que estoura a borda direita se alinha ao fim do gatilho", async () => {
|
|
50
|
+
medirLista(1457, 1440);
|
|
51
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, variant: "filter" }));
|
|
52
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
53
|
+
await waitFor(() => expect(container.querySelector(".umds-select--list-end")).not.toBeNull());
|
|
54
|
+
});
|
|
55
|
+
it("a lista que cabe fica onde está", async () => {
|
|
56
|
+
medirLista(900, 1440);
|
|
57
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, variant: "filter" }));
|
|
58
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
59
|
+
await waitFor(() => expect(lista(container)).not.toBeNull());
|
|
60
|
+
expect(container.querySelector(".umds-select--list-end")).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
it("deixa 8px de respiro: encostada na borda ainda alinha", async () => {
|
|
63
|
+
medirLista(1436, 1440);
|
|
64
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, variant: "filter" }));
|
|
65
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
66
|
+
await waitFor(() => expect(container.querySelector(".umds-select--list-end")).not.toBeNull());
|
|
67
|
+
});
|
|
68
|
+
it("fechar desliga o alinhamento", async () => {
|
|
69
|
+
medirLista(1457, 1440);
|
|
70
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES, variant: "filter" }));
|
|
71
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
72
|
+
await waitFor(() => expect(container.querySelector(".umds-select--list-end")).not.toBeNull());
|
|
73
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
74
|
+
await waitFor(() => expect(container.querySelector(".umds-select--list-end")).toBeNull());
|
|
75
|
+
});
|
|
76
|
+
it("o Select padrão (não filtro) não é movido", async () => {
|
|
77
|
+
medirLista(1457, 1440);
|
|
78
|
+
const { container } = render(_jsx(Select, { ariaLabel: "x", options: OPCOES }));
|
|
79
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
80
|
+
await waitFor(() => expect(lista(container)).not.toBeNull());
|
|
81
|
+
expect(container.querySelector(".umds-select--list-end")).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe("Select filtro · CSS", () => {
|
|
85
|
+
const css = cssSelect.replace(/\r\n/g, "\n");
|
|
86
|
+
const bloco = (seletor) => {
|
|
87
|
+
const inicio = css.indexOf(seletor + " {");
|
|
88
|
+
return css.slice(inicio, css.indexOf("}", inicio));
|
|
89
|
+
};
|
|
90
|
+
it("o wrapper do filtro é fit-content (o auto o esticava até o pai e a lista herdava essa largura)", () => {
|
|
91
|
+
expect(bloco(".umds-select--filter")).toMatch(/width:\s*fit-content/);
|
|
92
|
+
});
|
|
93
|
+
it("a busca da lista fica fora da conta da largura natural", () => {
|
|
94
|
+
expect(bloco(".umds-select--filter .umds-select__search-container")).toMatch(/contain:\s*inline-size/);
|
|
95
|
+
expect(bloco(".umds-select__search-input")).toMatch(/min-width:\s*0/);
|
|
96
|
+
});
|
|
97
|
+
it("o alinhamento ao fim ancora a lista pela direita", () => {
|
|
98
|
+
const b = bloco(".umds-select--filter.umds-select--list-end .umds-select__dropdown");
|
|
99
|
+
expect(b).toMatch(/left:\s*auto/);
|
|
100
|
+
expect(b).toMatch(/right:\s*0/);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import StatCard from "../components/StatCard/StatCard";
|
|
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(_jsx(StatCard, { value: "22,31%", label: "Efici\u00EAncia", description: "Meu Setor", secondaryValue: "14,11%", secondaryLabel: "Geral", labelPosition: "top" }));
|
|
8
|
+
const filhos = [...container.firstElementChild.children].map((e) => e.className);
|
|
9
|
+
expect(filhos[filhos.length - 1]).toBe("umds-stat-card__secundaria");
|
|
10
|
+
const secundaria = container.querySelector(".umds-stat-card__secundaria");
|
|
11
|
+
expect(secundaria.querySelector(".umds-stat-card__valor-secundario")).toHaveTextContent("14,11%");
|
|
12
|
+
expect(secundaria.querySelector(".umds-stat-card__rotulo-secundario")).toHaveTextContent("Geral");
|
|
13
|
+
expect(container.firstElementChild).toHaveClass("umds-stat-card--com-secundaria");
|
|
14
|
+
const texto = container.firstElementChild.textContent;
|
|
15
|
+
expect(texto.indexOf("22,31%")).toBeLessThan(texto.indexOf("Eficiência"));
|
|
16
|
+
expect(texto.indexOf("Eficiência")).toBeLessThan(texto.indexOf("14,11%"));
|
|
17
|
+
});
|
|
18
|
+
it("secondaryValue 0 aparece; vazio e ausente não", () => {
|
|
19
|
+
const { container, rerender } = render(_jsx(StatCard, { value: "5", label: "x", secondaryValue: 0 }));
|
|
20
|
+
expect(container.querySelector(".umds-stat-card__valor-secundario")).toHaveTextContent("0");
|
|
21
|
+
rerender(_jsx(StatCard, { value: "5", label: "x", secondaryValue: "" }));
|
|
22
|
+
expect(container.querySelector(".umds-stat-card__secundaria")).toBeNull();
|
|
23
|
+
rerender(_jsx(StatCard, { value: "5", label: "x" }));
|
|
24
|
+
expect(container.querySelector(".umds-stat-card__secundaria")).toBeNull();
|
|
25
|
+
expect(container.firstElementChild).not.toHaveClass("umds-stat-card--com-secundaria");
|
|
26
|
+
});
|
|
27
|
+
it("secondaryValue sem secondaryLabel não desenha o rótulo", () => {
|
|
28
|
+
const { container } = render(_jsx(StatCard, { value: "5", label: "x", secondaryValue: "9" }));
|
|
29
|
+
expect(container.querySelector(".umds-stat-card__rotulo-secundario")).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
it("valueTone escreve a classe do tom; default e ausente não", () => {
|
|
32
|
+
const { container, rerender } = render(_jsx(StatCard, { value: "5", label: "x", valueTone: "negative" }));
|
|
33
|
+
expect(container.firstElementChild).toHaveClass("umds-stat-card--valor-negative");
|
|
34
|
+
rerender(_jsx(StatCard, { value: "5", label: "x", valueTone: "primary" }));
|
|
35
|
+
expect(container.firstElementChild).toHaveClass("umds-stat-card--valor-primary");
|
|
36
|
+
rerender(_jsx(StatCard, { value: "5", label: "x", valueTone: "default" }));
|
|
37
|
+
expect(container.firstElementChild.className).not.toMatch(/valor-/);
|
|
38
|
+
rerender(_jsx(StatCard, { value: "5", label: "x" }));
|
|
39
|
+
expect(container.firstElementChild.className).not.toMatch(/valor-/);
|
|
40
|
+
});
|
|
41
|
+
it("valueTone não mexe na variant do ícone", () => {
|
|
42
|
+
const { container } = render(_jsx(StatCard, { value: "5", label: "x", variant: "positive", valueTone: "negative" }));
|
|
43
|
+
expect(container.firstElementChild).toHaveClass("umds-stat-card--positive", "umds-stat-card--valor-negative");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import StatCard from "../components/StatCard/StatCard";
|
|
5
|
+
import { lerArquivo } from "./lerArquivo";
|
|
6
|
+
const cssStatCard = await lerArquivo("../core/src/components/StatCard/StatCard.css");
|
|
7
|
+
const css = cssStatCard.replace(/\r\n/g, "\n");
|
|
8
|
+
const bloco = (seletor) => {
|
|
9
|
+
const inicio = css.indexOf(seletor + " {");
|
|
10
|
+
return css.slice(inicio, css.indexOf("}", inicio));
|
|
11
|
+
};
|
|
12
|
+
describe("StatCard · size", () => {
|
|
13
|
+
it("sm escreve a classe; sem a prop e com md o cartão é o de antes", () => {
|
|
14
|
+
const { container } = render(_jsxs(_Fragment, { children: [_jsx(StatCard, { value: 44, label: "N\u00E3o lidos", size: "sm" }), _jsx(StatCard, { value: 44, label: "N\u00E3o lidos" }), _jsx(StatCard, { value: 44, label: "N\u00E3o lidos", size: "md" })] }));
|
|
15
|
+
expect(container.children[0]).toHaveClass("umds-stat-card--sm");
|
|
16
|
+
expect(container.children[1]).not.toHaveClass("umds-stat-card--sm");
|
|
17
|
+
expect(container.children[2]).not.toHaveClass("umds-stat-card--sm");
|
|
18
|
+
});
|
|
19
|
+
it("o número do sm é 18px/800, e a regra vence o 32/800 do rótulo no topo", () => {
|
|
20
|
+
const regra = bloco(".umds-stat-card.umds-stat-card--sm .umds-stat-card__valor");
|
|
21
|
+
expect(regra).toMatch(/font-size:\s*1\.125rem/);
|
|
22
|
+
expect(regra).toMatch(/font-weight:\s*var\(--umds-primitive-font-weight-extrabold\)/);
|
|
23
|
+
const { container } = render(_jsx(StatCard, { value: 44, label: "N\u00E3o lidos", size: "sm", labelPosition: "top" }));
|
|
24
|
+
expect(container.firstElementChild).toHaveClass("umds-stat-card--sm", "umds-stat-card--rotulo-topo");
|
|
25
|
+
});
|
|
26
|
+
it("o número continua antes do rótulo no HTML", () => {
|
|
27
|
+
const { container } = render(_jsx(StatCard, { value: 44, label: "N\u00E3o lidos", size: "sm" }));
|
|
28
|
+
const valor = container.querySelector(".umds-stat-card__valor");
|
|
29
|
+
const rotulo = container.querySelector(".umds-stat-card__rotulo");
|
|
30
|
+
expect(valor.compareDocumentPosition(rotulo) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import Tabs from "../components/Tabs/Tabs";
|
|
4
|
+
import Tab from "../components/Tabs/Tab";
|
|
5
|
+
import { render } from "@testing-library/react";
|
|
6
|
+
import { lerArquivo } from "./lerArquivo";
|
|
7
|
+
const cssTabs = await lerArquivo("../core/src/components/Tabs/Tabs.css");
|
|
8
|
+
const CSS = { Tabs: cssTabs };
|
|
9
|
+
const css = (componente) => CSS[componente].replace(/\r\n/g, "\n");
|
|
10
|
+
const bloco = (texto, seletor) => {
|
|
11
|
+
const inicio = texto.indexOf(seletor + " {");
|
|
12
|
+
expect(inicio, seletor).toBeGreaterThanOrEqual(0);
|
|
13
|
+
return texto.slice(inicio, texto.indexOf("}", inicio));
|
|
14
|
+
};
|
|
15
|
+
describe("Tabs · density", () => {
|
|
16
|
+
it("compact escreve a classe na raiz; sem a prop e com default, não", () => {
|
|
17
|
+
const { container } = render(_jsxs(_Fragment, { children: [_jsx(Tabs, { value: "0", density: "compact", children: _jsx(Tab, { label: "A", index: "0" }) }), _jsx(Tabs, { value: "0", children: _jsx(Tab, { label: "B", index: "0" }) }), _jsx(Tabs, { value: "0", density: "default", children: _jsx(Tab, { label: "C", index: "0" }) })] }));
|
|
18
|
+
expect(container.children[0]).toHaveClass("umds-tabs--compact");
|
|
19
|
+
expect(container.children[1]).not.toHaveClass("umds-tabs--compact");
|
|
20
|
+
expect(container.children[2]).not.toHaveClass("umds-tabs--compact");
|
|
21
|
+
});
|
|
22
|
+
it("CSS: a compacta tem altura mínima de 40px (degrau sm) e padding vertical de 8px; o padrão segue em 48px", () => {
|
|
23
|
+
const t = css("Tabs");
|
|
24
|
+
const compacta = bloco(t, ".umds-tabs--compact .umds-tabs__tab");
|
|
25
|
+
expect(compacta).toMatch(/min-height:\s*var\(--umds-primitive-spacing-sm\)/);
|
|
26
|
+
expect(compacta).toMatch(/padding-block:\s*var\(--umds-primitive-spacing-nano\)/);
|
|
27
|
+
expect(bloco(t, ".umds-tabs__tab")).toMatch(/min-height:\s*48px/);
|
|
28
|
+
});
|
|
29
|
+
it("a pílula do contador é cinza na aba inativa e azul só na ativa (nas duas densidades)", () => {
|
|
30
|
+
const t = css("Tabs");
|
|
31
|
+
expect(bloco(t, ".umds-tabs__count")).toMatch(/background-color:\s*var\(--umds-semantic-color-neutral-light-medium\)/);
|
|
32
|
+
expect(bloco(t, ".umds-tabs__tab--selected .umds-tabs__count")).toMatch(/background-color:\s*var\(--umds-semantic-color-primary-pure\)/);
|
|
33
|
+
expect(t).not.toMatch(/--compact[^{]*\.umds-tabs__count/);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import Tag from "../components/Tag/Tag";
|
|
5
|
+
import { lerArquivo } from "./lerArquivo";
|
|
6
|
+
const cssTag = await lerArquivo("../core/src/components/Tag/Tag.css");
|
|
7
|
+
const tema1doc = await lerArquivo("../tokens/dist/css/theme-1doc.css");
|
|
8
|
+
const temaEscuro = await lerArquivo("../tokens/dist/css/theme-1doc-dark.css");
|
|
9
|
+
const temaAltoContraste = await lerArquivo("../tokens/dist/css/theme-1doc-high-contrast.css");
|
|
10
|
+
const css = cssTag.replace(/\r\n/g, "\n");
|
|
11
|
+
const bloco = (seletor) => {
|
|
12
|
+
const inicio = css.indexOf(seletor + " {");
|
|
13
|
+
return css.slice(inicio, css.indexOf("}", inicio));
|
|
14
|
+
};
|
|
15
|
+
const TEMAS = { "theme-1doc.css": tema1doc, "theme-1doc-dark.css": temaEscuro, "theme-1doc-high-contrast.css": temaAltoContraste };
|
|
16
|
+
const tema = (arquivo) => {
|
|
17
|
+
const texto = TEMAS[arquivo];
|
|
18
|
+
const cor = (nome) => texto.match(new RegExp("--umds-theme-" + nome + ":\\s*(#[0-9A-Fa-f]{6})"))[1];
|
|
19
|
+
return cor;
|
|
20
|
+
};
|
|
21
|
+
const luz = (hex) => {
|
|
22
|
+
const c = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255).map((v) => (v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4));
|
|
23
|
+
return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
|
|
24
|
+
};
|
|
25
|
+
const contraste = (a, b) => {
|
|
26
|
+
const [x, y] = [luz(a), luz(b)].sort((m, n) => n - m);
|
|
27
|
+
return (x + 0.05) / (y + 0.05);
|
|
28
|
+
};
|
|
29
|
+
describe("Tag positive outlined sobre fundo tingido", () => {
|
|
30
|
+
it("escreve as classes que a regra de CSS escolhe", () => {
|
|
31
|
+
const { container } = render(_jsx(Tag, { label: "Entregue", variant: "positive", appearance: "outlined" }));
|
|
32
|
+
const tag = container.firstElementChild;
|
|
33
|
+
expect(tag).toHaveClass("umds-tag--outlined", "umds-tag--positive");
|
|
34
|
+
});
|
|
35
|
+
it("o texto é positive-dark e o contorno segue positive-pure", () => {
|
|
36
|
+
const regra = bloco(".umds-tag--outlined.umds-tag--positive");
|
|
37
|
+
expect(regra).toMatch(/color:\s*var\(--umds-semantic-color-feedback-positive-dark\)/);
|
|
38
|
+
expect(regra).toMatch(/border-color:\s*var\(--umds-semantic-color-feedback-positive-pure\)/);
|
|
39
|
+
});
|
|
40
|
+
it("no tema 1doc, sobre o azul-claro do card o texto passa de 4,5:1 (o pure dava 3,6:1)", () => {
|
|
41
|
+
const cor = tema("theme-1doc.css");
|
|
42
|
+
const fundo = cor("primary-light");
|
|
43
|
+
expect(contraste(cor("feedback-positive-pure"), fundo)).toBeLessThan(4.5);
|
|
44
|
+
expect(contraste(cor("feedback-positive-dark"), fundo)).toBeGreaterThanOrEqual(4.5);
|
|
45
|
+
});
|
|
46
|
+
it("nos temas escuro e de alto contraste o texto também passa de 4,5:1 sobre o fundo tingido e sobre a página", () => {
|
|
47
|
+
for (const arquivo of ["theme-1doc-dark.css", "theme-1doc-high-contrast.css"]) {
|
|
48
|
+
const cor = tema(arquivo);
|
|
49
|
+
for (const fundo of [cor("primary-light"), cor("background-white")]) {
|
|
50
|
+
expect(contraste(cor("feedback-positive-dark"), fundo)).toBeGreaterThanOrEqual(4.5);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { act, fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import Toast from "../components/Toast/Toast";
|
|
5
|
+
import ToastStack from "../components/Toast/ToastStack";
|
|
6
|
+
import { dismissAllToasts, toast } from "../utils/toast";
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
act(() => dismissAllToasts());
|
|
9
|
+
});
|
|
10
|
+
describe("Toast · ação e detalhes", () => {
|
|
11
|
+
it("actionLabel com onAction desenha o botão; acionar chama onAction e fecha", () => {
|
|
12
|
+
const aoAgir = vi.fn();
|
|
13
|
+
const aoFechar = vi.fn();
|
|
14
|
+
render(_jsx(Toast, { open: true, message: "Despacho enviado", actionLabel: "Desfazer", onAction: aoAgir, onClose: aoFechar }));
|
|
15
|
+
fireEvent.click(screen.getByRole("button", { name: "Desfazer" }));
|
|
16
|
+
expect(aoAgir).toHaveBeenCalledTimes(1);
|
|
17
|
+
expect(aoFechar).toHaveBeenCalledTimes(1);
|
|
18
|
+
});
|
|
19
|
+
it("a ação roda antes de fechar", () => {
|
|
20
|
+
const ordem = [];
|
|
21
|
+
render(_jsx(Toast, { open: true, message: "x", actionLabel: "Ver processo", onAction: () => ordem.push("acao"), onClose: () => ordem.push("fechar") }));
|
|
22
|
+
fireEvent.click(screen.getByRole("button", { name: "Ver processo" }));
|
|
23
|
+
expect(ordem).toEqual(["acao", "fechar"]);
|
|
24
|
+
});
|
|
25
|
+
it("actionLabel sem onAction, ou onAction sem actionLabel, não desenha botão de ação", () => {
|
|
26
|
+
const { rerender } = render(_jsx(Toast, { open: true, message: "x", actionLabel: "Desfazer" }));
|
|
27
|
+
expect(screen.queryByRole("button", { name: "Desfazer" })).toBeNull();
|
|
28
|
+
rerender(_jsx(Toast, { open: true, message: "x", onAction: () => { } }));
|
|
29
|
+
expect(document.querySelector(".umds-toast__action")).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
it("details vira uma lista de linhas abaixo da descrição", () => {
|
|
32
|
+
render(_jsx(Toast, { open: true, message: "3 anexos n\u00E3o enviados", description: "Corrija e envie de novo.", details: ["Anexo 1 acima de 10 MB", "Anexo 2 sem assunto"] }));
|
|
33
|
+
const itens = screen.getAllByRole("listitem");
|
|
34
|
+
expect(itens.map((i) => i.textContent)).toEqual(["Anexo 1 acima de 10 MB", "Anexo 2 sem assunto"]);
|
|
35
|
+
});
|
|
36
|
+
it("sem details não há lista", () => {
|
|
37
|
+
render(_jsx(Toast, { open: true, message: "Salvo" }));
|
|
38
|
+
expect(document.querySelector(".umds-toast__details")).toBeNull();
|
|
39
|
+
});
|
|
40
|
+
it("o botão de fechar continua ao lado da ação", () => {
|
|
41
|
+
render(_jsx(Toast, { open: true, message: "x", actionLabel: "Desfazer", onAction: () => { } }));
|
|
42
|
+
expect(screen.getByRole("button", { name: "Fechar notificação" })).toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe("toast() imperativo com ação e detalhes", () => {
|
|
46
|
+
it("passa ação e detalhes ao ToastStack, e acionar a ação fecha o toast", () => {
|
|
47
|
+
const aoAgir = vi.fn();
|
|
48
|
+
render(_jsx(ToastStack, {}));
|
|
49
|
+
act(() => {
|
|
50
|
+
toast({ message: "Despacho enviado", details: ["SADM", "SOBR"], actionLabel: "Desfazer", onAction: aoAgir });
|
|
51
|
+
});
|
|
52
|
+
expect(screen.getByText("Despacho enviado")).toBeInTheDocument();
|
|
53
|
+
expect(screen.getAllByRole("listitem")).toHaveLength(2);
|
|
54
|
+
fireEvent.click(screen.getByRole("button", { name: "Desfazer" }));
|
|
55
|
+
expect(aoAgir).toHaveBeenCalledTimes(1);
|
|
56
|
+
expect(screen.queryByText("Despacho enviado")).toBeNull();
|
|
57
|
+
});
|
|
58
|
+
it("toast com ação não some sozinho (duration 0); sem ação continua em 5000", () => {
|
|
59
|
+
vi.useFakeTimers();
|
|
60
|
+
try {
|
|
61
|
+
render(_jsx(ToastStack, {}));
|
|
62
|
+
act(() => {
|
|
63
|
+
toast({ message: "Com ação", actionLabel: "Desfazer", onAction: () => { } });
|
|
64
|
+
toast({ message: "Sem ação" });
|
|
65
|
+
});
|
|
66
|
+
expect(screen.getByText("Com ação")).toBeInTheDocument();
|
|
67
|
+
expect(screen.getByText("Sem ação")).toBeInTheDocument();
|
|
68
|
+
act(() => {
|
|
69
|
+
vi.advanceTimersByTime(5100);
|
|
70
|
+
});
|
|
71
|
+
expect(screen.queryByText("Sem ação")).toBeNull();
|
|
72
|
+
expect(screen.getByText("Com ação")).toBeInTheDocument();
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
vi.useRealTimers();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
it("um duration explícito vale também com ação", () => {
|
|
79
|
+
vi.useFakeTimers();
|
|
80
|
+
try {
|
|
81
|
+
render(_jsx(ToastStack, {}));
|
|
82
|
+
act(() => {
|
|
83
|
+
toast({ message: "Curto", actionLabel: "Desfazer", onAction: () => { }, duration: 1000 });
|
|
84
|
+
});
|
|
85
|
+
act(() => {
|
|
86
|
+
vi.advanceTimersByTime(1100);
|
|
87
|
+
});
|
|
88
|
+
expect(screen.queryByText("Curto")).toBeNull();
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
vi.useRealTimers();
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function lerArquivo(relativo: string): Promise<string>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lê um arquivo do pacote (relativo à pasta `packages/react`) para os testes que conferem uma regra de CSS na
|
|
3
|
+
* fonte: o jsdom não tem cascata de arquivo, e o `css: false` do vitest esvazia o `?raw` do CSS.
|
|
4
|
+
* O `node:fs` entra por import dinâmico com nome calculado porque o `tsc` do pacote não traz os tipos do Node.
|
|
5
|
+
*/
|
|
6
|
+
const modulo = (nome) => import(/* @vite-ignore */ nome);
|
|
7
|
+
export async function lerArquivo(relativo) {
|
|
8
|
+
const fs = await modulo("node:fs");
|
|
9
|
+
const path = await modulo("node:path");
|
|
10
|
+
const raiz = globalThis.process.cwd();
|
|
11
|
+
return fs.readFileSync(path.resolve(raiz, relativo), "utf8");
|
|
12
|
+
}
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* fora (um valor guardado, um texto colado) pode trazer `<img onerror>`,
|
|
6
6
|
* `<a href="javascript:...">`, `<script>`, `style` e classes de outro site. Este
|
|
7
7
|
* módulo reduz o HTML ao que o editor sabe escrever: negrito, itálico,
|
|
8
|
-
* sublinhado, tachado, listas, parágrafos, quebras, títulos, citação
|
|
8
|
+
* sublinhado, tachado, listas, parágrafos, quebras, títulos, citação, link,
|
|
9
|
+
* estilo de texto por token (`color`, `font-size`, `font-family` em `<span>`),
|
|
10
|
+
* alinhamento de bloco (`text-align`), imagem (`http(s)`, caminho ou `data:image`
|
|
11
|
+
* em PNG, JPEG, GIF e WebP) e tabela simples.
|
|
9
12
|
*
|
|
10
13
|
* Roda no navegador (precisa de DOM). Dentro de um `<template>` o HTML é inerte:
|
|
11
14
|
* nada executa e nenhuma imagem carrega enquanto se higieniza. Sem DOM
|
|
@@ -19,8 +22,23 @@
|
|
|
19
22
|
export declare const enderecoSeguro: (bruto: string) => string;
|
|
20
23
|
/** Devolve o endereço pronto para `href`: o seguro como veio, ou `https://` + o texto quando não tem esquema. "" se perigoso ou vazio. */
|
|
21
24
|
export declare const normalizarEndereco: (bruto: string) => string;
|
|
25
|
+
/**
|
|
26
|
+
* Declaração de estilo de texto que o editor aceita: `color`, `font-size` e `font-family`,
|
|
27
|
+
* cada uma só com um token do DS. Devolve a declaração limpa ("color: var(--x);") ou "".
|
|
28
|
+
*/
|
|
29
|
+
export declare const estiloDeTexto: (propriedade: string, valor: string) => string;
|
|
30
|
+
/**
|
|
31
|
+
* Endereço de imagem que o editor aceita: `http(s)`, caminho (`/x`, `./x`, `../x`) ou
|
|
32
|
+
* `data:image` em base64 de PNG, JPEG, GIF ou WebP (SVG fica de fora: carrega script).
|
|
33
|
+
* Devolve o endereço limpo, ou "" se for perigoso ou vazio.
|
|
34
|
+
*/
|
|
35
|
+
export declare const imagemSegura: (bruto: string) => string;
|
|
22
36
|
/** Reduz `html` ao que o editor escreve. Sem DOM, devolve o texto escapado. */
|
|
23
37
|
export declare const sanitizarHtml: (html: string) => string;
|
|
38
|
+
/** A tabela vazia que o editor insere: `linhas` × `colunas` células com uma quebra, para o cursor entrar. */
|
|
39
|
+
export declare const htmlDaTabela: (linhas: number, colunas: number) => string;
|
|
40
|
+
/** O `<img>` que o editor insere (endereço já seguro). */
|
|
41
|
+
export declare const htmlDaImagem: (endereco: string, alt: string) => string;
|
|
24
42
|
/** O editor está "vazio": sem texto, sem lista e sem quebra solta (o `<br>` que o navegador deixa). */
|
|
25
43
|
export declare const htmlVazio: (html: string) => boolean;
|
|
26
44
|
/** O `<a>` que o editor escreve quando o link não tem texto escolhido: o endereço (já seguro) é o href e o texto. */
|