foreman_puppet 10.1.3 → 11.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/foreman_puppet/extensions/hosts_controller_extensions.rb +1 -1
  3. data/app/controllers/foreman_puppet/api/v2/hosts_bulk_actions_controller.rb +75 -1
  4. data/app/models/concerns/foreman_puppet/extensions/host.rb +2 -2
  5. data/app/models/concerns/foreman_puppet/extensions/host_common.rb +35 -0
  6. data/app/models/concerns/foreman_puppet/extensions/hostgroup.rb +10 -3
  7. data/app/models/foreman_puppet/config_group.rb +6 -0
  8. data/app/models/foreman_puppet/puppetclass.rb +14 -0
  9. data/app/services/concerns/foreman_puppet/extensions/bulk_hosts_manager.rb +18 -0
  10. data/config/api_routes.rb +1 -0
  11. data/db/seeds.d/111_puppet_proxy_feature.rb +1 -1
  12. data/lib/foreman_puppet/register.rb +2 -1
  13. data/lib/foreman_puppet/version.rb +1 -1
  14. data/test/controllers/foreman_puppet/api/v2/hosts_bulk_actions_controller_test.rb +93 -0
  15. data/test/models/foreman_puppet/host_test.rb +66 -0
  16. data/test/models/foreman_puppet/hostgroup_test.rb +32 -0
  17. data/test/services/foreman_puppet/bulk_hosts_manager_test.rb +45 -0
  18. data/webpack/__mocks__/foremanReact/redux/API/index.js +8 -0
  19. data/webpack/global_index.js +18 -1
  20. data/webpack/src/Extends/Hosts/ActionsBar/index.js +20 -0
  21. data/webpack/src/Extends/Hosts/BulkActions/BulkChangeProxyCommon/__tests__/actions.test.js +0 -7
  22. data/webpack/src/Extends/Hosts/BulkActions/BulkChangeProxyCommon/index.js +9 -13
  23. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetCAProxy/__tests__/index.test.js +3 -0
  24. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetCAProxy/index.js +2 -0
  25. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/BulkChangePuppetEnvironmentModal.js +239 -0
  26. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/__tests__/BulkChangePuppetEnvironmentModal.test.js +155 -0
  27. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/__tests__/actions.test.js +49 -0
  28. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/__tests__/index.test.js +66 -0
  29. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/actions.js +37 -0
  30. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetEnvironment/index.js +30 -0
  31. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetProxy/__tests__/index.test.js +160 -44
  32. data/webpack/src/Extends/Hosts/BulkActions/BulkChangePuppetProxy/index.js +2 -0
  33. data/webpack/src/Extends/Hosts/BulkActions/BulkRemoveProxyCommon/__tests__/actions.test.js +0 -6
  34. data/webpack/src/Extends/Hosts/BulkActions/BulkRemoveProxyCommon/index.js +8 -13
  35. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetCAProxy/__tests__/index.test.js +138 -38
  36. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetCAProxy/index.js +2 -0
  37. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/BulkRemovePuppetEnvironmentModal.js +148 -0
  38. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/__tests__/BulkRemovePuppetEnvironmentModal.test.js +80 -0
  39. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/__tests__/index.test.js +66 -0
  40. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetEnvironment/index.js +30 -0
  41. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetProxy/__tests__/index.test.js +125 -33
  42. data/webpack/src/Extends/Hosts/BulkActions/BulkRemovePuppetProxy/index.js +2 -0
  43. data/webpack/src/Router/routes.fixtures.js +13 -0
  44. data/webpack/src/Router/routes.test.js +68 -8
  45. data/webpack/src/foreman_puppet_host_form.test.js +3 -1
  46. data/webpack/test_setup.js +1 -0
  47. metadata +14 -3
  48. data/webpack/src/Router/__snapshots__/routes.test.js.snap +0 -3
