foreman_remote_execution 4.6.0 → 5.0.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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby_ci.yml +7 -0
  3. data/.rubocop_todo.yml +1 -0
  4. data/app/controllers/api/v2/job_invocations_controller.rb +16 -1
  5. data/app/controllers/job_invocations_controller.rb +1 -1
  6. data/app/controllers/ui_job_wizard_controller.rb +21 -2
  7. data/app/graphql/mutations/job_invocations/create.rb +43 -0
  8. data/app/graphql/types/job_invocation.rb +16 -0
  9. data/app/graphql/types/job_invocation_input.rb +13 -0
  10. data/app/graphql/types/recurrence_input.rb +8 -0
  11. data/app/graphql/types/scheduling_input.rb +6 -0
  12. data/app/graphql/types/targeting_enum.rb +7 -0
  13. data/app/helpers/concerns/foreman_remote_execution/hosts_helper_extensions.rb +5 -1
  14. data/app/helpers/remote_execution_helper.rb +9 -3
  15. data/app/lib/actions/remote_execution/run_host_job.rb +10 -1
  16. data/app/lib/actions/remote_execution/run_hosts_job.rb +58 -4
  17. data/app/mailers/rex_job_mailer.rb +15 -0
  18. data/app/models/concerns/foreman_remote_execution/host_extensions.rb +10 -0
  19. data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +6 -0
  20. data/app/models/host_proxy_invocation.rb +4 -0
  21. data/app/models/host_status/execution_status.rb +3 -3
  22. data/app/models/job_invocation.rb +12 -5
  23. data/app/models/job_invocation_composer.rb +25 -17
  24. data/app/models/job_template.rb +1 -1
  25. data/app/models/remote_execution_feature.rb +5 -1
  26. data/app/models/remote_execution_provider.rb +18 -2
  27. data/app/models/rex_mail_notification.rb +13 -0
  28. data/app/models/targeting.rb +7 -3
  29. data/app/services/ui_notifications/remote_execution_jobs/base_job_finish.rb +2 -1
  30. data/app/views/dashboard/_latest-jobs.html.erb +21 -0
  31. data/app/views/job_invocations/index.html.erb +1 -1
  32. data/app/views/job_invocations/refresh.js.erb +1 -0
  33. data/app/views/rex_job_mailer/job_finished.html.erb +24 -0
  34. data/app/views/rex_job_mailer/job_finished.text.erb +9 -0
  35. data/app/views/template_invocations/show.html.erb +2 -1
  36. data/app/views/templates/ssh/module_action.erb +1 -0
  37. data/app/views/templates/ssh/power_action.erb +2 -0
  38. data/app/views/templates/ssh/puppet_run_once.erb +1 -0
  39. data/config/routes.rb +1 -0
  40. data/db/migrate/2021051713291621250977_add_host_proxy_invocations.rb +12 -0
  41. data/db/migrate/20210816100932_rex_setting_category_to_dsl.rb +5 -0
  42. data/db/seeds.d/50-notification_blueprints.rb +14 -0
  43. data/db/seeds.d/95-mail_notifications.rb +24 -0
  44. data/foreman_remote_execution.gemspec +2 -3
  45. data/lib/foreman_remote_execution/engine.rb +114 -8
  46. data/lib/foreman_remote_execution/version.rb +1 -1
  47. data/package.json +9 -7
  48. data/test/functional/api/v2/job_invocations_controller_test.rb +20 -0
  49. data/test/functional/cockpit_controller_test.rb +0 -1
  50. data/test/graphql/mutations/job_invocations/create.rb +58 -0
  51. data/test/graphql/queries/job_invocation_query_test.rb +31 -0
  52. data/test/graphql/queries/job_invocations_query_test.rb +35 -0
  53. data/test/helpers/remote_execution_helper_test.rb +0 -1
  54. data/test/unit/actions/run_host_job_test.rb +21 -0
  55. data/test/unit/actions/run_hosts_job_test.rb +99 -4
  56. data/test/unit/concerns/host_extensions_test.rb +40 -7
  57. data/test/unit/input_template_renderer_test.rb +1 -89
  58. data/test/unit/job_invocation_composer_test.rb +18 -18
  59. data/test/unit/job_invocation_report_template_test.rb +16 -13
  60. data/test/unit/job_invocation_test.rb +1 -1
  61. data/test/unit/job_template_effective_user_test.rb +0 -4
  62. data/test/unit/remote_execution_provider_test.rb +46 -4
  63. data/test/unit/targeting_test.rb +68 -1
  64. data/webpack/JobWizard/JobWizard.js +158 -24
  65. data/webpack/JobWizard/JobWizard.scss +93 -1
  66. data/webpack/JobWizard/JobWizardConstants.js +54 -0
  67. data/webpack/JobWizard/JobWizardSelectors.js +41 -0
  68. data/webpack/JobWizard/__tests__/fixtures.js +188 -3
  69. data/webpack/JobWizard/__tests__/integration.test.js +41 -106
  70. data/webpack/JobWizard/__tests__/validation.test.js +141 -0
  71. data/webpack/JobWizard/autofill.js +38 -0
  72. data/webpack/JobWizard/index.js +7 -0
  73. data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +41 -10
  74. data/webpack/JobWizard/steps/AdvancedFields/DescriptionField.js +90 -0
  75. data/webpack/JobWizard/steps/AdvancedFields/Fields.js +116 -55
  76. data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +354 -16
  77. data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap +79 -246
  78. data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js +5 -2
  79. data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +123 -51
  80. data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +3 -2
  81. data/webpack/JobWizard/steps/HostsAndInputs/HostPreviewModal.js +62 -0
  82. data/webpack/JobWizard/steps/HostsAndInputs/HostSearch.js +54 -0
  83. data/webpack/JobWizard/steps/HostsAndInputs/SelectAPI.js +33 -0
  84. data/webpack/JobWizard/steps/HostsAndInputs/SelectGQL.js +52 -0
  85. data/webpack/JobWizard/steps/HostsAndInputs/SelectedChips.js +100 -0
  86. data/webpack/JobWizard/steps/HostsAndInputs/TemplateInputs.js +23 -0
  87. data/webpack/JobWizard/steps/HostsAndInputs/__tests__/HostsAndInputs.test.js +151 -0
  88. data/webpack/JobWizard/steps/HostsAndInputs/__tests__/TemplateInputs.test.js +53 -0
  89. data/webpack/JobWizard/steps/HostsAndInputs/buildHostQuery.js +18 -0
  90. data/webpack/JobWizard/steps/HostsAndInputs/hostgroups.gql +8 -0
  91. data/webpack/JobWizard/steps/HostsAndInputs/hosts.gql +8 -0
  92. data/webpack/JobWizard/steps/HostsAndInputs/index.js +214 -0
  93. data/webpack/JobWizard/steps/ReviewDetails/index.js +193 -0
  94. data/webpack/JobWizard/steps/Schedule/PurposeField.js +31 -0
  95. data/webpack/JobWizard/steps/Schedule/QueryType.js +51 -0
  96. data/webpack/JobWizard/steps/Schedule/RepeatCron.js +53 -0
  97. data/webpack/JobWizard/steps/Schedule/RepeatDaily.js +37 -0
  98. data/webpack/JobWizard/steps/Schedule/RepeatHour.js +54 -0
  99. data/webpack/JobWizard/steps/Schedule/RepeatMonth.js +46 -0
  100. data/webpack/JobWizard/steps/Schedule/RepeatOn.js +125 -0
  101. data/webpack/JobWizard/steps/Schedule/RepeatWeek.js +70 -0
  102. data/webpack/JobWizard/steps/Schedule/ScheduleType.js +28 -0
  103. data/webpack/JobWizard/steps/Schedule/StartEndDates.js +106 -0
  104. data/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +402 -0
  105. data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +32 -0
  106. data/webpack/JobWizard/steps/Schedule/index.js +178 -0
  107. data/webpack/JobWizard/steps/form/DateTimePicker.js +126 -0
  108. data/webpack/JobWizard/steps/form/FormHelpers.js +5 -0
  109. data/webpack/JobWizard/steps/form/Formatter.js +181 -0
  110. data/webpack/JobWizard/steps/form/NumberInput.js +36 -0
  111. data/webpack/JobWizard/steps/form/ResourceSelect.js +29 -0
  112. data/webpack/JobWizard/steps/form/SearchSelect.js +121 -0
  113. data/webpack/JobWizard/steps/form/SelectField.js +28 -5
  114. data/webpack/JobWizard/steps/form/WizardTitle.js +14 -0
  115. data/webpack/JobWizard/steps/form/__tests__/SelectSearch.test.js +33 -0
  116. data/webpack/JobWizard/submit.js +120 -0
  117. data/webpack/JobWizard/validation.js +53 -0
  118. data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext/index.js +2 -0
  119. data/webpack/__mocks__/foremanReact/common/I18n.js +2 -0
  120. data/webpack/__mocks__/foremanReact/components/AutoComplete/AutoCompleteActions.js +1 -0
  121. data/webpack/__mocks__/foremanReact/components/AutoComplete/AutoCompleteConstants.js +1 -0
  122. data/webpack/__mocks__/foremanReact/components/SearchBar.js +18 -1
  123. data/webpack/__mocks__/foremanReact/routes/RouterSelector.js +1 -0
  124. data/webpack/helpers.js +1 -0
  125. data/webpack/react_app/components/RecentJobsCard/JobStatusIcon.js +43 -0
  126. data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +73 -66
  127. data/webpack/react_app/components/RecentJobsCard/RecentJobsTable.js +98 -0
  128. data/webpack/react_app/components/RecentJobsCard/constants.js +11 -0
  129. data/webpack/react_app/components/RecentJobsCard/styles.scss +11 -0
  130. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +1 -0
  131. data/webpack/react_app/extend/fillRecentJobsCard.js +1 -1
  132. metadata +71 -16
  133. data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +0 -70
  134. data/app/models/setting/remote_execution.rb +0 -88
  135. data/test/models/orchestration/ssh_test.rb +0 -56
  136. data/webpack/JobWizard/__tests__/JobWizard.test.js +0 -13
  137. data/webpack/JobWizard/__tests__/__snapshots__/JobWizard.test.js.snap +0 -32
  138. data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap +0 -113
  139. data/webpack/JobWizard/steps/form/__tests__/GroupedSelectField.test.js +0 -38
  140. data/webpack/JobWizard/steps/form/__tests__/SelectField.test.js +0 -23
  141. data/webpack/JobWizard/steps/form/__tests__/__snapshots__/GroupedSelectField.test.js.snap +0 -37
  142. data/webpack/JobWizard/steps/form/__tests__/__snapshots__/SelectField.test.js.snap +0 -23
  143. data/webpack/react_app/components/RecentJobsCard/styles.css +0 -15
