foreman_remote_execution 7.2.1 → 8.0.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby_ci.yml +2 -2
  3. data/app/controllers/ui_job_wizard_controller.rb +15 -0
  4. data/app/helpers/remote_execution_helper.rb +1 -1
  5. data/app/models/job_invocation.rb +2 -4
  6. data/app/models/job_invocation_composer.rb +5 -2
  7. data/app/views/templates/script/package_action.erb +8 -3
  8. data/config/routes.rb +3 -1
  9. data/lib/foreman_remote_execution/engine.rb +5 -5
  10. data/lib/foreman_remote_execution/version.rb +1 -1
  11. data/test/functional/api/v2/job_invocations_controller_test.rb +8 -0
  12. data/test/helpers/remote_execution_helper_test.rb +4 -0
  13. data/test/unit/job_invocation_report_template_test.rb +1 -1
  14. data/test/unit/job_invocation_test.rb +1 -2
  15. data/webpack/JobWizard/JobWizard.js +154 -20
  16. data/webpack/JobWizard/JobWizard.scss +43 -1
  17. data/webpack/JobWizard/JobWizardConstants.js +11 -1
  18. data/webpack/JobWizard/JobWizardPageRerun.js +112 -0
  19. data/webpack/JobWizard/__tests__/JobWizardPageRerun.test.js +79 -0
  20. data/webpack/JobWizard/__tests__/fixtures.js +73 -0
  21. data/webpack/JobWizard/__tests__/integration.test.js +17 -3
  22. data/webpack/JobWizard/autofill.js +8 -1
  23. data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +36 -17
  24. data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +3 -3
  25. data/webpack/JobWizard/steps/ReviewDetails/index.js +1 -3
  26. data/webpack/JobWizard/steps/Schedule/PurposeField.js +1 -3
  27. data/webpack/JobWizard/steps/Schedule/QueryType.js +33 -40
  28. data/webpack/JobWizard/steps/Schedule/RepeatHour.js +55 -16
  29. data/webpack/JobWizard/steps/Schedule/RepeatOn.js +19 -56
  30. data/webpack/JobWizard/steps/Schedule/RepeatWeek.js +1 -1
  31. data/webpack/JobWizard/steps/Schedule/ScheduleFuture.js +126 -0
  32. data/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js +287 -0
  33. data/webpack/JobWizard/steps/Schedule/ScheduleType.js +88 -20
  34. data/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +206 -186
  35. data/webpack/JobWizard/steps/form/DateTimePicker.js +23 -6
  36. data/webpack/JobWizard/steps/form/Formatter.js +7 -8
  37. data/webpack/JobWizard/submit.js +8 -3
  38. data/webpack/Routes/routes.js +8 -2
  39. data/webpack/__mocks__/foremanReact/common/hooks/API/APIHooks.js +1 -0
  40. data/webpack/react_app/components/HostKebab/KebabItems.js +0 -1
  41. data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +0 -5
  42. data/webpack/react_app/components/RecentJobsCard/RecentJobsTable.js +59 -51
  43. data/webpack/react_app/extend/Fills.js +4 -4
  44. metadata +8 -6
  45. data/webpack/JobWizard/steps/Schedule/StartEndDates.js +0 -106
  46. data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +0 -32
  47. data/webpack/JobWizard/steps/Schedule/index.js +0 -178
@@ -1,28 +1,96 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { FormGroup, Radio } from '@patternfly/react-core';
3
+ import { Form, FormGroup, Radio, Divider } from '@patternfly/react-core';
4
4
  import { translate as __ } from 'foremanReact/common/I18n';
5
+ import {
6
+ WIZARD_TITLES,
7
+ SCHEDULE_TYPES,
8
+ repeatTypes,
9
+ } from '../../JobWizardConstants';
10
+ import { WizardTitle } from '../form/WizardTitle';
11
+ import { QueryType } from './QueryType';
5
12
 
