katello 3.15.0.rc1.3 → 3.15.0.rc2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of katello might be problematic. Click here for more details.

Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/v2/api_controller.rb +5 -0
  3. data/app/controllers/katello/api/v2/host_packages_controller.rb +1 -0
  4. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +1 -1
  5. data/app/lib/actions/katello/content_view/destroy.rb +1 -0
  6. data/app/lib/actions/katello/host/erratum/applicable_errata_install.rb +1 -1
  7. data/app/lib/actions/pulp3/content_view/delete_repository_references.rb +26 -0
  8. data/app/lib/actions/pulp3/orchestration/repository/delete.rb +8 -1
  9. data/app/lib/actions/pulp3/repository/delete_version.rb +20 -0
  10. data/app/lib/katello/concerns/base_template_scope_extensions.rb +23 -1
  11. data/app/lib/katello/errors.rb +2 -0
  12. data/app/models/katello/repository.rb +44 -9
  13. data/app/models/setting/content.rb +8 -2
  14. data/app/services/katello/pulp3/migration.rb +19 -4
  15. data/app/services/katello/pulp3/repository.rb +4 -0
  16. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-details.controller.js +13 -0
  17. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-subscriptions.controller.js +4 -2
  18. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-subscriptions.html +11 -8
  19. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/katello-agent-notice.html +8 -0
  20. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-errata-modal.html +2 -0
  21. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-packages-modal.html +2 -0
  22. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-errata.html +2 -0
  23. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-actions.html +1 -0
  24. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-applicable.html +2 -1
  25. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-installed.html +4 -2
  26. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-details.controller.js +10 -1
  27. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +6 -3
  28. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-subscriptions.html +4 -2
  29. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-client.html +9 -1
  30. data/lib/katello/tasks/pulp3_content_switchover.rake +2 -1
  31. data/lib/katello/version.rb +1 -1
  32. data/webpack/__mocks__/foremanReact/redux/API.js +6 -0
  33. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware/IntervalSelectors.js +6 -0
  34. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware/index.js +11 -0
  35. data/webpack/scenes/Subscriptions/Manifest/ManifestHistoryReducer.js +0 -12
  36. data/webpack/scenes/Subscriptions/Manifest/index.js +0 -1
  37. data/webpack/scenes/Subscriptions/SubscriptionActions.js +49 -10
  38. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +10 -5
  39. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +37 -43
  40. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +55 -131
  41. data/webpack/scenes/Subscriptions/SubscriptionsSelectors.js +2 -5
  42. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +1 -1
  43. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsActions.test.js +75 -8
  44. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +35 -8
  45. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsReducer.test.js +58 -46
  46. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsSelectors.test.js +3 -5
  47. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsActions.test.js.snap +85 -9
  48. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +0 -2
  49. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsReducer.test.js.snap +111 -124
  50. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsSelectors.test.js.snap +2 -12
  51. data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +2 -8
  52. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +1 -16
  53. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +1 -6
  54. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Dialogs/UpdateDialog.js +0 -25
  55. data/webpack/scenes/Subscriptions/index.js +2 -5
  56. data/webpack/scenes/Tasks/TaskActions.js +34 -104
  57. data/webpack/scenes/Tasks/TaskSelectors.js +7 -0
  58. data/webpack/scenes/Tasks/__tests__/TaskActions.test.js +17 -154
  59. data/webpack/scenes/Tasks/__tests__/TaskSelectors.test.js +21 -0
  60. data/webpack/scenes/Tasks/__tests__/__snapshots__/TaskActions.test.js.snap +57 -0
  61. data/webpack/scenes/Tasks/__tests__/__snapshots__/TaskSelectors.test.js.snap +9 -0
  62. data/webpack/scenes/Tasks/__tests__/task.fixtures.js +0 -82
  63. data/webpack/scenes/Tasks/helpers.js +13 -6
  64. metadata +12 -3
  65. data/webpack/scenes/Tasks/TaskConstants.js +0 -9
@@ -3,11 +3,10 @@ import PropTypes from 'prop-types';
3
3
  import Immutable from 'seamless-immutable';
4
4
  import { translate as __ } from 'foremanReact/common/I18n';
