foreman_remote_execution 7.2.2 → 8.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/models/remote_execution_provider.rb +1 -1
- 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/test/unit/remote_execution_provider_test.rb +0 -22
- 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
|
});
|