Skip to content

Commit d2f7033

Browse files
committed
Added a story, added tests
1 parent 9e7f048 commit d2f7033

3 files changed

Lines changed: 180 additions & 14 deletions

File tree

src/cmem/ActivityControl/ActivityControlWidget.stories.tsx

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1-
import React from "react";
1+
import React, { useMemo, useState } from "react";
22
import { loremIpsum } from "react-lorem-ipsum";
3+
import { OverlaysProvider } from "@blueprintjs/core";
34
import { Meta, StoryFn } from "@storybook/react";
45

56
import { helpersArgTypes } from "../../../.storybook/helpers";
6-
import { ActivityControlWidget, Tag, TagList } from "../../../index";
7+
import {
8+
ActivityControlWidget,
9+
ActivityControlWidgetAction,
10+
IconButton,
11+
SimpleDialog,
12+
Tag,
13+
TagList,
14+
} from "../../../index";
715

816
export default {
917
title: "Cmem/ActivityControlWidget",
@@ -19,7 +27,7 @@ const Template: StoryFn<typeof ActivityControlWidget> = (args) => <ActivityContr
1927

2028
export const FullExample = Template.bind({});
2129

22-
const actions = [
30+
const actions: ActivityControlWidgetAction[] = [
2331
{
2432
"data-test-id": "activity-reload-activity",
2533
icon: "item-reload",
@@ -57,8 +65,8 @@ const commonWidgetArgs = {
5765
progressSpinner: {
5866
intent: "none",
5967
value: 0.5,
60-
},
61-
};
68+
} as const,
69+
} as const;
6270

6371
FullExample.args = {
6472
...commonWidgetArgs,
@@ -80,3 +88,33 @@ WidgetWithTags.args = {
8088
...commonWidgetArgs,
8189
tags: widgetTags,
8290
};
91+
92+
export const WidgetWithAdditionalActions: StoryFn<typeof ActivityControlWidget> = (args) => {
93+
const [isOpen, setIsOpen] = useState(false);
94+
95+
const params = useMemo(
96+
() => ({
97+
...commonWidgetArgs,
98+
...args,
99+
additionalActions: args.additionalActions ?? [
100+
<IconButton name="application-explore" onClick={() => setIsOpen(true)} />,
101+
],
102+
}),
103+
[]
104+
);
105+
106+
return (
107+
<OverlaysProvider>
108+
<ActivityControlWidget {...params} />
109+
<SimpleDialog
110+
title="Additional actions dialog"
111+
isOpen={isOpen}
112+
onClose={() => setIsOpen(false)}
113+
canOutsideClickClose
114+
canEscapeKeyClose
115+
>
116+
Modal content
117+
</SimpleDialog>
118+
</OverlaysProvider>
119+
);
120+
};

src/cmem/ActivityControl/ActivityControlWidget.tsx

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ interface IActivityMenuAction extends ActivityControlWidgetAction {
114114
/** Shows the status of activities and supports actions on these activities. */
115115
export function ActivityControlWidget(props: ActivityControlWidgetProps) {
116116
const {
117-
"data-test-id": dataTestId,
117+
"data-test-id": dataTestIdLegacy,
118+
"data-testid": dataTestId,
118119
progressBar,
119120
progressSpinner,
120121
activityActions,
@@ -131,10 +132,19 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
131132
} = props;
132133
const spinnerClassNames = (progressSpinner?.className ?? "") + ` ${eccgui}-spinner--permanent`;
133134
const widget = (
134-
<OverviewItem data-test-id={dataTestId} hasSpacing={border || hasSpacing} densityHigh={small}>
135+
<OverviewItem
136+
data-test-id={dataTestIdLegacy}
137+
data-testid={dataTestId}
138+
hasSpacing={border || hasSpacing}
139+
densityHigh={small}
140+
>
135141
{progressBar && <ProgressBar {...progressBar} />}
136142
{(progressSpinner || progressSpinnerFinishedIcon) && (
137-
<OverviewItemDepiction keepColors>
143+
<OverviewItemDepiction
144+
data-testid={`${dataTestId}-progress-spinner`}
145+
data-test-id={`${dataTestIdLegacy}-progress-spinner`}
146+
keepColors
147+
>
138148
{progressSpinnerFinishedIcon ? (
139149
React.cloneElement(progressSpinnerFinishedIcon as JSX.Element, { small, large: !small })
140150
) : (
@@ -150,13 +160,21 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
150160
)}
151161
<OverviewItemDescription>
152162
{props.label && (
153-
<OverviewItemLine small={small}>
163+
<OverviewItemLine
164+
data-testid={`${dataTestId}-label`}
165+
data-test-id={`${dataTestIdLegacy}-label`}
166+
small={small}
167+
>
154168
{React.cloneElement(labelWrapper, {}, props.label)}
155169
{timerExecutionMsg && (props.statusMessage || tags) && <>&nbsp;({timerExecutionMsg})</>}
156170
</OverviewItemLine>
157171
)}
158172
{(props.statusMessage || tags) && (
159-
<OverviewItemLine small>
173+
<OverviewItemLine
174+
data-testid={`${dataTestId}-status-message`}
175+
data-test-id={`${dataTestIdLegacy}-status-message`}
176+
small
177+
>
160178
{tags}
161179
{props.statusMessage && (
162180
<OverflowText passDown>
@@ -177,21 +195,32 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
177195
</OverviewItemLine>
178196
)}
179197
{timerExecutionMsg && !(props.statusMessage || tags) && (
180-
<OverviewItemLine small>{timerExecutionMsg}</OverviewItemLine>
198+
<OverviewItemLine
199+
data-testid={`${dataTestId}-status-message`}
200+
data-test-id={`${dataTestIdLegacy}-status-message`}
201+
small
202+
>
203+
{timerExecutionMsg}
204+
</OverviewItemLine>
181205
)}
182206
</OverviewItemDescription>
183-
<OverviewItemActions>
207+
<OverviewItemActions data-testid={`${dataTestId}-actions`} data-test-id={`${dataTestIdLegacy}-actions`}>
184208
{activityActions &&
185209
activityActions.map((action, idx) => {
186210
return (
187211
<IconButton
188-
key={typeof action.icon === "string" ? action.icon : action["data-test-id"] ?? idx}
212+
key={
213+
typeof action.icon === "string"
214+
? action.icon
215+
: action["data-test-id"] ?? action["data-testid"] ?? idx
216+
}
189217
data-test-id={action["data-test-id"]}
218+
data-testid={action["data-testid"]}
190219
name={action.icon}
191220
text={action.tooltip}
192221
onClick={action.action}
193222
disabled={action.disabled}
194-
hasStateWarning={action.hasStateWarning}
223+
intent={action.hasStateWarning ? "warning" : undefined}
195224
tooltipProps={{
196225
hoverOpenDelay: 200,
197226
placement: "bottom",
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import React from "react";
2+
import { fireEvent, render, screen } from "@testing-library/react";
3+
4+
import "@testing-library/jest-dom";
5+
6+
import { IconButton, Tag, TagList } from "../../../index";
7+
import { ActivityControlWidget, ActivityControlWidgetAction } from "../ActivityControlWidget";
8+
9+
describe("ActivityControlWidget", () => {
10+
it("Renders basic widget with actions and handles clicks", () => {
11+
const mockAction1 = jest.fn();
12+
const mockAction2 = jest.fn();
13+
const actions: ActivityControlWidgetAction[] = [
14+
{
15+
"data-testid": "action-1",
16+
icon: "item-reload",
17+
action: mockAction1,
18+
tooltip: "Action 1",
19+
},
20+
{
21+
"data-testid": "action-2",
22+
icon: "item-start",
23+
action: mockAction2,
24+
tooltip: "Action 2",
25+
},
26+
];
27+
28+
render(
29+
<ActivityControlWidget
30+
label="Basic widget"
31+
data-testid="basic-widget"
32+
activityActions={actions}
33+
statusMessage="Status message"
34+
/>
35+
);
36+
37+
const button1 = screen.getByTestId("action-1");
38+
const button2 = screen.getByTestId("action-2");
39+
40+
const label = screen.getByTestId("basic-widget-label");
41+
const statusMessage = screen.getByTestId("basic-widget-status-message");
42+
const actionsContainer = screen.getByTestId("basic-widget-actions");
43+
44+
expect(label).toBeInTheDocument();
45+
expect(statusMessage).toBeInTheDocument();
46+
expect(actionsContainer).toBeInTheDocument();
47+
48+
expect(label).toHaveTextContent("Basic widget");
49+
expect(statusMessage).toHaveTextContent("Status message");
50+
51+
expect(button1).toBeInTheDocument();
52+
expect(button2).toBeInTheDocument();
53+
54+
fireEvent.click(button1);
55+
expect(mockAction1).toHaveBeenCalledTimes(1);
56+
57+
fireEvent.click(button2);
58+
expect(mockAction2).toHaveBeenCalledTimes(1);
59+
});
60+
61+
it("Renders widget with tags", () => {
62+
const tags = (
63+
<TagList>
64+
<Tag>Tag one</Tag>
65+
<Tag>Other tag</Tag>
66+
</TagList>
67+
);
68+
render(<ActivityControlWidget label="Widget with tags" tags={tags} data-testid="widget-with-tags" />);
69+
70+
const label = screen.getByTestId("widget-with-tags-label");
71+
const statusMessage = screen.getByTestId("widget-with-tags-status-message");
72+
73+
expect(label).toBeInTheDocument();
74+
expect(statusMessage).toBeInTheDocument();
75+
76+
expect(label).toHaveTextContent("Widget with tags");
77+
expect(statusMessage).toHaveTextContent("Tag one");
78+
expect(statusMessage).toHaveTextContent("Other tag");
79+
});
80+
81+
it("Renders widget with additional actions and handles click", () => {
82+
const mockAction = jest.fn();
83+
const additionalActions = [
84+
<IconButton
85+
key="add-btn"
86+
name="application-explore"
87+
onClick={mockAction}
88+
data-testid="additional-action"
89+
/>,
90+
];
91+
render(<ActivityControlWidget additionalActions={additionalActions} />);
92+
93+
const customButton = screen.getByTestId("additional-action");
94+
expect(customButton).toBeInTheDocument();
95+
96+
fireEvent.click(customButton);
97+
expect(mockAction).toHaveBeenCalledTimes(1);
98+
});
99+
});

0 commit comments

Comments
 (0)