@@ -0,0 +1,148 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { FormattedMessage } from 'react-intl';
4
+ import { useDispatch } from 'react-redux';
5
+ import { Modal, Button, TextContent, Text } from '@patternfly/react-core';
6
+ import { translate as __ } from 'foremanReact/common/I18n';
7
+ import { addToast } from 'foremanReact/components/ToastsList/slice';
8
+ import { useForemanOrganization } from 'foremanReact/Root/Context/ForemanContext';
9
+ import { bulkActionErrorToastParams } from '../toastHelpers';
10
+ import {
11
+ bulkChangePuppetEnvironment,
12
+ BULK_CHANGE_PUPPET_ENVIRONMENT_KEY,
13
+ } from '../BulkChangePuppetEnvironment/actions';
14
+
15
+ const BulkRemovePuppetEnvironmentModal = ({
16
+ isOpen,
17
+ closeModal,
18
+ selectAllHostsMode,
19
+ selectedCount,
20
+ fetchBulkParams,
21
+ onSuccess: onSuccessCallback,
22
+ }) => {
23
+ const dispatch = useDispatch();
24
+ const currentOrganization = useForemanOrganization();
25
+
26
+ const handleModalClose = () => {
27
+ closeModal();
28
+ };
29
+
30
+ const handleError = response => {
31
+ handleModalClose();
32
+ dispatch(
33
+ addToast(
34
+ bulkActionErrorToastParams(
35
+ response,
36
+ __('Failed to remove Puppet Environment'),
37
+ BULK_CHANGE_PUPPET_ENVIRONMENT_KEY
38
+ )
39
+ )
40
+ );
41
+ };
42
+
43
+ const handleSuccess = response => {
44
+ dispatch(
45
+ addToast({
46
+ type: 'success',
47
+ message: response.data.message,
48
+ })
49
+ );
50
+ try {
51
+ if (onSuccessCallback) onSuccessCallback();
52
+ } finally {
53
+ handleModalClose();
54
+ }
55
+ };
56
+
57
+ const handleConfirm = () => {
58
+ const requestBody = {
59
+ included: {
60
+ search: fetchBulkParams(),
61
+ },
62
+ environment_id: null,
63
+ organization_id: currentOrganization?.id,
64
+ };
65
+
66
+ dispatch(
67
+ bulkChangePuppetEnvironment(requestBody, handleSuccess, handleError)
68
+ );
69
+ };
70
+
71
+ const modalActions = [
72
+ <Button
73
+ key="remove"
74
+ ouiaId="bulk-remove-puppet-environment-modal-remove-button"
75
+ variant="primary"
76
+ onClick={handleConfirm}
77
+ >
78
+ {__('Remove Puppet Environment')}
79
+ </Button>,
80
+ <Button
81
+ key="cancel"
82
+ ouiaId="bulk-remove-puppet-environment-modal-cancel-button"
83
+ variant="link"
84
+ onClick={handleModalClose}
85
+ >
86
+ {__('Cancel')}
87
+ </Button>,
88
+ ];
89
+
90
+ return (
91
+ <Modal
92
+ isOpen={isOpen}
93
+ onClose={handleModalClose}
94
+ onEscapePress={handleModalClose}
95
+ title={__('Remove Puppet Environment')}
96
+ width="50%"
97
+ position="top"
98
+ actions={modalActions}
99
+ id="bulk-remove-puppet-environment"
100
+ key="bulk-remove-puppet-environment"
101
+ ouiaId="bulk-remove-puppet-environment"
102
+ >
103
+ <TextContent>
104
+ <Text ouiaId="bulk-remove-puppet-environment-options">
105
+ {selectAllHostsMode ? (
106
+ <FormattedMessage
107
+ id="bulk-remove-puppet-environment-warning-message-all"
108
+ defaultMessage={__(
109
+ 'Removing the Puppet environment will affect {boldCount} selected hosts.'
110
+ )}
111
+ values={{
112
+ boldCount: <strong>{__('All')}</strong>,
113
+ }}
114
+ />
115
+ ) : (
116
+ <FormattedMessage
117
+ id="bulk-remove-puppet-environment-warning-message"
118
+ defaultMessage={__(
119
+ 'Removing the Puppet environment will affect {boldCount} selected {count, plural, one {host} other {hosts}}.'
120
+ )}
121
+ values={{
122
+ count: selectedCount,
123
+ boldCount: <strong>{selectedCount}</strong>,
124
+ }}
125
+ />
126
+ )}
127
+ </Text>
128
+ </TextContent>
129
+ </Modal>
130
+ );
131
+ };
132
+
133
+ BulkRemovePuppetEnvironmentModal.propTypes = {
134
+ isOpen: PropTypes.bool,
135
+ closeModal: PropTypes.func,
136
+ fetchBulkParams: PropTypes.func.isRequired,
137
+ onSuccess: PropTypes.func,
138
+ selectedCount: PropTypes.number.isRequired,
139
+ selectAllHostsMode: PropTypes.bool.isRequired,
140
+ };
141
+
142
+ BulkRemovePuppetEnvironmentModal.defaultProps = {
143
+ isOpen: false,
144
+ closeModal: () => {},
145
+ onSuccess: undefined,
146
+ };
147
+
148
+ export default BulkRemovePuppetEnvironmentModal;
@@ -0,0 +1,80 @@
1
+ import React from 'react';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import { IntlProvider } from 'react-intl';
5
+ import { useDispatch } from 'react-redux';
6
+
7
+ import BulkRemovePuppetEnvironmentModal from '../BulkRemovePuppetEnvironmentModal';
8
+ import { bulkChangePuppetEnvironment } from '../../BulkChangePuppetEnvironment/actions';
9
+
10
+ jest.mock('react-redux', () => ({
11
+ ...jest.requireActual('react-redux'),
12
+ useDispatch: jest.fn(),
13
+ }));
14
+
15
+ jest.mock('foremanReact/Root/Context/ForemanContext', () => ({
16
+ useForemanOrganization: jest.fn(() => ({ id: 23 })),
17
+ }));
18
+
19
+ jest.mock('../../BulkChangePuppetEnvironment/actions', () => ({
20
+ bulkChangePuppetEnvironment: jest.fn(() => ({
21
+ type: 'BULK_CHANGE_PUPPET_ENVIRONMENT',
22
+ })),
23
+ BULK_CHANGE_PUPPET_ENVIRONMENT_KEY: 'BULK_CHANGE_PUPPET_ENVIRONMENT',
24
+ }));
25
+
26
+ describe('BulkRemovePuppetEnvironmentModal', () => {
27
+ const dispatch = jest.fn();
28
+
29
+ const renderComponent = (fetchBulkParams = jest.fn()) =>
30
+ render(
31
+ <IntlProvider locale="en">
32
+ <BulkRemovePuppetEnvironmentModal
33
+ isOpen
34
+ closeModal={jest.fn()}
35
+ fetchBulkParams={fetchBulkParams}
36
+ selectedCount={2}
37
+ selectAllHostsMode={false}
38
+ />
39
+ </IntlProvider>
40
+ );
41
+
42
+ beforeEach(() => {
43
+ jest.clearAllMocks();
44
+ useDispatch.mockReturnValue(dispatch);
45
+ });
46
+
47
+ it('renders the removal warning', () => {
48
+ renderComponent();
49
+
50
+ expect(
51
+ screen.getAllByText('Remove Puppet Environment')[0]
52
+ ).toBeInTheDocument();
53
+ expect(
54
+ screen.getByText(/Removing the Puppet environment will affect/)
55
+ ).toBeInTheDocument();
56
+ });
57
+
58
+ it('submits organization scope with the bulk remove request', () => {
59
+ const fetchBulkParams = jest.fn(
60
+ () => 'organization = "Default Organization"'
61
+ );
62
+ renderComponent(fetchBulkParams);
63
+
64
+ fireEvent.click(
65
+ screen.getByRole('button', { name: 'Remove Puppet Environment' })
66
+ );
67
+
68
+ expect(bulkChangePuppetEnvironment).toHaveBeenCalledWith(
69
+ {
70
+ included: {
71
+ search: 'organization = "Default Organization"',
72
+ },
73
+ environment_id: null,
74
+ organization_id: 23,
75
+ },
76
+ expect.any(Function),
77
+ expect.any(Function)
78
+ );
79
+ });
80
+ });
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import renderer, { act } from 'react-test-renderer';
3
+
4
+ import { useBulkModalOpen } from 'foremanReact/common/BulkModalStateHelper';
5
+ import { ForemanActionsBarContext } from 'foremanReact/components/HostDetails/ActionsBar';
6
+
7
+ import BulkRemovePuppetEnvironmentScene from '../index';
8
+ import BulkRemovePuppetEnvironmentModal from '../BulkRemovePuppetEnvironmentModal';
9
+
10
+ jest.mock('foremanReact/common/BulkModalStateHelper', () => ({
11
+ useBulkModalOpen: jest.fn(),
12
+ }));
13
+
14
+ jest.mock('../BulkRemovePuppetEnvironmentModal', () => ({
15
+ __esModule: true,
16
+ default: jest.fn(() => null),
17
+ }));
18
+
19
+ describe('BulkRemovePuppetEnvironmentScene', () => {
20
+ const fetchBulkParams = jest.fn();
21
+ const refreshTableData = jest.fn();
22
+ const contextValue = {
23
+ selectAllHostsMode: false,
24
+ selectedCount: 2,
25
+ selectedResults: [1, 2],
26
+ fetchBulkParams,
27
+ refreshTableData,
28
+ };
29
+
30
+ beforeEach(() => {
31
+ jest.clearAllMocks();
32
+ useBulkModalOpen.mockReturnValue({
33
+ isOpen: true,
34
+ close: jest.fn(),
35
+ });
36
+ });
37
+
38
+ it('opens with bulk modal state and passes expected props', () => {
39
+ let component;
40
+ act(() => {
41
+ component = renderer.create(
42
+ <ForemanActionsBarContext.Provider value={contextValue}>
43
+ <BulkRemovePuppetEnvironmentScene />
44
+ </ForemanActionsBarContext.Provider>
45
+ );
46
+ });
47
+
48
+ const componentType =
49
+ BulkRemovePuppetEnvironmentModal.default ||
50
+ BulkRemovePuppetEnvironmentModal;
51
+ const { props } = component.root.findByType(componentType);
52
+
53
+ expect(props).toEqual(
54
+ expect.objectContaining({
55
+ fetchBulkParams,
56
+ selectedCount: 2,
57
+ selectAllHostsMode: false,
58
+ isOpen: true,
59
+ closeModal: expect.any(Function),
60
+ onSuccess: refreshTableData,
61
+ })
62
+ );
63
+
64
+ component.unmount();
65
+ });
66
+ });
@@ -0,0 +1,30 @@
1
+ import React, { useContext } from 'react';
2
+ import { ForemanActionsBarContext } from 'foremanReact/components/HostDetails/ActionsBar';
3
+ import { useBulkModalOpen } from 'foremanReact/common/BulkModalStateHelper';
4
+ import BulkRemovePuppetEnvironmentModal from './BulkRemovePuppetEnvironmentModal';
5
+
6
+ const BulkRemovePuppetEnvironmentScene = () => {
7
+ const {
8
+ selectAllHostsMode,
9
+ selectedCount,
10
+ fetchBulkParams,
11
+ refreshTableData,
12
+ } = useContext(ForemanActionsBarContext);
13
+ const { isOpen, close: closeModal } = useBulkModalOpen(
14
+ 'bulk-remove-puppet-environment'
15
+ );
16
+
17
+ return (
18
+ <BulkRemovePuppetEnvironmentModal
19
+ fetchBulkParams={fetchBulkParams}
20
+ selectedCount={selectedCount}
21
+ selectAllHostsMode={selectAllHostsMode}
22
+ isOpen={isOpen}
23
+ closeModal={closeModal}
24
+ onSuccess={refreshTableData}
25
+ />
26
+ );
27
+ };
28
+
29
+ export { BulkRemovePuppetEnvironmentModal };
30
+ export default BulkRemovePuppetEnvironmentScene;
@@ -1,61 +1,153 @@
1
1
  import React from 'react';
