foreman-tasks 11.0.6 → 11.0.7

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/foreman_tasks/version.rb +1 -1
  3. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +37 -9
  4. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +19 -16
  5. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +197 -71
  6. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +24 -40
  7. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +2 -16
  8. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +0 -16
  9. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/GenericConfirmModal.js +70 -0
  10. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +25 -14
  11. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +8 -7
  12. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/index.test.js +409 -0
  13. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/createBulkTaskModal.js +67 -0
  14. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/createTaskModal.js +51 -0
  15. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/index.js +73 -23
  16. data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +5 -2
  17. data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +1 -1
  18. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +67 -11
  19. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +86 -6
  20. data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.test.js +225 -39
  21. data/webpack/ForemanTasks/Components/common/ClickConfirmation/index.js +136 -37
  22. metadata +6 -19
  23. data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.js +0 -60
  24. data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.test.js +0 -14
  25. data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/UnlockModals.test.js.snap +0 -25
  26. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskButtons.test.js.snap +0 -212
  27. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModal.js +0 -83
  28. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalActions.js +0 -106
  29. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalReducer.js +0 -38
  30. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModal.test.js +0 -36
  31. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalActions.test.js +0 -205
  32. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalReducer.test.js +0 -27
  33. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModal.test.js.snap +0 -41
  34. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalReducer.test.js.snap +0 -19
  35. data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.scss +0 -9
  36. data/webpack/ForemanTasks/Components/common/ClickConfirmation/__snapshots__/ClickConfirmation.test.js.snap +0 -52
  37. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +0 -2
  38. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +0 -10
  39. data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +0 -18
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useSelector } from 'react-redux';
4
+ import { sprintf } from 'foremanReact/common/I18n';
5
+ import { selectClicked } from './ConfirmModalSelectors';
6
+ import { GenericConfirmModal } from './GenericConfirmModal';
7
+
8
+ export const createTaskModal = ({
9
+ actionCreator,
10
+ title,
11
+ messageTemplate,
12
+ confirmButtonVariant = 'primary',
13
+ ouiaIdPrefix,
14
+ }) => {
15
+ const TaskModal = ({ isModalOpen, setIsModalOpen, url, parentTaskID }) => {
16
+ const { taskId, taskName } = useSelector(selectClicked);
17
+
18
+ const handleConfirm = () =>
19
+ actionCreator({
20
+ taskId,
21
+ taskName,
22
+ url,
23
+ parentTaskID,
24
+ });
25
+
26
+ return (
27
+ <GenericConfirmModal
28
+ isModalOpen={isModalOpen}
29
+ setIsModalOpen={setIsModalOpen}
30
+ title={title}
31
+ message={sprintf(messageTemplate, { taskName })}
32
+ onConfirm={handleConfirm}
33
+ confirmButtonVariant={confirmButtonVariant}
34
+ ouiaIdPrefix={ouiaIdPrefix}
35
+ />
36
+ );
37
+ };
38
+
39
+ TaskModal.propTypes = {
40
+ isModalOpen: PropTypes.bool.isRequired,
41
+ setIsModalOpen: PropTypes.func.isRequired,
42
+ url: PropTypes.string.isRequired,
43
+ parentTaskID: PropTypes.string,
44
+ };
45
+
46
+ TaskModal.defaultProps = {
47
+ parentTaskID: null,
48
+ };
49
+
50
+ return TaskModal;
51
+ };
@@ -1,29 +1,79 @@
1
- import { connect } from 'react-redux';
2
- import { bindActionCreators } from 'redux';
3
- import { ConfirmModal } from './ConfirmModal';
4
- import reducer from './ConfirmModalReducer';
5
- import tasksActions from './ConfirmModalActions';
1
+ import { translate as __ } from 'foremanReact/common/I18n';
2
+ import { createTaskModal } from './createTaskModal';
3
+ import { createBulkTaskModal } from './createBulkTaskModal';
6
4
  import {
7
- selectActionText,
8
- selectActionState,
9
- selectActionType,
10
- selectClicked,
11
- selectSelectedRowsLen,
12
- } from './ConfirmModalSelectors';
13
- import { selectAllRowsSelected } from '../../TasksTableSelectors';
5
+ cancelTask,
6
+ forceCancelTask,
7
+ resumeTask,
8
+ } from '../../TasksTableActions';
9
+ import {
10
+ bulkCancelBySearch,
11
+ bulkCancelById,
12
+ bulkForceCancelBySearch,
13
+ bulkForceCancelById,
14
+ bulkResumeBySearch,
15
+ bulkResumeById,
16
+ } from '../../TasksBulkActions';
17
+
18
+ export const CancelModal = createTaskModal({
19
+ actionCreator: cancelTask,
20
+ title: __('Cancel Task'),
21
+ messageTemplate: __(
22
+ 'This will cancel task "%(taskName)s", putting it in the stopped state. Are you sure?'
23
+ ),
24
+ confirmButtonVariant: 'primary',
25
+ ouiaIdPrefix: 'cancel',
26
+ });
27
+
28
+ export const CancelSelectedModal = createBulkTaskModal({
29
+ bulkActionBySearch: bulkCancelBySearch,
30
+ bulkActionById: bulkCancelById,
31
+ title: __('Cancel Selected Tasks'),
32
+ messageTemplate: __(
33
+ 'This will cancel %(number)s task(s), putting them in the stopped state. Are you sure?'
34
+ ),
35
+ confirmButtonVariant: 'primary',
36
+ ouiaIdPrefix: 'cancel-selected',
37
+ });
14
38
 
