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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby_ci.yml +2 -2
- data/app/controllers/ui_job_wizard_controller.rb +15 -0
- data/app/helpers/remote_execution_helper.rb +1 -1
- data/app/models/job_invocation.rb +2 -4
- data/app/models/job_invocation_composer.rb +5 -2
- data/app/views/templates/script/package_action.erb +8 -3
- data/config/routes.rb +3 -1
- data/lib/foreman_remote_execution/engine.rb +5 -5
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/functional/api/v2/job_invocations_controller_test.rb +8 -0
- data/test/helpers/remote_execution_helper_test.rb +4 -0
- data/test/unit/job_invocation_report_template_test.rb +1 -1
- data/test/unit/job_invocation_test.rb +1 -2
- data/webpack/JobWizard/JobWizard.js +154 -20
- data/webpack/JobWizard/JobWizard.scss +43 -1
- data/webpack/JobWizard/JobWizardConstants.js +11 -1
- data/webpack/JobWizard/JobWizardPageRerun.js +112 -0
- data/webpack/JobWizard/__tests__/JobWizardPageRerun.test.js +79 -0
- data/webpack/JobWizard/__tests__/fixtures.js +73 -0
- data/webpack/JobWizard/__tests__/integration.test.js +17 -3
- data/webpack/JobWizard/autofill.js +8 -1
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +36 -17
- data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +3 -3
- data/webpack/JobWizard/steps/ReviewDetails/index.js +1 -3
- data/webpack/JobWizard/steps/Schedule/PurposeField.js +1 -3
- data/webpack/JobWizard/steps/Schedule/QueryType.js +33 -40
- data/webpack/JobWizard/steps/Schedule/RepeatHour.js +55 -16
- data/webpack/JobWizard/steps/Schedule/RepeatOn.js +19 -56
- data/webpack/JobWizard/steps/Schedule/RepeatWeek.js +1 -1
- data/webpack/JobWizard/steps/Schedule/ScheduleFuture.js +126 -0
- data/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js +287 -0
- data/webpack/JobWizard/steps/Schedule/ScheduleType.js +88 -20
- data/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +206 -186
- data/webpack/JobWizard/steps/form/DateTimePicker.js +23 -6
- data/webpack/JobWizard/steps/form/Formatter.js +7 -8
- data/webpack/JobWizard/submit.js +8 -3
- data/webpack/Routes/routes.js +8 -2
- data/webpack/__mocks__/foremanReact/common/hooks/API/APIHooks.js +1 -0
- data/webpack/react_app/components/HostKebab/KebabItems.js +0 -1
- data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +0 -5
- data/webpack/react_app/components/RecentJobsCard/RecentJobsTable.js +59 -51
- data/webpack/react_app/extend/Fills.js +4 -4
- metadata +8 -6
- data/webpack/JobWizard/steps/Schedule/StartEndDates.js +0 -106
- data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +0 -32
- 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 = ({
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
27
|
-
|
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('
|
51
|
+
it('sub steps appear', () => {
|
51
52
|
render(
|
52
53
|
<Provider store={store}>
|
53
54
|
<JobWizard />
|
54
55
|
</Provider>
|
55
56
|
);
|
56
|
-
|
57
|
-
fireEvent.click(screen.getByText('
|
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
|
-
|
91
|
-
|
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
|
-
|
96
|
-
fireEvent.click(screen.getByText('
|
97
|
-
jest.runAllTimers();
|
63
|
+
act(() => {
|
64
|
+
fireEvent.click(screen.getByText('Future execution'));
|
98
65
|
});
|
99
|
-
expect(
|
100
|
-
expect(
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
expect(
|
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('
|
74
|
+
it('Future execution', async () => {
|
107
75
|
render(
|
108
76
|
<Provider store={store}>
|
109
77
|
<JobWizard />
|
110
78
|
</Provider>
|
111
79
|
);
|
112
|
-
|
113
|
-
fireEvent.click(screen.getByText('
|
80
|
+
act(() => {
|
81
|
+
fireEvent.click(screen.getByText('Type of execution'));
|
114
82
|
});
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
)
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
const
|
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(
|
126
|
-
target: { value:
|
106
|
+
await fireEvent.change(startsAtDateField(), {
|
107
|
+
target: { value: newStartAtDate },
|
127
108
|
});
|
128
|
-
|
129
|
-
target: { value:
|
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(
|
134
|
-
expect(
|
135
|
-
|
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.
|
138
|
-
|
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
|
-
|
141
|
-
expect(
|
142
|
-
expect(
|
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('
|
169
|
+
it('Recurring execution - date pickers', async () => {
|
146
170
|
render(
|
147
171
|
<Provider store={store}>
|
148
172
|
<JobWizard />
|
149
173
|
</Provider>
|
150
174
|
);
|
151
|
-
|
152
|
-
|
153
|
-
|
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
|
159
|
-
const
|
160
|
-
|
161
|
-
screen.getByLabelText('
|
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.
|
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(
|
167
|
-
expect(endsTimeField.disabled).toBeFalsy();
|
217
|
+
expect(endsAtDateField().disabled).toBeFalsy();
|
168
218
|
await act(async () => {
|
169
|
-
fireEvent.
|
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
|
-
|
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
|
-
|
183
|
-
fireEvent.click(screen.getByText('
|
184
|
-
jest.runAllTimers(); // to handle pf4 date picker popover useTimer
|
259
|
+
act(() => {
|
260
|
+
fireEvent.click(screen.getByText('Type of execution'));
|
185
261
|
});
|
186
|
-
|
187
|
-
screen.
|
188
|
-
)
|
189
|
-
|
190
|
-
await act(async () => {
|
262
|
+
act(() => {
|
263
|
+
fireEvent.click(screen.getByText('Recurring execution'));
|
264
|
+
});
|
265
|
+
act(() => {
|
191
266
|
fireEvent.click(
|
192
|
-
screen.
|
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.
|
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.
|
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(
|
294
|
+
fireEvent.click(
|
295
|
+
screen.getByRole('button', { name: 'Recurring execution' })
|
296
|
+
);
|
228
297
|
jest.runAllTimers();
|
229
298
|
});
|
230
|
-
expect(screen.queryAllByText('
|
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
|
-
|
365
|
+
act(() => {
|
299
366
|
fireEvent.click(screen.getByText('Daily'));
|
300
367
|
});
|
301
368
|
|
302
369
|
expect(screen.getByText('Review details').disabled).toBeFalsy();
|
303
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
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.
|
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('
|
405
|
+
screen.queryAllByText('Minute can only be a number between 0-59')
|
369
406
|
).toHaveLength(1);
|
370
407
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
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(
|
414
|
+
await fireEvent.click(screen.getByText(`Create "${newMinutes}"`));
|
397
415
|
});
|
398
|
-
expect(
|
399
|
-
|
400
|
-
|
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
|
});
|