foreman-tasks 12.1.1 → 12.2.2
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.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -1
- data/foreman-tasks.gemspec +1 -3
- data/lib/foreman_tasks/version.rb +1 -1
- data/test/controllers/api/tasks_controller_test.rb +2 -2
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Dependencies.js +69 -58
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Errors.js +25 -5
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Locks.js +170 -43
- data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +12 -4
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +217 -201
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskSkeleton.js +30 -34
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Dependencies.test.js +90 -29
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Errors.test.js +50 -27
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Locks.test.js +256 -23
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Raw.test.js +44 -22
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +56 -24
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +42 -22
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +45 -54
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +65 -25
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +37 -13
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +53 -8
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.test.js +53 -7
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.test.js +53 -7
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.js +5 -4
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.test.js +44 -14
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +6 -5
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.js +5 -4
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.scss +3 -8
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.test.js +75 -34
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.test.js +57 -34
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChartHelper.test.js +23 -9
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.fixtures.js +14 -11
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.js +19 -21
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.test.js +63 -14
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.js +9 -17
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.test.js +49 -13
- metadata +2 -46
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Errors.test.js.snap +0 -77
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Locks.test.js.snap +0 -116
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Raw.test.js.snap +0 -174
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/RunningSteps.test.js.snap +0 -62
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +0 -127
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +0 -580
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +0 -172
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +0 -52
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/__snapshots__/PausedTasksCard.test.js.snap +0 -38
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/__snapshots__/RunningTasksCard.test.js.snap +0 -38
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/__snapshots__/ScheduledTasksCard.test.js.snap +0 -97
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/__snapshots__/TasksDonutCard.test.js.snap +0 -183
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChart.test.js.snap +0 -302
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChartHelper.test.js.snap +0 -21
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap +0 -210
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/__snapshots__/TimeDropDown.test.js.snap +0 -85
|
@@ -1,59 +1,50 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
jest.mock('foremanReact/components/common/dates/RelativeDateTime', () => {
|
|
6
|
+
const RelativeDateTime = ({ date, defaultValue }) => (
|
|
7
|
+
<span>{date || defaultValue}</span>
|
|
8
|
+
);
|
|
9
|
+
return RelativeDateTime;
|
|
10
|
+
});
|
|
4
11
|
|
|
5
|
-
|
|
6
|
-
'render without Props': { id: 'test' },
|
|
7
|
-
'render with Props': {
|
|
8
|
-
id: 'test',
|
|
9
|
-
startAt: '2019-06-17 16:04:09 +0300',
|
|
10
|
-
label: 'Actions::Katello::EventQueue::Monitor',
|
|
11
|
-
pending: true,
|
|
12
|
-
action: 'Monitor Event Queue',
|
|
13
|
-
username: 'admin',
|
|
14
|
-
startedAt: '2019-06-17 16:04:09 +0300',
|
|
15
|
-
endedAt: null,
|
|
16
|
-
state: 'paused',
|
|
17
|
-
result: 'error',
|
|
18
|
-
progress: 0.5,
|
|
19
|
-
input: {
|
|
20
|
-
locale: 'en',
|
|
21
|
-
current_request_id: null,
|
|
22
|
-
current_timezone: 'Asia/Jerusalem',
|
|
23
|
-
current_user_id: 4,
|
|
24
|
-
current_organization_id: null,
|
|
25
|
-
current_location_id: null,
|
|
26
|
-
},
|
|
27
|
-
output: {},
|
|
28
|
-
humanized: {
|
|
29
|
-
action: 'Monitor Event Queue',
|
|
30
|
-
input: '',
|
|
31
|
-
output: '',
|
|
32
|
-
errors: [
|
|
33
|
-
'Action Actions::Katello::EventQueue::Monitor is already active',
|
|
34
|
-
],
|
|
35
|
-
},
|
|
36
|
-
cli_example: null,
|
|
37
|
-
executionPlan: {
|
|
38
|
-
state: 'paused',
|
|
39
|
-
cancellable: false,
|
|
40
|
-
},
|
|
41
|
-
help:
|
|
42
|
-
"A paused task represents a process that has not finished properly. Any task in paused state can lead to potential inconsistency and needs to be resolved.\nThe recommended approach is to investigate the error messages below and in 'errors' tab, address the primary cause of the issue and resume the task.",
|
|
43
|
-
hasSubTasks: false,
|
|
44
|
-
locks: [
|
|
45
|
-
{
|
|
46
|
-
name: 'task_owner',
|
|
47
|
-
exclusive: false,
|
|
48
|
-
resource_type: 'User',
|
|
49
|
-
resource_id: 4,
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
username_path: '<a href="/users/4-admin/edit">admin</a>',
|
|
53
|
-
},
|
|
54
|
-
};
|
|
12
|
+
import TaskInfo from '../TaskInfo';
|
|
55
13
|
|
|
56
14
|
describe('TaskInfo', () => {
|
|
57
|
-
|
|
58
|
-
|
|
15
|
+
it('renders default metadata labels when given minimal props', () => {
|
|
16
|
+
render(<TaskInfo id="test" />);
|
|
17
|
+
expect(screen.getByText(/name:/i)).toBeInTheDocument();
|
|
18
|
+
expect(screen.getByText(/start at:/i)).toBeInTheDocument();
|
|
19
|
+
expect(screen.getByText(/result:/i)).toBeInTheDocument();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('renders task fields and troubleshooting when full props are provided', () => {
|
|
23
|
+
render(
|
|
24
|
+
<TaskInfo
|
|
25
|
+
id="test"
|
|
26
|
+
startAt="2019-06-17 16:04:09 +0300"
|
|
27
|
+
label="Actions::Katello::EventQueue::Monitor"
|
|
28
|
+
action="Monitor Event Queue"
|
|
29
|
+
username="admin"
|
|
30
|
+
startedAt="2019-06-17 16:04:09 +0300"
|
|
31
|
+
endedAt={null}
|
|
32
|
+
state="paused"
|
|
33
|
+
result="error"
|
|
34
|
+
progress={0.5}
|
|
35
|
+
help={
|
|
36
|
+
"A paused task represents a process that has not finished properly. Any task in paused state can lead to potential inconsistency and needs to be resolved.\nThe recommended approach is to investigate the error messages below and in 'errors' tab, address the primary cause of the issue and resume the task."
|
|
37
|
+
}
|
|
38
|
+
output={{}}
|
|
39
|
+
usernamePath=""
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
expect(screen.getByText('Monitor Event Queue')).toBeInTheDocument();
|
|
43
|
+
expect(screen.getByText(/troubleshooting/i)).toBeInTheDocument();
|
|
44
|
+
expect(
|
|
45
|
+
screen.getByText(/a paused task represents a process/i)
|
|
46
|
+
).toBeInTheDocument();
|
|
47
|
+
expect(screen.getByText(/^paused$/)).toBeInTheDocument();
|
|
48
|
+
expect(screen.getByText(/^error$/)).toBeInTheDocument();
|
|
49
|
+
});
|
|
59
50
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { Tab,
|
|
3
|
+
import { Tabs, Tab, TabTitleText } from '@patternfly/react-core';
|
|
4
4
|
import { translate as __, sprintf } from 'foremanReact/common/I18n';
|
|
5
5
|
import { STATUS } from 'foremanReact/constants';
|
|
6
6
|
import MessageBox from 'foremanReact/components/common/MessageBox';
|
|
@@ -31,6 +31,7 @@ const TaskDetails = ({
|
|
|
31
31
|
}) => {
|
|
32
32
|
const id = getTaskID();
|
|
33
33
|
const { taskReload, status, isLoading } = props;
|
|
34
|
+
const [activeTabKey, setActiveTabKey] = useState(1);
|
|
34
35
|
|
|
35
36
|
useEffect(() => {
|
|
36
37
|
taskReloadStart(id);
|
|
@@ -58,27 +59,42 @@ const TaskDetails = ({
|
|
|
58
59
|
}
|
|
59
60
|
const resumable = executionPlan ? executionPlan.state === 'paused' : false;
|
|
60
61
|
const cancellable = executionPlan ? executionPlan.cancellable : false;
|
|
62
|
+
const lockRecords = locks.concat(links);
|
|
63
|
+
|
|
64
|
+
const taskComponentProps = {
|
|
65
|
+
...props,
|
|
66
|
+
cancellable,
|
|
67
|
+
resumable,
|
|
68
|
+
id,
|
|
69
|
+
status,
|
|
70
|
+
taskProgressToggle,
|
|
71
|
+
taskReloadStart,
|
|
72
|
+
};
|
|
73
|
+
|
|
61
74
|
return (
|
|
62
75
|
<div className="task-details-react well">
|
|
63
|
-
<Tabs
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}}
|
|
78
|
-
/>
|
|
79
|
-
)}
|
|
76
|
+
<Tabs
|
|
77
|
+
id="task-details-tabs"
|
|
78
|
+
ouiaId="task-details-tabs"
|
|
79
|
+
activeKey={activeTabKey}
|
|
80
|
+
onSelect={(_event, tabKey) => setActiveTabKey(tabKey)}
|
|
81
|
+
mountOnEnter
|
|
82
|
+
>
|
|
83
|
+
<Tab
|
|
84
|
+
eventKey={1}
|
|
85
|
+
title={<TabTitleText>{__('Task')}</TabTitleText>}
|
|
86
|
+
aria-label={__('Task')}
|
|
87
|
+
ouiaId="task-details-tab-task"
|
|
88
|
+
>
|
|
89
|
+
{isLoading ? <TaskSkeleton /> : <Task {...taskComponentProps} />}
|
|
80
90
|
</Tab>
|
|
81
|
-
<Tab
|
|
91
|
+
<Tab
|
|
92
|
+
eventKey={2}
|
|
93
|
+
title={<TabTitleText>{__('Running Steps')}</TabTitleText>}
|
|
94
|
+
isDisabled={isLoading}
|
|
95
|
+
aria-label={__('Running Steps')}
|
|
96
|
+
ouiaId="task-details-tab-running-steps"
|
|
97
|
+
>
|
|
82
98
|
<RunningSteps
|
|
83
99
|
runningSteps={runningSteps}
|
|
84
100
|
id={id}
|
|
@@ -87,16 +103,40 @@ const TaskDetails = ({
|
|
|
87
103
|
taskReloadStart={taskReloadStart}
|
|
88
104
|
/>
|
|
89
105
|
</Tab>
|
|
90
|
-
<Tab
|
|
106
|
+
<Tab
|
|
107
|
+
eventKey={3}
|
|
108
|
+
title={<TabTitleText>{__('Errors')}</TabTitleText>}
|
|
109
|
+
isDisabled={isLoading}
|
|
110
|
+
aria-label={__('Errors')}
|
|
111
|
+
ouiaId="task-details-tab-errors"
|
|
112
|
+
>
|
|
91
113
|
<Errors executionPlan={executionPlan} failedSteps={failedSteps} />
|
|
92
114
|
</Tab>
|
|
93
|
-
<Tab
|
|
94
|
-
|
|
115
|
+
<Tab
|
|
116
|
+
eventKey={4}
|
|
117
|
+
title={<TabTitleText>{__('Locks')}</TabTitleText>}
|
|
118
|
+
isDisabled={isLoading}
|
|
119
|
+
aria-label={__('Locks')}
|
|
120
|
+
ouiaId="task-details-tab-locks"
|
|
121
|
+
>
|
|
122
|
+
<Locks locks={lockRecords} />
|
|
95
123
|
</Tab>
|
|
96
|
-
<Tab
|
|
124
|
+
<Tab
|
|
125
|
+
eventKey={5}
|
|
126
|
+
title={<TabTitleText>{__('Dependencies')}</TabTitleText>}
|
|
127
|
+
isDisabled={isLoading}
|
|
128
|
+
aria-label={__('Dependencies')}
|
|
129
|
+
ouiaId="task-details-tab-dependencies"
|
|
130
|
+
>
|
|
97
131
|
<Dependencies dependsOn={dependsOn} blocks={blocks} />
|
|
98
132
|
</Tab>
|
|
99
|
-
<Tab
|
|
133
|
+
<Tab
|
|
134
|
+
eventKey={6}
|
|
135
|
+
title={<TabTitleText>{__('Raw')}</TabTitleText>}
|
|
136
|
+
isDisabled={isLoading}
|
|
137
|
+
aria-label={__('Raw')}
|
|
138
|
+
ouiaId="task-details-tab-raw"
|
|
139
|
+
>
|
|
100
140
|
<Raw
|
|
101
141
|
id={id}
|
|
102
142
|
label={props.label}
|
|
@@ -1,24 +1,48 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
2
4
|
|
|
3
5
|
import TaskDetails from '../TaskDetails';
|
|
4
6
|
import { minProps } from './TaskDetails.fixtures';
|
|
5
7
|
|
|
6
|
-
const fixtures = {
|
|
7
|
-
'render with loading Props': { ...minProps, isLoading: true },
|
|
8
|
-
'render with error Props': {
|
|
9
|
-
...minProps,
|
|
10
|
-
status: 'ERROR',
|
|
11
|
-
APIerror: { message: 'some-error' },
|
|
12
|
-
},
|
|
13
|
-
'render with min Props': minProps,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
8
|
delete window.location;
|
|
17
9
|
window.location = new URL(
|
|
18
10
|
'https://foreman.com/foreman_tasks/tasks/a15dd820-32f1-4ced-9ab7-c0fab8234c47/'
|
|
19
11
|
);
|
|
20
12
|
|
|
21
13
|
describe('TaskDetails', () => {
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
it('shows error message when status is ERROR', () => {
|
|
15
|
+
render(
|
|
16
|
+
<TaskDetails
|
|
17
|
+
{...minProps}
|
|
18
|
+
status="ERROR"
|
|
19
|
+
APIerror={{ message: 'some-error' }}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
expect(
|
|
23
|
+
screen.getByText(/could not receive data: some-error/i)
|
|
24
|
+
).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('shows skeleton while loading on the Task tab', () => {
|
|
28
|
+
const { container } = render(<TaskDetails {...minProps} isLoading />);
|
|
29
|
+
expect(
|
|
30
|
+
container.querySelector('.react-loading-skeleton')
|
|
31
|
+
).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('renders six tabs with expected labels', () => {
|
|
35
|
+
render(<TaskDetails {...minProps} />);
|
|
36
|
+
expect(document.getElementById('task-details-tabs')).toBeInTheDocument();
|
|
37
|
+
expect(screen.getByRole('tab', { name: /^task$/i })).toBeInTheDocument();
|
|
38
|
+
expect(
|
|
39
|
+
screen.getByRole('tab', { name: /running steps/i })
|
|
40
|
+
).toBeInTheDocument();
|
|
41
|
+
expect(screen.getByRole('tab', { name: /errors/i })).toBeInTheDocument();
|
|
42
|
+
expect(screen.getByRole('tab', { name: /locks/i })).toBeInTheDocument();
|
|
43
|
+
expect(
|
|
44
|
+
screen.getByRole('tab', { name: /dependencies/i })
|
|
45
|
+
).toBeInTheDocument();
|
|
46
|
+
expect(screen.getByRole('tab', { name: /raw/i })).toBeInTheDocument();
|
|
47
|
+
});
|
|
24
48
|
});
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { testActionSnapshotWithFixtures } from '@theforeman/test';
|
|
2
1
|
import {
|
|
3
2
|
taskReloadStop,
|
|
4
3
|
taskReloadStart,
|
|
5
4
|
cancelStep,
|
|
6
5
|
} from '../TaskDetailsActions';
|
|
6
|
+
import {
|
|
7
|
+
FOREMAN_TASK_DETAILS,
|
|
8
|
+
TASK_STEP_CANCEL,
|
|
9
|
+
} from '../TaskDetailsConstants';
|
|
7
10
|
|
|
8
11
|
jest.mock('foremanReact/components/ToastsList', () => ({
|
|
9
12
|
addToast: toast => ({
|
|
@@ -14,11 +17,53 @@ jest.mock('foremanReact/components/ToastsList', () => ({
|
|
|
14
17
|
}),
|
|
15
18
|
}));
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
'should
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
describe('TaskDetails - Actions', () => {
|
|
21
|
+
it('should stop reload', () => {
|
|
22
|
+
expect(taskReloadStop()).toEqual({
|
|
23
|
+
type: 'STOP_INTERVAL',
|
|
24
|
+
key: FOREMAN_TASK_DETAILS,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should start reload', () => {
|
|
29
|
+
const dispatch = jest.fn();
|
|
30
|
+
taskReloadStart(1)(dispatch);
|
|
31
|
+
|
|
32
|
+
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
33
|
+
const [action] = dispatch.mock.calls[0];
|
|
34
|
+
expect(action.type).toBe('API_GET');
|
|
35
|
+
expect(action.interval).toBe(5000);
|
|
36
|
+
expect(action.payload.key).toBe(FOREMAN_TASK_DETAILS);
|
|
37
|
+
expect(action.payload.url).toBe(
|
|
38
|
+
'/foreman_tasks/api/tasks/1/details?include_permissions'
|
|
39
|
+
);
|
|
40
|
+
expect(action.payload.handleSuccess).toEqual(expect.any(Function));
|
|
41
|
+
expect(action.payload.handleError).toEqual(expect.any(Function));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should cancelStep', async () => {
|
|
45
|
+
const dispatch = jest.fn();
|
|
46
|
+
await cancelStep('task-id', 'step-id')(dispatch);
|
|
47
|
+
|
|
48
|
+
expect(dispatch).toHaveBeenCalledTimes(2);
|
|
49
|
+
|
|
50
|
+
expect(dispatch.mock.calls[0][0]).toEqual({
|
|
51
|
+
type: 'TOASTS_ADD',
|
|
52
|
+
payload: {
|
|
53
|
+
message: {
|
|
54
|
+
message: 'Trying to cancel step step-id',
|
|
55
|
+
type: 'info',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
22
59
|
|
|
23
|
-
|
|
24
|
-
|
|
60
|
+
const postAction = dispatch.mock.calls[1][0];
|
|
61
|
+
expect(postAction.type).toBe('API_POST');
|
|
62
|
+
expect(postAction.payload.key).toBe(TASK_STEP_CANCEL);
|
|
63
|
+
expect(postAction.payload.url).toBe(
|
|
64
|
+
'/foreman_tasks/tasks/task-id/cancel_step?step_id=step-id'
|
|
65
|
+
);
|
|
66
|
+
expect(postAction.payload.handleSuccess).toEqual(expect.any(Function));
|
|
67
|
+
expect(postAction.payload.handleError).toEqual(expect.any(Function));
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,11 +1,57 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
|
|
5
|
+
import { TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS } from '../TasksDonutChart/TasksDonutChartConstants';
|
|
2
6
|
|
|
3
7
|
import PausedTasksCard from './PausedTasksCard';
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
jest.mock('../TasksDonutChart/TasksDonutChart', () => {
|
|
10
|
+
const React = require('react');
|
|
11
|
+
const Stub = props => (
|
|
12
|
+
<div
|
|
13
|
+
data-testid="tasks-donut-chart-stub"
|
|
14
|
+
data-last={props.last}
|
|
15
|
+
data-older={props.older}
|
|
16
|
+
data-focused-on={props.focusedOn}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
Stub.displayName = 'TasksDonutChart';
|
|
20
|
+
return Stub;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('PausedTasksCard', () => {
|
|
24
|
+
it('renders Paused title, card id, and chart area', () => {
|
|
25
|
+
render(<PausedTasksCard />);
|
|
26
|
+
expect(screen.getByText('Paused')).toBeInTheDocument();
|
|
27
|
+
expect(document.getElementById('paused-tasks-card')).toBeInTheDocument();
|
|
28
|
+
const chart = screen.getByTestId('tasks-donut-chart-stub');
|
|
29
|
+
expect(chart).toHaveAttribute('data-last', '0');
|
|
30
|
+
expect(chart).toHaveAttribute('data-older', '0');
|
|
31
|
+
expect(chart).toHaveAttribute(
|
|
32
|
+
'data-focused-on',
|
|
33
|
+
TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS.NORMAL
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('forwards extra props to the underlying donut card', () => {
|
|
38
|
+
const updateQuery = jest.fn();
|
|
39
|
+
render(
|
|
40
|
+
<PausedTasksCard
|
|
41
|
+
updateQuery={updateQuery}
|
|
42
|
+
data={{ last: 1, older: 2 }}
|
|
43
|
+
query={{ state: 'paused' }}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
const chart = screen.getByTestId('tasks-donut-chart-stub');
|
|
47
|
+
expect(chart).toHaveAttribute('data-last', '1');
|
|
48
|
+
expect(chart).toHaveAttribute('data-older', '2');
|
|
49
|
+
expect(chart).toHaveAttribute(
|
|
50
|
+
'data-focused-on',
|
|
51
|
+
TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS.TOTAL
|
|
52
|
+
);
|
|
9
53
|
|
|
10
|
-
|
|
11
|
-
|
|
54
|
+
fireEvent.click(screen.getByText('Paused'));
|
|
55
|
+
expect(updateQuery).toHaveBeenCalledWith({ state: 'paused' });
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -1,11 +1,57 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
|
|
5
|
+
import { TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS } from '../TasksDonutChart/TasksDonutChartConstants';
|
|
2
6
|
|
|
3
7
|
import RunningTasksCard from './RunningTasksCard';
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
jest.mock('../TasksDonutChart/TasksDonutChart', () => {
|
|
10
|
+
const React = require('react');
|
|
11
|
+
const Stub = props => (
|
|
12
|
+
<div
|
|
13
|
+
data-testid="tasks-donut-chart-stub"
|
|
14
|
+
data-last={props.last}
|
|
15
|
+
data-older={props.older}
|
|
16
|
+
data-focused-on={props.focusedOn}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
Stub.displayName = 'TasksDonutChart';
|
|
20
|
+
return Stub;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('RunningTasksCard', () => {
|
|
24
|
+
it('renders Running title, card id, and chart area', () => {
|
|
25
|
+
render(<RunningTasksCard />);
|
|
26
|
+
expect(screen.getByText('Running')).toBeInTheDocument();
|
|
27
|
+
expect(document.getElementById('running-tasks-card')).toBeInTheDocument();
|
|
28
|
+
const chart = screen.getByTestId('tasks-donut-chart-stub');
|
|
29
|
+
expect(chart).toHaveAttribute('data-last', '0');
|
|
30
|
+
expect(chart).toHaveAttribute('data-older', '0');
|
|
31
|
+
expect(chart).toHaveAttribute(
|
|
32
|
+
'data-focused-on',
|
|
33
|
+
TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS.NORMAL
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('forwards extra props to the underlying donut card', () => {
|
|
38
|
+
const updateQuery = jest.fn();
|
|
39
|
+
render(
|
|
40
|
+
<RunningTasksCard
|
|
41
|
+
updateQuery={updateQuery}
|
|
42
|
+
data={{ last: 2, older: 4 }}
|
|
43
|
+
query={{ state: 'running' }}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
const chart = screen.getByTestId('tasks-donut-chart-stub');
|
|
47
|
+
expect(chart).toHaveAttribute('data-last', '2');
|
|
48
|
+
expect(chart).toHaveAttribute('data-older', '4');
|
|
49
|
+
expect(chart).toHaveAttribute(
|
|
50
|
+
'data-focused-on',
|
|
51
|
+
TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS.TOTAL
|
|
52
|
+
);
|
|
9
53
|
|
|
10
|
-
|
|
11
|
-
|
|
54
|
+
fireEvent.click(screen.getByText('Running'));
|
|
55
|
+
expect(updateQuery).toHaveBeenCalledWith({ state: 'running' });
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { Card } from 'patternfly-
|
|
3
|
+
import { Card, CardTitle, CardBody } from '@patternfly/react-core';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import { noop } from 'foremanReact/common/helpers';
|
|
6
6
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
@@ -32,14 +32,15 @@ const ScheduledTasksCard = ({
|
|
|
32
32
|
)}
|
|
33
33
|
{...props}
|
|
34
34
|
id="scheduled-tasks-card"
|
|
35
|
+
ouiaId="scheduled-tasks-card"
|
|
35
36
|
>
|
|
36
|
-
<
|
|
37
|
-
<
|
|
37
|
+
<CardTitle onClick={onClick}>{__('Scheduled')}</CardTitle>
|
|
38
|
+
<CardBody>
|
|
38
39
|
<div className="scheduled-data" onClick={onClick}>
|
|
39
40
|
{data}
|
|
40
41
|
<p>{__('Total')}</p>
|
|
41
42
|
</div>
|
|
42
|
-
</
|
|
43
|
+
</CardBody>
|
|
43
44
|
</Card>
|
|
44
45
|
);
|
|
45
46
|
};
|
|
@@ -1,18 +1,48 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
2
4
|
|
|
3
5
|
import { TASKS_DASHBOARD_AVAILABLE_QUERY_STATES } from '../../../../TasksDashboardConstants';
|
|
4
6
|
import ScheduledTasksCard from './ScheduledTasksCard';
|
|
5
7
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
const { SCHEDULED } = TASKS_DASHBOARD_AVAILABLE_QUERY_STATES;
|
|
9
|
+
|
|
10
|
+
describe('ScheduledTasksCard', () => {
|
|
11
|
+
it('renders scheduled count, labels, and card structure', () => {
|
|
12
|
+
render(<ScheduledTasksCard data={3} />);
|
|
13
|
+
expect(screen.getByText('Scheduled')).toBeInTheDocument();
|
|
14
|
+
expect(screen.getByText('Total')).toBeInTheDocument();
|
|
15
|
+
expect(document.getElementById('scheduled-tasks-card')).toBeInTheDocument();
|
|
16
|
+
expect(document.querySelector('.scheduled-data')?.textContent).toContain(
|
|
17
|
+
'3'
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('merges optional className onto the card', () => {
|
|
22
|
+
const { container } = render(
|
|
23
|
+
<ScheduledTasksCard className="extra-scheduled-class" />
|
|
24
|
+
);
|
|
25
|
+
expect(container.querySelector('.extra-scheduled-class')).toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('marks the card selected when query state is scheduled', () => {
|
|
29
|
+
const { container } = render(
|
|
30
|
+
<ScheduledTasksCard query={{ state: SCHEDULED }} />
|
|
31
|
+
);
|
|
32
|
+
expect(container.querySelector('#scheduled-tasks-card')).toHaveClass(
|
|
33
|
+
'selected-tasks-card'
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('calls updateQuery with scheduled state when title or data area is clicked', () => {
|
|
38
|
+
const updateQuery = jest.fn();
|
|
39
|
+
render(<ScheduledTasksCard updateQuery={updateQuery} />);
|
|
40
|
+
|
|
41
|
+
fireEvent.click(screen.getByText('Scheduled'));
|
|
42
|
+
expect(updateQuery).toHaveBeenCalledWith({ state: SCHEDULED });
|
|
43
|
+
|
|
44
|
+
updateQuery.mockClear();
|
|
45
|
+
fireEvent.click(document.querySelector('.scheduled-data'));
|
|
46
|
+
expect(updateQuery).toHaveBeenCalledWith({ state: SCHEDULED });
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { Card } from 'patternfly-
|
|
3
|
+
import { Card, CardTitle, CardBody } from '@patternfly/react-core';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import { noop } from 'foremanReact/common/helpers';
|
|
6
6
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
@@ -38,11 +38,12 @@ const StoppedTasksCard = ({
|
|
|
38
38
|
)}
|
|
39
39
|
{...props}
|
|
40
40
|
id="stopped-tasks-card"
|
|
41
|
+
ouiaId="stopped-tasks-card"
|
|
41
42
|
>
|
|
42
|
-
<
|
|
43
|
+
<CardTitle onClick={() => updateQuery({ state: STOPPED })}>
|
|
43
44
|
{__('Stopped')}
|
|
44
|
-
</
|
|
45
|
-
<
|
|
45
|
+
</CardTitle>
|
|
46
|
+
<CardBody>
|
|
46
47
|
<React.Fragment>
|
|
47
48
|
<StoppedTable
|
|
48
49
|
data={data.results}
|
|
@@ -56,7 +57,7 @@ const StoppedTasksCard = ({
|
|
|
56
57
|
query={query}
|
|
57
58
|
/>
|
|
58
59
|
</React.Fragment>
|
|
59
|
-
</
|
|
60
|
+
</CardBody>
|
|
60
61
|
</Card>
|
|
61
62
|
);
|
|
62
63
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
|
-
import { Card } from 'patternfly-
|
|
4
|
+
import { Card, CardTitle, CardBody } from '@patternfly/react-core';
|
|
5
5
|
import { noop } from 'foremanReact/common/helpers';
|
|
6
6
|
|
|
7
7
|
import {
|
|
@@ -42,9 +42,10 @@ const TasksDonutCard = ({
|
|
|
42
42
|
'not-focused': focusedOn === TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS.NONE,
|
|
43
43
|
})}
|
|
44
44
|
{...props}
|
|
45
|
+
ouiaId="tasks-donut-card"
|
|
45
46
|
>
|
|
46
|
-
<
|
|
47
|
-
<
|
|
47
|
+
<CardTitle onClick={onTotalClick}>{title}</CardTitle>
|
|
48
|
+
<CardBody className="card-pf-body">
|
|
48
49
|
<TasksDonutChart
|
|
49
50
|
last={data.last}
|
|
50
51
|
older={data.older}
|
|
@@ -66,7 +67,7 @@ const TasksDonutCard = ({
|
|
|
66
67
|
})
|
|
67
68
|
}
|
|
68
69
|
/>
|
|
69
|
-
</
|
|
70
|
+
</CardBody>
|
|
70
71
|
</Card>
|
|
71
72
|
);
|
|
72
73
|
};
|