@@ -1,25 +1,363 @@
1
+ /* eslint-disable max-lines */
1
2
  import React from 'react';
2
3
  import { Provider } from 'react-redux';
3
- import configureMockStore from 'redux-mock-store';
4
- import * as patternfly from '@patternfly/react-core';
5
4
  import { mount } from '@theforeman/test';
6
- import { AdvancedFields } from '../AdvancedFields';
7
-
8
- jest.spyOn(patternfly, 'FormGroup');
9
- patternfly.FormGroup.mockImplementation(props => (
10
- <div>{props.navAriaLabel}</div>
11
- ));
12
- const mockStore = configureMockStore([]);
13
- const store = mockStore({
14
- JOB_TEMPLATE: { response: { effective_user: { overridable: true } } },
15
- });
5
+ import { fireEvent, screen, render, act } from '@testing-library/react';
6
+ import { MockedProvider } from '@apollo/client/testing';
7
+ import * as api from 'foremanReact/redux/API';
8
+ import { JobWizard } from '../../../JobWizard';
9
+ import * as selectors from '../../../JobWizardSelectors';
10
+ import {
11
+ jobTemplateResponse,
12
+ jobTemplate,
13
+ testSetup,
14
+ mockApi,
15
+ jobCategories,
16
+ gqlMock,
17
+ } from '../../../__tests__/fixtures';
18
+ import { WIZARD_TITLES } from '../../../JobWizardConstants';
19
+
20
+ const store = testSetup(selectors, api);
21
+ mockApi(api);
22
+
23
+ jest.spyOn(selectors, 'selectEffectiveUser');
24
+
25
+ selectors.selectEffectiveUser.mockImplementation(
26
+ () => jobTemplateResponse.effective_user
27
+ );
16
28
  describe('AdvancedFields', () => {
17
- it('rendring', () => {
18
- const component = mount(
29
+ it('should save data between steps for advanced fields', async () => {
30
+ const wrapper = mount(
31
+ <MockedProvider mocks={gqlMock} addTypename={false}>
32
+ <Provider store={store}>
33
+ <JobWizard />
34
+ </Provider>
35
+ </MockedProvider>
36
+ );
37
+ // setup
38
+ wrapper.find('.pf-c-button.pf-c-select__toggle-button').simulate('click');
39
+ wrapper
40
+ .find('.pf-c-select__menu-item')
41
+ .first()
42
+ .simulate('click');
43
+
44
+ // test
45
+ expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-disabled')).toHaveLength(
46
+ 0
47
+ );
48
+ wrapper
49
+ .find('.pf-c-wizard__nav-link')
50
+ .at(2)
51
+ .simulate('click'); // Advanced step
52
+ const effectiveUserInput = () => wrapper.find('input#effective-user');
53
+ const advancedTemplateInput = () =>
54
+ wrapper.find('.pf-c-form__group-control textarea');
55
+ const effectiveUesrValue = 'effective user new value';
56
+ const advancedTemplateInputValue = 'advanced input new value';
57
+ effectiveUserInput().getDOMNode().value = effectiveUesrValue;
58
+
59
+ effectiveUserInput().simulate('change');
60
+ wrapper.update();
61
+ advancedTemplateInput().getDOMNode().value = advancedTemplateInputValue;
62
+ advancedTemplateInput().simulate('change');
63
+ expect(effectiveUserInput().prop('value')).toEqual(effectiveUesrValue);
64
+ expect(advancedTemplateInput().prop('value')).toEqual(
65
+ advancedTemplateInputValue
66
+ );
67
+
68
+ wrapper
69
+ .find('.pf-c-wizard__nav-link')
70
+ .at(1)
71
+ .simulate('click');
72
+
73
+ expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-current').text()).toEqual(
74
+ 'Target hosts and inputs'
75
+ );
76
+ wrapper
77
+ .find('.pf-c-wizard__nav-link')
78
+ .at(2)
79
+ .simulate('click'); // Advanced step
80
+
81
+ expect(effectiveUserInput().prop('value')).toEqual(effectiveUesrValue);
82
+ expect(advancedTemplateInput().prop('value')).toEqual(
83
+ advancedTemplateInputValue
84
+ );
85
+ });
86
+ it('fill template fields', async () => {
87
+ render(
88
+ <MockedProvider mocks={gqlMock} addTypename={false}>
89
+ <Provider store={store}>
90
+ <JobWizard />
91
+ </Provider>
92
+ </MockedProvider>
93
+ );
94
+ await act(async () => {
95
+ fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
96
+ });
97
+ const searchValue = 'search test';
98
+ const textValue = 'I am a text';
99
+ const dateValue = '08/07/2021';
100
+ const textField = screen.getByLabelText('adv plain hidden', {
101
+ selector: 'textarea',
102
+ });
103
+ const selectField = screen.getByLabelText('adv plain select toggle');
104
+ const resourceSelectField = screen.getByLabelText(
105
+ 'adv resource select toggle'
106
+ );
107
+ const searchField = screen.getByPlaceholderText('Filter...');
108
+ const dateField = screen.getByLabelText('adv date', {
109
+ selector: 'input',
110
+ });
111
+
112
+ fireEvent.click(selectField);
113
+ await act(async () => {
114
+ await fireEvent.click(screen.getByText('option 2'));
115
+ fireEvent.click(screen.getAllByText(WIZARD_TITLES.advanced)[0]); // to remove focus
116
+
117
+ fireEvent.click(resourceSelectField);
118
+ await fireEvent.click(screen.getByText('resource2'));
119
+
120
+ await fireEvent.change(textField, {
121
+ target: { value: textValue },
122
+ });
123
+
124
+ await fireEvent.change(searchField, {
125
+ target: { value: searchValue },
126
+ });
127
+ await fireEvent.change(dateField, {
128
+ target: { value: dateValue },
129
+ });
130
+ });
131
+ expect(
132
+ screen.getByLabelText('adv plain hidden', {
133
+ selector: 'textarea',
134
+ }).value
135
+ ).toBe(textValue);
136
+ expect(searchField.value).toBe(searchValue);
137
+ expect(dateField.value).toBe(dateValue);
138
+ await act(async () => {
139
+ fireEvent.click(screen.getByText(WIZARD_TITLES.categoryAndTemplate));
140
+ });
141
+ expect(screen.getAllByText(WIZARD_TITLES.categoryAndTemplate)).toHaveLength(
142
+ 3
143
+ );
144
+
145
+ await act(async () => {
146
+ fireEvent.click(screen.getByText('Advanced Fields'));
147
+ });
148
+ expect(textField.value).toBe(textValue);
149
+ expect(searchField.value).toBe(searchValue);
150
+ expect(dateField.value).toBe(dateValue);
151
+ expect(screen.queryAllByText('option 1')).toHaveLength(0);
152
+ expect(screen.queryAllByText('option 2')).toHaveLength(1);
153
+ expect(screen.queryAllByDisplayValue('resource1')).toHaveLength(0);
154
+ expect(screen.queryAllByDisplayValue('resource2')).toHaveLength(1);
155
+ });
156
+ it('fill defaults into fields', async () => {
157
+ render(
158
+ <MockedProvider mocks={gqlMock} addTypename={false}>
159
+ <Provider store={store}>
160
+ <JobWizard />
161
+ </Provider>
162
+ </MockedProvider>
163
+ );
164
+ await act(async () => {
165
+ fireEvent.click(screen.getByText('Advanced Fields'));
166
+ });
167
+
168
+ expect(
169
+ screen.getByLabelText('effective user', {
170
+ selector: 'input',
171
+ }).value
172
+ ).toBe('default effective user');
173
+ expect(
174
+ screen.getByLabelText('timeout to kill', {
175
+ selector: 'input',
176
+ }).value
177
+ ).toBe('2');
178
+
179
+ expect(
180
+ screen.getByLabelText('description preview', {
181
+ selector: 'input',
182
+ }).value
183
+ ).toBe(
184
+ 'template1 with inputs adv plain hidden="Default val" adv plain select="" adv resource select="" adv search="" adv date="" plain hidden="Default val"'
185
+ );
186
+ });
187
+ it('DescriptionField', async () => {
188
+ render(
19
189
  <Provider store={store}>
20
- <AdvancedFields advancedValues={{}} setAdvancedValues={jest.fn()} />
190
+ <JobWizard />
21
191
  </Provider>
22
192
  );
23
- expect(component).toMatchSnapshot();
193
+ await act(async () => {
194
+ fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
195
+ });
196
+
197
+ const textField = screen.getByLabelText('adv plain hidden', {
198
+ selector: 'textarea',
199
+ });
200
+ await act(async () => {
201
+ await fireEvent.change(textField, {
202
+ target: { value: 'test command' },
203
+ });
204
+ });
205
+ const descriptionValue = 'Run %{adv plain hidden} %{wrong command name}';
206
+
207
+ await act(async () => {
208
+ fireEvent.click(screen.getByText('Edit job description template'));
209
+ });
210
+
211
+ const editText = screen.getByLabelText('description edit', {
212
+ selector: 'input',
213
+ });
214
+ await fireEvent.change(editText, {
215
+ target: { value: descriptionValue },
216
+ });
217
+ await act(async () => {
218
+ fireEvent.click(screen.getByText('Preview job description'));
219
+ });
220
+ expect(
221
+ screen.getByLabelText('description preview', {
222
+ selector: 'input',
223
+ }).value
224
+ ).toBe('Run test command %{wrong command name}');
225
+ });
226
+
227
+ it('DescriptionField with no inputs', async () => {
228
+ jest.spyOn(api, 'get');
229
+
230
+ jest.spyOn(selectors, 'selectTemplateInputs');
231
+ jest.spyOn(selectors, 'selectAdvancedTemplateInputs');
232
+ selectors.selectTemplateInputs.mockImplementation(() => []);
233
+ selectors.selectAdvancedTemplateInputs.mockImplementation(() => []);
234
+ api.get.mockImplementation(({ handleSuccess, ...action }) => {
235
+ if (action.key === 'JOB_CATEGORIES') {
236
+ handleSuccess &&
237
+ handleSuccess({ data: { job_categories: jobCategories } });
238
+ } else if (action.key === 'JOB_TEMPLATE') {
239
+ handleSuccess &&
240
+ handleSuccess({
241
+ data: {
242
+ ...jobTemplateResponse,
243
+ advanced_template_inputs: [],
244
+ template_inputs: [],
245
+ },
246
+ });
247
+ } else if (action.key === 'JOB_TEMPLATES') {
248
+ handleSuccess &&
249
+ handleSuccess({
250
+ data: { results: [jobTemplate] },
251
+ });
252
+ }
253
+ return { type: 'get', ...action };
254
+ });
255
+ render(
256
+ <Provider store={store}>
257
+ <JobWizard />
258
+ </Provider>
259
+ );
260
+ await act(async () => {
261
+ fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
262
+ });
263
+ expect(
264
+ screen.getByLabelText('description preview', {
265
+ selector: 'input',
266
+ }).value
267
+ ).toBe('template1');
268
+ });
269
+
270
+ it('DescriptionField with description_format', async () => {
271
+ jest.spyOn(api, 'get');
272
+ jest.spyOn(selectors, 'selectTemplateInputs');
273
+ selectors.selectTemplateInputs.mockImplementation(() => [
274
+ {
275
+ name: 'command',
276
+ required: true,
277
+ input_type: 'user',
278
+ description: 'some Description',
279
+ advanced: true,
280
+ value_type: 'plain',
281
+ resource_type: 'ansible_roles',
282
+ default: 'Default val',
283
+ hidden_value: true,
284
+ },
285
+ ]);
286
+ api.get.mockImplementation(({ handleSuccess, ...action }) => {
287
+ if (action.key === 'JOB_CATEGORIES') {
288
+ handleSuccess &&
289
+ handleSuccess({ data: { job_categories: jobCategories } });
290
+ } else if (action.key === 'JOB_TEMPLATE') {
291
+ handleSuccess &&
292
+ handleSuccess({
293
+ data: {
294
+ ...jobTemplateResponse,
295
+ job_template: {
296
+ ...jobTemplateResponse.jobTemplate,
297
+ description_format: 'Run %{command}',
298
+ },
299
+
300
+ template_inputs: [
301
+ {
302
+ name: 'command',
303
+ required: true,
304
+ input_type: 'user',
305
+ description: 'some Description',
306
+ advanced: true,
307
+ value_type: 'plain',
308
+ resource_type: 'ansible_roles',
309
+ default: 'Default val',
310
+ hidden_value: true,
311
+ },
312
+ ],
313
+ },
314
+ });
315
+ } else if (action.key === 'JOB_TEMPLATES') {
316
+ handleSuccess &&
317
+ handleSuccess({
318
+ data: { results: [jobTemplate] },
319
+ });
320
+ }
321
+ return { type: 'get', ...action };
322
+ });
323
+ render(
324
+ <Provider store={store}>
325
+ <JobWizard />
326
+ </Provider>
327
+ );
328
+ await act(async () => {
329
+ fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
330
+ });
331
+ expect(
332
+ screen.getByLabelText('description preview', {
333
+ selector: 'input',
334
+ }).value
335
+ ).toBe('Run Default val');
336
+ });
337
+
338
+ it('search resources action', async () => {
339
+ jest.useFakeTimers();
340
+ mockApi(api);
341
+ const newStore = testSetup(selectors, api);
342
+ render(
343
+ <Provider store={newStore}>
344
+ <JobWizard />
345
+ </Provider>
346
+ );
347
+ await act(async () => {
348
+ fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
349
+ });
350
+ const resourceSelectField = screen.getByLabelText(
351
+ 'adv resource select typeahead input'
352
+ );
353
+
354
+ await act(async () => {
355
+ await fireEvent.change(resourceSelectField, {
356
+ target: { value: 'some search' },
357
+ });
358
+
359
+ await jest.runAllTimers();
360
+ });
361
+ expect(newStore.getActions()).toMatchSnapshot('resource search');
24
362
  });
25
363
  });