15
- const mapStateToProps = state => ({
16
- actionText: selectActionText(state),
17
- actionType: selectActionType(state),
18
- actionState: selectActionState(state),
19
- allRowsSelected: selectAllRowsSelected(state),
20
- clicked: selectClicked(state),
21
- selectedRowsLen: selectSelectedRowsLen(state),
39
+ export const ForceUnlockModal = createTaskModal({
40
+ actionCreator: forceCancelTask,
41
+ title: __('Force Unlock Task'),
42
+ messageTemplate: __(
43
+ 'This will force unlock task "%(taskName)s". This may cause harm and should be used with caution. Are you sure?'
44
+ ),
45
+ confirmButtonVariant: 'danger',
46
+ ouiaIdPrefix: 'force-unlock',
22
47
  });
23
48
 
24
- const mapDispatchToProps = dispatch =>
25
- bindActionCreators(tasksActions, dispatch);
49
+ export const ForceUnlockSelectedModal = createBulkTaskModal({
50
+ bulkActionBySearch: bulkForceCancelBySearch,
51
+ bulkActionById: bulkForceCancelById,
52
+ title: __('Force Unlock Selected Tasks'),
53
+ messageTemplate: __(
54
+ 'This will force unlock %(number)s task(s). This may cause harm and should be used with caution. Are you sure?'
55
+ ),
56
+ confirmButtonVariant: 'danger',
57
+ ouiaIdPrefix: 'force-unlock-selected',
58
+ });
26
59
 
27
- export const reducers = { confirmModal: reducer };
60
+ export const ResumeModal = createTaskModal({
61
+ actionCreator: resumeTask,
62
+ title: __('Resume Task'),
63
+ messageTemplate: __(
64
+ 'This will resume task "%(taskName)s", putting it in the running state. Are you sure?'
65
+ ),
66
+ confirmButtonVariant: 'primary',
67
+ ouiaIdPrefix: 'resume',
68
+ });
28
69
 
29
- export default connect(mapStateToProps, mapDispatchToProps)(ConfirmModal);
70
+ export const ResumeSelectedModal = createBulkTaskModal({
71
+ bulkActionBySearch: bulkResumeBySearch,
72
+ bulkActionById: bulkResumeById,
73
+ title: __('Resume Selected Tasks'),
74
+ messageTemplate: __(
75
+ 'This will resume %(number)s task(s), putting them in the running state. Are you sure?'
76
+ ),
77
+ confirmButtonVariant: 'primary',
78
+ ouiaIdPrefix: 'resume-selected',
79
+ });
@@ -8,8 +8,11 @@ import Pagination from 'foremanReact/components/Pagination';
8
8
  import { getURIQuery } from 'foremanReact/common/helpers';
9
9
  import createTasksTableSchema from './TasksTableSchema';
10
10
  import { updateURlQuery } from './TasksTableHelpers';
11
- import { RESUME_MODAL, CANCEL_MODAL } from './TasksTableConstants';
12
- import { FORCE_UNLOCK_MODAL } from '../TaskActions/TaskActionsConstants';
11
+ import {
12
+ RESUME_MODAL,
13
+ CANCEL_MODAL,
14
+ FORCE_UNLOCK_MODAL,
15
+ } from './TasksTableConstants';
13
16
 
14
17
  const TasksTable = ({
15
18
  getTableItems,
@@ -16,7 +16,7 @@ export const CANCEL_MODAL = 'cancelConfirmModal';
16
16
  export const RESUME_MODAL = 'resumeConfirmModal';
17
17
  export const CANCEL_SELECTED_MODAL = 'cancelSelectedConfirmModal';
18
18
  export const RESUME_SELECTED_MODAL = 'resumeSelectedConfirmModal';
19
- export const CONFIRM_MODAL = 'ConfirmModal';
19
+ export const FORCE_UNLOCK_MODAL = 'forceUnlockConfirmModal';
20
20
  export const FORCE_UNLOCK_SELECTED_MODAL = 'forceUnlockSelectedConfirmModal';
21
21
 
22
22
  export const UPDATE_CLICKED = 'UPDATE_CLICKED';
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import URI from 'urijs';
4
4
  import { getURIsearch } from 'foremanReact/common/urlHelpers';
@@ -8,17 +8,25 @@ import { translate as __ } from 'foremanReact/common/I18n';
8
8
  import { getURIQuery } from 'foremanReact/common/helpers';
9
9
  import ExportButton from 'foremanReact/routes/common/PageLayout/components/ExportButton/ExportButton';
10
10
  import { STATUS } from 'foremanReact/constants';
11
- import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
12
11
  import TasksDashboard from '../TasksDashboard';
13
12
  import TasksTable from './TasksTable';
14
13
  import { getCSVurl, updateURlQuery } from './TasksTableHelpers';
15
- import ConfirmModal from './Components/ConfirmModal/';
14
+ import {
15
+ CancelModal,
16
+ ResumeModal,
17
+ CancelSelectedModal,
18
+ ResumeSelectedModal,
19
+ ForceUnlockModal,
20
+ ForceUnlockSelectedModal,
21
+ } from './Components/ConfirmModal';
16
22
  import {
17
23
  TASKS_SEARCH_PROPS,
18
24
  CANCEL_SELECTED_MODAL,
19
25
  RESUME_SELECTED_MODAL,
20
26
  FORCE_UNLOCK_SELECTED_MODAL,
21
- CONFIRM_MODAL,
27
+ CANCEL_MODAL,
28
+ RESUME_MODAL,
29
+ FORCE_UNLOCK_MODAL,
22
30
  } from './TasksTableConstants';
23
31
  import { ActionSelectButton } from './Components/ActionSelectButton';
24
32
  import './TasksTablePage.scss';
@@ -48,21 +56,69 @@ const TasksTablePage = ({
48
56
  updateURlQuery(newUriQuery, history);
49
57
  }
50
58
  };
51
-
52
- const { setModalOpen, setModalClosed } = useForemanModal({
53
- id: CONFIRM_MODAL,
59
+ const [modalStates, setModalStates] = useState({
60
+ [CANCEL_MODAL]: false,
61
+ [RESUME_MODAL]: false,
62
+ [CANCEL_SELECTED_MODAL]: false,
63
+ [RESUME_SELECTED_MODAL]: false,
64
+ [FORCE_UNLOCK_MODAL]: false,
65
+ [FORCE_UNLOCK_SELECTED_MODAL]: false,
54
66
  });
55
67
 
56
- const openModal = id => openModalAction(id, setModalOpen);
68
+ const openModal = id => {
69
+ setModalStates(prev => ({
70
+ ...prev,
71
+ [id]: true,
72
+ }));
73
+ };
74
+
75
+ const closeModal = id => {
76
+ setModalStates(prev => ({
77
+ ...prev,
78
+ [id]: false,
79
+ }));
80
+ };
57
81
 
58
82
  return (
59
83
  <div className="tasks-table-wrapper">
60
- <ConfirmModal
61
- id={CONFIRM_MODAL}
84
+ <CancelModal
85
+ isModalOpen={modalStates[CANCEL_MODAL]}
86
+ setIsModalOpen={() => closeModal(CANCEL_MODAL)}
87
+ url={url}
88
+ parentTaskID={props.parentTaskID}
89
+ />
90
+ <ResumeModal
91
+ isModalOpen={modalStates[RESUME_MODAL]}
92
+ setIsModalOpen={() => closeModal(RESUME_MODAL)}
93
+ url={url}
94
+ parentTaskID={props.parentTaskID}
95
+ />
96
+ <CancelSelectedModal
97
+ isModalOpen={modalStates[CANCEL_SELECTED_MODAL]}
98
+ setIsModalOpen={() => closeModal(CANCEL_SELECTED_MODAL)}
62
99
  url={url}
100
+ uriQuery={uriQuery}
63
101
  parentTaskID={props.parentTaskID}
102
+ />
103
+ <ResumeSelectedModal
104
+ isModalOpen={modalStates[RESUME_SELECTED_MODAL]}
105
+ setIsModalOpen={() => closeModal(RESUME_SELECTED_MODAL)}
106
+ url={url}
64
107
  uriQuery={uriQuery}
65
- setModalClosed={setModalClosed}
108
+ parentTaskID={props.parentTaskID}
109
+ />
110
+ <ForceUnlockModal
111
+ isModalOpen={modalStates[FORCE_UNLOCK_MODAL]}
112
+ setIsModalOpen={() => closeModal(FORCE_UNLOCK_MODAL)}
113
+ url={url}
114
+ parentTaskID={props.parentTaskID}
115
+ />
116
+ <ForceUnlockSelectedModal
117
+ isModalOpen={modalStates[FORCE_UNLOCK_SELECTED_MODAL]}
118
+ setIsModalOpen={() => closeModal(FORCE_UNLOCK_SELECTED_MODAL)}
119
+ url={url}
120
+ uriQuery={uriQuery}
121
+ parentTaskID={props.parentTaskID}
66
122
  />
67
123
  <PageLayout
68
124
  searchable
@@ -4,10 +4,50 @@ exports[`TasksTablePage rendering render with Breadcrubs and edit permissions 1`
4
4
  <div
5
5
  className="tasks-table-wrapper"
6
6
  >
7
- <Connect(ConfirmModal)
8
- id="ConfirmModal"
7
+ <TaskModal
8
+ isModalOpen={false}
9
9
  parentTaskID={null}
10
- setModalClosed={[MockFunction]}
10
+ setIsModalOpen={[Function]}
11
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
12
+ />
13
+ <TaskModal
14
+ isModalOpen={false}
15
+ parentTaskID={null}
16
+ setIsModalOpen={[Function]}
17
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
18
+ />
19
+ <BulkTaskModal
20
+ isModalOpen={false}
21
+ parentTaskID={null}
22
+ setIsModalOpen={[Function]}
23
+ uriQuery={
24
+ Object {
25
+ "state": "stopped",
26
+ }
27
+ }
28
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
29
+ />
30
+ <BulkTaskModal
31
+ isModalOpen={false}
32
+ parentTaskID={null}
33
+ setIsModalOpen={[Function]}
34
+ uriQuery={
35
+ Object {
36
+ "state": "stopped",
37
+ }
38
+ }
39
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
40
+ />
41
+ <TaskModal
42
+ isModalOpen={false}
43
+ parentTaskID={null}
44
+ setIsModalOpen={[Function]}
45
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
46
+ />
47
+ <BulkTaskModal
48
+ isModalOpen={false}
49
+ parentTaskID={null}
50
+ setIsModalOpen={[Function]}
11
51
  uriQuery={
12
52
  Object {
13
53
  "state": "stopped",
@@ -156,10 +196,50 @@ exports[`TasksTablePage rendering render with minimal props 1`] = `
156
196
  <div
157
197
  className="tasks-table-wrapper"
158
198
  >
159
- <Connect(ConfirmModal)
160
- id="ConfirmModal"
199
+ <TaskModal
200
+ isModalOpen={false}
201
+ parentTaskID={null}
202
+ setIsModalOpen={[Function]}
203
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
204
+ />
205
+ <TaskModal
206
+ isModalOpen={false}
207
+ parentTaskID={null}
208
+ setIsModalOpen={[Function]}
209
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
210
+ />
211
+ <BulkTaskModal
212
+ isModalOpen={false}
213
+ parentTaskID={null}
214
+ setIsModalOpen={[Function]}
215
+ uriQuery={
216
+ Object {
217
+ "state": "stopped",
218
+ }
219
+ }
220
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
221
+ />
222
+ <BulkTaskModal
223
+ isModalOpen={false}
224
+ parentTaskID={null}
225
+ setIsModalOpen={[Function]}
226
+ uriQuery={
227
+ Object {
228
+ "state": "stopped",
229
+ }
230
+ }
231
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
232
+ />
233
+ <TaskModal
234
+ isModalOpen={false}
235
+ parentTaskID={null}
236
+ setIsModalOpen={[Function]}
237
+ url="/foreman_tasks/tasks?action=\\"some-name\\""
238
+ />
239
+ <BulkTaskModal
240
+ isModalOpen={false}
161
241
  parentTaskID={null}
162
- setModalClosed={[MockFunction]}
242
+ setIsModalOpen={[Function]}
163
243
  uriQuery={
164
244
  Object {
165
245
  "state": "stopped",
@@ -1,44 +1,230 @@
1
1
  import React from 'react';
2
- import { testComponentSnapshotsWithFixtures, mount } from '@theforeman/test';
3
- import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
4
- import { ClickConfirmation } from './';
5
-
6
- const fixtures = {
7
- render: {
8
- title: 'some-title',
9
- confirmType: 'danger',
10
- body: 'some-body',
11
- confirmationMessage: 'some-message',
12
- id: 'some-id',
13
- confirmAction: 'some-confirm',
14
- onClick: jest.fn(),
15
- },
16
- };
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import {
5
+ ClickConfirmation,
6
+ UnlockConfirmationModal,
7
+ ForceUnlockConfirmationModal,
8
+ } from './';
17
9
 
18
10
  describe('ClickConfirmation', () => {
19
- testComponentSnapshotsWithFixtures(ClickConfirmation, fixtures);
20
- it('enable button on checkbox click', () => {
21
- const component = mount(<ClickConfirmation {...fixtures.render} />);
22
- const getButton = () => component.find('.confirm-button').at(0);
23
- expect(getButton().props().disabled).toBeTruthy();
24
- const checkbox = component.find('input').at(0);
25
- checkbox.simulate('change', { target: { checked: true } });
26
- expect(getButton().props().disabled).toBeFalsy();
27
- });
28
-
29
- it('click test', () => {
30
- const setModalClosed = jest.fn();
31
- useForemanModal.mockImplementation(id => ({
32
- setModalClosed: () => setModalClosed(id),
33
- }));
34
- const onClick = jest.fn();
35
- const props = { ...fixtures.render, onClick };
36
- const component = mount(<ClickConfirmation {...props} />);
37
- const getButton = () => component.find('.confirm-button').at(0);
38
- const checkbox = component.find('input').at(0);
39
- checkbox.simulate('change', { target: { checked: true } });
40
- getButton().simulate('click');
41
- expect(onClick).toBeCalled();
42
- expect(setModalClosed).toBeCalledWith({ id: fixtures.render.id });
11
+ const defaultProps = {
12
+ title: 'Test Modal',
13
+ body: 'This is a test modal body',
14
+ confirmationMessage: 'I understand the consequences',
15
+ confirmAction: 'Confirm',
16
+ onClick: jest.fn(),
17
+ id: 'test-modal',
18
+ isOpen: true,
19
+ setModalClosed: jest.fn(),
20
+ };
21
+
22
+ beforeEach(() => {
23
+ jest.clearAllMocks();
24
+ });
25
+
26
+ describe('Basic Rendering', () => {
27
+ it('renders modal with correct title and content when open', () => {
28
+ render(<ClickConfirmation {...defaultProps} />);
29
+
30
+ expect(screen.getByText('Test Modal')).toBeInTheDocument();
31
+ expect(screen.getByText('This is a test modal body')).toBeInTheDocument();
32
+ expect(
33
+ screen.getByText('I understand the consequences')
34
+ ).toBeInTheDocument();
35
+ expect(screen.getByText('Confirm')).toBeInTheDocument();
36
+ });
37
+
38
+ it('does not render modal when isOpen is false', () => {
39
+ render(<ClickConfirmation {...defaultProps} isOpen={false} />);
40
+
41
+ expect(screen.queryByText('Test Modal')).not.toBeInTheDocument();
42
+ });
43
+
44
+ it('renders with warning variant by default', () => {
45
+ render(<ClickConfirmation {...defaultProps} />);
46
+
47
+ const modal = screen.getByRole('dialog');
48
+ expect(modal).toBeInTheDocument();
49
+ });
50
+
51
+ it('renders with danger variant when specified', () => {
52
+ render(<ClickConfirmation {...defaultProps} confirmType="danger" />);
53
+
54
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
55
+ expect(confirmButton).toHaveClass('pf-m-danger');
56
+ });
57
+ });
58
+
59
+ describe('Checkbox Interaction', () => {
60
+ it('starts with checkbox unchecked and confirm button disabled', () => {
61
+ render(<ClickConfirmation {...defaultProps} />);
62
+
63
+ const checkbox = screen.getByRole('checkbox');
64
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
65
+
66
+ expect(checkbox).not.toBeChecked();
67
+ expect(confirmButton).toBeDisabled();
68
+ });
69
+
70
+ it('enables confirm button when checkbox is checked', () => {
71
+ render(<ClickConfirmation {...defaultProps} />);
72
+
73
+ const checkbox = screen.getByRole('checkbox');
74
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
75
+
76
+ fireEvent.click(checkbox);
77
+
78
+ expect(checkbox).toBeChecked();
79
+ expect(confirmButton).toBeEnabled();
80
+ });
81
+
82
+ it('disables confirm button when checkbox is unchecked', () => {
83
+ render(<ClickConfirmation {...defaultProps} />);
84
+
85
+ const checkbox = screen.getByRole('checkbox');
86
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
87
+
88
+ // Check the checkbox first
89
+ fireEvent.click(checkbox);
90
+ expect(confirmButton).toBeEnabled();
91
+
92
+ // Uncheck the checkbox
93
+ fireEvent.click(checkbox);
94
+ expect(checkbox).not.toBeChecked();
95
+ expect(confirmButton).toBeDisabled();
96
+ });
97
+ });
98
+
99
+ describe('Button Actions', () => {
100
+ it('calls onClick and setModalClosed when confirm button is clicked', () => {
101
+ const onClick = jest.fn();
102
+ const setModalClosed = jest.fn();
103
+
104
+ render(
105
+ <ClickConfirmation
106
+ {...defaultProps}
107
+ onClick={onClick}
108
+ setModalClosed={setModalClosed}
109
+ />
110
+ );
111
+
112
+ const checkbox = screen.getByRole('checkbox');
113
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
114
+
115
+ // Enable the button by checking the checkbox
116
+ fireEvent.click(checkbox);
117
+
118
+ // Click the confirm button
119
+ fireEvent.click(confirmButton);
120
+
121
+ expect(onClick).toHaveBeenCalledTimes(1);
122
+ expect(setModalClosed).toHaveBeenCalledTimes(1);
123
+ });
124
+
125
+ it('calls setModalClosed when cancel button is clicked', () => {
126
+ const setModalClosed = jest.fn();
127
+
128
+ render(
129
+ <ClickConfirmation {...defaultProps} setModalClosed={setModalClosed} />
130
+ );
131
+
132
+ const cancelButton = screen.getByRole('button', { name: 'Cancel' });
133
+ fireEvent.click(cancelButton);
134
+
135
+ expect(setModalClosed).toHaveBeenCalledTimes(1);
136
+ });
137
+
138
+ it('does not call onClick when confirm button is clicked while disabled', () => {
139
+ const onClick = jest.fn();
140
+
141
+ render(<ClickConfirmation {...defaultProps} onClick={onClick} />);
142
+
143
+ const confirmButton = screen.getByRole('button', { name: 'Confirm' });
144
+
145
+ // Try to click the disabled button
146
+ fireEvent.click(confirmButton);
147
+
148
+ expect(onClick).not.toHaveBeenCalled();
149
+ });
150
+ });
151
+ });
152
+
153
+ describe('UnlockModal', () => {
154
+ const defaultProps = {
155
+ onClick: jest.fn(),
156
+ id: 'unlock-modal',
157
+ isOpen: true,
158
+ setModalClosed: jest.fn(),
159
+ };
160
+
161
+ beforeEach(() => {
162
+ jest.clearAllMocks();
163
+ });
164
+
165
+ it('renders with correct unlock-specific content and warning variant', () => {
166
+ render(<UnlockConfirmationModal {...defaultProps} />);
167
+
168
+ expect(
169
+ screen.getByRole('heading', { name: 'Warning alert: Unlock' })
170
+ ).toBeInTheDocument();
171
+ expect(
172
+ screen.getByText(
173
+ /This will unlock the resources that the task is running against/
174
+ )
175
+ ).toBeInTheDocument();
176
+ expect(
177
+ screen.getByText(
178
+ 'I understand that this may cause harm and have working database backups of all backend services.'
179
+ )
180
+ ).toBeInTheDocument();
181
+
182
+ const confirmButton = screen.getByRole('button', { name: 'Unlock' });
183
+ expect(confirmButton).toBeInTheDocument();
184
+ expect(confirmButton).toHaveClass('pf-m-primary');
185
+ });
186
+ });
187
+
188
+ describe('ForceUnlockModal', () => {
189
+ const defaultProps = {
190
+ onClick: jest.fn(),
191
+ id: 'force-unlock-modal',
192
+ selectedRowsLen: 3,
193
+ isOpen: true,
194
+ setModalClosed: jest.fn(),
195
+ };
196
+
197
+ beforeEach(() => {
198
+ jest.clearAllMocks();
199
+ });
200
+
201
+ it('renders with correct force unlock-specific content and danger variant', () => {
202
+ render(<ForceUnlockConfirmationModal {...defaultProps} />);
203
+
204
+ expect(
205
+ screen.getByRole('heading', { name: 'Danger alert: Force Unlock' })
206
+ ).toBeInTheDocument();
207
+ expect(
208
+ screen.getByText(/Resources for 3 task\(s\) will be unlocked/)
209
+ ).toBeInTheDocument();
210
+ expect(
211
+ screen.getByText(
212
+ 'I understand that this may cause harm and have working database backups of all backend services.'
213
+ )
214
+ ).toBeInTheDocument();
215
+
216
+ const confirmButton = screen.getByRole('button', { name: 'Force Unlock' });
217
+ expect(confirmButton).toBeInTheDocument();
218
+ expect(confirmButton).toHaveClass('pf-m-danger');
219
+ });
220
+
221
+ it('displays correct number of tasks in body', () => {
222
+ render(
223
+ <ForceUnlockConfirmationModal {...defaultProps} selectedRowsLen={5} />
224
+ );
225
+
226
+ expect(
227
+ screen.getByText(/Resources for 5 task\(s\) will be unlocked/)
228
+ ).toBeInTheDocument();
43
229
  });
44
230
  });