orc-shared 1.5.0-dev.8 → 1.5.0
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/dist/actions/navigation.js +16 -1
- package/dist/actions/requestsApi.js +1 -0
- package/dist/actions/tasks.js +190 -0
- package/dist/buildStore.js +3 -1
- package/dist/components/AppFrame/Sidebar.js +4 -8
- package/dist/components/CategoryList.js +6 -0
- package/dist/components/MaterialUI/DataDisplay/PredefinedElements/DiscountedPrice.js +1 -0
- package/dist/components/MaterialUI/DataDisplay/PredefinedElements/InformationItem.js +13 -5
- package/dist/components/MaterialUI/DataDisplay/TooltippedElements/MultipleLinesText.js +4 -2
- package/dist/components/MaterialUI/Inputs/PredefinedElements/SearchControl.js +43 -46
- package/dist/components/MaterialUI/hocs/withDeferredTooltip.js +3 -2
- package/dist/components/Navigation/index.js +0 -1
- package/dist/components/Routing/withWaypointing.js +1 -1
- package/dist/components/TaskDetailsModal.js +193 -0
- package/dist/constants.js +17 -2
- package/dist/content/iconsSheet.svg +22 -0
- package/dist/reducers/navigation.js +16 -0
- package/dist/reducers/request.js +4 -0
- package/dist/reducers/tasks.js +99 -0
- package/dist/selectors/authentication.js +17 -1
- package/dist/selectors/tasks.js +66 -0
- package/dist/sharedMessages.js +17 -1
- package/dist/utils/propertyHelper.js +35 -0
- package/dist/whyDidYouRerender.js +1 -0
- package/package.json +5 -5
- package/src/actions/navigation.js +7 -0
- package/src/actions/navigation.test.js +12 -0
- package/src/actions/tasks.js +77 -0
- package/src/actions/tasks.test.js +169 -0
- package/src/buildStore.js +2 -0
- package/src/components/AppFrame/About.test.js +3 -3
- package/src/components/AppFrame/Sidebar.js +4 -3
- package/src/components/MaterialUI/DataDisplay/PredefinedElements/InformationItem.js +15 -3
- package/src/components/MaterialUI/DataDisplay/TooltippedElements/MultipleLinesText.js +2 -1
- package/src/components/MaterialUI/Inputs/PredefinedElements/SearchControl.js +39 -27
- package/src/components/MaterialUI/Inputs/PredefinedElements/SearchControl.test.js +39 -34
- package/src/components/MaterialUI/hocs/withDeferredTooltip.js +2 -1
- package/src/components/MaterialUI/hocs/withDeferredTooltip.test.js +52 -0
- package/src/components/TaskDetailsModal.js +132 -0
- package/src/components/TaskDetailsModal.test.js +317 -0
- package/src/components/Text.test.js +44 -59
- package/src/constants.js +14 -1
- package/src/content/iconsSheet.svg +22 -0
- package/src/hooks/useLabelMessage.test.js +16 -10
- package/src/reducers/navigation.js +24 -0
- package/src/reducers/navigation.test.js +38 -0
- package/src/reducers/request.js +4 -0
- package/src/reducers/request.test.js +11 -0
- package/src/reducers/tasks.js +56 -0
- package/src/reducers/tasks.test.js +404 -0
- package/src/selectors/authentication.js +13 -0
- package/src/selectors/authentication.test.js +322 -0
- package/src/selectors/tasks.js +16 -0
- package/src/selectors/tasks.test.js +60 -0
- package/src/sharedMessages.js +17 -1
- package/src/translations/en-US.json +16 -12
- package/src/translations/fr-CA.json +16 -12
- package/src/utils/propertyHelper.js +38 -0
- package/src/utils/propertyHelper.test.js +160 -0
- package/src/utils/timezoneHelper.test.js +4 -2
|
@@ -53,10 +53,11 @@ describe("useStyles", () => {
|
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
describe("SearchControl Component", () => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
beforeEach(() => {
|
|
57
|
+
jest.useFakeTimers();
|
|
58
|
+
});
|
|
59
59
|
afterEach(() => {
|
|
60
|
+
jest.useRealTimers();
|
|
60
61
|
jest.clearAllMocks();
|
|
61
62
|
});
|
|
62
63
|
|
|
@@ -232,8 +233,7 @@ describe("SearchControl Component", () => {
|
|
|
232
233
|
expect(searchInput.length, "to be", 1);
|
|
233
234
|
|
|
234
235
|
searchInput.instance().value = "abc";
|
|
235
|
-
|
|
236
|
-
searchInput.simulate("keydown", { key: "Enter" });
|
|
236
|
+
mountedComponent.find("form").simulate("submit", { preventDefault: () => {} });
|
|
237
237
|
|
|
238
238
|
expect(onSearchEvent, "to have calls satisfying", [{ args: ["aValue", "abc"] }]);
|
|
239
239
|
});
|
|
@@ -371,7 +371,7 @@ describe("SearchControl Component", () => {
|
|
|
371
371
|
expect(onSearchEvent, "to have calls satisfying", [{ args: ["anotherValue", "abcdef123"] }]);
|
|
372
372
|
});
|
|
373
373
|
|
|
374
|
-
it("Search Control should
|
|
374
|
+
it("Search Control should clear the search when changing the option", () => {
|
|
375
375
|
const options = [
|
|
376
376
|
{ value: "aValue", label: "aLabel" },
|
|
377
377
|
{ value: "anotherValue", label: "anotherLabel" },
|
|
@@ -385,8 +385,8 @@ describe("SearchControl Component", () => {
|
|
|
385
385
|
placeholder="placeHolderTest"
|
|
386
386
|
defaultValue={"abcdef123"}
|
|
387
387
|
searchOptions={options}
|
|
388
|
-
searchOption={"anotherValue"}
|
|
389
388
|
onSearch={onSearchEvent}
|
|
389
|
+
focusSearchOnSearchOptionChange={true}
|
|
390
390
|
/>
|
|
391
391
|
</TestWrapper>
|
|
392
392
|
);
|
|
@@ -395,48 +395,53 @@ describe("SearchControl Component", () => {
|
|
|
395
395
|
|
|
396
396
|
const selectMui = mountedComponent.find(SelectMUI);
|
|
397
397
|
|
|
398
|
-
|
|
399
|
-
|
|
398
|
+
const event = {
|
|
399
|
+
target: {
|
|
400
|
+
value: "anotherValue",
|
|
401
|
+
},
|
|
402
|
+
};
|
|
400
403
|
|
|
401
|
-
|
|
402
|
-
|
|
404
|
+
onSearchEvent.resetHistory();
|
|
405
|
+
|
|
406
|
+
selectMui.invoke("onChange")(event);
|
|
407
|
+
|
|
408
|
+
expect(onSearchEvent.callCount, "to equal", 1);
|
|
409
|
+
expect(onSearchEvent, "to have calls satisfying", [{ args: ["anotherValue", ""] }]);
|
|
410
|
+
|
|
411
|
+
const allInputs = mountedComponent.find("input");
|
|
412
|
+
const searchInput = allInputs.find("[placeholder='placeHolderTest']");
|
|
413
|
+
expect(searchInput.length, "to be", 1);
|
|
403
414
|
|
|
415
|
+
expect(searchInput.instance().value, "to be", "abcdef123");
|
|
416
|
+
jest.runOnlyPendingTimers();
|
|
417
|
+
expect(searchInput.instance().value, "to be", "");
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it("Search Control should render with the 2nd value", () => {
|
|
404
421
|
const options = [
|
|
405
422
|
{ value: "aValue", label: "aLabel" },
|
|
406
423
|
{ value: "anotherValue", label: "anotherLabel" },
|
|
407
424
|
];
|
|
408
425
|
|
|
426
|
+
const onSearchEvent = sinon.spy().named("search");
|
|
427
|
+
|
|
409
428
|
const component = (
|
|
410
429
|
<TestWrapper stylesProvider muiThemeProvider={{ theme }}>
|
|
411
|
-
<SearchControl
|
|
430
|
+
<SearchControl
|
|
431
|
+
placeholder="placeHolderTest"
|
|
432
|
+
defaultValue={"abcdef123"}
|
|
433
|
+
searchOptions={options}
|
|
434
|
+
searchOption={"anotherValue"}
|
|
435
|
+
onSearch={onSearchEvent}
|
|
436
|
+
/>
|
|
412
437
|
</TestWrapper>
|
|
413
438
|
);
|
|
414
439
|
|
|
415
440
|
const mountedComponent = mount(component);
|
|
416
441
|
|
|
417
|
-
const
|
|
418
|
-
const searchInput = allInputs.find("[placeholder='placeHolderTest']");
|
|
419
|
-
expect(searchInput.length, "to be", 1);
|
|
420
|
-
|
|
421
|
-
let searchEditParent = mountedComponent.find('[data-qa="searchInput"]');
|
|
422
|
-
expect(searchEditParent.length, "to be", 1);
|
|
423
|
-
|
|
424
|
-
expect(searchEditParent.props()["data-qa-is-focused"], "to be", false);
|
|
425
|
-
|
|
426
|
-
const event = {
|
|
427
|
-
preventDefault: () => {},
|
|
428
|
-
stopPropagation: () => {},
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
searchInput.invoke("onFocus")(event);
|
|
432
|
-
|
|
433
|
-
searchEditParent = mountedComponent.find('[data-qa="searchInput"]');
|
|
434
|
-
expect(searchEditParent.props()["data-qa-is-focused"], "to be", true);
|
|
435
|
-
|
|
436
|
-
searchInput.invoke("onBlur")(event);
|
|
442
|
+
const selectMui = mountedComponent.find(SelectMUI);
|
|
437
443
|
|
|
438
|
-
|
|
439
|
-
expect(searchEditParent.props()["data-qa-is-focused"], "to be", false);
|
|
444
|
+
expect(selectMui.props().value, "to equal", "anotherValue");
|
|
440
445
|
});
|
|
441
446
|
|
|
442
447
|
it("Renders Search Control component without errors when disabled", () => {
|
|
@@ -8,7 +8,7 @@ import { isString, isObject, isStringNullOrWhitespace, isReactComponent } from "
|
|
|
8
8
|
|
|
9
9
|
const withDeferredTooltip =
|
|
10
10
|
Comp =>
|
|
11
|
-
({ titleValue, alwaysDisplay, ...props }) => {
|
|
11
|
+
({ titleValue, alwaysDisplay, tooltipClasses, ...props }) => {
|
|
12
12
|
const [shouldBeTooltipped, setShouldBeTooltipped] = useState(false);
|
|
13
13
|
|
|
14
14
|
const defaultComponent = <Comp onMouseEnter={event => makeComponentTooltipped(event)} {...props} />;
|
|
@@ -32,6 +32,7 @@ const withDeferredTooltip =
|
|
|
32
32
|
return (
|
|
33
33
|
<MuiTooltip
|
|
34
34
|
arrow
|
|
35
|
+
classes={tooltipClasses ?? null}
|
|
35
36
|
title={titleValue}
|
|
36
37
|
disableHoverListener={false}
|
|
37
38
|
disableFocusListener={true}
|
|
@@ -155,4 +155,56 @@ describe("withDeferredTooltip", () => {
|
|
|
155
155
|
|
|
156
156
|
expect(wrapper.prop("onMouseEnter"), "to be", undefined);
|
|
157
157
|
});
|
|
158
|
+
|
|
159
|
+
it("Always displays passed title in tooltip with tooltip classes when specified", () => {
|
|
160
|
+
const Wrapper = props => <ComponentToBeTooltipped {...props} />;
|
|
161
|
+
|
|
162
|
+
const TooltippedCompponent = withDeferredTooltip(Wrapper);
|
|
163
|
+
|
|
164
|
+
const mountedTooltippedComponent = shallow(
|
|
165
|
+
<TooltippedCompponent alwaysDisplay titleValue="test" tooltipClasses={{ classTest: "testMyMojo" }} />,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const event = {
|
|
169
|
+
target: {
|
|
170
|
+
offsetWidth: 100,
|
|
171
|
+
scrollWidth: 100,
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
mountedTooltippedComponent.find(Wrapper).invoke("onMouseEnter")(event);
|
|
176
|
+
|
|
177
|
+
let expected = (
|
|
178
|
+
<MuiTooltip title="test" classes={{ classTest: "testMyMojo" }}>
|
|
179
|
+
<Wrapper />
|
|
180
|
+
</MuiTooltip>
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
expect(mountedTooltippedComponent.containsMatchingElement(expected), "to be true");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("Always displays passed title in tooltip without tooltip classes when not specified", () => {
|
|
187
|
+
const Wrapper = props => <ComponentToBeTooltipped {...props} />;
|
|
188
|
+
|
|
189
|
+
const TooltippedCompponent = withDeferredTooltip(Wrapper);
|
|
190
|
+
|
|
191
|
+
const mountedTooltippedComponent = shallow(<TooltippedCompponent alwaysDisplay titleValue="test" />);
|
|
192
|
+
|
|
193
|
+
const event = {
|
|
194
|
+
target: {
|
|
195
|
+
offsetWidth: 100,
|
|
196
|
+
scrollWidth: 100,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
mountedTooltippedComponent.find(Wrapper).invoke("onMouseEnter")(event);
|
|
201
|
+
|
|
202
|
+
let expected = (
|
|
203
|
+
<MuiTooltip title="test" classes={null}>
|
|
204
|
+
<Wrapper />
|
|
205
|
+
</MuiTooltip>
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
expect(mountedTooltippedComponent.containsMatchingElement(expected), "to be true");
|
|
209
|
+
});
|
|
158
210
|
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { useDispatch, useSelector } from "react-redux";
|
|
3
|
+
import Button from "@material-ui/core/Button";
|
|
4
|
+
import { FormattedMessage } from "react-intl";
|
|
5
|
+
import { makeStyles } from "@material-ui/core/styles";
|
|
6
|
+
import { taskStatuses } from "../constants";
|
|
7
|
+
import useSelectorAndUnwrap from "../hooks/useSelectorAndUnwrap";
|
|
8
|
+
import InformationItem from "./MaterialUI/DataDisplay/PredefinedElements/InformationItem";
|
|
9
|
+
import { taskInfo, taskLogs } from "../selectors/tasks";
|
|
10
|
+
import { compareObjectProperty } from "../utils/propertyHelper";
|
|
11
|
+
import useLoader from "../hooks/useLoader";
|
|
12
|
+
import { clearTaskLog, getTaskInfo, getTaskLog } from "../actions/tasks";
|
|
13
|
+
import ModalProps from "./MaterialUI/DataDisplay/modalProps";
|
|
14
|
+
import Modal from "./MaterialUI/DataDisplay/Modal";
|
|
15
|
+
import { namedLookupLocalizedSelector } from "../selectors/metadata";
|
|
16
|
+
import sharedMessages from "../sharedMessages";
|
|
17
|
+
|
|
18
|
+
export const useStyles = makeStyles(theme => ({
|
|
19
|
+
actionPanel: {
|
|
20
|
+
display: "flex",
|
|
21
|
+
marginLeft: "auto",
|
|
22
|
+
flex: "1 1 0",
|
|
23
|
+
justifyContent: "flex-end",
|
|
24
|
+
},
|
|
25
|
+
taskContainer: {
|
|
26
|
+
display: "flex",
|
|
27
|
+
width: "100%",
|
|
28
|
+
flexDirection: "column",
|
|
29
|
+
"&>div": {
|
|
30
|
+
"&:last-child": {
|
|
31
|
+
flex: 1,
|
|
32
|
+
display: "flex",
|
|
33
|
+
flexDirection: "column",
|
|
34
|
+
"&>textarea": {
|
|
35
|
+
overflowY: "scroll",
|
|
36
|
+
resize: "none",
|
|
37
|
+
flex: 1,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
const isTaskCompleted = status => {
|
|
45
|
+
switch (status) {
|
|
46
|
+
case taskStatuses.faulted:
|
|
47
|
+
case taskStatuses.ranToCompletion:
|
|
48
|
+
case taskStatuses.canceled:
|
|
49
|
+
case taskStatuses.ignored:
|
|
50
|
+
return true;
|
|
51
|
+
default:
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const TaskDetailsModal = ({ taskId, open, closeModal }) => {
|
|
57
|
+
const classes = useStyles();
|
|
58
|
+
const dispatch = useDispatch();
|
|
59
|
+
|
|
60
|
+
const taskDetails = useSelectorAndUnwrap(taskInfo(taskId));
|
|
61
|
+
const logs = useSelectorAndUnwrap(taskLogs(taskId));
|
|
62
|
+
const logsText = logs
|
|
63
|
+
.sort((a, b) => compareObjectProperty(a, b, "executionTime"))
|
|
64
|
+
.reduce((accumulator, currentValue) => {
|
|
65
|
+
if (currentValue.message === null) {
|
|
66
|
+
return accumulator;
|
|
67
|
+
}
|
|
68
|
+
if (accumulator === "") {
|
|
69
|
+
return currentValue.message.trim();
|
|
70
|
+
}
|
|
71
|
+
return accumulator + "\n" + currentValue.message.trim();
|
|
72
|
+
}, "");
|
|
73
|
+
|
|
74
|
+
useLoader(getTaskInfo(taskId), () => taskDetails !== null);
|
|
75
|
+
|
|
76
|
+
const internalCloseModal = () => {
|
|
77
|
+
dispatch(clearTaskLog(taskId));
|
|
78
|
+
closeModal();
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const taskStatus = taskDetails?.status;
|
|
82
|
+
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
const timer = setInterval(() => {
|
|
85
|
+
if (!isTaskCompleted(taskStatus)) {
|
|
86
|
+
dispatch(getTaskInfo(taskId));
|
|
87
|
+
dispatch(getTaskLog(taskId, false));
|
|
88
|
+
}
|
|
89
|
+
}, 10000);
|
|
90
|
+
return () => clearInterval(timer);
|
|
91
|
+
}, [dispatch, taskId, taskStatus]);
|
|
92
|
+
|
|
93
|
+
const localizedStatus = useSelector(namedLookupLocalizedSelector("order", "TaskStatus", taskStatus));
|
|
94
|
+
const modalProps = new ModalProps();
|
|
95
|
+
const titleComponent = <FormattedMessage {...sharedMessages.taskInProgressModalTitle} />;
|
|
96
|
+
|
|
97
|
+
modalProps.set(ModalProps.propNames.title, titleComponent);
|
|
98
|
+
modalProps.set(ModalProps.propNames.open, open);
|
|
99
|
+
modalProps.set(ModalProps.propNames.type, "wide");
|
|
100
|
+
modalProps.set(ModalProps.propNames.backdropClickCallback, internalCloseModal);
|
|
101
|
+
|
|
102
|
+
const actionPanel = (
|
|
103
|
+
<div className={classes.actionPanel}>
|
|
104
|
+
<Button
|
|
105
|
+
key={sharedMessages.close.id}
|
|
106
|
+
data-qa={sharedMessages.close.id}
|
|
107
|
+
variant="contained"
|
|
108
|
+
color="primary"
|
|
109
|
+
disableElevation={true}
|
|
110
|
+
onClick={e => internalCloseModal(e)}
|
|
111
|
+
>
|
|
112
|
+
<FormattedMessage {...sharedMessages.close} />
|
|
113
|
+
</Button>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
modalProps.set(ModalProps.propNames.actionPanel, actionPanel);
|
|
118
|
+
|
|
119
|
+
const taskContent = (
|
|
120
|
+
<div className={classes.taskContainer}>
|
|
121
|
+
<InformationItem label={sharedMessages.taskId}>{taskId}</InformationItem>
|
|
122
|
+
<InformationItem label={sharedMessages.taskStatus}>{localizedStatus}</InformationItem>
|
|
123
|
+
<InformationItem label={sharedMessages.taskLogs}>
|
|
124
|
+
<textarea readOnly value={logsText} />
|
|
125
|
+
</InformationItem>
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
return <Modal message={taskContent} modalProps={modalProps} />;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export default TaskDetailsModal;
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Immutable from "immutable";
|
|
3
|
+
import { mount } from "enzyme";
|
|
4
|
+
import TaskDetailsModal from "./TaskDetailsModal";
|
|
5
|
+
import Modal from "./MaterialUI/DataDisplay/Modal";
|
|
6
|
+
import { defaultCulture } from "../selectors/locale";
|
|
7
|
+
import sinon from "sinon";
|
|
8
|
+
import { createMuiTheme, extractMessages, TestWrapper } from "../utils/testUtils";
|
|
9
|
+
import sharedMessages from "../sharedMessages";
|
|
10
|
+
import ModalProps from "./MaterialUI/DataDisplay/modalProps";
|
|
11
|
+
import { Ignore } from "unexpected-reaction";
|
|
12
|
+
import InformationItem from "./MaterialUI/DataDisplay/PredefinedElements/InformationItem";
|
|
13
|
+
import { clearTaskLog, getTaskInfo, getTaskLog } from "../actions/tasks";
|
|
14
|
+
import { taskStatuses } from "../constants";
|
|
15
|
+
|
|
16
|
+
const messages = extractMessages(sharedMessages);
|
|
17
|
+
|
|
18
|
+
jest.mock("../utils/buildUrl", () => {
|
|
19
|
+
const modExport = {};
|
|
20
|
+
modExport.loadConfig = () => Promise.resolve({});
|
|
21
|
+
modExport.buildUrl = (path = [], params = "") => "URL: " + path.join("/") + " " + JSON.stringify(params);
|
|
22
|
+
return modExport;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function removeBailout(obj) {
|
|
26
|
+
delete obj["@@redux-api-middleware/RSAA"].bailout;
|
|
27
|
+
return obj;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe("TaskDetailsModal", () => {
|
|
31
|
+
let state, dispatch, store, clearIntervalSpy;
|
|
32
|
+
const theme = createMuiTheme();
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
//window.bypassDebounce = true;
|
|
36
|
+
|
|
37
|
+
dispatch = sinon.spy().named("dispatch");
|
|
38
|
+
jest.useFakeTimers();
|
|
39
|
+
clearIntervalSpy = sinon.spy(global, "clearInterval");
|
|
40
|
+
|
|
41
|
+
state = Immutable.fromJS({
|
|
42
|
+
requests: {
|
|
43
|
+
logout: false,
|
|
44
|
+
},
|
|
45
|
+
metadata: {
|
|
46
|
+
lookups: {},
|
|
47
|
+
},
|
|
48
|
+
tasks: {
|
|
49
|
+
taskInfos: {},
|
|
50
|
+
tasks: [],
|
|
51
|
+
logs: {},
|
|
52
|
+
},
|
|
53
|
+
locale: {
|
|
54
|
+
defaultCulture: defaultCulture,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
store = {
|
|
59
|
+
getState: () => state,
|
|
60
|
+
subscribe: () => {},
|
|
61
|
+
dispatch: dispatch,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
afterEach(() => {
|
|
65
|
+
jest.useRealTimers();
|
|
66
|
+
jest.restoreAllMocks();
|
|
67
|
+
clearIntervalSpy.restore();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("renders a modal for task", () => {
|
|
71
|
+
const modalProps = new ModalProps();
|
|
72
|
+
|
|
73
|
+
modalProps.set(ModalProps.propNames.title, "Task In Progress");
|
|
74
|
+
modalProps.set(ModalProps.propNames.open, true);
|
|
75
|
+
modalProps.set(ModalProps.propNames.type, "wide");
|
|
76
|
+
modalProps.set(ModalProps.propNames.actionPanel, <Ignore />);
|
|
77
|
+
|
|
78
|
+
const expectedContent = (
|
|
79
|
+
<div>
|
|
80
|
+
<InformationItem label={sharedMessages.taskId}>1234</InformationItem>
|
|
81
|
+
<InformationItem label={sharedMessages.taskStatus}>
|
|
82
|
+
<Ignore />
|
|
83
|
+
</InformationItem>
|
|
84
|
+
<InformationItem label={sharedMessages.taskLogs}>
|
|
85
|
+
<textarea />
|
|
86
|
+
</InformationItem>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
expect(
|
|
91
|
+
<TestWrapper
|
|
92
|
+
provider={{ store }}
|
|
93
|
+
memoryRouter
|
|
94
|
+
stylesProvider
|
|
95
|
+
muiThemeProvider={{ theme }}
|
|
96
|
+
intlProvider={{ messages }}
|
|
97
|
+
>
|
|
98
|
+
<TaskDetailsModal taskId="1234" open={true} closeModal={() => {}} />
|
|
99
|
+
</TestWrapper>,
|
|
100
|
+
"when mounted",
|
|
101
|
+
"to satisfy",
|
|
102
|
+
<TestWrapper
|
|
103
|
+
provider={{ store }}
|
|
104
|
+
memoryRouter
|
|
105
|
+
stylesProvider
|
|
106
|
+
muiThemeProvider={{ theme }}
|
|
107
|
+
intlProvider={{ messages }}
|
|
108
|
+
>
|
|
109
|
+
<Modal message={expectedContent} modalProps={modalProps} />
|
|
110
|
+
</TestWrapper>,
|
|
111
|
+
).then(() => expect(console.error, "was not called"));
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("renders a modal for task with status and logs", () => {
|
|
115
|
+
state = state.setIn(
|
|
116
|
+
["tasks", "logs", "1234"],
|
|
117
|
+
[
|
|
118
|
+
{ executionTime: "", message: null },
|
|
119
|
+
{ executionTime: "4", message: "msg\r\n" },
|
|
120
|
+
{ executionTime: "3", message: "another" },
|
|
121
|
+
],
|
|
122
|
+
);
|
|
123
|
+
state = state.setIn(["tasks", "taskInfos", "1234"], { status: taskStatuses.running });
|
|
124
|
+
|
|
125
|
+
const modalProps = new ModalProps();
|
|
126
|
+
|
|
127
|
+
modalProps.set(ModalProps.propNames.title, "Task In Progress");
|
|
128
|
+
modalProps.set(ModalProps.propNames.open, true);
|
|
129
|
+
modalProps.set(ModalProps.propNames.type, "wide");
|
|
130
|
+
modalProps.set(ModalProps.propNames.actionPanel, <Ignore />);
|
|
131
|
+
|
|
132
|
+
const expectedContent = (
|
|
133
|
+
<div>
|
|
134
|
+
<InformationItem label={sharedMessages.taskId}>1234</InformationItem>
|
|
135
|
+
<InformationItem label={sharedMessages.taskStatus}>[Running]</InformationItem>
|
|
136
|
+
<InformationItem label={sharedMessages.taskLogs}>
|
|
137
|
+
<textarea readOnly value={"another\nmsg"} />
|
|
138
|
+
</InformationItem>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
expect(
|
|
143
|
+
<TestWrapper
|
|
144
|
+
provider={{ store }}
|
|
145
|
+
memoryRouter
|
|
146
|
+
stylesProvider
|
|
147
|
+
muiThemeProvider={{ theme }}
|
|
148
|
+
intlProvider={{ messages }}
|
|
149
|
+
>
|
|
150
|
+
<TaskDetailsModal taskId="1234" open={true} closeModal={() => {}} />
|
|
151
|
+
</TestWrapper>,
|
|
152
|
+
"when mounted",
|
|
153
|
+
"to satisfy",
|
|
154
|
+
<TestWrapper
|
|
155
|
+
provider={{ store }}
|
|
156
|
+
memoryRouter
|
|
157
|
+
stylesProvider
|
|
158
|
+
muiThemeProvider={{ theme }}
|
|
159
|
+
intlProvider={{ messages }}
|
|
160
|
+
>
|
|
161
|
+
<Modal message={expectedContent} modalProps={modalProps} />
|
|
162
|
+
</TestWrapper>,
|
|
163
|
+
).then(() => expect(console.error, "was not called"));
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("close the dialog", () => {
|
|
167
|
+
const closeSpy = sinon.spy().named("close");
|
|
168
|
+
|
|
169
|
+
const content = (
|
|
170
|
+
<TestWrapper
|
|
171
|
+
provider={{ store }}
|
|
172
|
+
memoryRouter
|
|
173
|
+
stylesProvider
|
|
174
|
+
muiThemeProvider={{ theme }}
|
|
175
|
+
intlProvider={{ messages }}
|
|
176
|
+
>
|
|
177
|
+
<TaskDetailsModal taskId="1234" open={true} closeModal={closeSpy} />
|
|
178
|
+
</TestWrapper>
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
const mountedComponent = mount(content);
|
|
182
|
+
store.dispatch.resetHistory();
|
|
183
|
+
|
|
184
|
+
const input = mountedComponent.find("[data-qa='" + sharedMessages.close.id + "']").at(0);
|
|
185
|
+
input.simulate("click");
|
|
186
|
+
|
|
187
|
+
expect(closeSpy, "was called");
|
|
188
|
+
expect(store.dispatch, "to have calls satisfying", [
|
|
189
|
+
{
|
|
190
|
+
args: [clearTaskLog("1234")],
|
|
191
|
+
},
|
|
192
|
+
]);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("clear timer on unmount", () => {
|
|
196
|
+
const closeSpy = sinon.spy().named("close");
|
|
197
|
+
const content = (
|
|
198
|
+
<TestWrapper
|
|
199
|
+
provider={{ store }}
|
|
200
|
+
memoryRouter
|
|
201
|
+
stylesProvider
|
|
202
|
+
muiThemeProvider={{ theme }}
|
|
203
|
+
intlProvider={{ messages }}
|
|
204
|
+
>
|
|
205
|
+
<TaskDetailsModal taskId="1234" open={true} closeModal={closeSpy} />
|
|
206
|
+
</TestWrapper>
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const mountedComponent = mount(content);
|
|
210
|
+
clearIntervalSpy.resetHistory();
|
|
211
|
+
mountedComponent.unmount();
|
|
212
|
+
|
|
213
|
+
expect(clearIntervalSpy, "was called");
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("taskInfo is called to load data", () => {
|
|
217
|
+
const content = (
|
|
218
|
+
<TestWrapper
|
|
219
|
+
provider={{ store }}
|
|
220
|
+
memoryRouter
|
|
221
|
+
stylesProvider
|
|
222
|
+
muiThemeProvider={{ theme }}
|
|
223
|
+
intlProvider={{ messages }}
|
|
224
|
+
>
|
|
225
|
+
<TaskDetailsModal taskId="1234" open={true} closeModal={() => {}} />
|
|
226
|
+
</TestWrapper>
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
mount(content);
|
|
230
|
+
|
|
231
|
+
expect(store.dispatch, "to have calls satisfying", [
|
|
232
|
+
{
|
|
233
|
+
args: [removeBailout(getTaskInfo("1234"))],
|
|
234
|
+
},
|
|
235
|
+
]);
|
|
236
|
+
expect(store.dispatch, "not to have calls satisfying", [
|
|
237
|
+
{
|
|
238
|
+
args: [removeBailout(getTaskLog("1234"))],
|
|
239
|
+
},
|
|
240
|
+
]);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it("taskLogs is called to load data", () => {
|
|
244
|
+
const content = (
|
|
245
|
+
<TestWrapper
|
|
246
|
+
provider={{ store }}
|
|
247
|
+
memoryRouter
|
|
248
|
+
stylesProvider
|
|
249
|
+
muiThemeProvider={{ theme }}
|
|
250
|
+
intlProvider={{ messages }}
|
|
251
|
+
>
|
|
252
|
+
<TaskDetailsModal taskId="1234" open={true} closeModal={() => {}} />
|
|
253
|
+
</TestWrapper>
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
mount(content);
|
|
257
|
+
|
|
258
|
+
expect(store.dispatch, "to have calls satisfying", [
|
|
259
|
+
{
|
|
260
|
+
args: [removeBailout(getTaskInfo("1234"))],
|
|
261
|
+
},
|
|
262
|
+
]);
|
|
263
|
+
|
|
264
|
+
store.dispatch.resetHistory();
|
|
265
|
+
|
|
266
|
+
jest.runOnlyPendingTimers();
|
|
267
|
+
|
|
268
|
+
expect(store.dispatch, "to have calls satisfying", [
|
|
269
|
+
{
|
|
270
|
+
args: [removeBailout(getTaskInfo("1234"))],
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
args: [removeBailout(getTaskLog("1234", false))],
|
|
274
|
+
},
|
|
275
|
+
]);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it.each([taskStatuses.faulted, taskStatuses.ranToCompletion, taskStatuses.canceled, taskStatuses.ignored])(
|
|
279
|
+
"taskLogs is not called because task is completed (%s)",
|
|
280
|
+
newStatus => {
|
|
281
|
+
state = state.setIn(["tasks", "taskInfos", "1234"], { status: newStatus });
|
|
282
|
+
|
|
283
|
+
const content = (
|
|
284
|
+
<TestWrapper
|
|
285
|
+
provider={{ store }}
|
|
286
|
+
memoryRouter
|
|
287
|
+
stylesProvider
|
|
288
|
+
muiThemeProvider={{ theme }}
|
|
289
|
+
intlProvider={{ messages }}
|
|
290
|
+
>
|
|
291
|
+
<TaskDetailsModal taskId="1234" open={true} closeModal={() => {}} />
|
|
292
|
+
</TestWrapper>
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
mount(content);
|
|
296
|
+
|
|
297
|
+
expect(store.dispatch, "not to have calls satisfying", [
|
|
298
|
+
{
|
|
299
|
+
args: [removeBailout(getTaskInfo("1234"))],
|
|
300
|
+
},
|
|
301
|
+
]);
|
|
302
|
+
|
|
303
|
+
store.dispatch.resetHistory();
|
|
304
|
+
|
|
305
|
+
jest.runOnlyPendingTimers();
|
|
306
|
+
|
|
307
|
+
expect(store.dispatch, "not to have calls satisfying", [
|
|
308
|
+
{
|
|
309
|
+
args: [removeBailout(getTaskInfo("1234"))],
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
args: [removeBailout(getTaskLog("1234"))],
|
|
313
|
+
},
|
|
314
|
+
]);
|
|
315
|
+
},
|
|
316
|
+
);
|
|
317
|
+
});
|