|
4 | 4 | */ |
5 | 5 |
|
6 | 6 | import React from "react" |
7 | | -import { render, screen, cleanup, act, fireEvent } from "@testing-library/react" |
8 | | -import { SideNavigation } from "../SideNavigation/SideNavigation.component" |
| 7 | +import { render, screen, cleanup, fireEvent } from "@testing-library/react" |
9 | 8 | import { SideNavigationItem } from "./SideNavigationItem.component" |
10 | 9 |
|
11 | | -const mockOnClick = vi.fn() |
12 | | - |
13 | 10 | describe("SideNavigationItem", () => { |
14 | 11 | afterEach(() => { |
15 | 12 | cleanup() |
16 | | - vi.clearAllMocks() |
17 | | - }) |
18 | | - |
19 | | - test("renders a SideNavigationItem", () => { |
20 | | - render(<SideNavigationItem data-testid="side-nav-item" />) |
21 | | - expect(screen.getByTestId("side-nav-item")).toBeInTheDocument() |
22 | | - expect(screen.getByTestId("side-nav-item")).toHaveClass("juno-sidenavigation-item") |
23 | | - }) |
24 | | - |
25 | | - test("renders a label as passed", () => { |
26 | | - render(<SideNavigationItem label="My Label" />) |
27 | | - expect(screen.getByRole("button")).toBeInTheDocument() |
28 | | - expect(screen.getByRole("button")).toHaveTextContent("My Label") |
29 | | - }) |
30 | | - |
31 | | - test("renders children as passed", () => { |
32 | | - render(<SideNavigationItem>The Item Is A Child</SideNavigationItem>) |
33 | | - expect(screen.getByRole("button")).toBeInTheDocument() |
34 | | - expect(screen.getByRole("button")).toHaveTextContent("The Item Is A Child") |
35 | 13 | }) |
36 | 14 |
|
37 | | - test("renders an aria-label as passed", () => { |
38 | | - render(<SideNavigationItem ariaLabel="My ARIA-Label" />) |
39 | | - expect(screen.getByRole("button")).toBeInTheDocument() |
40 | | - expect(screen.getByRole("button")).toHaveAttribute("aria-label", "My ARIA-Label") |
| 15 | + it("renders with default properties", () => { |
| 16 | + render(<SideNavigationItem label="Home" />) |
| 17 | + const itemElement = screen.getByText("Home") |
| 18 | + expect(itemElement).toBeInTheDocument() |
41 | 19 | }) |
42 | 20 |
|
43 | | - test("renders an aria-label as passed, role link", () => { |
44 | | - render(<SideNavigationItem href="#" ariaLabel="hey nav item!" />) |
45 | | - expect(screen.getByRole("link")).toHaveAttribute("aria-label", "hey nav item!") |
| 21 | + it("applies disabled styles when disabled", () => { |
| 22 | + render(<SideNavigationItem label="Home" disabled />) |
| 23 | + const itemElement = screen.getByRole("button") |
| 24 | + expect(itemElement).toHaveClass("jn:opacity-50 jn:cursor-not-allowed") |
46 | 25 | }) |
47 | 26 |
|
48 | | - test("renders a disabled item as passed", () => { |
49 | | - render(<SideNavigationItem disabled />) |
50 | | - expect(screen.getByRole("button")).toBeInTheDocument() |
51 | | - expect(screen.getByRole("button")).toBeDisabled() |
52 | | - expect(screen.getByRole("button")).toHaveAttribute("aria-disabled", "true") |
53 | | - }) |
| 27 | + it("executes onClick handler when clicked", () => { |
| 28 | + const handleClick = vi.fn() |
| 29 | + render(<SideNavigationItem label="Clickable Item" onClick={handleClick} />) |
| 30 | + const clickableElement = screen.getByRole("button") |
54 | 31 |
|
55 | | - test("renders an icon as passed", () => { |
56 | | - render(<SideNavigationItem icon="warning" />) |
57 | | - expect(screen.getByRole("img")).toBeInTheDocument() |
58 | | - expect(screen.getByRole("img")).toHaveAttribute("alt", "warning") |
| 32 | + fireEvent.click(clickableElement) |
| 33 | + expect(handleClick).toHaveBeenCalledTimes(1) |
59 | 34 | }) |
60 | 35 |
|
61 | | - test("renders as a link when a href prop is passed", () => { |
62 | | - render(<SideNavigationItem href="#" />) |
63 | | - expect(screen.getByRole("link")).toBeInTheDocument() |
64 | | - expect(screen.getByRole("link")).toHaveClass("juno-sidenavigation-item") |
| 36 | + it("renders href as link and navigates correctly", () => { |
| 37 | + const href = "http://example.com" |
| 38 | + render(<SideNavigationItem label="External Link" href={href} />) |
| 39 | + const linkElement = screen.getByRole("link") |
| 40 | + expect(linkElement).toHaveAttribute("href", href) |
65 | 41 | }) |
66 | 42 |
|
67 | | - test("renders as a button when an onClick prop is passed", () => { |
| 43 | + it("toggles open state when clicked", () => { |
68 | 44 | render( |
69 | | - <SideNavigationItem |
70 | | - onClick={() => { |
71 | | - console.log("click") |
72 | | - }} |
73 | | - /> |
74 | | - ) |
75 | | - expect(screen.getByRole("button")).toBeInTheDocument() |
76 | | - expect(screen.getByRole("button")).toHaveClass("juno-sidenavigation-item") |
77 | | - }) |
78 | | - |
79 | | - test("renders an active NavigationItem as passed", () => { |
80 | | - render(<SideNavigationItem data-testid="side-nav-item" selected />) |
81 | | - expect(screen.getByRole("button")).toBeInTheDocument() |
82 | | - expect(screen.getByRole("button")).toHaveClass("juno-sidenavigation-item") |
83 | | - expect(screen.getByRole("button")).toHaveClass("juno-sidenavigation-item-selected") |
84 | | - expect(screen.getByRole("button")).toHaveAttribute("aria-selected", "true") |
85 | | - }) |
86 | | - |
87 | | - test("rerenders the active attribute of a navigation item", () => { |
88 | | - const { rerender } = render(<SideNavigationItem data-testid="side-nav-item" selected={true} />) |
89 | | - expect(screen.getByRole("button")).toBeInTheDocument() |
90 | | - expect(screen.getByRole("button")).toHaveClass("juno-sidenavigation-item-selected") |
91 | | - rerender(<SideNavigationItem data-testid="side-nav-item" selected={false} />) |
92 | | - expect(screen.getByRole("button")).toBeInTheDocument() |
93 | | - expect(screen.getByRole("button")).not.toHaveClass("juno-sidenavigation-item-selected") |
94 | | - }) |
95 | | - |
96 | | - test("executes an onClick handler as passed", () => { |
97 | | - render( |
98 | | - <SideNavigation> |
99 | | - <SideNavigationItem onClick={mockOnClick} label="My Item" /> |
100 | | - </SideNavigation> |
101 | | - ) |
102 | | - expect(screen.getByRole("button", { name: "My Item" })).toBeInTheDocument() |
103 | | - act(() => { |
104 | | - screen.getByRole("button", { name: "My Item" }).click() |
105 | | - }) |
106 | | - expect(mockOnClick).toHaveBeenCalled() |
107 | | - }) |
108 | | - |
109 | | - test("renders custom classNames as passed", () => { |
110 | | - render(<SideNavigationItem data-testid="side-nav-item" className="my-custom-class" />) |
111 | | - expect(screen.getByTestId("side-nav-item")).toHaveClass("my-custom-class") |
112 | | - }) |
113 | | - |
114 | | - test("renders all props as passed", () => { |
115 | | - render(<SideNavigationItem data-testid="side-nav-item" data-lol="Prop goes here" />) |
116 | | - expect(screen.getByTestId("side-nav-item")).toHaveAttribute("data-lol", "Prop goes here") |
117 | | - }) |
118 | | - |
119 | | - // test("handles href navigation when href is provided", () => { |
120 | | - // // Spy on window.location.assign method |
121 | | - // const locationSpy = jest.spyOn(window, "location", "get") |
122 | | - // const assignSpy = jest.fn() |
123 | | - // locationSpy.mockReturnValue({ |
124 | | - // assign: assignSpy, |
125 | | - // }) |
126 | | - |
127 | | - // render(<SideNavigationItem href="https://example.com" label="My Link Item" />) |
128 | | - // const linkItem = screen.getByRole("link", { name: "My Link Item" }) |
129 | | - |
130 | | - // fireEvent.click(linkItem) |
131 | | - |
132 | | - // expect(assignSpy).toHaveBeenCalledWith("https://example.com") // Check navigation call |
133 | | - |
134 | | - // // Clean up spies |
135 | | - // locationSpy.mockRestore() |
136 | | - // }) |
137 | | - |
138 | | - test("handles onClick when no href is provided", () => { |
139 | | - const mockOnClick = vi.fn() |
140 | | - |
141 | | - render(<SideNavigationItem onClick={mockOnClick} label="My Click Item" />) |
142 | | - const buttonItem = screen.getByRole("button", { name: "My Click Item" }) |
143 | | - |
144 | | - fireEvent.click(buttonItem) |
145 | | - expect(mockOnClick).toHaveBeenCalled() |
146 | | - }) |
147 | | - |
148 | | - test("prioritizes href over onClick if both are provided", () => { |
149 | | - const mockOnClick = vi.fn() |
150 | | - |
151 | | - render(<SideNavigationItem href="https://example.com" onClick={mockOnClick} label="My Item" />) |
152 | | - const linkItem = screen.getByRole("link", { name: "My Item" }) |
153 | | - |
154 | | - fireEvent.click(linkItem) |
155 | | - expect(window.location.href).toBe("https://example.com") |
156 | | - expect(mockOnClick).not.toHaveBeenCalled() // Ensure onClick is not triggered |
157 | | - }) |
158 | | - |
159 | | - test("renders expand icon for children and toggles open state", () => { |
160 | | - render( |
161 | | - <SideNavigationItem label="Parent Item"> |
162 | | - <SideNavigationItem label="Child Item" /> |
| 45 | + <SideNavigationItem label="Messages" open={false}> |
| 46 | + <SideNavigationItem label="Inbox" /> |
163 | 47 | </SideNavigationItem> |
164 | 48 | ) |
165 | 49 |
|
166 | | - const expandIcon = screen.getByRole("button", { |
167 | | - // Assumes aria-label or similar identifier for the icon |
168 | | - name: /expandMore|chevronRight/i, |
169 | | - }) |
170 | | - |
171 | | - expect(expandIcon).toBeInTheDocument() |
172 | | - |
173 | | - // Initially closed, expect children not in view |
174 | | - expect(screen.queryByText("Child Item")).not.toBeInTheDocument() |
175 | | - |
176 | | - fireEvent.click(expandIcon) |
| 50 | + const expandButton = screen.getAllByRole("button")[0] // To ensure correct element targeting |
| 51 | + fireEvent.click(expandButton) |
177 | 52 |
|
178 | | - // Check if children appear after click |
179 | | - expect(screen.getByText("Child Item")).toBeInTheDocument() |
| 53 | + const childElement = screen.getByText("Inbox") |
| 54 | + expect(childElement).toBeInTheDocument() |
180 | 55 | }) |
181 | 56 |
|
182 | | - test("does not collapse when item label is clicked if open", () => { |
| 57 | + it("does not toggle if disabled", () => { |
183 | 58 | render( |
184 | | - <SideNavigationItem label="Parent Item" open> |
185 | | - <SideNavigationItem label="Child Item" /> |
| 59 | + <SideNavigationItem label="Disabled Messages" disabled> |
| 60 | + <SideNavigationItem label="Inbox" /> |
186 | 61 | </SideNavigationItem> |
187 | 62 | ) |
188 | 63 |
|
189 | | - const item = screen.getByRole("button", { name: "Parent Item" }) |
190 | | - fireEvent.click(item) |
| 64 | + const expandButton = screen.getAllByRole("button")[0] // To ensure correct element targeting |
| 65 | + fireEvent.click(expandButton) |
191 | 66 |
|
192 | | - // Ensure item is still open after label click |
193 | | - expect(screen.getByText("Child Item")).toBeInTheDocument() |
| 67 | + const childElement = screen.queryByText("Inbox") |
| 68 | + expect(childElement).not.toBeInTheDocument() |
194 | 69 | }) |
195 | 70 |
|
196 | | - test("restricts children beyond level 3", () => { |
197 | | - render( |
198 | | - <SideNavigationItem label="Level 1"> |
199 | | - <SideNavigationItem label="Level 2"> |
200 | | - <SideNavigationItem label="Level 3"> |
201 | | - <SideNavigationItem label="Level 4" /> |
202 | | - </SideNavigationItem> |
203 | | - </SideNavigationItem> |
204 | | - </SideNavigationItem> |
205 | | - ) |
206 | | - |
207 | | - expect(screen.getByText("Level 1")).toBeInTheDocument() |
208 | | - expect(screen.getByText("Level 2")).toBeInTheDocument() |
209 | | - expect(screen.getByText("Level 3")).toBeInTheDocument() |
210 | | - expect(screen.queryByText("Level 4")).not.toBeInTheDocument() |
| 71 | + it("renders with selected styles when selected", () => { |
| 72 | + render(<SideNavigationItem label="Selected Item" selected />) |
| 73 | + const itemElement = screen.getByRole("button") |
| 74 | + expect(itemElement).toHaveClass("selected") |
211 | 75 | }) |
212 | 76 |
|
213 | | - test("ignores non-SideNavigationItem children", () => { |
214 | | - render( |
215 | | - <SideNavigationItem label="Parent Item"> |
216 | | - <span>Invalid Child</span> |
217 | | - <SideNavigationItem label="Valid Child" /> |
218 | | - </SideNavigationItem> |
219 | | - ) |
220 | | - |
221 | | - expect(screen.getByText("Parent Item")).toBeInTheDocument() |
222 | | - expect(screen.getByText("Valid Child")).toBeInTheDocument() |
223 | | - expect(screen.queryByText("Invalid Child")).not.toBeInTheDocument() |
| 77 | + it("renders Icon when icon prop is provided", () => { |
| 78 | + render(<SideNavigationItem label="Item with Icon" icon="home" />) |
| 79 | + // Check for the icon presence, depending on how Icon renders |
| 80 | + const iconElement = screen.getByRole("img") // Adjust role based on actual implementation |
| 81 | + expect(iconElement).toBeInTheDocument() |
224 | 82 | }) |
225 | 83 |
|
226 | | - test("applies css styles by level", () => { |
227 | | - render( |
228 | | - <SideNavigationItem label="Level 1"> |
229 | | - <SideNavigationItem label="Level 2"> |
230 | | - <SideNavigationItem label="Level 3" /> |
231 | | - </SideNavigationItem> |
232 | | - </SideNavigationItem> |
233 | | - ) |
234 | | - |
235 | | - const level1 = screen.getByText("Level 1") |
236 | | - const level2 = screen.getByText("Level 2") |
237 | | - const level3 = screen.getByText("Level 3") |
238 | | - |
239 | | - expect(level1).toHaveClass("juno-sidenavigation-item-content level-1") |
240 | | - expect(level2).toHaveClass("juno-sidenavigation-item-content level-2") |
241 | | - expect(level3).toHaveClass("juno-sidenavigation-item-content level-3") |
| 84 | + it("handles aria-label correctly", () => { |
| 85 | + render(<SideNavigationItem label="Aria Item" ariaLabel="Custom Aria Label" />) |
| 86 | + const itemElement = screen.getByRole("button") |
| 87 | + expect(itemElement).toHaveAttribute("aria-label", "Custom Aria Label") |
242 | 88 | }) |
243 | 89 | }) |
0 commit comments