foreman-tasks 1.1.0 → 1.1.1

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/foreman_tasks/api/tasks_controller.rb +12 -5
  3. data/app/lib/foreman_tasks/concerns/polling_action_extensions.rb +12 -0
  4. data/app/models/setting/foreman_tasks.rb +6 -1
  5. data/app/services/ui_notifications/tasks/task_bulk_cancel.rb +36 -0
  6. data/app/services/ui_notifications/tasks/task_bulk_resume.rb +38 -0
  7. data/db/seeds.d/30-notification_blueprints.rb +14 -0
  8. data/foreman-tasks.gemspec +1 -0
  9. data/gemfile.d/foreman-tasks.rb +1 -0
  10. data/lib/foreman_tasks/engine.rb +1 -0
  11. data/lib/foreman_tasks/version.rb +1 -1
  12. data/script/travis_run_js_tests.sh +2 -2
  13. data/test/lib/concerns/polling_action_extensions_test.rb +34 -0
  14. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +1 -3
  15. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardConstants.js +5 -0
  16. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardHelper.js +3 -2
  17. data/webpack/ForemanTasks/Components/TasksTable/Components/SelectAllAlert.js +43 -0
  18. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/SelectAllAlert.test.js +29 -0
  19. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/SelectAllAlert.test.js.snap +75 -0
  20. data/webpack/ForemanTasks/Components/TasksTable/SubTasksPage.js +2 -1
  21. data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +164 -0
  22. data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +24 -10
  23. data/webpack/ForemanTasks/Components/TasksTable/TasksTableActionHelpers.js +52 -0
  24. data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +66 -128
  25. data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +11 -1
  26. data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +4 -3
  27. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +64 -12
  28. data/webpack/ForemanTasks/Components/TasksTable/TasksTableReducer.js +21 -2
  29. data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +6 -0
  30. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksBulkActions.test.js +112 -0
  31. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +5 -3
  32. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActionHelpers.test.js +46 -0
  33. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActions.test.js +19 -41
  34. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableHelpers.test.js +17 -1
  35. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTablePage.test.js +9 -1
  36. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableReducer.test.js +22 -1
  37. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +5 -3
  38. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksBulkActions.test.js.snap +229 -0
  39. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +5 -3
  40. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableActions.test.js.snap +39 -124
  41. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +40 -16
  42. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableReducer.test.js.snap +34 -0
  43. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/selectionHeaderCellFormatter.test.js +1 -1
  44. data/webpack/ForemanTasks/Components/TasksTable/formatters/selectionHeaderCellFormatter.js +2 -2
  45. data/webpack/ForemanTasks/Components/TasksTable/index.js +8 -2
  46. data/webpack/ForemanTasks/Components/common/ToastTypesConstants.js +11 -0
  47. metadata +31 -2
@@ -1,12 +1,22 @@
1
1
  import { getControllerSearchProps } from 'foremanReact/constants';
2
2
 
3
3
  export const TASKS_TABLE_ID = 'TASKS_TABLE';
4
+
4
5
  export const SELECT_ROWS = 'SELECT_ROWS';
5
6
  export const UNSELECT_ROWS = 'UNSELECT_ROWS';
6
7
  export const UNSELECT_ALL_ROWS = 'UNSELECT_ALL_ROWS';
8
+ export const SELECT_ALL_ROWS = 'SELECT_ALL_ROWS';
9
+ export const OPEN_SELECT_ALL = 'OPEN_SELECT_ALL';
10
+
7
11
  export const TASKS_RESUME_REQUEST = 'TASKS_RESUME_REQUEST';
8
12
  export const TASKS_RESUME_SUCCESS = 'TASKS_RESUME_SUCCESS';
9
13
  export const TASKS_RESUME_FAILURE = 'TASKS_RESUME_FAILURE';