5
5
  import { propsToCamelCase } from 'foremanReact/common/helpers';
6
- import { isEmpty, isEqual } from 'lodash';
6
+ import { isEmpty } from 'lodash';
7
7
  import { Grid, Row, Col, Alert } from 'patternfly-react';
8
8
  import ModalProgressBar from 'foremanReact/components/common/ModalProgressBar';
9
9
  import PermissionDenied from 'foremanReact/components/PermissionDenied';
10
- import { renderTaskFinishedToast, renderTaskStartedToast } from '../Tasks/helpers';
11
10
  import ManageManifestModal from './Manifest/';
12
11
  import { MANAGE_MANIFEST_MODAL_ID } from './Manifest/ManifestConstants';
13
12
  import { SubscriptionsTable } from './components/SubscriptionsTable';
@@ -17,11 +16,8 @@ import api, { orgId } from '../../services/api';
17
16
 
18
17
  import { createSubscriptionParams } from './SubscriptionActions.js';
19
18
  import {
20
- BLOCKING_FOREMAN_TASK_TYPES,
21
- BULK_TASK_SEARCH_INTERVAL,
22
19
  SUBSCRIPTION_TABLE_NAME,
23
20
  } from './SubscriptionConstants';
24
- import { POLL_TASK_INTERVAL } from '../Tasks/TaskConstants';
25
21
  import './SubscriptionsPage.scss';
26
22
 
