Skip to content

Commit 801f08d

Browse files
fix type issue, tests
1 parent 27d549e commit 801f08d

7 files changed

Lines changed: 69 additions & 179 deletions

File tree

apps/greenhouse/src/components/core-apps/org-admin/components/SideNav.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
import React from "react"
7-
87
import { SideNavigation, SideNavigationItem, Badge } from "@cloudoperators/juno-ui-components"
98
import { useActivePlugin, useActions } from "../StoreProvider"
109

@@ -24,7 +23,7 @@ const SideNav = () => {
2423
<SideNavigation>
2524
{PLUGINS.map((plugin, index) => (
2625
<SideNavigationItem key={index} active={plugin.name === active} onClick={() => setActive(plugin.name)}>
27-
{plugin.label} {plugin.beta && <Badge text="beta" variant="info" />}
26+
{plugin.label} {plugin.beta ? <Badge text="beta" variant="info" /> : null}
2827
</SideNavigationItem>
2928
))}
3029
</SideNavigation>

packages/ui-components/src/components/SideNavigation/SideNavigation.stories.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ export const NavigationWithGroups: Story = {
8484
},
8585
}
8686

87-
// Add more complex examples to showcase different functionalities
88-
8987
export const InteractiveNavigation: Story = {
9088
render: (args) => (
9189
<SideNavigation {...args} onActiveItemChange={(item) => console.log("Active item changed:", item)}>

packages/ui-components/src/components/SideNavigation/SideNavigation.test.tsx

Lines changed: 44 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -3,202 +3,83 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import React from "react"
7-
import { render, screen, cleanup, act } from "@testing-library/react"
8-
import { SideNavigation } from "./index"
9-
import { SideNavigationItem } from "../SideNavigationItem/index"
10-
11-
const mockOnActiveItemChange = vi.fn()
6+
import React, { ReactNode } from "react"
7+
import { render, screen, fireEvent } from "@testing-library/react"
8+
import { SideNavigation } from "./SideNavigation.component"
9+
import { SideNavigationItem } from "../SideNavigationItem"
1210

1311
describe("SideNavigation", () => {
14-
afterEach(() => {
15-
cleanup()
16-
vi.clearAllMocks()
17-
})
18-
19-
test("render a SideNavigation", () => {
20-
render(<SideNavigation />)
21-
expect(screen.getByRole("navigation")).toBeInTheDocument()
22-
expect(screen.getByRole("navigation")).toHaveClass("juno-sidenavigation")
12+
it("renders correctly without children", () => {
13+
render(<SideNavigation ariaLabel="Test Navigation" />)
14+
const navigationElement = screen.getByRole("navigation")
15+
expect(navigationElement).toBeInTheDocument()
2316
})
2417

25-
test("renders children as passed", () => {
18+
it("renders children correctly", () => {
2619
render(
27-
<SideNavigation>
28-
<SideNavigationItem label="Item 1" key="i-1" />
29-
<SideNavigationItem label="Item 2" key="i-2" />
30-
<SideNavigationItem label="Item 3" key="i-3" />
20+
<SideNavigation ariaLabel="Test Navigation">
21+
<SideNavigationItem label="Home" />
22+
<SideNavigationItem label="Messages" />
3123
</SideNavigation>
3224
)
33-
expect(screen.getByRole("navigation")).toBeInTheDocument()
34-
expect(screen.queryAllByRole("button")).toHaveLength(3)
35-
expect(screen.getByRole("button", { name: "Item 1" })).toBeInTheDocument()
36-
expect(screen.getByRole("button", { name: "Item 2" })).toBeInTheDocument()
37-
expect(screen.getByRole("button", { name: "Item 3" })).toBeInTheDocument()
38-
})
3925

40-
test("renders an aria-label as passed", () => {
41-
render(<SideNavigation ariaLabel="describe the navigation" />)
42-
expect(screen.getByRole("navigation")).toBeInTheDocument()
43-
expect(screen.getByRole("navigation")).toHaveAttribute("aria-label", "describe the navigation")
26+
expect(screen.getByText("Home")).toBeInTheDocument()
27+
expect(screen.getByText("Messages")).toBeInTheDocument()
4428
})
4529

46-
test("renders disabled children as passed", () => {
30+
it("applies provided className", () => {
4731
render(
48-
<SideNavigation disabled>
49-
<SideNavigationItem label="Item 1" />
50-
<SideNavigationItem label="Item 2" />
32+
<SideNavigation ariaLabel="Test Navigation" className="custom-class">
33+
<SideNavigationItem label="Home" />
5134
</SideNavigation>
5235
)
53-
expect(screen.getByRole("navigation")).toBeInTheDocument()
54-
expect(screen.queryAllByRole("button")).toHaveLength(2)
55-
expect(screen.getByRole("button", { name: "Item 1" })).toBeInTheDocument()
56-
expect(screen.getByRole("button", { name: "Item 1" })).toBeDisabled()
57-
expect(screen.getByRole("button", { name: "Item 1" })).toHaveAttribute("aria-disabled", "true")
58-
expect(screen.getByRole("button", { name: "Item 2" })).toBeInTheDocument()
59-
expect(screen.getByRole("button", { name: "Item 2" })).toBeDisabled()
60-
expect(screen.getByRole("button", { name: "Item 2" })).toHaveAttribute("aria-disabled", "true")
61-
})
6236

63-
test("renders an active navigation item as passed", () => {
64-
render(
65-
<SideNavigation activeItem="Item 2">
66-
<SideNavigationItem label="Item 1" />
67-
<SideNavigationItem label="Item 2" />
68-
</SideNavigation>
69-
)
70-
expect(screen.getByRole("navigation")).toBeInTheDocument()
71-
expect(screen.queryAllByRole("button")).toHaveLength(2)
72-
expect(screen.getByRole("button", { name: "Item 1" })).toBeInTheDocument()
73-
expect(screen.getByRole("button", { name: "Item 1" })).not.toHaveAttribute("aria-selected")
74-
expect(screen.getByRole("button", { name: "Item 1" })).not.toHaveClass("juno-navigation-item-active")
75-
expect(screen.getByRole("button", { name: "Item 2" })).toBeInTheDocument()
76-
expect(screen.getByRole("button", { name: "Item 2" })).toHaveAttribute("aria-selected", "true")
77-
expect(screen.getByRole("button", { name: "Item 2" })).toHaveClass("juno-navigation-item-active")
37+
const navigationElement = screen.getByRole("navigation")
38+
expect(navigationElement).toHaveClass("custom-class")
7839
})
7940

80-
test("renders an active navigation item as passed by value", () => {
81-
render(
82-
<SideNavigation activeItem="i-2">
83-
<SideNavigationItem label="Item 1" />
84-
<SideNavigationItem label="Item 2" />
85-
</SideNavigation>
86-
)
87-
expect(screen.getByRole("navigation")).toBeInTheDocument()
88-
expect(screen.queryAllByRole("button")).toHaveLength(2)
89-
expect(screen.getByRole("button", { name: "Item 1" })).toBeInTheDocument()
90-
expect(screen.getByRole("button", { name: "Item 1" })).not.toHaveAttribute("aria-selected")
91-
expect(screen.getByRole("button", { name: "Item 1" })).not.toHaveClass("juno-navigation-item-active")
92-
expect(screen.getByRole("button", { name: "Item 2" })).toBeInTheDocument()
93-
expect(screen.getByRole("button", { name: "Item 2" })).toHaveAttribute("aria-selected", "true")
94-
expect(screen.getByRole("button", { name: "Item 2" })).toHaveClass("juno-navigation-item-active")
95-
})
41+
it("calls onActiveItemChange when item is clicked", () => {
42+
const handleActiveItemChange = vi.fn((_activeItem: ReactNode): void => {})
9643

97-
test("renders the active item as passed to the parent if conflicting with active prop passed to child item", () => {
9844
render(
99-
<SideNavigation activeItem="Item 2">
100-
<SideNavigationItem label="Item 1" selected />
101-
<SideNavigationItem label="Item 2" />
45+
<SideNavigation ariaLabel="Test Navigation" onActiveItemChange={handleActiveItemChange}>
46+
<SideNavigationItem label="Item 1" onClick={() => handleActiveItemChange("Item 1")} />
47+
<SideNavigationItem label="Item 2" onClick={() => handleActiveItemChange("Item 2")} />
10248
</SideNavigation>
10349
)
104-
expect(screen.getByRole("navigation")).toBeInTheDocument()
105-
expect(screen.queryAllByRole("button")).toHaveLength(2)
106-
expect(screen.getByRole("button", { name: "Item 1" })).toBeInTheDocument()
107-
expect(screen.getByRole("button", { name: "Item 1" })).not.toHaveAttribute("aria-selected")
108-
expect(screen.getByRole("button", { name: "Item 1" })).not.toHaveClass("juno-navigation-item-active")
109-
expect(screen.getByRole("button", { name: "Item 2" })).toBeInTheDocument()
110-
expect(screen.getByRole("button", { name: "Item 2" })).toHaveAttribute("aria-selected", "true")
111-
expect(screen.getByRole("button", { name: "Item 2" })).toHaveClass("juno-navigation-item-active")
112-
})
11350

114-
test("rerenders the active item as passed to the parent if conflicting with new state of active prop passed to child item", () => {
115-
const { rerender } = render(
116-
<SideNavigation activeItem="Item 2">
117-
<SideNavigationItem label="Item 1" />
118-
<SideNavigationItem label="Item 2" />
119-
</SideNavigation>
120-
)
121-
expect(screen.getByRole("button", { name: "Item 1" })).not.toHaveClass("juno-navigation-item-active")
122-
expect(screen.getByRole("button", { name: "Item 2" })).toHaveClass("juno-navigation-item-active")
123-
rerender(
124-
<SideNavigation activeItem="Item 1">
125-
<SideNavigationItem label="Item 1" />
126-
<SideNavigationItem label="Item 2" />
127-
</SideNavigation>
128-
)
129-
expect(screen.getByRole("button", { name: "Item 1" })).toHaveClass("juno-navigation-item-active")
130-
expect(screen.getByRole("button", { name: "Item 2" })).not.toHaveClass("juno-navigation-item-active")
131-
})
51+
const item1 = screen.getByText("Item 1")
52+
fireEvent.click(item1)
53+
expect(handleActiveItemChange).toHaveBeenCalledWith("Item 1")
13254

133-
test("rerenders the active item as passed to the parent if conflicting with new state of active prop passed to child item, 4 items", () => {
134-
const { rerender } = render(
135-
<SideNavigation activeItem="Item 2">
136-
<SideNavigationItem label="Item 1" selected />
137-
<SideNavigationItem label="Item 2" />
138-
<SideNavigationItem label="Item 3" />
139-
</SideNavigation>
140-
)
141-
expect(screen.getByRole("button", { name: "Item 2" })).toHaveClass("juno-navigation-item-active")
142-
expect(screen.getByRole("button", { name: "Item 1" })).not.toHaveClass("juno-navigation-item-active")
143-
expect(screen.getByRole("button", { name: "Item 3" })).not.toHaveClass("juno-navigation-item-active")
144-
rerender(
145-
<SideNavigation activeItem="Item 2">
146-
<SideNavigationItem label="Item 1" />
147-
<SideNavigationItem label="Item 2" />
148-
<SideNavigationItem label="Item 3" selected />
149-
</SideNavigation>
150-
)
151-
expect(screen.getByRole("button", { name: "Item 2" })).toHaveClass("juno-navigation-item-active")
152-
expect(screen.getByRole("button", { name: "Item 1" })).not.toHaveClass("juno-navigation-item-active")
153-
expect(screen.getByRole("button", { name: "Item 3" })).not.toHaveClass("juno-navigation-item-active")
55+
const item2 = screen.getByText("Item 2")
56+
fireEvent.click(item2)
57+
expect(handleActiveItemChange).toHaveBeenCalledWith("Item 2")
15458
})
15559

156-
test("changes the active item when the user clicks", () => {
60+
it("does not call onActiveItemChange if navigation is disabled", () => {
61+
const handleActiveItemChange = vi.fn()
62+
15763
render(
158-
<SideNavigation activeItem="Item 1">
64+
<SideNavigation ariaLabel="Test Navigation" disabled onActiveItemChange={handleActiveItemChange}>
15965
<SideNavigationItem label="Item 1" />
160-
<SideNavigationItem label="Item 2" />
16166
</SideNavigation>
16267
)
163-
expect(screen.getByRole("navigation")).toBeInTheDocument()
164-
expect(screen.queryAllByRole("button")).toHaveLength(2)
165-
const tab1 = screen.getByRole("button", { name: "Item 1" })
166-
const tab2 = screen.getByRole("button", { name: "Item 2" })
167-
expect(tab1).toHaveAttribute("aria-selected", "true")
168-
expect(tab1).toHaveClass("juno-navigation-item-active")
169-
expect(tab2).not.toHaveAttribute("aria-selected")
170-
expect(tab2).not.toHaveClass("juno-navigation-item-active")
171-
act(() => {
172-
tab2.click()
173-
})
174-
expect(tab1).not.toHaveAttribute("aria-selected")
175-
expect(tab1).not.toHaveClass("juno-navigation-item-active")
176-
expect(tab2).toHaveAttribute("aria-selected", "true")
177-
expect(tab2).toHaveClass("juno-navigation-item-active")
68+
69+
const item = screen.getByText("Item 1")
70+
fireEvent.click(item)
71+
expect(handleActiveItemChange).not.toHaveBeenCalled()
17872
})
17973

180-
test("executes a handler as passed when the selected item changes", () => {
74+
it("renders with correct aria-label", () => {
75+
const ariaLabel = "Custom Navigation Label"
18176
render(
182-
<SideNavigation activeItem="Item 1" onActiveItemChange={mockOnActiveItemChange}>
183-
<SideNavigationItem label="Item 1" />
184-
<SideNavigationItem label="Item 2" />
77+
<SideNavigation ariaLabel={ariaLabel}>
78+
<SideNavigationItem label="Home" />
18579
</SideNavigation>
18680
)
187-
expect(screen.getByRole("navigation")).toBeInTheDocument()
188-
expect(screen.queryAllByRole("button")).toHaveLength(2)
189-
act(() => {
190-
screen.getByRole("button", { name: "Item 2" }).click()
191-
})
192-
expect(mockOnActiveItemChange).toHaveBeenCalled()
193-
})
194-
195-
test("renders custom classNames as passed", () => {
196-
render(<SideNavigation className="my-custom-class" />)
197-
expect(screen.getByRole("navigation")).toHaveClass("my-custom-class")
198-
})
19981

200-
test("renders all props as passed", () => {
201-
render(<SideNavigation data-lol="Prop goes here" />)
202-
expect(screen.getByRole("navigation")).toHaveAttribute("data-lol", "Prop goes here")
82+
const navigationElement = screen.getByRole("navigation")
83+
expect(navigationElement).toHaveAttribute("aria-label", ariaLabel)
20384
})
20485
})

packages/ui-components/src/components/SideNavigationGroup/SideNavigationGroup.component.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,14 @@ export const SideNavigationGroup: React.FC<SideNavigationGroupProps> = ({
6666
size="24"
6767
className={`
6868
juno-sidenavigation-item
69-
${disabled ? disabledStyles : ""}`}
69+
`}
7070
icon={isOpen ? "expandMore" : "chevronRight"}
7171
/>
7272
</span>
7373
) : null
7474

7575
const renderGroup = () => (
76-
<div className={`juno-sidenavigation-group ` + sideNavGroupStyles}>
76+
<div className={`${disabled ? disabledStyles : ""} juno-sidenavigation-group ${sideNavGroupStyles}`}>
7777
<span className="font-bold text-sm">{label}</span>
7878
{renderExpandIcon()}
7979
</div>

packages/ui-components/src/components/SideNavigationGroup/SideNavigationGroup.stories.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
import React from "react"
77
import type { Meta, StoryObj } from "@storybook/react-vite"
8-
import { SideNavigationGroup } from "./index"
9-
import { SideNavigation } from "../SideNavigation"
8+
import { SideNavigationGroup } from "./SideNavigationGroup.component"
9+
import { SideNavigation } from "../SideNavigation/SideNavigation.component"
1010
import { SideNavigationItem } from "../SideNavigationItem"
1111

1212
const meta: Meta<typeof SideNavigationGroup> = {
@@ -38,6 +38,13 @@ export const Default: Story = {
3838
},
3939
}
4040

41+
export const Disabled: Story = {
42+
args: {
43+
label: "Group",
44+
disabled: true,
45+
},
46+
}
47+
4148
export const Expandable: Story = {
4249
args: {
4350
label: "Expandable Group",

packages/ui-components/src/components/SideNavigationGroup/SideNavigationGroup.test.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,15 @@ describe("SideNavigationGroup", () => {
7676
})
7777

7878
test("disables interaction and applies disabled styles", () => {
79-
render(<SideNavigationGroup label="Disabled Group" disabled />)
79+
render(
80+
<SideNavigationGroup label="Disabled Group" disabled>
81+
<SideNavigationItem label="Child Item" />
82+
</SideNavigationGroup>
83+
)
84+
85+
const groupContainer = screen.getByText("Disabled Group").closest("div")
8086

81-
const expandIcon = screen.queryByRole("button", { hidden: true })
82-
expect(expandIcon).toBeInTheDocument()
83-
expect(expandIcon).toHaveClass("jn:opacity-50 jn:cursor-not-allowed")
87+
expect(groupContainer).toBeInTheDocument()
88+
expect(groupContainer).toHaveClass("jn:opacity-50 jn:cursor-not-allowed")
8489
})
8590
})

packages/ui-components/src/components/SideNavigationList/SideNavigationList.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ describe("SideNavigationList", () => {
3737
</SideNavigationList>
3838
)
3939

40-
const item1 = screen.getByText("Item 1").closest("li")
41-
const item2 = screen.getByText("Item 2").closest("li")
40+
const item1 = screen.getByText("Item 1")
41+
const item2 = screen.getByText("Item 2")
4242

4343
expect(item1).toBeInTheDocument()
44-
expect(item1).toHaveClass("jn-bg-theme-sidenav-item")
44+
expect(item1).toHaveClass("juno-sidenavigation-item")
4545

4646
expect(item2).toBeInTheDocument()
47-
expect(item2).toHaveClass("jn-bg-theme-sidenav-item")
47+
expect(item2).toHaveClass("juno-sidenavigation-item")
4848
})
4949
})

0 commit comments

Comments
 (0)