14
+ export const TASKS_CANCEL_REQUEST = 'TASKS_CANCEL_REQUEST';
15
+ export const TASKS_CANCEL_SUCCESS = 'TASKS_CANCEL_SUCCESS';
16
+ export const TASKS_CANCEL_FAILURE = 'TASKS_CANCEL_FAILURE';
17
+
18
+ export const BULK_CANCEL_PATH = 'bulk_cancel';
19
+ export const BULK_RESUME_PATH = 'bulk_resume';
10
20
 
11
21
  export const CANCEL_CONFIRM_MODAL_ID = 'cancelConfirmModal';
12
22
  export const RESUME_CONFIRM_MODAL_ID = 'resumeConfirmModal';
@@ -16,5 +26,5 @@ export const UPDATE_CLICKED = 'UPDATE_CLICKED';
16
26
 
17
27
  export const TASKS_SEARCH_PROPS = {
18
28
  ...getControllerSearchProps('tasks'),
19
- controller: 'foreman_tasks/tasks'
29
+ controller: 'foreman_tasks/tasks',
20
30
  };
@@ -22,9 +22,10 @@ export const resolveSearchQuery = (search, history) => {
22
22
  updateURlQuery(uriQuery, history);
23
23
  };
24
24
 
25
- export const addSearchToURL = (path, query) => {
26
- const url = new URI(path);
27
- url.addSearch({ ...query, include_permissions: true });
25
+ export const getCSVurl = (path, query) => {
26
+ let url = new URI(path);
27
+ url = url.pathname(`${url.pathname()}.csv`);
28
+ url.addSearch(query);
28
29
  return url.toString();
29
30
  };
30
31
 
@@ -10,7 +10,7 @@ import { STATUS } from 'foremanReact/constants';
10
10
  import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
11
11
  import TasksDashboard from '../TasksDashboard';
12
12
  import TasksTable from './TasksTable';
13
- import { resolveSearchQuery, addSearchToURL } from './TasksTableHelpers';
13
+ import { resolveSearchQuery, getCSVurl } from './TasksTableHelpers';
14
14
  import { ConfirmationModals } from './Components/ConfirmationModals';
15
15
  import {
16
16
  TASKS_SEARCH_PROPS,
@@ -21,8 +21,17 @@ import {
21
21
  } from './TasksTableConstants';
22
22
  import { ActionSelectButton } from './Components/ActionSelectButton';
23
23
  import './TasksTablePage.scss';
24
+ import { SelectAllAlert } from './Components/SelectAllAlert';
24
25
 
25
- const TasksTablePage = ({ getBreadcrumbs, history, clicked, createHeader, ...props }) => {
26
+ const TasksTablePage = ({
27
+ getBreadcrumbs,
28
+ history,
29
+ clicked,
30
+ createHeader,
31
+ selectAllRows,
32
+ showSelectAll,
33
+ ...props
34
+ }) => {
26
35
  const url = history.location.pathname + history.location.search;
27
36
  const uriQuery = getURIQuery(url);
28
37
  const onSearch = searchQuery => {
@@ -53,15 +62,23 @@ const TasksTablePage = ({ getBreadcrumbs, history, clicked, createHeader, ...pro
53
62
  };
54
63
 
55
64
  const {
56
- bulkCancel,
57
- bulkResume,
65
+ bulkCancelById,
66
+ bulkCancelBySearch,
67
+ bulkResumeById,
68
+ bulkResumeBySearch,
58
69
  cancelTask,
59
70
  resumeTask,
60
71
  parentTaskID,
61
72
  } = props;
62
73
  const tasksActions = {
63
74
  cancelSelectedTasks: () => {
64
- bulkCancel({ selected: getSelectedTasks(), url, parentTaskID });
75
+ props.allRowsSelected
76
+ ? bulkCancelBySearch({ query: uriQuery, parentTaskID })
77
+ : bulkCancelById({
78
+ selected: getSelectedTasks(),
79
+ url,
80
+ parentTaskID,
81
+ });
65
82
  },
66
83
  cancelTask: () => {
67
84
  cancelTask({
@@ -72,7 +89,13 @@ const TasksTablePage = ({ getBreadcrumbs, history, clicked, createHeader, ...pro
72
89
  });
73
90
  },
74
91
  resumeSelectedTasks: () => {
75
- bulkResume({ selected: getSelectedTasks(), url, parentTaskID });
92
+ props.allRowsSelected
93
+ ? bulkResumeBySearch({ query: uriQuery, parentTaskID })
94
+ : bulkResumeById({
95
+ selected: getSelectedTasks(),
96
+ url,
97
+ parentTaskID,
98
+ });
76
99
  },
77
100
  resumeTask: () => {
78
101
  resumeTask({
@@ -88,7 +111,9 @@ const TasksTablePage = ({ getBreadcrumbs, history, clicked, createHeader, ...pro
88
111
  <div className="tasks-table-wrapper">
89
112
  <ConfirmationModals
90
113
  tasksActions={tasksActions}
91
- selectedRowsLen={props.selectedRows.length}
114
+ selectedRowsLen={
115
+ props.allRowsSelected ? props.itemCount : props.selectedRows.length
116
+ }
92
117
  modalProps={modalProps}
93
118
  />
94
119
  <PageLayout
@@ -102,11 +127,11 @@ const TasksTablePage = ({ getBreadcrumbs, history, clicked, createHeader, ...pro
102
127
  <React.Fragment>
103
128
  {props.status === STATUS.PENDING && <Spinner size="lg" loading />}
104
129
  <ExportButton
105
- url={addSearchToURL('/foreman_tasks/tasks.csv', uriQuery)}
130
+ url={getCSVurl(url, uriQuery)}
106
131
  title={__('Export All')}
107
132
  />
108
133
  <ActionSelectButton
109
- disabled={props.selectedRows.length < 1}
134
+ disabled={!(props.selectedRows.length || props.allRowsSelected)}
110
135
  onCancel={modalProps.cancelSelectedModal.setModalOpen}
111
136
  onResume={modalProps.resumeSelectedModal.setModalOpen}
112
137
  />
@@ -117,13 +142,30 @@ const TasksTablePage = ({ getBreadcrumbs, history, clicked, createHeader, ...pro
117
142
  <TasksDashboard history={history} parentTaskID={props.parentTaskID} />
118
143
  }
119
144
  >
120
- <TasksTable history={history} {...props} modalProps={modalProps} />
145
+ <React.Fragment>
146
+ {showSelectAll && props.itemCount >= props.pagination.perPage && (
147
+ <SelectAllAlert
148
+ itemCount={props.itemCount}
149
+ perPage={props.pagination.perPage}
150
+ selectAllRows={selectAllRows}
151
+ unselectAllRows={props.unselectAllRows}
152
+ allRowsSelected={props.allRowsSelected}
153
+ />
154
+ )}
155
+ <TasksTable history={history} {...props} modalProps={modalProps} />
156
+ </React.Fragment>
121
157
  </PageLayout>
122
158
  </div>
123
159
  );
124
160
  };
125
161
 
126
162
  TasksTablePage.propTypes = {
163
+ allRowsSelected: PropTypes.bool,
164
+ itemCount: PropTypes.number.isRequired,
165
+ pagination: PropTypes.shape({
166
+ perPage: PropTypes.number,
167
+ }),
168
+ selectAllRows: PropTypes.func.isRequired,
127
169
  results: PropTypes.array.isRequired,
128
170
  getTableItems: PropTypes.func.isRequired,
129
171
  getBreadcrumbs: PropTypes.func.isRequired,
@@ -132,8 +174,10 @@ TasksTablePage.propTypes = {
132
174
  history: PropTypes.object.isRequired,
133
175
  cancelTask: PropTypes.func.isRequired,
134
176
  resumeTask: PropTypes.func.isRequired,
135
- bulkCancel: PropTypes.func.isRequired,
136
- bulkResume: PropTypes.func.isRequired,
177
+ bulkCancelById: PropTypes.func.isRequired,
178
+ bulkCancelBySearch: PropTypes.func.isRequired,
179
+ bulkResumeById: PropTypes.func.isRequired,
180
+ bulkResumeBySearch: PropTypes.func.isRequired,
137
181
  selectedRows: PropTypes.arrayOf(PropTypes.string),
138
182
  parentTaskID: PropTypes.string,
139
183
  createHeader: PropTypes.func,
@@ -142,15 +186,23 @@ TasksTablePage.propTypes = {
142
186
  taskName: PropTypes.string,
143
187
  parentTaskID: PropTypes.string,
144
188
  }),
189
+ showSelectAll: PropTypes.bool,
190
+ unselectAllRows: PropTypes.func.isRequired,
145
191
  };
146
192
 
147
193
  TasksTablePage.defaultProps = {
194
+ pagination: {
195
+ page: 1,
196
+ perPage: 20,
197
+ },
198
+ allRowsSelected: false,
148
199
  actionName: '',
149
200
  status: STATUS.PENDING,
150
201
  selectedRows: [],
151
202
  parentTaskID: null,
152
203
  clicked: {},
153
204
  createHeader: () => __('Tasks'),
205
+ showSelectAll: false,
154
206
  };
155
207
 
156
208
  export default TasksTablePage;
@@ -9,6 +9,8 @@ import {
9
9
  UNSELECT_ROWS,
10
10
  UNSELECT_ALL_ROWS,
11
11
  UPDATE_CLICKED,
12
+ SELECT_ALL_ROWS,
13
+ OPEN_SELECT_ALL,
12
14
  } from './TasksTableConstants';
13
15
 
14
16
  const initialState = Immutable({
@@ -21,6 +23,8 @@ export const TasksTableQueryReducer = (state = initialState, action) => {
21
23
  response || {};
22
24
  const ACTION_TYPES = createTableActionTypes(TASKS_TABLE_ID);
23
25
  switch (type) {
26
+ case SELECT_ALL_ROWS:
27
+ return state.set('allRowsSelected', true);
24
28
  case ACTION_TYPES.SUCCESS:
25
29
  return Immutable.merge(state, {
26
30
  itemCount: subtotal,
@@ -33,13 +37,28 @@ export const TasksTableQueryReducer = (state = initialState, action) => {
33
37
  });
34
38
  case SELECT_ROWS:
35
39
  return state.set('selectedRows', union(payload, state.selectedRows));
40
+ case OPEN_SELECT_ALL:
41
+ return state.set('showSelectAll', true);
36
42
  case UNSELECT_ROWS:
43
+ if (state.allRowsSelected) {
44
+ // User can unselect rows if only the page rows are selected
45
+ return state
46
+ .set(
47
+ 'selectedRows',
48
+ payload.results.map(row => row.id).filter(row => row !== payload.id)
49
+ )
50
+ .set('allRowsSelected', false)
51
+ .set('showSelectAll', false);
52
+ }
37
53
  return state.set(
38
54
  'selectedRows',
39
- state.selectedRows.filter(row => row !== payload)
55
+ state.selectedRows.filter(row => row !== payload.id)
40
56
  );
41
57
  case UNSELECT_ALL_ROWS:
42
- return state.set('selectedRows', []);
58
+ return state
59
+ .set('selectedRows', [])
60
+ .set('allRowsSelected', false)
61
+ .set('showSelectAll', false);
43
62
  case UPDATE_CLICKED:
44
63
  return state.set('clicked', payload.clicked);
45
64
  default:
@@ -48,3 +48,9 @@ export const selectError = state => selectTasksTableContent(state).error;
48
48
 
49
49
  export const selectSort = state =>
50
50
  selectTasksTableQuery(state).sort || { by: 'started_at', order: 'DESC' };
51
+
52
+ export const selectAllRowsSelected = state =>
53
+ selectTasksTableQuery(state).allRowsSelected;
54
+
55
+ export const selectShowSelectAll = state =>
56
+ selectTasksTableQuery(state).showSelectAll;
@@ -0,0 +1,112 @@
1
+ import { testActionSnapshotWithFixtures } from '@theforeman/test';
2
+ import API from 'foremanReact/API';
3
+ import {
4
+ bulkCancelById,
5
+ bulkCancelBySearch,
6
+ bulkResumeById,
7
+ bulkResumeBySearch,
8
+ } from '../TasksBulkActions';
9
+
10
+ jest.mock('foremanReact/components/common/table', () => ({
11
+ getTableItemsAction: jest.fn(controller => controller),
12
+ }));
13
+
14
+ jest.mock('foremanReact/API');
15
+
16
+ const task = {
17
+ id: 'some-id',
18
+ name: 'some-name',
19
+ };
20
+
21
+ const fixtures = {
22
+ 'handles bulkResumeById requests that fail': () => {
23
+ const selected = [{ ...task, isResumable: true }];
24
+
25
+ API.post.mockImplementation(() =>
26
+ Promise.reject(new Error('Network Error'))
27
+ );
28
+ return bulkResumeById({ selected, url: 'some-url' });
29
+ },
30
+ 'handles resumable bulkResumeById requests': () => {
31
+ const selected = [{ ...task, isResumable: true }];
32
+
33
+ API.post.mockImplementation(() => ({
34
+ data: {
35
+ resumed: [{ action: 'I am resumed' }],
36
+ failed: [{ action: 'I am failed' }],
37
+ },
38
+ }));
39
+ return bulkResumeById({ selected, url: 'some-url' });
40
+ },
41
+ 'handles bulkCancelById requests': () => {
42
+ const selected = [{ ...task, isCancellable: true }];
43
+
44
+ API.post.mockImplementation(() => ({
45
+ data: {
46
+ cancelled: [{ action: 'I am cancelled' }],
47
+ },
48
+ }));
49
+ return bulkCancelById({ selected, url: 'some-url' });
50
+ },
51
+ 'handles skipped bulkResumeById requests': () => {
52
+ const selected = [{ ...task, isResumable: true }];
53
+
54
+ API.post.mockImplementation(() => ({
55
+ data: {
56
+ skipped: [{ action: 'I am skipped' }],
57
+ },
58
+ }));
59
+ return bulkResumeById({ selected, url: 'some-url' });
60
+ },
61
+ 'handles skipped bulkCancelById requests': () => {
62
+ const selected = [{ ...task, isCancellable: true }];
63
+
64
+ API.post.mockImplementation(() => ({
65
+ data: {
66
+ skipped: [{ action: 'I am skipped' }],
67
+ },
68
+ }));
69
+ return bulkCancelById({ selected, url: 'some-url' });
70
+ },
71
+ 'handles bulkCancelById requests that are not cancellable': () => {
72
+ const selected = [{ ...task, isCancellable: false }];
73
+ return bulkCancelById({ selected, url: 'some-url' });
74
+ },
75
+ 'handles bulkResumeById requests that are not resumable': () => {
76
+ const selected = [{ ...task, isResumable: false, isCancellable: false }];
77
+ return bulkResumeById({ selected, url: 'some-url' });
78
+ },
79
+
80
+ 'handles bulkCancelBySearch requests': () => {
81
+ API.post.mockImplementation(() => ({
82
+ data: {
83
+ cancelled: [{ action: 'I am cancelled' }],
84
+ skipped: [{ action: 'I am skipped' }],
85
+ },
86
+ }));
87
+ return bulkCancelBySearch({
88
+ query: { search: {} },
89
+ url: 'some-url',
90
+ parentTaskID: 'parent',
91
+ });
92
+ },
93
+
94
+ 'handles bulkResumeBySearch requests': () => {
95
+ API.post.mockImplementation(() => ({
96
+ data: {
97
+ cancelled: [{ action: 'I am cancelled' }],
98
+ skipped: [{ action: 'I am skipped' }],
99
+ failed: [{ action: 'I am failed' }],
100
+ },
101
+ }));
102
+ return bulkResumeBySearch({
103
+ query: { search: {} },
104
+ url: 'some-url',
105
+ parentTaskID: 'parent',
106
+ });
107
+ },
108
+ };
109
+
110
+ describe('TasksTable bulk actions', () => {
111
+ testActionSnapshotWithFixtures(fixtures);
112
+ });
@@ -6,8 +6,11 @@ export const minProps = {
6
6
  itemCount: 2,
7
7
  cancelTask: jest.fn(),
8
8
  resumeTask: jest.fn(),
9
- bulkCancel: jest.fn(),
10
- bulkResume: jest.fn(),
9
+ bulkResumeById: jest.fn(),
10
+ bulkCancelById: jest.fn(),
11
+ bulkResumeBySearch: jest.fn(),
12
+ bulkCancelBySearch: jest.fn(),
13
+ selectPage: jest.fn(),
11
14
  selectAllRows: jest.fn(),
12
15
  unselectAllRows: jest.fn(),
13
16
  selectRow: jest.fn(),
@@ -18,7 +21,6 @@ export const minProps = {
18
21
  perPage: 10,
19
22
  },
20
23
  history: { location: { search: '' } },
21
- status: STATUS.RESOLVED,
22
24
  results: ['a', 'b'],
23
25
  sort: {
24
26
  by: 'q',
@@ -0,0 +1,46 @@
1
+ import { convertDashboardQuery } from '../TasksTableActionHelpers';
2
+ import {
3
+ TASKS_DASHBOARD_JS_QUERY_MODES,
4
+ TASKS_DASHBOARD_AVAILABLE_TIMES,
5
+ } from '../../TasksDashboard/TasksDashboardConstants';
6
+
7
+ let realDate;
8
+
9
+ describe('convertDashboardQuery', () => {
10
+ it('convertDashboardQuery should work with full query', () => {
11
+ // Setup
12
+ const currentDate = new Date('2020-05-08T11:01:58.135Z');
13
+ realDate = Date;
14
+ global.Date = class extends Date {
15
+ constructor(date) {
16
+ if (date) {
17
+ // eslint-disable-next-line constructor-super
18
+ return super(date);
19
+ }
20
+ return currentDate;
21
+ }
22
+ };
23
+ const query = {
24
+ time_mode: TASKS_DASHBOARD_JS_QUERY_MODES.RECENT,
25
+ time_horizon: TASKS_DASHBOARD_AVAILABLE_TIMES.WEEK,
26
+ state: 'stopped',
27
+ result: 'error',
28
+ search: 'action~job',
29
+ };
30
+ expect(convertDashboardQuery(query)).toEqual(
31
+ 'state=stopped and result=error and action~job and (state_updated_at>2020-05-01T11:01:58.135Z or state_updated_at = NULL)'
32
+ );
33
+ // Cleanup
34
+ global.Date = realDate;
35
+ });
36
+ it('convertDashboardQuery should work with only search query', () => {
37
+ const query = {
38
+ search: 'action~job',
39
+ };
40
+ expect(convertDashboardQuery(query)).toEqual('action~job');
41
+ });
42
+ it('convertDashboardQuery should work with no query', () => {
43
+ const query = {};
44
+ expect(convertDashboardQuery(query)).toEqual('');
45
+ });
46
+ });
@@ -1,4 +1,7 @@
1
- import { testActionSnapshotWithFixtures } from '@theforeman/test';
1
+ import {
2
+ testActionSnapshotWithFixtures,
3
+ IntegrationTestHelper,
4
+ } from '@theforeman/test';
2
5
  import API from 'foremanReact/API';
3
6
  import { TASKS_TABLE_ID } from '../TasksTableConstants';
4
7
  import {
@@ -7,8 +10,7 @@ import {
7
10
  cancelTaskRequest,
8
11
  resumeTask,
9
12
  resumeTaskRequest,
10
- bulkCancel,
11
- bulkResume,
13
+ selectPage,
12
14
  } from '../TasksTableActions';
13
15
 
14
16
  jest.mock('foremanReact/components/common/table', () => ({
@@ -24,13 +26,7 @@ const taskInfo = {
24
26
  taskName: 'some-name',
25
27
  };
26
28
 
27
- const task = {
28
- id: 'some-id',
29
- name: 'some-name',
30
- };
31
-
32
29
  const fixtures = {
33
- 'should cancelTask': () => cancelTask({ ...taskInfo, url: 'some-url' }),
34
30
  'should cancelTaskRequest and succeed': () =>
35
31
  cancelTaskRequest('some-id', 'some-name'),
36
32
  'should cancelTaskRequest and fail': () => {
@@ -40,7 +36,6 @@ const fixtures = {
40
36
  return cancelTaskRequest('some-id', 'some-name');
41
37
  },
42
38
 
43
- 'should resumeTask': () => resumeTask({ ...taskInfo, url: 'some-url' }),
44
39
  'should resumeTaskRequest and succeed': () => {
45
40
  API.post.mockImplementation(() => ({ data: 'some-data' }));
46
41
  return resumeTaskRequest('some-id', 'some-name');
@@ -51,41 +46,24 @@ const fixtures = {
51
46
  );
52
47
  return resumeTaskRequest('some-id', 'some-name');
53
48
  },
54
- 'handles bulkResume requests that fail': () => {
55
- const selected = [{ ...task, isResumable: true, isCancellable: false }];
56
-
57
- API.post.mockImplementation(() =>
58
- Promise.reject(new Error('Network Error'))
59
- );
60
- return bulkResume({ selected, url: 'some-url' });
61
- },
62
- 'handles resumable bulkResume requests': () => {
63
- const selected = [{ ...task, isResumable: true, isCancellable: false }];
64
-
65
- API.post.mockImplementation(() => ({
66
- data: {
67
- resumed: [{ action: 'I am resumed' }],
68
- failed: [{ action: 'I am failed' }],
69
- },
70
- }));
71
- return bulkResume({ selected, url: 'some-url' });
72
- },
73
- 'handles bulkCancel requests': () => {
74
- const selected = [{ ...task, isResumable: false, isCancellable: true }];
75
- return bulkCancel({ selected, url: 'some-url' });
76
- },
77
- 'handles bulkCancel requests that are not cancellable': () => {
78
- const selected = [{ ...task, isResumable: false, isCancellable: false }];
79
- return bulkCancel({ selected, url: 'some-url' });
80
- },
81
- 'handles bulkResume requests that are not resumable': () => {
82
- const selected = [{ ...task, isResumable: false, isCancellable: false }];
83
- return bulkResume({ selected, url: 'some-url' });
84
- },
49
+ 'should selectPage and succeed': () => selectPage([{ id: 'some-id' }]),
85
50
  };
86
51
  describe('TasksTable actions', () => {
87
52
  it('getTableItems should reuse common/table/getTableItemsAction', () => {
88
53
  expect(getTableItems('')).toEqual(TASKS_TABLE_ID);
89
54
  });
55
+
56
+ it('should resumeTask', async () => {
57
+ const dispatch = jest.fn();
58
+ resumeTask({ ...taskInfo, url: 'some-url' })(dispatch);
59
+ await IntegrationTestHelper.flushAllPromises();
60
+ expect(dispatch.mock.calls).toHaveLength(3);
61
+ });
62
+ it('should cancelTask', async () => {
63
+ const dispatch = jest.fn();
64
+ cancelTask({ ...taskInfo, url: 'some-url' })(dispatch);
65
+ await IntegrationTestHelper.flushAllPromises();
66
+ expect(dispatch.mock.calls).toHaveLength(3);
67
+ });
90
68
  testActionSnapshotWithFixtures(fixtures);
91
69
  });