27
23
  class SubscriptionsPage extends Component {
@@ -34,64 +30,41 @@ class SubscriptionsPage extends Component {
34
30
 
35
31
  componentDidMount() {
36
32
  this.props.resetTasks();
37
- this.props.loadSetting('content_disconnected');
38
- this.props.loadSubscriptions();
33
+
34
+ const { id } = this.props.organization;
35
+ if (id) { // navigating from another react page
36
+ this.loadData();
37
+ }
39
38
  }
40
39
 
41
40
  componentDidUpdate(prevProps) {
42
41
  const {
43
- tasks = [], organization, taskModalOpened, openTaskModal, closeTaskModal,
42
+ organization, task, handleTask,
44
43
  } = this.props;
45
- const { tasks: prevTasks = [] } = prevProps;
46
- const currentOrg = Number(orgId());
47
- const numberOfTasks = tasks.length;
48
- const numberOfPrevTasks = prevTasks.length;
49
- const [task] = tasks;
50
-
51
- if (numberOfTasks > 0) {
52
- if (currentOrg === task.input.current_organization_id) {
53
- if (!taskModalOpened) {
54
- openTaskModal();
55
- }
56
- }
57
44
 
58
- if (numberOfPrevTasks === 0 || prevTasks[0].id !== task.id) {
59
- if (currentOrg === task.input.current_organization_id) {
60
- this.handleDoneTask(task);
61
- } else if (taskModalOpened) {
62
- closeTaskModal();
63
- }
64
- }
45
+ if (task) {
46
+ handleTask(task);
65
47
  }
66
48
 
67
- if (numberOfTasks === 0) {
68
- if (taskModalOpened && !this.state.pollingATask) {
69
- closeTaskModal();
49
+ if (organization) {
50
+ if (!prevProps.organization || prevProps.organization.id !== organization.id) {
51
+ this.loadData();
70
52
  }
71
53
  }
54
+ }
72
55
 
73
- const getOrgInfo = (org) => {
74
- // remove the loading attribute so the action isn't called when org starts loading
75
- const { loading, ...info } = org;
76
- return info;
77
- };
78
-
79
- const currentOrgInfo = getOrgInfo(organization);
80
- const prevOrgInfo = getOrgInfo(prevProps.organization);
81
-
82
- if (!isEqual(currentOrgInfo, prevOrgInfo)) {
83
- this.pollTasks();
84
- }
56
+ componentWillUnmount() {
57
+ this.props.cancelPollTasks();
85
58
  }
86
59
 
87
60
  getDisabledReason(deleteButton) {
88
- const { tasks = [], subscriptions, organization } = this.props;
61
+ const { task, subscriptions, organization } = this.props;
89
62
  const { disconnected } = subscriptions;
90
63
  let disabledReason = null;
91
64
 
92
65
  if (disconnected) {
93
66
  disabledReason = __('This is disabled because disconnected mode is enabled.');
94
- } else if (tasks.length > 0) {
67
+ } else if (task) {
95
68
  disabledReason = __('This is disabled because a manifest related task is in progress.');
96
69
  } else if (deleteButton && !disabledReason) {
97
70
  disabledReason = __('This is disabled because no subscriptions are selected.');
@@ -106,75 +79,30 @@ class SubscriptionsPage extends Component {
106
79
  this.setState({ selectedRows });
107
80
  };
108
81
 
109
- async pollTasks() {
110
- const { pollBulkSearch, organization } = this.props;
111
-
112
- if (organization && organization.owner_details) {
113
- pollBulkSearch({
114
- action: `organization '${organization.owner_details.displayName}'`,
115
- result: 'pending',
116
- label: BLOCKING_FOREMAN_TASK_TYPES.join(' or '),
117
- }, BULK_TASK_SEARCH_INTERVAL, organization.id);
118
- }
119
-
120
- this.props.loadSetting('content_disconnected');
121
- this.props.loadSubscriptions();
122
- await this.props.loadTables();
123
- const { subscriptionTableSettings, loadTableColumns } = this.props;
124
- loadTableColumns(subscriptionTableSettings);
125
- }
126
-
127
- async handleDoneTask(taskToPoll) {
128
- const { pollTaskUntilDone, loadSubscriptions, organization } = this.props;
82
+ async loadData() {
83
+ const {
84
+ loadSetting,
85
+ loadSubscriptions,
86
+ loadTableColumns,
87
+ loadTables,
88
+ pollTasks,
89
+ subscriptionTableSettings,
90
+ } = this.props;
129
91
 
130
- const task = await pollTaskUntilDone(taskToPoll.id, {}, POLL_TASK_INTERVAL, organization.id);
131
- renderTaskFinishedToast(task);
92
+ pollTasks();
93
+ loadSetting('content_disconnected');
132
94
  loadSubscriptions();
133
- this.setState({ pollingATask: false });
95
+ await loadTables();
96
+ loadTableColumns(subscriptionTableSettings);
134
97
  }
135
98
 
136
- startManifestTask = () => {
137
- this.props.openTaskModal();
138
- this.setState({
139
- pollingATask: true,
140
- });
141
- };
142
-
143
- cleanUpManifestTask = async () => {
144
- await renderTaskStartedToast(this.props.taskDetails);
145
- setTimeout(() => this.props.bulkSearch({
146
- action: `organization '${this.props.organization.owner_details.displayName}'`,
147
- result: 'pending',
148
- label: BLOCKING_FOREMAN_TASK_TYPES.join(' or '),
149
- }), 100);
150
- };
151
-
152
- uploadManifest = async (file) => {
153
- this.startManifestTask();
154
- await this.props.uploadManifest(file);
155
- this.cleanUpManifestTask();
156
- };
157
-
158
- deleteManifest = async () => {
159
- this.startManifestTask();
160
- await this.props.deleteManifest();
161
- this.cleanUpManifestTask();
162
- };
163
-
164
- refreshManifest = async () => {
165
- this.startManifestTask();
166
- await this.props.refreshManifest();
167
- this.cleanUpManifestTask();
168
- };
169
-
170
99
  render() {
171
100
  const currentOrg = orgId();
172
101
  const {
173
102
  deleteModalOpened, openDeleteModal, closeDeleteModal,
174
103
  deleteButtonDisabled, disableDeleteButton, enableDeleteButton,
175
- searchQuery, updateSearchQuery,
176
- taskModalOpened, simpleContentAccess,
177
- tasks = [], activePermissions, subscriptions, organization, subscriptionTableSettings,
104
+ searchQuery, updateSearchQuery, simpleContentAccess,
105
+ task, activePermissions, subscriptions, organization, subscriptionTableSettings,
178
106
  } = this.props;
179
107
  // Basic permissions - should we even show this page?
180
108
  if (subscriptions.missingPermissions && subscriptions.missingPermissions.length > 0) {
@@ -189,15 +117,10 @@ class SubscriptionsPage extends Component {
189
117
  canEditOrganizations,
190
118
  } = permissions;
191
119
  const { disconnected } = subscriptions;
192
- const taskInProgress = tasks.length > 0;
193
- const disableManifestActions = taskInProgress || disconnected;
194
- let task = null;
120
+ const disableManifestActions = !!task || disconnected;
195
121
 
196
122
  const openManageManifestModal = () => this.props.setModalOpen({ id: MANAGE_MANIFEST_MODAL_ID });
197
123
 
198
- if (taskInProgress) {
199
- [task] = tasks;
200
- }
201
124
  const tableColumns = Immutable.asMutable(subscriptions.tableColumns, { deep: true });
202
125
  const onSearch = (search) => {
203
126
  this.props.loadSubscriptions({ search });
@@ -212,7 +135,6 @@ class SubscriptionsPage extends Component {
212
135
  });
213
136
 
214
137
  const onDeleteSubscriptions = (selectedRows) => {
215
- this.startManifestTask();
216
138
  this.props.deleteSubscriptions(selectedRows);
217
139
  this.handleSelectedRowsChange([]);
218
140
  closeDeleteModal();
@@ -221,7 +143,6 @@ class SubscriptionsPage extends Component {
221
143
  const toggleDeleteButton = rowsSelected =>
222
144
  (rowsSelected ? enableDeleteButton() : disableDeleteButton());
223
145
 
224
-
225
146
  const csvParams = createSubscriptionParams({ search: searchQuery });
226
147
  const getEnabledColumns = (columns) => {
227
148
  const enabledColumns = [];
@@ -289,12 +210,12 @@ class SubscriptionsPage extends Component {
289
210
  canImportManifest={canImportManifest}
290
211
  canDeleteManifest={canDeleteManifest}
291
212
  canEditOrganizations={canEditOrganizations}
292
- taskInProgress={taskInProgress}
213
+ taskInProgress={!!task}
293
214
  disableManifestActions={disableManifestActions}
294
215
  disabledReason={this.getDisabledReason()}
295
- upload={this.uploadManifest}
296
- delete={this.deleteManifest}
297
- refresh={this.refreshManifest}
216
+ upload={this.props.uploadManifest}
217
+ delete={this.props.deleteManifest}
218
+ refresh={this.props.refreshManifest}
298
219
  />
299
220
 
300
221
  <div id="subscriptions-table" className="modal-container">
@@ -317,12 +238,11 @@ class SubscriptionsPage extends Component {
317
238
  onDeleteSubscriptions={onDeleteSubscriptions}
318
239
  toggleDeleteButton={toggleDeleteButton}
319
240
  task={task}
320
- bulkSearch={this.props.bulkSearch}
321
241
  selectedRows={this.state.selectedRows}
322
242
  onSelectedRowsChange={this.handleSelectedRowsChange}
323
243
  />
324
244
  <ModalProgressBar
325
- show={taskModalOpened}
245
+ show={!!task}
326
246
  container={document.getElementById('subscriptions-table')}
327
247
  title={task ? task.humanized.action : null}
328
248
  progress={task ? Math.round(task.progress * 100) : 0}
@@ -342,7 +262,6 @@ SubscriptionsPage.propTypes = {
342
262
  resetTasks: PropTypes.func.isRequired,
343
263
  updateQuantity: PropTypes.func.isRequired,
344
264
  loadTableColumns: PropTypes.func.isRequired,
345
- taskDetails: PropTypes.shape({}),
346
265
  simpleContentAccess: PropTypes.bool,
347
266
  subscriptions: PropTypes.shape({
348
267
  disconnected: PropTypes.bool,
@@ -357,18 +276,29 @@ SubscriptionsPage.propTypes = {
357
276
  organization: PropTypes.shape({
358
277
  id: PropTypes.number,
359
278
  owner_details: PropTypes.shape({
360
- displayName: PropTypes.string,
279
+ upstreamConsumer: PropTypes.shape({
280
+ name: PropTypes.string,
281
+ webUrl: PropTypes.string,
282
+ uuid: PropTypes.string,
283
+ }),
284
+ }),
285
+ }),
286
+ task: PropTypes.shape({
287
+ id: PropTypes.string,
288
+ progress: PropTypes.number,
289
+ humanized: PropTypes.shape({
290
+ action: PropTypes.string,
361
291
  }),
292
+ pending: PropTypes.bool,
362
293
  }),
363
- pollBulkSearch: PropTypes.func.isRequired,
364
- bulkSearch: PropTypes.func,
365
- pollTaskUntilDone: PropTypes.func.isRequired,
294
+ pollTasks: PropTypes.func.isRequired,
295
+ cancelPollTasks: PropTypes.func.isRequired,
296
+ handleTask: PropTypes.func.isRequired,
366
297
  loadSetting: PropTypes.func.isRequired,
367
298
  loadTables: PropTypes.func.isRequired,
368
299
  createColumns: PropTypes.func.isRequired,
369
300
  updateColumns: PropTypes.func.isRequired,
370
301
  subscriptionTableSettings: PropTypes.shape({}),
371
- tasks: PropTypes.arrayOf(PropTypes.shape({})),
372
302
  deleteSubscriptions: PropTypes.func.isRequired,
373
303
  refreshManifest: PropTypes.func.isRequired,
374
304
  searchQuery: PropTypes.string,
@@ -377,22 +307,16 @@ SubscriptionsPage.propTypes = {
377
307
  deleteModalOpened: PropTypes.bool,
378
308
  openDeleteModal: PropTypes.func.isRequired,
379
309
  closeDeleteModal: PropTypes.func.isRequired,
380
- taskModalOpened: PropTypes.bool,
381
- openTaskModal: PropTypes.func.isRequired,
382
- closeTaskModal: PropTypes.func.isRequired,
383
310
  deleteButtonDisabled: PropTypes.bool,
384
311
  disableDeleteButton: PropTypes.func.isRequired,
385
312
  enableDeleteButton: PropTypes.func.isRequired,
386
313
  };
387
314
 
388
315
  SubscriptionsPage.defaultProps = {
389
- tasks: [],
390
- bulkSearch: undefined,
391
- taskDetails: {},
316
+ task: undefined,
392
317
  organization: undefined,
393
318
  searchQuery: '',
394
319
  deleteModalOpened: false,
395
- taskModalOpened: false,
396
320
  deleteButtonDisabled: true,
397
321
  subscriptionTableSettings: {},
398
322
  simpleContentAccess: false,
@@ -7,17 +7,14 @@ export const selectSearchQuery = state =>
7
7
  export const selectDeleteModalOpened = state =>
8
8
  selectSubscriptionsState(state).deleteModalOpened;
9
9
 
10
- export const selectTaskModalOpened = state =>
11
- selectSubscriptionsState(state).taskModalOpened;
12
-
13
10
  export const selectDeleteButtonDisabled = state =>
14
11
  selectSubscriptionsState(state).deleteButtonDisabled;
15
12
 
16
13
  export const selectActivePermissions = state =>
17
14
  selectSubscriptionsState(state).activePermissions;
18
15
 
19
- export const selectSubscriptionsTasks = state =>
20
- selectSubscriptionsState(state).tasks;
16
+ export const selectSubscriptionsTask = state =>
17
+ selectSubscriptionsState(state).task;
21
18
 
22
19
  export const selectTableSettings = (state, tableName) =>
23
20
  state.katello.settings.tables[tableName] || undefined;
@@ -265,7 +265,7 @@ UpstreamSubscriptionsPage.propTypes = {
265
265
  results: PropTypes.array,
266
266
  pagination: PropTypes.shape({}),
267
267
  task: PropTypes.shape({
268
- id: PropTypes.number,
268
+ id: PropTypes.string,
269
269
  }),
270
270
  }).isRequired,
271
271
  history: PropTypes.shape({ push: PropTypes.func.isRequired }).isRequired,
@@ -18,6 +18,10 @@ import {
18
18
  loadTableColumnsSuccessAction,
19
19
  } from './subscriptions.fixtures';
20
20
  import {
21
+ handleTask,
22
+ pollTasks,
23
+ cancelPollTasks,
24
+ resetTasks,
21
25
  loadSubscriptions,
22
26
  updateQuantity,
23
27
  loadAvailableQuantities,
@@ -25,14 +29,24 @@ import {
25
29
  updateSearchQuery,
26
30
  openDeleteModal,
27
31
  closeDeleteModal,
28
- openTaskModal,
29
- closeTaskModal,
30
32
  disableDeleteButton,
31
33
  enableDeleteButton,
32
34
  } from '../SubscriptionActions';
33
35
 
36
+ import { getTaskPendingResponse, getTaskSuccessResponse } from '../../Tasks/__tests__/task.fixtures';
37
+
34
38
  const mockStore = configureMockStore([thunk]);
35
- const store = mockStore({ subscriptions: Immutable({}) });
39
+ const store = mockStore(Immutable({
40
+ intervals: {
41
+ SUBSCRIPTIONS_TASK_SEARCH: 5,
42
+ },
43
+ katello: {
44
+ subscriptions: {},
45
+ organization: {
46
+ id: 1,
47
+ },
48
+ },
49
+ }));
36
50
 
37
51
  afterEach(() => {
38
52
  store.clearActions();
@@ -145,6 +159,64 @@ describe('subscription actions', () => {
145
159
  );
146
160
  });
147
161
 
162
+ describe('handleTask', () => {
163
+ describe('when not polling a task', () => {
164
+ it('starts polling the task', async () => {
165
+ await store.dispatch(handleTask(getTaskSuccessResponse));
166
+
167
+ expect(store.getActions()).toMatchSnapshot();
168
+ });
169
+ });
170
+
171
+ it('does nothing if already polling and task is pending', async () => {
172
+ const pollStore = configureMockStore([thunk])({
173
+ intervals: {
174
+ SUBSCRIPTIONS_POLL_TASK: 5,
175
+ },
176
+ });
177
+
178
+ await pollStore.dispatch(handleTask(getTaskPendingResponse));
179
+
180
+ expect(pollStore.getActions()).toMatchSnapshot();
181
+ });
182
+
183
+ it('handles a finished task', async () => {
184
+ const pollStore = configureMockStore([thunk])({
185
+ intervals: {
186
+ SUBSCRIPTIONS_POLL_TASK: 5,
187
+ },
188
+ });
189
+
190
+ await pollStore.dispatch(handleTask(getTaskSuccessResponse));
191
+
192
+ expect(pollStore.getActions()).toMatchSnapshot();
193
+ });
194
+ });
195
+
196
+ describe('pollTasks', () => testActionSnapshotWithFixtures({
197
+ 'can search tasks': () => store.dispatch(pollTasks()),
198
+ }));
199
+
200
+ describe('cancelPollTasks', () => {
201
+ it('cancels the tasks search', async () => {
202
+ await store.dispatch(cancelPollTasks());
203
+
204
+ expect(store.getActions()).toMatchSnapshot();
205
+ });
206
+
207
+ it('does nothing if not already polling', async () => {
208
+ const pollStore = configureMockStore([thunk])({});
209
+
210
+ await pollStore.dispatch(cancelPollTasks());
211
+
212
+ expect(pollStore.getActions()).toMatchSnapshot();
213
+ });
214
+ });
215
+
216
+ describe('resetTasks', () => testActionSnapshotWithFixtures({
217
+ 'resets the task state': () => resetTasks(),
218
+ }));
219
+
148
220
  describe('deleteModal', () => testActionSnapshotWithFixtures({
149
221
  'it should open delete modal': () => openDeleteModal(),
150
222
  'it should close delete modal': () => closeDeleteModal(),
@@ -154,11 +226,6 @@ describe('subscription actions', () => {
154
226
  'it should update the search-query': () => updateSearchQuery('some-query'),
155
227
  }));
156
228
 
157
- describe('taskModal', () => testActionSnapshotWithFixtures({
158
- 'it should open task modal': () => openTaskModal(),
159
- 'it should close task modal': () => closeTaskModal(),
160
- }));
161
-
162
229
  describe('deleteButtonDisabled', () => testActionSnapshotWithFixtures({
163
230
  'it should disable the delete button': () => disableDeleteButton(),
164
231
  'it should enable the delete button': () => enableDeleteButton(),