6
- export const ScheduleType = ({ isFuture, setIsFuture }) => (
7
- <FormGroup label={__('Schedule type')} fieldId="schedule-type">
8
- <Radio
9
- isChecked={!isFuture}
10
- name="schedule-type"
11
- onChange={() => setIsFuture(false)}
12
- id="schedule-type-now"
13
- label={__('Execute now')}
14
- />
15
- <Radio
16
- isChecked={isFuture}
17
- name="schedule-type"
18
- onChange={() => setIsFuture(true)}
19
- id="schedule-type-future"
20
- label={__('Schedule for future execution')}
21
- />
22
- </FormGroup>
13
+ export const ScheduleType = ({
14
+ scheduleType,
15
+ isTypeStatic,
16
+ setScheduleValue,
17
+ setValid,
18
+ }) => (
19
+ <div className="schedule-tab">
20
+ <WizardTitle title={WIZARD_TITLES.schedule} />
21
+ <Form>
22
+ <FormGroup
23
+ fieldId="schedule-type-now"
24
+ label={__('Select the type of execution')}
25
+ >
26
+ <Radio
27
+ isChecked={scheduleType === SCHEDULE_TYPES.NOW}
28
+ name="schedule-type-now"
29
+ id="schedule-type-now"
30
+ onChange={() => {
31
+ setScheduleValue(current => ({
32
+ ...current,
33
+ scheduleType: SCHEDULE_TYPES.NOW,
34
+ repeatType: repeatTypes.noRepeat,
35
+ startsAt: null,
36
+ startsBefore: null,
37
+ }));
38
+ setValid(true);
39
+ }}
40
+ label={__('Immediate execution')}
41
+ body={__('Execute the job now.')}
42
+ />
43
+ </FormGroup>
44
+ <FormGroup fieldId="schedule-type-future">
45
+ <Radio
46
+ isChecked={scheduleType === SCHEDULE_TYPES.FUTURE}
47
+ onChange={() => {
48
+ setScheduleValue(current => ({
49
+ ...current,
50
+ startsAt: new Date().toISOString(),
51
+ scheduleType: SCHEDULE_TYPES.FUTURE,
52
+ repeatType: repeatTypes.noRepeat,
53
+ }));
54
+ setValid(true);
55
+ }}
56
+ name="schedule-type-future"
57
+ id="schedule-type-future"
58
+ label={__('Future execution')}
59
+ body={__('Execute the job later, at a scheduled time.')}
60
+ />
61
+ </FormGroup>
62
+ <FormGroup fieldId="schedule-type-recurring">
63
+ <Radio
64
+ isChecked={scheduleType === SCHEDULE_TYPES.RECURRING}
65
+ onChange={() => {
66
+ setScheduleValue(current => ({
67
+ ...current,
68
+ scheduleType: SCHEDULE_TYPES.RECURRING,
69
+ repeatType: repeatTypes.daily,
70
+ repeatData: { at: '12:00' },
71
+ }));
72
+ setValid(true);
73
+ }}
74
+ name="schedule-type-recurring"
75
+ id="schedule-type-recurring"
76
+ label={__('Recurring execution')}
77
+ body={__('Execute the job on a repeating schedule.')}
78
+ />
79
+ </FormGroup>
80
+ <Divider component="div" />
81
+ <QueryType
82
+ isTypeStatic={isTypeStatic}
83
+ setIsTypeStatic={newValue => {
84
+ setScheduleValue(current => ({ ...current, isTypeStatic: newValue }));
85
+ }}
86
+ />
87
+ </Form>
88
+ </div>
23
89
  );
24
90
 
25
91
  ScheduleType.propTypes = {
26
- isFuture: PropTypes.bool.isRequired,
27
- setIsFuture: PropTypes.func.isRequired,
92
+ isTypeStatic: PropTypes.bool.isRequired,
93
+ scheduleType: PropTypes.string.isRequired,
94
+ setScheduleValue: PropTypes.func.isRequired,
95
+ setValid: PropTypes.func.isRequired,
28
96
  };
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import { Provider } from 'react-redux';
4
4
  import configureMockStore from 'redux-mock-store';
5
5
  import { fireEvent, screen, render, act } from '@testing-library/react';
6
+ import '@testing-library/jest-dom';
6
7
  import * as api from 'foremanReact/redux/API';
7
8
  import { JobWizard } from '../../../JobWizard';
8
9
  import * as selectors from '../../../JobWizardSelectors';
@@ -47,166 +48,232 @@ const store = mockStore({});
47
48
  jest.useFakeTimers();
48
49
 
49
50
  describe('Schedule', () => {
50
- it('should save date time between steps ', async () => {
51
+ it('sub steps appear', () => {
51
52
  render(
52
53
  <Provider store={store}>
53
54
  <JobWizard />
54
55
  </Provider>
55
56
  );
56
- await act(async () => {
57
- fireEvent.click(screen.getByText('Schedule'));
58
- });
59
- const newStartDate = '2020/03/12';
60
- const newStartTime = '12:03';
61
- const newEndsDate = '2030/03/12';
62
- const newEndsTime = '17:34';
63
- const startsDateField = screen.getByLabelText('starts at datepicker');
64
- const endsDateField = screen.getByLabelText('ends datepicker');
65
-
66
- const startsTimeField = screen.getByLabelText('starts at timepicker');
67
- const endsTimeField = screen.getByLabelText('ends timepicker');
68
-
69
- const staticQuery = screen.getByLabelText('Static query');
70
- const dynamicQuery = screen.getByLabelText('Dynamic query');
71
- const purpose = screen.getByLabelText('purpose');
72
- const newPurposeLabel = 'some fun text';
73
- expect(staticQuery.checked).toBeTruthy();
74
- await act(async () => {
75
- await fireEvent.change(startsDateField, {
76
- target: { value: newStartDate },
77
- });
78
- await fireEvent.change(startsTimeField, {
79
- target: { value: newStartTime },
80
- });
81
- await fireEvent.change(purpose, {
82
- target: { value: newPurposeLabel },
83
- });
84
- await fireEvent.change(endsDateField, { target: { value: newEndsDate } });
85
- await fireEvent.change(endsTimeField, { target: { value: newEndsTime } });
86
-
87
- await fireEvent.click(dynamicQuery);
88
- jest.runAllTimers(); // to handle pf4 date picker popover useTimer
57
+ act(() => {
58
+ fireEvent.click(screen.getByText('Type of execution'));
89
59
  });
90
- await act(async () => {
91
- fireEvent.click(screen.getByText('Category and Template'));
92
- });
93
- expect(screen.getAllByText('Category and Template')).toHaveLength(3);
60
+ expect(screen.getAllByText('Future execution')).toHaveLength(1);
61
+ expect(screen.getAllByText('Recurring execution')).toHaveLength(1);
94
62
 
95
- await act(async () => {
96
- fireEvent.click(screen.getByText('Schedule'));
97
- jest.runAllTimers();
63
+ act(() => {
64
+ fireEvent.click(screen.getByText('Future execution'));
98
65
  });
99
- expect(startsDateField.value).toBe(newStartDate);
100
- expect(startsTimeField.value).toBe(newStartTime);
101
- expect(endsDateField.value).toBe(newEndsDate);
102
- expect(endsTimeField.value).toBe(newEndsTime);
103
- expect(dynamicQuery.checked).toBeTruthy();
104
- expect(purpose.value).toBe(newPurposeLabel);
66
+ expect(screen.getAllByText('Future execution')).toHaveLength(2);
67
+ expect(screen.getAllByText('Recurring execution')).toHaveLength(1);
68
+ act(() => {
69
+ fireEvent.click(screen.getByText('Recurring execution'));
70
+ });
71
+ expect(screen.getAllByText('Future execution')).toHaveLength(1);
72
+ expect(screen.getAllByText('Recurring execution')).toHaveLength(2);
105
73
  });
106
- it('should remove start date time on execute now', async () => {
74
+ it('Future execution', async () => {
107
75
  render(
108
76
  <Provider store={store}>
109
77
  <JobWizard />
110
78
  </Provider>
111
79
  );
112
- await act(async () => {
113
- fireEvent.click(screen.getByText('Schedule'));
80
+ act(() => {
81
+ fireEvent.click(screen.getByText('Type of execution'));
114
82
  });
115
- const executeNow = screen.getByLabelText('Execute now');
116
- const executeFuture = screen.getByLabelText(
117
- 'Schedule for future execution'
118
- );
119
- expect(executeNow.checked).toBeTruthy();
120
- const newStartDate = '2020/03/12';
121
- const newStartTime = '12:03';
122
- const startsDateField = screen.getByLabelText('starts at datepicker');
123
- const startsTimeField = screen.getByLabelText('starts at timepicker');
83
+ act(() => {
84
+ fireEvent.click(screen.getByText('Future execution'));
85
+ });
86
+ act(() => {
87
+ fireEvent.click(screen.getByRole('button', { name: 'Future execution' }));
88
+ jest.runAllTimers(); // to handle pf4 date picker popover useTimer
89
+ });
90
+
91
+ const newStartAtDate = '2030/03/12';
92
+ const newStartBeforeDate = '2030/05/22';
93
+ const newStartAtTime = '12:46';
94
+ const newStartBeforeTime = '14:27';
95
+ const startsAtDateField = () =>
96
+ screen.getByLabelText('starts at datepicker');
97
+ const startsAtTimeField = () =>
98
+ screen.getByLabelText('starts at timepicker');
99
+
100
+ const startsBeforeDateField = () =>
101
+ screen.getByLabelText('starts before datepicker');
102
+ const startsBeforeTimeField = () =>
103
+ screen.getByLabelText('starts before timepicker');
104
+
124
105
  await act(async () => {
125
- await fireEvent.change(startsDateField, {
126
- target: { value: newStartDate },
106
+ await fireEvent.change(startsAtDateField(), {
107
+ target: { value: newStartAtDate },
127
108
  });
128
- await fireEvent.change(startsTimeField, {
129
- target: { value: newStartTime },
109
+ fireEvent.change(startsAtTimeField(), {
110
+ target: { value: newStartAtTime },
111
+ });
112
+ await fireEvent.change(startsBeforeDateField(), {
113
+ target: { value: newStartBeforeDate },
114
+ });
115
+ fireEvent.change(startsBeforeTimeField(), {
116
+ target: { value: newStartBeforeTime },
117
+ });
118
+ jest.runOnlyPendingTimers();
119
+ });
120
+
121
+ act(() => {
122
+ fireEvent.click(screen.getByText('Category and Template'));
123
+ });
124
+ act(() => {
125
+ fireEvent.click(screen.getByRole('button', { name: 'Future execution' }));
126
+ jest.runAllTimers(); // to handle pf4 date picker popover useTimer
127
+ });
128
+ expect(startsAtDateField().value).toBe(newStartAtDate);
129
+ expect(startsAtTimeField().value).toBe(newStartAtTime);
130
+ expect(startsBeforeDateField().value).toBe(newStartBeforeDate);
131
+ expect(startsBeforeTimeField().value).toBe(newStartBeforeTime);
132
+
133
+ expect(
134
+ screen.queryAllByText(
135
+ "'Starts before' date must be after 'Starts at' date"
136
+ )
137
+ ).toHaveLength(0);
138
+ await act(async () => {
139
+ await fireEvent.change(startsBeforeDateField(), {
140
+ target: { value: '2030/03/11' },
130
141
  });
142
+ await fireEvent.click(startsBeforeTimeField());
131
143
  await jest.runOnlyPendingTimers();
132
144
  });
133
- expect(startsDateField.value).toBe(newStartDate);
134
- expect(startsTimeField.value).toBe(newStartTime);
135
- expect(executeFuture.checked).toBeTruthy();
145
+ expect(startsBeforeDateField().value).toBe('2030/03/11');
146
+ expect(
147
+ screen.getAllByText("'Starts before' date must be after 'Starts at' date")
148
+ ).toHaveLength(1);
149
+
150
+ expect(
151
+ screen.queryAllByText("'Starts before' date must in the future")
152
+ ).toHaveLength(0);
136
153
  await act(async () => {
137
- await fireEvent.click(executeNow);
138
- jest.runAllTimers();
154
+ await fireEvent.change(startsBeforeDateField(), {
155
+ target: { value: '2019/03/11' },
156
+ });
157
+ await fireEvent.change(startsAtDateField(), {
158
+ target: { value: '' },
159
+ });
160
+ jest.runOnlyPendingTimers();
139
161
  });
140
- expect(executeNow.checked).toBeTruthy();
141
- expect(startsDateField.value).toBe('');
142
- expect(startsTimeField.value).toBe('');
162
+
163
+ expect(startsBeforeDateField().value).toBe('2019/03/11');
164
+ expect(
165
+ screen.getAllByText("'Starts before' date must in the future")
166
+ ).toHaveLength(1);
143
167
  });
144
168
 
145
- it('should disable end date on never ends', async () => {
169
+ it('Recurring execution - date pickers', async () => {
146
170
  render(
147
171
  <Provider store={store}>
148
172
  <JobWizard />
149
173
  </Provider>
150
174
  );
151
- await act(async () => {
152
- await fireEvent.click(screen.getByText('Schedule'));
153
- jest.runAllTimers();
175
+ act(() => {
176
+ fireEvent.click(screen.getByText('Type of execution'));
177
+ });
178
+ act(() => {
179
+ fireEvent.click(screen.getByText('Recurring execution'));
180
+ });
181
+ act(() => {
182
+ fireEvent.click(
183
+ screen.getByRole('button', { name: 'Recurring execution' })
184
+ );
185
+ jest.runAllTimers(); // to handle pf4 date picker popover useTimer
154
186
  });
155
- const neverEnds = screen.getByLabelText('Never ends');
156
- expect(neverEnds.checked).toBeFalsy();
157
187
 
158
- const endsDateField = screen.getByLabelText('ends datepicker');
159
- const endsTimeField = screen.getByLabelText('ends timepicker');
160
- fireEvent.click(
161
- screen.getByLabelText('Does not repeat', { selector: 'button' })
162
- );
188
+ const newStartAtDate = '2030/03/12';
189
+ const newStartAtTime = '12:46';
190
+ const startsAtDateField = () =>
191
+ screen.getByLabelText('starts at datepicker');
192
+ const startsAtTimeField = () =>
193
+ screen.getByLabelText('starts at timepicker');
194
+
195
+ const endsAtDateField = () => screen.getByLabelText('ends on datepicker');
196
+ const endsAtTimeField = () => screen.getByLabelText('ends on timepicker');
197
+
198
+ expect(startsAtDateField().disabled).toBeTruthy();
199
+ act(() => {
200
+ fireEvent.click(screen.getAllByText('At')[0]);
201
+ });
202
+ expect(startsAtDateField().disabled).toBeFalsy();
163
203
  await act(async () => {
164
- fireEvent.click(screen.getByText('Cronline'));
204
+ await fireEvent.change(startsAtDateField(), {
205
+ target: { value: newStartAtDate },
206
+ });
207
+ fireEvent.change(startsAtTimeField(), {
208
+ target: { value: newStartAtTime },
209
+ });
210
+ jest.runOnlyPendingTimers();
211
+ });
212
+
213
+ expect(endsAtDateField().disabled).toBeTruthy();
214
+ act(() => {
215
+ fireEvent.click(screen.getByText('On'));
165
216
  });
166
- expect(endsDateField.disabled).toBeFalsy();
167
- expect(endsTimeField.disabled).toBeFalsy();
217
+ expect(endsAtDateField().disabled).toBeFalsy();
168
218
  await act(async () => {
169
- fireEvent.click(neverEnds);
219
+ await fireEvent.change(endsAtDateField(), {
220
+ target: { value: newStartAtDate },
221
+ });
222
+ fireEvent.change(endsAtTimeField(), {
223
+ target: { value: newStartAtTime },
224
+ });
225
+ jest.runOnlyPendingTimers();
170
226
  });
171
- expect(neverEnds.checked).toBeTruthy();
172
- expect(endsDateField.disabled).toBeTruthy();
173
- expect(endsTimeField.disabled).toBeTruthy();
174
- });
175
227
 
176
- it('should change between repeat on states', async () => {
228
+ act(() => {
229
+ fireEvent.click(screen.getByText('Category and Template'));
230
+ });
231
+ act(() => {
232
+ fireEvent.click(
233
+ screen.getByRole('button', { name: 'Recurring execution' })
234
+ );
235
+ jest.runAllTimers(); // to handle pf4 date picker popover useTimer
236
+ });
237
+ expect(startsAtDateField().value).toBe(newStartAtDate);
238
+ expect(startsAtTimeField().value).toBe(newStartAtTime);
239
+ expect(endsAtDateField().value).toBe(newStartAtDate);
240
+ expect(endsAtTimeField().value).toBe(newStartAtTime);
241
+
242
+ act(() => {
243
+ fireEvent.click(screen.getByText('Now'));
244
+ fireEvent.click(screen.getByText('After'));
245
+ });
246
+ expect(startsAtDateField().disabled).toBeTruthy();
247
+ expect(endsAtDateField().disabled).toBeTruthy();
248
+ expect(startsAtDateField().value).toBe('');
249
+ expect(startsAtTimeField().value).toBe('');
250
+ expect(endsAtDateField().value).toBe('');
251
+ expect(endsAtTimeField().value).toBe('');
252
+ });
253
+ it('Recurring execution - repeat', async () => {
177
254
  render(
178
255
  <Provider store={store}>
179
256
  <JobWizard />
180
257
  </Provider>
181
258
  );
182
- await act(async () => {
183
- fireEvent.click(screen.getByText('Schedule'));
184
- jest.runAllTimers(); // to handle pf4 date picker popover useTimer
259
+ act(() => {
260
+ fireEvent.click(screen.getByText('Type of execution'));
185
261
  });
186
- expect(
187
- screen.getByPlaceholderText('Repeat N times').hasAttribute('disabled')
188
- ).toBeTruthy();
189
- expect(screen.getByText('Review details').disabled).toBeFalsy();
190
- await act(async () => {
262
+ act(() => {
263
+ fireEvent.click(screen.getByText('Recurring execution'));
264
+ });
265
+ act(() => {
191
266
  fireEvent.click(
192
- screen.getByLabelText('Does not repeat', { selector: 'button' })
267
+ screen.getByRole('button', { name: 'Recurring execution' })
193
268
  );
269
+ jest.runAllTimers(); // to handle pf4 date picker popover useTimer
194
270
  });
195
-
196
271
  await act(async () => {
197
- fireEvent.click(screen.getByText('Cronline'));
272
+ fireEvent.click(screen.getByLabelText('Daily', { selector: 'button' }));
198
273
  });
199
- expect(screen.getByText('Review details').disabled).toBeTruthy();
200
- const newRepeatTimes = '3';
201
- const repeatNTimes = screen.getByPlaceholderText('Repeat N times');
202
- expect(repeatNTimes.value).toBe('');
203
274
  await act(async () => {
204
- fireEvent.change(repeatNTimes, {
205
- target: { value: newRepeatTimes },
206
- });
275
+ fireEvent.click(screen.getByText('Cronline'));
207
276
  });
208
- expect(repeatNTimes.value).toBe(newRepeatTimes);
209
-
210
277
  const newCronline = '1 2';
211
278
  const cronline = screen.getByLabelText('cronline');
212
279
  expect(cronline.value).toBe('');
@@ -224,11 +291,12 @@ describe('Schedule', () => {
224
291
  expect(screen.getAllByText('Category and Template')).toHaveLength(3);
225
292
 
226
293
  await act(async () => {
227
- fireEvent.click(screen.getByText('Schedule'));
294
+ fireEvent.click(
295
+ screen.getByRole('button', { name: 'Recurring execution' })
296
+ );
228
297
  jest.runAllTimers();
229
298
  });
230
- expect(screen.queryAllByText('Schedule')).toHaveLength(3);
231
- expect(repeatNTimes.value).toBe(newRepeatTimes);
299
+ expect(screen.queryAllByText('Recurring execution')).toHaveLength(3);
232
300
  expect(cronline.value).toBe(newCronline);
233
301
 
234
302
  fireEvent.click(screen.getByText('Cronline'));
@@ -244,7 +312,6 @@ describe('Schedule', () => {
244
312
  fireEvent.change(days, {
245
313
  target: { value: newDays },
246
314
  });
247
- fireEvent.click(repeatNTimes);
248
315
  });
249
316
  expect(days.value).toBe(newDays);
250
317
 
@@ -295,12 +362,12 @@ describe('Schedule', () => {
295
362
 
296
363
  expect(screen.getByText('Review details').disabled).toBeFalsy();
297
364
  fireEvent.click(screen.getByText('Weekly'));
298
- await act(async () => {
365
+ act(() => {
299
366
  fireEvent.click(screen.getByText('Daily'));
300
367
  });
301
368
 
302
369
  expect(screen.getByText('Review details').disabled).toBeFalsy();
303
- await act(async () => {
370
+ act(() => {
304
371
  fireEvent.change(at(), {
305
372
  target: { value: '' },
306
373
  });
@@ -308,7 +375,7 @@ describe('Schedule', () => {
308
375
  expect(screen.getByText('Review details').disabled).toBeTruthy();
309
376
  const newAtDaily = '17:07';
310
377
  expect(at().value).toBe('');
311
- await act(async () => {
378
+ act(() => {
312
379
  fireEvent.change(at(), {
313
380
  target: { value: newAtDaily },
314
381
  });
@@ -317,86 +384,39 @@ describe('Schedule', () => {
317
384
  expect(screen.getByText('Review details').disabled).toBeFalsy();
318
385
 
319
386
  fireEvent.click(screen.getByText('Daily'));
320
- await act(async () => {
387
+ act(() => {
321
388
  fireEvent.click(screen.getByText('Hourly'));
322
389
  });
323
390
 
324
- expect(screen.getByText('Review details').disabled).toBeTruthy();
325
- const newMinutes = '6';
326
- const atHourly = screen.getByLabelText('repeat-at-minute-typeahead');
327
- expect(atHourly.value).toBe('');
328
- await act(async () => {
329
- fireEvent.click(screen.getByLabelText('select minute toggle'));
330
- });
331
- await act(async () => {
332
- fireEvent.click(screen.getByText(newMinutes));
333
- });
334
391
  expect(screen.getByText('Review details').disabled).toBeFalsy();
335
- expect(atHourly.value).toBe(newMinutes);
336
- });
337
- it('should show invalid error on start date after end', async () => {
338
- render(
339
- <Provider store={store}>
340
- <JobWizard />
341
- </Provider>
342
- );
343
- await act(async () => {
344
- await fireEvent.click(screen.getByText('Schedule'));
345
- jest.runAllTimers();
392
+ const newMinutes = '6';
393
+ const atHourly = () => screen.getByLabelText('repeat-at-minute-typeahead');
394
+ expect(atHourly().value).toBe('0');
395
+ act(() => {
396
+ fireEvent.change(atHourly(), {
397
+ target: { value: '62' },
398
+ });
346
399
  });
347
- const neverEnds = screen.getByLabelText('Never ends');
348
- expect(neverEnds.checked).toBeFalsy();
349
-
350
- const startsDateField = screen.getByLabelText('starts at datepicker');
351
- const endsDateField = screen.getByLabelText('ends datepicker');
352
-
353
- expect(
354
- screen.queryAllByText('End time needs to be after start time')
355
- ).toHaveLength(0);
356
- expect(screen.getByText('Review details').disabled).toBeFalsy();
357
400
  await act(async () => {
358
- await fireEvent.change(startsDateField, {
359
- target: { value: '2020/10/15' },
360
- });
361
- await fireEvent.change(endsDateField, {
362
- target: { value: '2020/10/14' },
363
- });
364
- await jest.runOnlyPendingTimers();
401
+ await fireEvent.click(screen.getByText('Create "62"'));
365
402
  });
366
-
403
+ expect(atHourly().value).toBe('0');
367
404
  expect(
368
- screen.queryAllByText('End time needs to be after start time')
405
+ screen.queryAllByText('Minute can only be a number between 0-59')
369
406
  ).toHaveLength(1);
370
407
 
371
- expect(screen.getByText('Review details').disabled).toBeTruthy();
372
- });
373
- it('purpose and ends should be disabled when no reaccurence ', async () => {
374
- render(
375
- <Provider store={store}>
376
- <JobWizard />
377
- </Provider>
378
- );
379
- await act(async () => {
380
- await fireEvent.click(screen.getByText('Schedule'));
381
- jest.runAllTimers();
382
- });
383
-
384
- const endsDateField = screen.getByLabelText('ends datepicker');
385
- const endsTimeField = screen.getByLabelText('ends timepicker');
386
- const purpose = screen.getByLabelText('purpose');
387
- expect(endsDateField.disabled).toBeTruthy();
388
- expect(endsTimeField.disabled).toBeTruthy();
389
- expect(purpose.disabled).toBeTruthy();
390
- await act(async () => {
391
- fireEvent.click(
392
- screen.getByLabelText('Does not repeat', { selector: 'button' })
393
- );
408
+ act(() => {
409
+ fireEvent.change(atHourly(), {
410
+ target: { value: newMinutes },
411
+ });
394
412
  });
395
413
  await act(async () => {
396
- fireEvent.click(screen.getByText('Cronline'));
414
+ await fireEvent.click(screen.getByText(`Create "${newMinutes}"`));
397
415
  });
398
- expect(endsDateField.disabled).toBeFalsy();
399
- expect(endsTimeField.disabled).toBeFalsy();
400
- expect(purpose.disabled).toBeFalsy();
416
+ expect(
417
+ screen.queryAllByText('Minute can only be a number between 0-59')
418
+ ).toHaveLength(0);
419
+ expect(screen.getByText('Review details').disabled).toBeFalsy();
420
+ expect(atHourly().value).toBe(newMinutes);
401
421
  });
402
422
  });