@evenicanpm/storefront-core 1.7.0 → 1.8.1
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/package.json +4 -3
- package/src/components-v2/T/__tests__/T.test.tsx +91 -0
- package/src/components-v2/accordion/__tests__/accordion-header.test.tsx +28 -0
- package/src/components-v2/carousel/__tests__/carousel.test.tsx +208 -0
- package/src/components-v2/carousel-cards/carousel-card-1/__tests__/carousel-card-1.test.tsx +81 -0
- package/src/components-v2/categories/__tests__/category-menu.test.tsx +115 -0
- package/src/components-v2/flex-box/__tests__/flex-box.test.tsx +88 -0
- package/src/components-v2/header/__tests__/header.test.tsx +122 -0
- package/src/components-v2/icons/__tests__/icons.test.tsx +53 -0
- package/src/components-v2/mobile-navigation/__tests__/mobile-navigation-bar.test.tsx +94 -0
- package/src/components-v2/nav-link/__tests__/nav-link.test.tsx +75 -0
- package/src/components-v2/navbar/__tests__/navbar.test.tsx +96 -0
- package/src/components-v2/product-cards/__tests__/product-cards.test.tsx +91 -0
- package/src/components-v2/product-dialog/__tests__/product-dialog.test.tsx +129 -0
- package/src/components-v2/product-dimensions/__tests__/product-dimensions.test.tsx +130 -0
- package/src/components-v2/product-quantity-buttons/__tests__/product-quantity-buttons.test.tsx +77 -0
- package/src/components-v2/product-quantity-variants/__tests__/product-quantity-variants.test.tsx +109 -0
- package/src/components-v2/products-view/__tests__/products-view.test.tsx +147 -0
- package/src/components-v2/progress/__tests__/progress.test.tsx +62 -0
- package/src/components-v2/scrollbar/__tests__/scrollbar.test.tsx +93 -0
- package/src/components-v2/search-bar/__tests__/search-bar.test.tsx +142 -0
- package/src/components-v2/section/__tests__/section.test.tsx +100 -0
- package/src/components-v2/side-nav/__tests__/side-nav.test.tsx +156 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evenicanpm/storefront-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "Core module for D365/e4 Headless Storefront",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"author": "Evenica",
|
|
17
17
|
"license": "ISC",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@evenicanpm/ui": "
|
|
19
|
+
"@evenicanpm/ui": "^1.8.1"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@storybook/addon-docs": "^9.1.6",
|
|
@@ -48,5 +48,6 @@
|
|
|
48
48
|
"@storybook/builder-manager": {
|
|
49
49
|
"esbuild": "0.19.11"
|
|
50
50
|
}
|
|
51
|
-
}
|
|
51
|
+
},
|
|
52
|
+
"gitHead": "07cfd4496c6a137e1420a6572298998b25b6369d"
|
|
52
53
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { vi } from "vitest";
|
|
3
|
+
import T from "../index";
|
|
4
|
+
|
|
5
|
+
vi.mock("next-intl", () => ({
|
|
6
|
+
useTranslations: vi.fn(() => (key: string) => {
|
|
7
|
+
const translations: Record<string, string> = {
|
|
8
|
+
"HomePage.welcome": "Welcome to our store",
|
|
9
|
+
"HomePage.products": "Products",
|
|
10
|
+
"Navigation.home": "Home",
|
|
11
|
+
"Navigation.about": "About Us",
|
|
12
|
+
"Common.loading": "Loading...",
|
|
13
|
+
"Common.error": "An error occurred",
|
|
14
|
+
};
|
|
15
|
+
return translations[key] || key;
|
|
16
|
+
}),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
describe("T (Translation Component)", () => {
|
|
20
|
+
it("renders translation for given path", () => {
|
|
21
|
+
render(<T path="HomePage.welcome" />);
|
|
22
|
+
expect(screen.getByText("Welcome to our store")).toBeInTheDocument();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("renders multiple translations", () => {
|
|
26
|
+
const { container } = render(
|
|
27
|
+
<>
|
|
28
|
+
<T path="HomePage.welcome" />
|
|
29
|
+
<T path="Navigation.home" />
|
|
30
|
+
</>,
|
|
31
|
+
);
|
|
32
|
+
const text = container.textContent || "";
|
|
33
|
+
expect(text).toContain("Welcome to our store");
|
|
34
|
+
expect(text).toContain("Home");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("renders fallback path when translation not found", () => {
|
|
38
|
+
render(<T path="Unknown.path" />);
|
|
39
|
+
expect(screen.getByText("Unknown.path")).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("handles nested translation paths", () => {
|
|
43
|
+
render(<T path="Navigation.home" />);
|
|
44
|
+
expect(screen.getByText("Home")).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("renders common translations", () => {
|
|
48
|
+
render(<T path="Common.loading" />);
|
|
49
|
+
expect(screen.getByText("Loading...")).toBeInTheDocument();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("renders multiple different paths together", () => {
|
|
53
|
+
const { container } = render(
|
|
54
|
+
<>
|
|
55
|
+
<T path="HomePage.welcome" />
|
|
56
|
+
<T path="Navigation.home" />
|
|
57
|
+
</>,
|
|
58
|
+
);
|
|
59
|
+
const text = container.textContent || "";
|
|
60
|
+
expect(text).toContain("Welcome to our store");
|
|
61
|
+
expect(text).toContain("Home");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("renders translation with special characters", () => {
|
|
65
|
+
render(<T path="Common.error" />);
|
|
66
|
+
expect(screen.getByText("An error occurred")).toBeInTheDocument();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("accepts dynamic paths", () => {
|
|
70
|
+
const paths = ["HomePage.welcome", "Navigation.home", "Common.loading"];
|
|
71
|
+
const { container } = render(
|
|
72
|
+
<>
|
|
73
|
+
{paths.map((path) => (
|
|
74
|
+
<T key={path} path={path} />
|
|
75
|
+
))}
|
|
76
|
+
</>,
|
|
77
|
+
);
|
|
78
|
+
const text = container.textContent || "";
|
|
79
|
+
expect(text).toContain("Welcome to our store");
|
|
80
|
+
expect(text).toContain("Home");
|
|
81
|
+
expect(text).toContain("Loading...");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("re-renders when path changes", () => {
|
|
85
|
+
const { rerender } = render(<T path="HomePage.welcome" />);
|
|
86
|
+
expect(screen.getByText("Welcome to our store")).toBeInTheDocument();
|
|
87
|
+
|
|
88
|
+
rerender(<T path="Navigation.home" />);
|
|
89
|
+
expect(screen.getByText("Home")).toBeInTheDocument();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import AccordionHeader from "../accordion-header";
|
|
3
|
+
|
|
4
|
+
describe("accordion-header", () => {
|
|
5
|
+
it("renders the provided header text", () => {
|
|
6
|
+
render(<AccordionHeader>Accordion Title</AccordionHeader>);
|
|
7
|
+
|
|
8
|
+
expect(screen.getByText("Accordion Title")).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("shows the caret icon by default", () => {
|
|
12
|
+
const { container } = render(
|
|
13
|
+
<AccordionHeader>Accordion With Icon</AccordionHeader>,
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
expect(container.querySelector(".caret")).toBeInTheDocument();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("hides the caret icon when showIcon is false", () => {
|
|
20
|
+
const { container } = render(
|
|
21
|
+
<AccordionHeader showIcon={false}>
|
|
22
|
+
Accordion Without Icon
|
|
23
|
+
</AccordionHeader>,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
expect(container.querySelector(".caret")).not.toBeInTheDocument();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { createTheme, ThemeProvider } from "@mui/material/styles";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import type React from "react";
|
|
4
|
+
import { vi } from "vitest";
|
|
5
|
+
import Carousel from "../carousel";
|
|
6
|
+
|
|
7
|
+
vi.mock("react-slick", () => {
|
|
8
|
+
const Slider = ({
|
|
9
|
+
children,
|
|
10
|
+
rtl,
|
|
11
|
+
autoplay,
|
|
12
|
+
autoplaySpeed,
|
|
13
|
+
slidesToShow,
|
|
14
|
+
arrows,
|
|
15
|
+
dots,
|
|
16
|
+
nextArrow,
|
|
17
|
+
prevArrow,
|
|
18
|
+
appendDots,
|
|
19
|
+
customPaging,
|
|
20
|
+
}: {
|
|
21
|
+
children: React.ReactNode;
|
|
22
|
+
rtl?: boolean;
|
|
23
|
+
autoplay?: boolean;
|
|
24
|
+
autoplaySpeed?: number;
|
|
25
|
+
slidesToShow?: number;
|
|
26
|
+
arrows?: boolean;
|
|
27
|
+
dots?: boolean;
|
|
28
|
+
nextArrow?: React.ReactNode;
|
|
29
|
+
prevArrow?: React.ReactNode;
|
|
30
|
+
appendDots?: (dots: React.ReactNode) => React.ReactNode;
|
|
31
|
+
customPaging?: (index: number) => React.ReactNode;
|
|
32
|
+
}) => (
|
|
33
|
+
<div
|
|
34
|
+
data-testid="mock-slider"
|
|
35
|
+
data-rtl={String(Boolean(rtl))}
|
|
36
|
+
data-autoplay={String(Boolean(autoplay))}
|
|
37
|
+
data-autoplay-speed={String(autoplaySpeed ?? "")}
|
|
38
|
+
data-slides-to-show={String(slidesToShow ?? "")}
|
|
39
|
+
data-arrows={String(Boolean(arrows))}
|
|
40
|
+
data-dots={String(Boolean(dots))}
|
|
41
|
+
>
|
|
42
|
+
<div data-testid="mock-arrows">
|
|
43
|
+
{nextArrow}
|
|
44
|
+
{prevArrow}
|
|
45
|
+
</div>
|
|
46
|
+
{dots && appendDots && customPaging ? (
|
|
47
|
+
<div data-testid="mock-dots">
|
|
48
|
+
{appendDots(<li>{customPaging(0)}</li>)}
|
|
49
|
+
</div>
|
|
50
|
+
) : null}
|
|
51
|
+
<div data-testid="mock-children">{children}</div>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
default: Slider,
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const renderWithTheme = (
|
|
61
|
+
ui: React.ReactElement,
|
|
62
|
+
direction: "ltr" | "rtl" = "ltr",
|
|
63
|
+
) => {
|
|
64
|
+
const theme = createTheme({ direction });
|
|
65
|
+
return render(<ThemeProvider theme={theme}>{ui}</ThemeProvider>);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
describe("carousel", () => {
|
|
69
|
+
it("renders slide content", () => {
|
|
70
|
+
renderWithTheme(
|
|
71
|
+
<Carousel>
|
|
72
|
+
<div>Slide One</div>
|
|
73
|
+
<div>Slide Two</div>
|
|
74
|
+
</Carousel>,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
expect(screen.getByText("Slide One")).toBeInTheDocument();
|
|
78
|
+
expect(screen.getByText("Slide Two")).toBeInTheDocument();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("enables custom arrows when arrows config is provided", () => {
|
|
82
|
+
renderWithTheme(
|
|
83
|
+
<Carousel arrows={{ sx: { color: "red" } }}>
|
|
84
|
+
<div>Slide</div>
|
|
85
|
+
</Carousel>,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const slider = screen.getByTestId("mock-slider");
|
|
89
|
+
expect(slider).toHaveAttribute("data-arrows", "true");
|
|
90
|
+
expect(document.querySelector(".next")).toBeInTheDocument();
|
|
91
|
+
expect(document.querySelector(".prev")).toBeInTheDocument();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("enables custom dots when dots config is provided", () => {
|
|
95
|
+
renderWithTheme(
|
|
96
|
+
<Carousel dots={{ dotColor: "orange" }}>
|
|
97
|
+
<div>Slide</div>
|
|
98
|
+
</Carousel>,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const slider = screen.getByTestId("mock-slider");
|
|
102
|
+
expect(slider).toHaveAttribute("data-dots", "true");
|
|
103
|
+
expect(screen.getByTestId("mock-dots")).toBeInTheDocument();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("enables custom arrows when legacy arrowStyles is provided", () => {
|
|
107
|
+
renderWithTheme(
|
|
108
|
+
<Carousel arrowStyles={{ color: "blue" }}>
|
|
109
|
+
<div>Slide</div>
|
|
110
|
+
</Carousel>,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const slider = screen.getByTestId("mock-slider");
|
|
114
|
+
expect(slider).toHaveAttribute("data-arrows", "true");
|
|
115
|
+
expect(document.querySelector(".next")).toBeInTheDocument();
|
|
116
|
+
expect(document.querySelector(".prev")).toBeInTheDocument();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("uses react-slick default arrows when arrows is true", () => {
|
|
120
|
+
renderWithTheme(
|
|
121
|
+
<Carousel arrows={true}>
|
|
122
|
+
<div>Slide</div>
|
|
123
|
+
</Carousel>,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const slider = screen.getByTestId("mock-slider");
|
|
127
|
+
expect(slider).toHaveAttribute("data-arrows", "true");
|
|
128
|
+
expect(document.querySelector(".next")).not.toBeInTheDocument();
|
|
129
|
+
expect(document.querySelector(".prev")).not.toBeInTheDocument();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("disables arrows by default", () => {
|
|
133
|
+
renderWithTheme(
|
|
134
|
+
<Carousel>
|
|
135
|
+
<div>Slide</div>
|
|
136
|
+
</Carousel>,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
expect(screen.getByTestId("mock-slider")).toHaveAttribute(
|
|
140
|
+
"data-arrows",
|
|
141
|
+
"false",
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("enables custom dots when legacy dotColor or dotStyles is provided", () => {
|
|
146
|
+
renderWithTheme(
|
|
147
|
+
<Carousel dotColor="green" dotStyles={{ bottom: 0 }}>
|
|
148
|
+
<div>Slide</div>
|
|
149
|
+
</Carousel>,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const slider = screen.getByTestId("mock-slider");
|
|
153
|
+
expect(slider).toHaveAttribute("data-dots", "true");
|
|
154
|
+
expect(screen.getByTestId("mock-dots")).toBeInTheDocument();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("uses react-slick default dots when dots is true", () => {
|
|
158
|
+
renderWithTheme(
|
|
159
|
+
<Carousel dots={true}>
|
|
160
|
+
<div>Slide</div>
|
|
161
|
+
</Carousel>,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const slider = screen.getByTestId("mock-slider");
|
|
165
|
+
expect(slider).toHaveAttribute("data-dots", "true");
|
|
166
|
+
expect(screen.queryByTestId("mock-dots")).not.toBeInTheDocument();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("disables dots by default", () => {
|
|
170
|
+
renderWithTheme(
|
|
171
|
+
<Carousel>
|
|
172
|
+
<div>Slide</div>
|
|
173
|
+
</Carousel>,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
expect(screen.getByTestId("mock-slider")).toHaveAttribute(
|
|
177
|
+
"data-dots",
|
|
178
|
+
"false",
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("passes rtl setting from theme direction", () => {
|
|
183
|
+
renderWithTheme(
|
|
184
|
+
<Carousel>
|
|
185
|
+
<div>RTL Slide</div>
|
|
186
|
+
</Carousel>,
|
|
187
|
+
"rtl",
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
expect(screen.getByTestId("mock-slider")).toHaveAttribute(
|
|
191
|
+
"data-rtl",
|
|
192
|
+
"true",
|
|
193
|
+
);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("passes autoplay and other settings through to slider", () => {
|
|
197
|
+
renderWithTheme(
|
|
198
|
+
<Carousel autoplay={true} autoplaySpeed={4500} slidesToShow={3}>
|
|
199
|
+
<div>Slide</div>
|
|
200
|
+
</Carousel>,
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const slider = screen.getByTestId("mock-slider");
|
|
204
|
+
expect(slider).toHaveAttribute("data-autoplay", "true");
|
|
205
|
+
expect(slider).toHaveAttribute("data-autoplay-speed", "4500");
|
|
206
|
+
expect(slider).toHaveAttribute("data-slides-to-show", "3");
|
|
207
|
+
});
|
|
208
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import CarouselCard1 from "../carousel-card-1";
|
|
3
|
+
|
|
4
|
+
describe("carousel-card-1", () => {
|
|
5
|
+
it("renders composed carousel card content", () => {
|
|
6
|
+
render(
|
|
7
|
+
<CarouselCard1>
|
|
8
|
+
<CarouselCard1.Info>
|
|
9
|
+
<CarouselCard1.Title title="Amazing Product" />
|
|
10
|
+
<CarouselCard1.Description description="Built for everyday comfort" />
|
|
11
|
+
<CarouselCard1.Button
|
|
12
|
+
buttonLink="/products/amazing"
|
|
13
|
+
buttonText="Buy Now"
|
|
14
|
+
/>
|
|
15
|
+
</CarouselCard1.Info>
|
|
16
|
+
<CarouselCard1.Image imgUrl="/images/product.png" />
|
|
17
|
+
</CarouselCard1>,
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
expect(
|
|
21
|
+
screen.getByRole("heading", { name: "Amazing Product" }),
|
|
22
|
+
).toBeInTheDocument();
|
|
23
|
+
expect(screen.getByText("Built for everyday comfort")).toBeInTheDocument();
|
|
24
|
+
expect(screen.getByRole("button", { name: "Buy Now" })).toBeInTheDocument();
|
|
25
|
+
expect(
|
|
26
|
+
screen.getByRole("img", { name: "carousel card image" }),
|
|
27
|
+
).toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("renders info section children", () => {
|
|
31
|
+
render(
|
|
32
|
+
<CarouselCard1.Info>
|
|
33
|
+
<div>Info content</div>
|
|
34
|
+
</CarouselCard1.Info>,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
expect(screen.getByText("Info content")).toBeInTheDocument();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("renders title text", () => {
|
|
41
|
+
render(<CarouselCard1.Title title="Featured Item" />);
|
|
42
|
+
|
|
43
|
+
expect(
|
|
44
|
+
screen.getByRole("heading", { name: "Featured Item" }),
|
|
45
|
+
).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("renders description text", () => {
|
|
49
|
+
render(<CarouselCard1.Description description="Limited time offer" />);
|
|
50
|
+
|
|
51
|
+
expect(screen.getByText("Limited time offer")).toBeInTheDocument();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("renders button with link and text", () => {
|
|
55
|
+
render(<CarouselCard1.Button buttonLink="/sale" buttonText="Shop Sale" />);
|
|
56
|
+
|
|
57
|
+
expect(
|
|
58
|
+
screen.getByRole("button", { name: "Shop Sale" }),
|
|
59
|
+
).toBeInTheDocument();
|
|
60
|
+
expect(screen.getByRole("link", { name: "Shop Sale" })).toHaveAttribute(
|
|
61
|
+
"href",
|
|
62
|
+
"/sale",
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("renders image with provided source", () => {
|
|
67
|
+
render(<CarouselCard1.Image imgUrl="/images/carousel-item.png" />);
|
|
68
|
+
|
|
69
|
+
expect(
|
|
70
|
+
screen.getByRole("img", { name: "carousel card image" }),
|
|
71
|
+
).toHaveAttribute("src", "/images/carousel-item.png");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("renders image with empty source when imgUrl is not provided", () => {
|
|
75
|
+
render(<CarouselCard1.Image />);
|
|
76
|
+
|
|
77
|
+
expect(
|
|
78
|
+
screen.getByRole("img", { name: "carousel card image" }),
|
|
79
|
+
).not.toHaveAttribute("src");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
2
|
+
import { vi } from "vitest";
|
|
3
|
+
import CategoryMenu from "../category-menu";
|
|
4
|
+
|
|
5
|
+
vi.mock(
|
|
6
|
+
"@evenicanpm/storefront-core/src/components-v2/categories/category-list/index",
|
|
7
|
+
() => ({
|
|
8
|
+
default: ({ open }: { open: boolean }) => (
|
|
9
|
+
<div data-testid="category-list" data-open={String(open)}>
|
|
10
|
+
Category List
|
|
11
|
+
</div>
|
|
12
|
+
),
|
|
13
|
+
}),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
describe("category-menu", () => {
|
|
17
|
+
it("renders with the provided render prop", () => {
|
|
18
|
+
render(
|
|
19
|
+
<CategoryMenu
|
|
20
|
+
render={(handler) => (
|
|
21
|
+
<button type="button" onClick={handler} data-testid="toggle-btn">
|
|
22
|
+
Toggle Categories
|
|
23
|
+
</button>
|
|
24
|
+
)}
|
|
25
|
+
/>,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
expect(screen.getByTestId("toggle-btn")).toBeInTheDocument();
|
|
29
|
+
expect(screen.getByTestId("category-list")).toBeInTheDocument();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("toggles dropdown open state on click", () => {
|
|
33
|
+
render(
|
|
34
|
+
<CategoryMenu
|
|
35
|
+
render={(handler) => (
|
|
36
|
+
<button type="button" onClick={handler} data-testid="toggle-btn">
|
|
37
|
+
Toggle
|
|
38
|
+
</button>
|
|
39
|
+
)}
|
|
40
|
+
/>,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const button = screen.getByTestId("toggle-btn");
|
|
44
|
+
const categoryList = screen.getByTestId("category-list");
|
|
45
|
+
|
|
46
|
+
expect(categoryList).toHaveAttribute("data-open", "false");
|
|
47
|
+
|
|
48
|
+
fireEvent.click(button);
|
|
49
|
+
expect(categoryList).toHaveAttribute("data-open", "true");
|
|
50
|
+
|
|
51
|
+
fireEvent.click(button);
|
|
52
|
+
expect(categoryList).toHaveAttribute("data-open", "false");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("closes dropdown when clicking outside", () => {
|
|
56
|
+
render(
|
|
57
|
+
<div>
|
|
58
|
+
<CategoryMenu
|
|
59
|
+
render={(handler) => (
|
|
60
|
+
<button type="button" onClick={handler} data-testid="toggle-btn">
|
|
61
|
+
Toggle
|
|
62
|
+
</button>
|
|
63
|
+
)}
|
|
64
|
+
/>
|
|
65
|
+
<div data-testid="outside">Outside Element</div>
|
|
66
|
+
</div>,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const button = screen.getByTestId("toggle-btn");
|
|
70
|
+
const categoryList = screen.getByTestId("category-list");
|
|
71
|
+
const outside = screen.getByTestId("outside");
|
|
72
|
+
|
|
73
|
+
fireEvent.click(button);
|
|
74
|
+
expect(categoryList).toHaveAttribute("data-open", "true");
|
|
75
|
+
|
|
76
|
+
fireEvent.click(outside);
|
|
77
|
+
expect(categoryList).toHaveAttribute("data-open", "false");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("does not close dropdown when clicking inside it", () => {
|
|
81
|
+
render(
|
|
82
|
+
<CategoryMenu
|
|
83
|
+
render={(handler) => (
|
|
84
|
+
<button type="button" onClick={handler} data-testid="toggle-btn">
|
|
85
|
+
Toggle
|
|
86
|
+
</button>
|
|
87
|
+
)}
|
|
88
|
+
/>,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const button = screen.getByTestId("toggle-btn");
|
|
92
|
+
const categoryList = screen.getByTestId("category-list");
|
|
93
|
+
|
|
94
|
+
fireEvent.click(button);
|
|
95
|
+
expect(categoryList).toHaveAttribute("data-open", "true");
|
|
96
|
+
|
|
97
|
+
fireEvent.click(categoryList);
|
|
98
|
+
expect(categoryList).toHaveAttribute("data-open", "true");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("applies dropdown-icon styling", () => {
|
|
102
|
+
const { container } = render(
|
|
103
|
+
<CategoryMenu
|
|
104
|
+
render={(handler) => (
|
|
105
|
+
<button type="button" onClick={handler}>
|
|
106
|
+
<span className="dropdown-icon">Icon</span>
|
|
107
|
+
</button>
|
|
108
|
+
)}
|
|
109
|
+
/>,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const icon = container.querySelector(".dropdown-icon");
|
|
113
|
+
expect(icon).toBeInTheDocument();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import FlexBox from "../flex-box";
|
|
3
|
+
import FlexBetween from "../flex-between";
|
|
4
|
+
import FlexRowCenter from "../flex-row-center";
|
|
5
|
+
|
|
6
|
+
describe("FlexBox components", () => {
|
|
7
|
+
describe("FlexBox", () => {
|
|
8
|
+
it("renders children and applies flex display", () => {
|
|
9
|
+
render(
|
|
10
|
+
<FlexBox data-testid="flex-box-test">
|
|
11
|
+
<div>Child 1</div>
|
|
12
|
+
<div>Child 2</div>
|
|
13
|
+
</FlexBox>,
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
expect(screen.getByText("Child 1")).toBeInTheDocument();
|
|
17
|
+
expect(screen.getByText("Child 2")).toBeInTheDocument();
|
|
18
|
+
expect(screen.getByTestId("flex-box-test")).toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("accepts and applies custom BoxProps", () => {
|
|
22
|
+
render(
|
|
23
|
+
<FlexBox data-testid="flex-box" gap={2} padding={1}>
|
|
24
|
+
Content
|
|
25
|
+
</FlexBox>,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const box = screen.getByTestId("flex-box");
|
|
29
|
+
expect(box).toBeInTheDocument();
|
|
30
|
+
expect(box).toHaveStyle("display: flex");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("FlexBetween", () => {
|
|
35
|
+
it("renders children with space-between and center alignment", () => {
|
|
36
|
+
render(
|
|
37
|
+
<FlexBetween data-testid="flex-between">
|
|
38
|
+
<div>Left</div>
|
|
39
|
+
<div>Right</div>
|
|
40
|
+
</FlexBetween>,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
expect(screen.getByText("Left")).toBeInTheDocument();
|
|
44
|
+
expect(screen.getByText("Right")).toBeInTheDocument();
|
|
45
|
+
|
|
46
|
+
const box = screen.getByTestId("flex-between");
|
|
47
|
+
expect(box).toHaveStyle("display: flex");
|
|
48
|
+
expect(box).toHaveStyle("justify-content: space-between");
|
|
49
|
+
expect(box).toHaveStyle("align-items: center");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("accepts custom props", () => {
|
|
53
|
+
render(
|
|
54
|
+
<FlexBetween data-testid="flex-between-custom" sx={{ height: 100 }}>
|
|
55
|
+
Content
|
|
56
|
+
</FlexBetween>,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
expect(screen.getByTestId("flex-between-custom")).toBeInTheDocument();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("FlexRowCenter", () => {
|
|
64
|
+
it("renders children centered both horizontally and vertically", () => {
|
|
65
|
+
render(
|
|
66
|
+
<FlexRowCenter data-testid="flex-row-center">
|
|
67
|
+
<span>Centered</span>
|
|
68
|
+
</FlexRowCenter>,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const box = screen.getByTestId("flex-row-center");
|
|
72
|
+
expect(screen.getByText("Centered")).toBeInTheDocument();
|
|
73
|
+
expect(box).toHaveStyle("display: flex");
|
|
74
|
+
expect(box).toHaveStyle("justify-content: center");
|
|
75
|
+
expect(box).toHaveStyle("align-items: center");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("applies custom styles", () => {
|
|
79
|
+
render(
|
|
80
|
+
<FlexRowCenter data-testid="flex-row-custom" minHeight={200}>
|
|
81
|
+
Flex Center
|
|
82
|
+
</FlexRowCenter>,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(screen.getByTestId("flex-row-custom")).toBeInTheDocument();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|