2
- import { mount } from '@theforeman/test';
2
+ import { screen, act } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import '@testing-library/jest-dom';
3
5
 
4
6
  import { openBulkModal } from 'foremanReact/common/BulkModalStateHelper';
5
7
  import { ForemanActionsBarContext } from 'foremanReact/components/HostDetails/ActionsBar';
8
+ import { rtlHelpers } from 'foremanReact/common/rtlTestHelpers';
9
+ import { APIActions } from 'foremanReact/redux/API';
10
+ import { foremanUrl } from 'foremanReact/common/helpers';
6
11
 
7
12
  import BulkRemovePuppetProxyScene from '../index';
8
- import BulkRemoveProxyCommon from '../../BulkRemoveProxyCommon';
13
+ import { BULK_REMOVE_PUPPET_PROXY_KEY } from '../../BulkRemoveProxyCommon/actions';
9
14
 
10
- jest.mock('foremanReact/components/HostDetails/ActionsBar', () => ({
11
- ForemanActionsBarContext: jest.requireActual('react').createContext(),
12
- }));
15
+ jest.mock(
16
+ 'foremanReact/components/HostDetails/ActionsBar',
17
+ () => ({
18
+ ForemanActionsBarContext: jest.requireActual('react').createContext(),
19
+ }),
20
+ { virtual: true }
21
+ );
13
22
 
