Skip to content

Commit a2b87df

Browse files
authored
Merge pull request #490 from huwshimi/add-sidepanel-tests
WD-17055 - chore(tests): add SidePanel tests
2 parents 583d733 + 84968ea commit a2b87df

File tree

6 files changed

+162
-17
lines changed

6 files changed

+162
-17
lines changed

ui/src/components/Loader/Loader.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { FC } from "react";
22
import { Spinner } from "@canonical/react-components";
33

4+
import { LoaderTestId } from "./index";
5+
import { testId } from "test/utils";
6+
47
interface Props {
58
text?: string;
69
}
710

811
const Loader: FC<Props> = ({ text = "Loading..." }) => {
912
return (
10-
<div className="u-loader">
13+
<div className="u-loader" {...testId(LoaderTestId.COMPONENT)}>
1114
<Spinner text={text} />
1215
</div>
1316
);

ui/src/components/Loader/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { default } from "./Loader";
2+
export { TestId as LoaderTestId } from "./test-types";
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export enum TestId {
2+
COMPONENT = "Loader",
3+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import { screen, within } from "@testing-library/dom";
2+
import { render } from "@testing-library/react";
3+
4+
import SidePanel from "./SidePanel";
5+
import { Label } from "./types";
6+
import { LoaderTestId } from "components/Loader";
7+
8+
describe("SidePanel", () => {
9+
test("displays content", () => {
10+
const content = "Content";
11+
render(<SidePanel>{content}</SidePanel>);
12+
expect(
13+
screen.getByRole("complementary", {
14+
name: Label.SIDE_PANEL,
15+
}),
16+
).toHaveTextContent(content);
17+
});
18+
19+
test("can display as normal width", () => {
20+
render(<SidePanel>Content</SidePanel>);
21+
const sidePanel = screen.getByRole("complementary", {
22+
name: Label.SIDE_PANEL,
23+
});
24+
expect(sidePanel).not.toHaveClass("is-wide");
25+
expect(sidePanel).not.toHaveClass("is-narrow");
26+
});
27+
28+
test("can display as wide", () => {
29+
render(<SidePanel width="wide">Content</SidePanel>);
30+
expect(
31+
screen.getByRole("complementary", {
32+
name: Label.SIDE_PANEL,
33+
}),
34+
).toHaveClass("is-wide");
35+
});
36+
37+
test("can display as narrow", () => {
38+
render(<SidePanel width="narrow">Content</SidePanel>);
39+
expect(
40+
screen.getByRole("complementary", {
41+
name: Label.SIDE_PANEL,
42+
}),
43+
).toHaveClass("is-narrow");
44+
});
45+
46+
test("can display as split", () => {
47+
render(<SidePanel isSplit>Content</SidePanel>);
48+
expect(
49+
screen.getByRole("complementary", {
50+
name: Label.SIDE_PANEL,
51+
}),
52+
).toHaveClass("is-split");
53+
});
54+
55+
test("can display as an overlay", () => {
56+
render(<SidePanel isOverlay>Content</SidePanel>);
57+
expect(
58+
screen.getByRole("complementary", {
59+
name: Label.SIDE_PANEL,
60+
}),
61+
).toHaveClass("is-overlay");
62+
});
63+
64+
test("can display as pinned", () => {
65+
render(<SidePanel pinned>Content</SidePanel>);
66+
expect(
67+
screen.getByRole("complementary", {
68+
name: Label.SIDE_PANEL,
69+
}),
70+
).toHaveClass("is-pinned");
71+
});
72+
73+
test("can display loading state", () => {
74+
render(<SidePanel loading>Content</SidePanel>);
75+
expect(
76+
within(
77+
screen.getByRole("complementary", {
78+
name: Label.SIDE_PANEL,
79+
}),
80+
).getByTestId(LoaderTestId.COMPONENT),
81+
).toBeInTheDocument();
82+
});
83+
84+
test("can display loading error", () => {
85+
render(<SidePanel hasError>Content</SidePanel>);
86+
expect(
87+
within(
88+
screen.getByRole("complementary", {
89+
name: Label.SIDE_PANEL,
90+
}),
91+
).getByText(Label.ERROR_LOADING),
92+
).toBeInTheDocument();
93+
});
94+
});
95+
96+
test("HeaderControls", () => {
97+
const content = "Content";
98+
render(<SidePanel.HeaderControls>{content}</SidePanel.HeaderControls>);
99+
expect(screen.getByText(content)).toHaveClass("p-panel__controls");
100+
});
101+
102+
test("HeaderTitle", () => {
103+
const content = "Content";
104+
render(<SidePanel.HeaderTitle>{content}</SidePanel.HeaderTitle>);
105+
expect(screen.getByText(content)).toHaveClass("p-panel__title");
106+
});
107+
test("Sticky", () => {
108+
const content = "Content";
109+
render(<SidePanel.Sticky>{content}</SidePanel.Sticky>);
110+
expect(screen.getByText(content)).toHaveClass("sticky-wrapper");
111+
});
112+
113+
test("Header", () => {
114+
const content = "Content";
115+
render(<SidePanel.Header>{content}</SidePanel.Header>);
116+
expect(screen.getByText(content)).toHaveClass("p-panel__header");
117+
});
118+
119+
test("Container", () => {
120+
const content = "Content";
121+
render(<SidePanel.Container>{content}</SidePanel.Container>);
122+
expect(screen.getByText(content).parentElement).toHaveClass("p-panel");
123+
});
124+
125+
test("Content", () => {
126+
const content = "Content";
127+
render(<SidePanel.Content>{content}</SidePanel.Content>);
128+
expect(screen.getByText(content)).toHaveClass("p-panel__content");
129+
});
130+
131+
test("Footer", () => {
132+
const content = "Content";
133+
render(<SidePanel.Footer>{content}</SidePanel.Footer>);
134+
expect(screen.getByText(content)).toHaveClass("panel-footer");
135+
});

ui/src/components/SidePanel/SidePanel.tsx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { FC, PropsWithChildren, ReactNode } from "react";
22
import Loader from "components/Loader";
33
import classnames from "classnames";
4-
import { AppAside, Panel, Spinner } from "@canonical/react-components";
4+
import { AppAside, Panel } from "@canonical/react-components";
5+
import { Label } from "./types";
56

67
interface CommonProps {
78
className?: string;
@@ -78,8 +79,8 @@ interface SidePanelProps {
7879
isOverlay?: boolean;
7980
isSplit?: boolean;
8081
children: ReactNode;
81-
loading: boolean;
82-
hasError: boolean;
82+
loading?: boolean;
83+
hasError?: boolean;
8384
className?: string;
8485
width?: "narrow" | "wide";
8586
pinned?: boolean;
@@ -90,12 +91,20 @@ const SidePanelComponent: FC<SidePanelProps> = ({
9091
isOverlay,
9192
isSplit = false,
9293
loading = false,
93-
hasError,
94+
hasError = false,
9495
className,
9596
width,
9697
pinned,
9798
...props
9899
}) => {
100+
let content: ReactNode = null;
101+
if (loading) {
102+
content = <Loader />;
103+
} else if (hasError) {
104+
content = Label.ERROR_LOADING;
105+
} else {
106+
content = children;
107+
}
99108
return (
100109
<AppAside
101110
className={classnames(className, {
@@ -104,21 +113,11 @@ const SidePanelComponent: FC<SidePanelProps> = ({
104113
"is-split": isSplit,
105114
"is-overlay": isOverlay,
106115
})}
107-
aria-label="Side panel"
116+
aria-label={Label.SIDE_PANEL}
108117
pinned={pinned}
109118
{...props}
110119
>
111-
{loading ? (
112-
<div className="loading">
113-
<Spinner />
114-
</div>
115-
) : (
116-
<>
117-
{loading && <Loader />}
118-
{!loading && hasError && <>Loading failed</>}
119-
{!hasError && children}
120-
</>
121-
)}
120+
{content}
122121
</AppAside>
123122
);
124123
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export enum Label {
2+
ERROR_LOADING = "Loading failed",
3+
SIDE_PANEL = "Side panel",
4+
}

0 commit comments

Comments
 (0)