14
- jest.mock('../../BulkRemoveProxyCommon', () => ({
15
- __esModule: true,
16
- default: jest.fn(() => null),
23
+ jest.mock('foremanReact/redux/API', () => ({
24
+ APIActions: {
25
+ put: jest.fn(payload => ({ type: 'MOCK_API_PUT', payload })),
26
+ },
17
27
  }));
18
28
 
29
+ const { renderWithStoreAndI18n } = rtlHelpers;
30
+
19
31
  describe('BulkRemovePuppetProxyScene', () => {
20
- const fetchBulkParams = jest.fn();
32
+ const fetchBulkParams = jest.fn(() => 'name = host1');
33
+ const refreshTableData = jest.fn();
21
34
  const contextValue = {
22
35
  selectAllHostsMode: false,
23
36
  selectedCount: 2,
24
37
  selectedResults: [1, 2],
25
38
  fetchBulkParams,
39
+ refreshTableData,
40
+ };
41
+
42
+ const renderScene = (context = contextValue) =>
43
+ renderWithStoreAndI18n(
44
+ <ForemanActionsBarContext.Provider value={context}>
45
+ <BulkRemovePuppetProxyScene />
46
+ </ForemanActionsBarContext.Provider>
47
+ );
48
+
49
+ const openSceneModal = async () => {
50
+ openBulkModal('bulk-remove-puppet-proxy', true);
51
+
52
+ return screen.findByRole('dialog', { name: 'Remove Puppet Proxy' });
26
53
  };
27
54
 
28
55
  beforeEach(() => {
29
- jest.clearAllMocks();
30
56
  openBulkModal('bulk-remove-puppet-proxy', false);
31
57
  });
32
58
 
33
- it('opens with bulk modal state and passes expected props', () => {
34
- openBulkModal('bulk-remove-puppet-proxy', true);
35
- const wrapper = mount(
36
- <ForemanActionsBarContext.Provider value={contextValue}>
37
- <BulkRemovePuppetProxyScene />
38
- </ForemanActionsBarContext.Provider>
59
+ afterEach(() => {
60
+ jest.clearAllMocks();
61
+ });
62
+
63
+ it('does not show the modal when bulk modal state is closed', () => {
64
+ renderScene();
65
+
66
+ expect(
67
+ screen.queryByRole('dialog', { name: 'Remove Puppet Proxy' })
68
+ ).not.toBeInTheDocument();
69
+ });
70
+
71
+ it('shows the modal with a warning for the selected hosts when opened', async () => {
72
+ renderScene();
73
+ await openSceneModal();
74
+
75
+ expect(
76
+ screen.getByText(/Removing the Puppet proxy will affect/)
77
+ ).toBeInTheDocument();
78
+ expect(screen.getByText('2', { selector: 'strong' })).toBeInTheDocument();
79
+ expect(screen.getByText(/selected hosts/)).toBeInTheDocument();
80
+ expect(
81
+ screen.getByRole('button', { name: 'Remove Puppet Proxy' })
82
+ ).toBeInTheDocument();
83
+ expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
84
+ });
85
+
86
+ it('shows the all hosts warning when select all hosts mode is enabled', async () => {
87
+ renderScene({
88
+ ...contextValue,
89
+ selectAllHostsMode: true,
90
+ });
91
+ await openSceneModal();
92
+
93
+ expect(
94
+ screen.getByText(/Removing the Puppet proxy will affect/)
95
+ ).toBeInTheDocument();
96
+ expect(screen.getByText('All', { selector: 'strong' })).toBeInTheDocument();
97
+ expect(screen.getByText(/selected hosts/)).toBeInTheDocument();
98
+ });
99
+
100
+ it('closes the modal when Cancel is clicked', async () => {
101
+ renderScene();
102
+ await openSceneModal();
103
+
104
+ await userEvent.click(screen.getByRole('button', { name: 'Cancel' }));
105
+
106
+ expect(
107
+ screen.queryByRole('dialog', { name: 'Remove Puppet Proxy' })
108
+ ).not.toBeInTheDocument();
109
+ });
110
+
111
+ it('dispatches the bulk remove puppet proxy action when confirmed', async () => {
112
+ renderScene();
113
+ await openSceneModal();
114
+
115
+ await userEvent.click(
116
+ screen.getByRole('button', { name: 'Remove Puppet Proxy' })
39
117
  );
40
118
 
41
- const componentType =
42
- BulkRemoveProxyCommon.default || BulkRemoveProxyCommon;
43
- const props = wrapper.find(componentType).props();
44
-
45
- expect(props).toEqual(
46
- expect.objectContaining({
47
- isCAProxy: false,
48
- selectAllHostsMode: false,
49
- selectedCount: 2,
50
- selectedResults: [1, 2],
51
- fetchBulkParams,
52
- isOpen: true,
53
- closeModal: expect.any(Function),
54
- handleErrorMessage: 'Failed to remove Puppet Proxy',
55
- removeMessage: 'Remove Puppet Proxy',
56
- })
119
+ expect(fetchBulkParams).toHaveBeenCalledTimes(1);
120
+ expect(APIActions.put).toHaveBeenCalledWith({
121
+ key: BULK_REMOVE_PUPPET_PROXY_KEY,
122
+ url: foremanUrl('/api/v2/hosts/bulk/remove_puppet_proxy'),
123
+ handleSuccess: expect.any(Function),
124
+ handleError: expect.any(Function),
125
+ params: {
126
+ included: {
127
+ search: 'name = host1',
128
+ },
129
+ ca_proxy: false,
130
+ },
131
+ });
132
+ });
133
+
134
+ it('refreshes table data after a successful bulk remove', async () => {
135
+ renderScene();
136
+ await openSceneModal();
137
+
138
+ await userEvent.click(
139
+ screen.getByRole('button', { name: 'Remove Puppet Proxy' })
57
140
  );
58
141
 
59
- wrapper.unmount();
142
+ const { handleSuccess } = APIActions.put.mock.calls[0][0];
143
+
144
+ act(() => {
145
+ handleSuccess({ data: { message: 'Puppet proxy removed' } });
146
+ });
147
+
148
+ expect(refreshTableData).toHaveBeenCalledTimes(1);
149
+ expect(
150
+ screen.queryByRole('dialog', { name: 'Remove Puppet Proxy' })
151
+ ).not.toBeInTheDocument();
60
152
  });
61
153
  });
@@ -10,6 +10,7 @@ const BulkRemovePuppetProxyScene = () => {
10
10
  selectedCount,
11
11
  selectedResults,
12
12
  fetchBulkParams,
13
+ refreshTableData,
13
14
  } = useContext(ForemanActionsBarContext);
14
15
  const { isOpen, close: closeModal } = useBulkModalOpen(
15
16
  'bulk-remove-puppet-proxy'
@@ -24,6 +25,7 @@ const BulkRemovePuppetProxyScene = () => {
24
25
  fetchBulkParams={fetchBulkParams}
25
26
  isOpen={isOpen}
26
27
  closeModal={closeModal}
28
+ onSuccess={refreshTableData}
27
29
  handleErrorMessage={__('Failed to remove Puppet Proxy')}
28
30
  allHostsMessage={__(
29
31
  'Removing the Puppet proxy will affect {boldCount} selected hosts.'
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+
3
+ export const ExampleRoutePage = () => (
4
+ <h1>Foreman Puppet example route</h1>
5
+ );
6
+
7
+ export const exampleRoutes = {
8
+ example: {
9
+ path: '/foreman_puppet_example',
10
+ exact: true,
11
+ component: ExampleRoutePage,
12
+ },
13
+ };
@@ -1,16 +1,76 @@
1
1
  import React from 'react';
2
- import { shallow } from '@theforeman/test';
2
+ import { createMemoryHistory } from 'history';
3
+ import { Router, Route, Switch } from 'react-router-dom';
4
+ import { screen } from '@testing-library/react';
5
+ import '@testing-library/jest-dom';
3
6
 
4
- import Routes from './routes';
7
+ import routes from './routes';
8
+ import ForemanPuppetRouter from './index';
9
+ import { exampleRoutes } from './routes.fixtures';
10
+ import { rtlHelpers } from 'foremanReact/common/rtlTestHelpers';
11
+
12
+ const { renderWithStore } = rtlHelpers;
13
+
14
+ const renderForemanPuppetRouterAtPath = path => {
15
+ const history = createMemoryHistory({ initialEntries: [path] });
16
+
17
+ return renderWithStore(
18
+ <Router history={history}>
19
+ <ForemanPuppetRouter />
20
+ </Router>
21
+ );
22
+ };
23
+
24
+ const renderRoutesAtPath = (routeMap, path) => {
25
+ const history = createMemoryHistory({ initialEntries: [path] });
26
+
27
+ return renderWithStore(
28
+ <Router history={history}>
29
+ <Switch>
30
+ {Object.entries(routeMap).map(([key, props]) => (
31
+ <Route key={key} {...props} />
32
+ ))}
33
+ </Switch>
34
+ </Router>
35
+ );
36
+ };
5
37
 
6
38
  describe('ForemanPuppetRoutes', () => {
7
- it('should create routes', () => {
8
- Object.entries(Routes).forEach(([key, Route]) => {
9
- const Component = Route.component;
10
- const component = shallow(<Component history={{}} some="props" />);
11
- Route.renderResult = component;
39
+ it('exports an empty routes configuration object', () => {
40
+ expect(routes).toEqual({});
41
+ expect(routes).not.toBeNull();
42
+ expect(Array.isArray(routes)).toBe(false);
43
+ });
44
+
45
+ describe('fixture routes', () => {
46
+ it('defines valid route entries', () => {
47
+ Object.entries(exampleRoutes).forEach(([routeKey, route]) => {
48
+ expect(routeKey).toBeTruthy();
49
+ expect(route).toEqual(
50
+ expect.objectContaining({
51
+ path: expect.any(String),
52
+ component: expect.any(Function),
53
+ })
54
+ );
55
+ });
12
56
  });
13
57
 
14
- expect(Routes).toMatchSnapshot();
58
+ it('renders a fixture route at its path', () => {
59
+ const { path } = exampleRoutes.example;
60
+
61
+ renderRoutesAtPath(exampleRoutes, path);
62
+
63
+ expect(
64
+ screen.getByRole('heading', { name: 'Foreman Puppet example route' })
65
+ ).toBeInTheDocument();
66
+ });
67
+ });
68
+
69
+ describe('ForemanPuppetRouter', () => {
70
+ it('renders without content when no routes are configured', () => {
71
+ const { container } = renderForemanPuppetRouterAtPath('/');
72
+
73
+ expect(container).toBeEmptyDOMElement();
74
+ });
15
75
  });
16
76
  });
@@ -4,6 +4,8 @@ import $ from 'jquery';
4
4
 
5
5
  import { checkForUnavailablePuppetclasses } from './foreman_puppet_host_form';
6
6
 
7
+ const WARNING_RENDER_TIMEOUT = 100;
8
+
7
9
  jest.unmock('jquery');
8
10
  jest.unmock('./foreman_puppet_host_form');
9
11
 
@@ -59,6 +61,6 @@ describe('checkForUnavailablePuppetclasses', () => {
59
61
  checkForUnavailablePuppetclasses();
60
62
  setTimeout(() => {
61
63
  expect($('a .pficon')).toHaveLength(1);
62
- }, 100);
64
+ }, WARNING_RENDER_TIMEOUT);
63
65
  });
64
66
  });
@@ -0,0 +1 @@
1
+ import 'foremanJSTestSetup';