foreman_remote_execution 17.2.0 → 18.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/app/controllers/api/v2/foreign_input_sets_controller.rb +4 -0
- data/app/controllers/job_invocations_controller.rb +16 -1
- data/config/routes.rb +2 -1
- data/db/seeds.d/60-ssh_proxy_feature.rb +2 -2
- data/db/seeds.d/90-bookmarks.rb +1 -1
- data/db/seeds.d/95-mail_notifications.rb +1 -1
- data/lib/foreman_remote_execution/plugin.rb +2 -2
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/functional/job_invocations_controller_test.rb +84 -0
- data/webpack/JobInvocationDetail/JobInvocationConstants.js +10 -2
- data/webpack/JobInvocationDetail/JobInvocationHostTable.js +8 -1
- data/webpack/JobInvocationDetail/JobInvocationToolbarButtons.js +6 -78
- data/webpack/JobInvocationDetail/__tests__/JobInvocationHostTablePolling.test.js +113 -7
- data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +4 -39
- data/webpack/JobInvocationDetail/__tests__/areAllHostsTerminal.test.js +40 -0
- data/webpack/JobInvocationDetail/__tests__/fixtures.js +0 -8
- data/webpack/JobWizard/Footer.js +16 -13
- data/webpack/JobWizard/__tests__/Footer.test.js +64 -0
- data/webpack/JobWizard/__tests__/integration.test.js +98 -53
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +191 -212
- data/webpack/react_app/components/TargetingHosts/__tests__/HostItem.test.js +73 -3
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js +69 -36
- metadata +5 -5
- data/webpack/JobWizard/__tests__/__snapshots__/integration.test.js.snap +0 -51
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostItem.test.js.snap +0 -31
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/* eslint-disable max-lines */
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Provider } from 'react-redux';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import { screen, render, act, fireEvent } from '@testing-library/react';
|
|
5
|
+
import userEvent from '@testing-library/user-event';
|
|
6
|
+
import '@testing-library/jest-dom';
|
|
6
7
|
import { MockedProvider } from '@apollo/client/testing';
|
|
7
8
|
import * as api from 'foremanReact/redux/API';
|
|
8
9
|
import { JobWizard } from '../../../JobWizard';
|
|
@@ -20,11 +21,55 @@ import { WIZARD_TITLES } from '../../../JobWizardConstants';
|
|
|
20
21
|
const lodash = require('lodash');
|
|
21
22
|
|
|
22
23
|
lodash.debounce = fn => fn;
|
|
24
|
+
|
|
23
25
|
const store = testSetup(selectors, api);
|
|
24
26
|
mockApi(api);
|
|
25
27
|
|
|
26
28
|
jest.useFakeTimers();
|
|
27
29
|
|
|
30
|
+
const clickOptions = { skipHover: true };
|
|
31
|
+
|
|
32
|
+
const wizardStepButton = title =>
|
|
33
|
+
screen.getByText(title, { selector: 'button' });
|
|
34
|
+
|
|
35
|
+
const clickWizardStep = async title => {
|
|
36
|
+
await act(async () => {
|
|
37
|
+
fireEvent.click(wizardStepButton(title));
|
|
38
|
+
jest.advanceTimersByTime(1000);
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const typeIntoField = async (field, value) => {
|
|
43
|
+
await act(async () => {
|
|
44
|
+
await userEvent.click(field, {}, clickOptions);
|
|
45
|
+
await userEvent.clear(field);
|
|
46
|
+
userEvent.paste(field, value);
|
|
47
|
+
jest.advanceTimersByTime(1000);
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const renderJobWizard = ({ customStore = store, withGql = true } = {}) => {
|
|
52
|
+
const wizard = (
|
|
53
|
+
<Provider store={customStore}>
|
|
54
|
+
<JobWizard />
|
|
55
|
+
</Provider>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (withGql) {
|
|
59
|
+
return render(
|
|
60
|
+
<MockedProvider mocks={gqlMock} addTypename={false}>
|
|
61
|
+
{wizard}
|
|
62
|
+
</MockedProvider>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return render(wizard);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const goToAdvancedStep = async () => {
|
|
70
|
+
await clickWizardStep(WIZARD_TITLES.advanced);
|
|
71
|
+
};
|
|
72
|
+
|
|
28
73
|
describe('AdvancedFields', () => {
|
|
29
74
|
beforeEach(() => {
|
|
30
75
|
jest.spyOn(selectors, 'selectRouterSearch');
|
|
@@ -32,87 +77,45 @@ describe('AdvancedFields', () => {
|
|
|
32
77
|
'host_ids[]': ['105', '37'],
|
|
33
78
|
}));
|
|
34
79
|
});
|
|
80
|
+
|
|
35
81
|
afterEach(() => {
|
|
36
82
|
selectors.selectRouterSearch.mockRestore();
|
|
37
83
|
});
|
|
38
|
-
it('should save data between steps for advanced fields', async () => {
|
|
39
|
-
const wrapper = mount(
|
|
40
|
-
<MockedProvider mocks={gqlMock} addTypename={false}>
|
|
41
|
-
<Provider store={store}>
|
|
42
|
-
<JobWizard />
|
|
43
|
-
</Provider>
|
|
44
|
-
</MockedProvider>
|
|
45
|
-
);
|
|
46
|
-
// setup
|
|
47
|
-
wrapper
|
|
48
|
-
.find('.pf-v5-c-button.pf-v5-c-select__toggle-button')
|
|
49
|
-
.simulate('click');
|
|
50
|
-
wrapper
|
|
51
|
-
.find('.pf-v5-c-select__menu-item')
|
|
52
|
-
.first()
|
|
53
|
-
.simulate('click');
|
|
54
|
-
|
|
55
|
-
// test
|
|
56
|
-
expect(
|
|
57
|
-
wrapper.find('.pf-v5-c-wizard__nav-link.pf-m-disabled')
|
|
58
|
-
).toHaveLength(0);
|
|
59
|
-
wrapper
|
|
60
|
-
.find('.pf-v5-c-wizard__nav-link')
|
|
61
|
-
.at(2)
|
|
62
|
-
.simulate('click'); // Advanced step
|
|
63
84
|
|
|
64
|
-
|
|
65
|
-
|
|
85
|
+
it('preserves advanced field values when navigating between wizard steps', async () => {
|
|
86
|
+
renderJobWizard();
|
|
87
|
+
await goToAdvancedStep();
|
|
88
|
+
|
|
89
|
+
const effectiveUserInput = screen.getByLabelText('effective user', {
|
|
90
|
+
selector: 'input',
|
|
91
|
+
});
|
|
92
|
+
const advancedTemplateInput = screen.getByLabelText('adv plain hidden', {
|
|
93
|
+
selector: 'textarea',
|
|
66
94
|
});
|
|
67
|
-
const
|
|
68
|
-
const advancedTemplateInput = () =>
|
|
69
|
-
wrapper.find('.pf-v5-c-form__group-control textarea');
|
|
70
|
-
const effectiveUesrValue = 'effective user new value';
|
|
95
|
+
const effectiveUserValue = 'effective user new value';
|
|
71
96
|
const advancedTemplateInputValue = 'advanced input new value';
|
|
72
|
-
effectiveUserInput().getDOMNode().value = effectiveUesrValue;
|
|
73
|
-
|
|
74
|
-
effectiveUserInput().simulate('change');
|
|
75
|
-
wrapper.update();
|
|
76
|
-
advancedTemplateInput().getDOMNode().value = advancedTemplateInputValue;
|
|
77
|
-
advancedTemplateInput().simulate('change');
|
|
78
|
-
expect(effectiveUserInput().prop('value')).toEqual(effectiveUesrValue);
|
|
79
|
-
expect(advancedTemplateInput().prop('value')).toEqual(
|
|
80
|
-
advancedTemplateInputValue
|
|
81
|
-
);
|
|
82
97
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
.at(1)
|
|
86
|
-
.simulate('click');
|
|
98
|
+
await typeIntoField(effectiveUserInput, effectiveUserValue);
|
|
99
|
+
await typeIntoField(advancedTemplateInput, advancedTemplateInputValue);
|
|
87
100
|
|
|
88
|
-
expect(
|
|
89
|
-
|
|
90
|
-
).toEqual('Target hosts and inputs');
|
|
91
|
-
wrapper
|
|
92
|
-
.find('.pf-v5-c-wizard__nav-link')
|
|
93
|
-
.at(2)
|
|
94
|
-
.simulate('click'); // Advanced step
|
|
101
|
+
expect(effectiveUserInput).toHaveValue(effectiveUserValue);
|
|
102
|
+
expect(advancedTemplateInput).toHaveValue(advancedTemplateInputValue);
|
|
95
103
|
|
|
96
|
-
await
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
expect(advancedTemplateInput().prop('value')).toEqual(
|
|
101
|
-
advancedTemplateInputValue
|
|
104
|
+
await clickWizardStep(WIZARD_TITLES.hostsAndInputs);
|
|
105
|
+
expect(wizardStepButton(WIZARD_TITLES.hostsAndInputs)).toHaveAttribute(
|
|
106
|
+
'aria-current',
|
|
107
|
+
'step'
|
|
102
108
|
);
|
|
109
|
+
|
|
110
|
+
await goToAdvancedStep();
|
|
111
|
+
|
|
112
|
+
expect(effectiveUserInput).toHaveValue(effectiveUserValue);
|
|
113
|
+
expect(advancedTemplateInput).toHaveValue(advancedTemplateInputValue);
|
|
103
114
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
<JobWizard />
|
|
109
|
-
</Provider>
|
|
110
|
-
</MockedProvider>
|
|
111
|
-
);
|
|
112
|
-
await act(async () => {
|
|
113
|
-
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
|
114
|
-
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
|
115
|
-
});
|
|
115
|
+
|
|
116
|
+
it('preserves template field values when navigating between wizard steps', async () => {
|
|
117
|
+
renderJobWizard();
|
|
118
|
+
await goToAdvancedStep();
|
|
116
119
|
|
|
117
120
|
const searchValue = 'search test';
|
|
118
121
|
const textValue = 'I am a text';
|
|
@@ -131,134 +134,126 @@ describe('AdvancedFields', () => {
|
|
|
131
134
|
|
|
132
135
|
fireEvent.click(selectField);
|
|
133
136
|
await act(async () => {
|
|
134
|
-
await
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
fireEvent.change(timeField, {
|
|
149
|
-
target: { value: timeValue },
|
|
150
|
-
});
|
|
151
|
-
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
|
152
|
-
});
|
|
153
|
-
expect(
|
|
154
|
-
screen.getByLabelText('adv plain hidden', {
|
|
155
|
-
selector: 'textarea',
|
|
156
|
-
}).value
|
|
157
|
-
).toBe(textValue);
|
|
158
|
-
expect(searchField.value).toBe(searchValue);
|
|
159
|
-
expect(screen.getByLabelText('adv date datepicker').value).toBe(dateValue);
|
|
160
|
-
expect(timeField.value).toBe(timeValue);
|
|
161
|
-
await act(async () => {
|
|
162
|
-
fireEvent.click(screen.getByText(WIZARD_TITLES.categoryAndTemplate));
|
|
137
|
+
await userEvent.click(screen.getByText('option 2'), {}, clickOptions);
|
|
138
|
+
await userEvent.click(
|
|
139
|
+
screen.getAllByText(WIZARD_TITLES.advanced)[0],
|
|
140
|
+
{},
|
|
141
|
+
clickOptions
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
await userEvent.click(resourceSelectField, {}, clickOptions);
|
|
145
|
+
await userEvent.click(screen.getByText('resource2'), {}, clickOptions);
|
|
146
|
+
await typeIntoField(textField, textValue);
|
|
147
|
+
await typeIntoField(searchField, searchValue);
|
|
148
|
+
fireEvent.change(dateField, { target: { value: dateValue } });
|
|
149
|
+
fireEvent.change(timeField, { target: { value: timeValue } });
|
|
150
|
+
jest.advanceTimersByTime(1000);
|
|
163
151
|
});
|
|
152
|
+
|
|
153
|
+
expect(textField).toHaveValue(textValue);
|
|
154
|
+
expect(searchField).toHaveValue(searchValue);
|
|
155
|
+
expect(dateField).toHaveValue(dateValue);
|
|
156
|
+
expect(timeField).toHaveValue(timeValue);
|
|
157
|
+
|
|
158
|
+
await clickWizardStep(WIZARD_TITLES.categoryAndTemplate);
|
|
164
159
|
expect(screen.getAllByText(WIZARD_TITLES.categoryAndTemplate)).toHaveLength(
|
|
165
160
|
3
|
|
166
161
|
);
|
|
167
162
|
|
|
168
|
-
await
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
expect(
|
|
173
|
-
expect(
|
|
174
|
-
expect(
|
|
175
|
-
expect(
|
|
176
|
-
expect(screen.
|
|
177
|
-
expect(screen.
|
|
178
|
-
expect(screen.queryAllByDisplayValue('resource1')).toHaveLength(0);
|
|
179
|
-
expect(screen.queryAllByDisplayValue('resource2')).toHaveLength(1);
|
|
163
|
+
await goToAdvancedStep();
|
|
164
|
+
|
|
165
|
+
expect(textField).toHaveValue(textValue);
|
|
166
|
+
expect(searchField).toHaveValue(searchValue);
|
|
167
|
+
expect(dateField).toHaveValue(dateValue);
|
|
168
|
+
expect(timeField).toHaveValue(timeValue);
|
|
169
|
+
expect(screen.queryByText('option 1')).not.toBeInTheDocument();
|
|
170
|
+
expect(screen.getByText('option 2')).toBeInTheDocument();
|
|
171
|
+
expect(screen.queryByDisplayValue('resource1')).not.toBeInTheDocument();
|
|
172
|
+
expect(screen.getByDisplayValue('resource2')).toBeInTheDocument();
|
|
180
173
|
});
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
<JobWizard />
|
|
186
|
-
</Provider>
|
|
187
|
-
</MockedProvider>
|
|
188
|
-
);
|
|
189
|
-
await act(async () => {
|
|
190
|
-
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
|
191
|
-
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
|
192
|
-
});
|
|
174
|
+
|
|
175
|
+
it('fills default values into advanced fields', async () => {
|
|
176
|
+
renderJobWizard();
|
|
177
|
+
await goToAdvancedStep();
|
|
193
178
|
|
|
194
179
|
expect(
|
|
195
|
-
screen.getByLabelText('ssh user', {
|
|
196
|
-
|
|
197
|
-
}).value
|
|
198
|
-
).toBe('');
|
|
180
|
+
screen.getByLabelText('ssh user', { selector: 'input' })
|
|
181
|
+
).toHaveValue('');
|
|
199
182
|
expect(
|
|
200
|
-
screen.getByLabelText('effective user', {
|
|
201
|
-
|
|
202
|
-
}).value
|
|
203
|
-
).toBe('default effective user');
|
|
183
|
+
screen.getByLabelText('effective user', { selector: 'input' })
|
|
184
|
+
).toHaveValue('default effective user');
|
|
204
185
|
expect(
|
|
205
|
-
screen.getByLabelText('timeout to kill', {
|
|
206
|
-
|
|
207
|
-
}).value
|
|
208
|
-
).toBe('2');
|
|
209
|
-
|
|
186
|
+
screen.getByLabelText('timeout to kill', { selector: 'input' })
|
|
187
|
+
).toHaveValue('2');
|
|
210
188
|
expect(
|
|
211
|
-
screen.getByLabelText('description preview', {
|
|
212
|
-
|
|
213
|
-
}).value
|
|
214
|
-
).toBe(
|
|
189
|
+
screen.getByLabelText('description preview', { selector: 'input' })
|
|
190
|
+
).toHaveValue(
|
|
215
191
|
'template1 with inputs adv plain hidden="Default val" adv plain select="" adv resource select="" adv search="" adv date="" plain hidden="Default val"'
|
|
216
192
|
);
|
|
217
193
|
});
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
194
|
+
|
|
195
|
+
it('renders advanced fields step with expected form fields', async () => {
|
|
196
|
+
renderJobWizard();
|
|
197
|
+
await goToAdvancedStep();
|
|
198
|
+
|
|
199
|
+
expect(
|
|
200
|
+
screen.getByLabelText('adv plain hidden', { selector: 'textarea' })
|
|
201
|
+
).toBeInTheDocument();
|
|
202
|
+
expect(
|
|
203
|
+
screen.getByLabelText('adv plain select toggle')
|
|
204
|
+
).toBeInTheDocument();
|
|
205
|
+
expect(
|
|
206
|
+
screen.getByLabelText('adv resource select toggle')
|
|
207
|
+
).toBeInTheDocument();
|
|
208
|
+
expect(
|
|
209
|
+
screen.getByLabelText('ssh user', { selector: 'input' })
|
|
210
|
+
).toBeInTheDocument();
|
|
211
|
+
expect(
|
|
212
|
+
screen.getByLabelText('effective user', { selector: 'input' })
|
|
213
|
+
).toBeInTheDocument();
|
|
214
|
+
expect(
|
|
215
|
+
screen.getByLabelText('description preview', { selector: 'input' })
|
|
216
|
+
).toBeInTheDocument();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('updates description preview when editing the description template', async () => {
|
|
220
|
+
renderJobWizard({ withGql: false });
|
|
221
|
+
await goToAdvancedStep();
|
|
228
222
|
|
|
229
223
|
const textField = screen.getByLabelText('adv plain hidden', {
|
|
230
224
|
selector: 'textarea',
|
|
231
225
|
});
|
|
232
|
-
await
|
|
233
|
-
|
|
234
|
-
target: { value: 'test command' },
|
|
235
|
-
});
|
|
236
|
-
});
|
|
226
|
+
await typeIntoField(textField, 'test command');
|
|
227
|
+
|
|
237
228
|
const descriptionValue = 'Run %{adv plain hidden} %{wrong command name}';
|
|
238
229
|
|
|
239
230
|
await act(async () => {
|
|
240
|
-
|
|
231
|
+
await userEvent.click(
|
|
232
|
+
screen.getByText('Edit job description template'),
|
|
233
|
+
{},
|
|
234
|
+
clickOptions
|
|
235
|
+
);
|
|
241
236
|
});
|
|
242
237
|
|
|
243
238
|
const editText = screen.getByLabelText('description edit', {
|
|
244
239
|
selector: 'input',
|
|
245
240
|
});
|
|
246
|
-
await
|
|
247
|
-
target: { value: descriptionValue },
|
|
248
|
-
});
|
|
241
|
+
await typeIntoField(editText, descriptionValue);
|
|
249
242
|
await act(async () => {
|
|
250
|
-
|
|
243
|
+
await userEvent.click(
|
|
244
|
+
screen.getByText('Preview job description'),
|
|
245
|
+
{},
|
|
246
|
+
clickOptions
|
|
247
|
+
);
|
|
251
248
|
});
|
|
249
|
+
|
|
252
250
|
expect(
|
|
253
|
-
screen.getByLabelText('description preview', {
|
|
254
|
-
|
|
255
|
-
}).value
|
|
256
|
-
).toBe('Run test command %{wrong command name}');
|
|
251
|
+
screen.getByLabelText('description preview', { selector: 'input' })
|
|
252
|
+
).toHaveValue('Run test command %{wrong command name}');
|
|
257
253
|
});
|
|
258
254
|
|
|
259
|
-
it('
|
|
255
|
+
it('shows template name in description preview when template has no inputs', async () => {
|
|
260
256
|
jest.spyOn(api, 'get');
|
|
261
|
-
|
|
262
257
|
jest.spyOn(selectors, 'selectTemplateInputs');
|
|
263
258
|
jest.spyOn(selectors, 'selectAdvancedTemplateInputs');
|
|
264
259
|
selectors.selectTemplateInputs.mockImplementation(() => []);
|
|
@@ -289,23 +284,20 @@ describe('AdvancedFields', () => {
|
|
|
289
284
|
}
|
|
290
285
|
return { type: 'get', ...action };
|
|
291
286
|
});
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
);
|
|
297
|
-
await act(async () => {
|
|
298
|
-
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
|
299
|
-
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
|
300
|
-
});
|
|
287
|
+
|
|
288
|
+
renderJobWizard({ withGql: false });
|
|
289
|
+
await goToAdvancedStep();
|
|
290
|
+
|
|
301
291
|
expect(
|
|
302
|
-
screen.getByLabelText('description preview', {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
292
|
+
screen.getByLabelText('description preview', { selector: 'input' })
|
|
293
|
+
).toHaveValue('template1');
|
|
294
|
+
|
|
295
|
+
selectors.selectTemplateInputs.mockRestore();
|
|
296
|
+
selectors.selectAdvancedTemplateInputs.mockRestore();
|
|
297
|
+
api.get.mockRestore();
|
|
306
298
|
});
|
|
307
299
|
|
|
308
|
-
it('
|
|
300
|
+
it('uses description_format for description preview', async () => {
|
|
309
301
|
jest.spyOn(api, 'get');
|
|
310
302
|
jest.spyOn(selectors, 'selectTemplateInputs');
|
|
311
303
|
selectors.selectTemplateInputs.mockImplementation(() => [
|
|
@@ -334,7 +326,6 @@ describe('AdvancedFields', () => {
|
|
|
334
326
|
...jobTemplateResponse.job_template,
|
|
335
327
|
description_format: 'Run %{command}',
|
|
336
328
|
},
|
|
337
|
-
|
|
338
329
|
template_inputs: [
|
|
339
330
|
{
|
|
340
331
|
name: 'command',
|
|
@@ -363,46 +354,34 @@ describe('AdvancedFields', () => {
|
|
|
363
354
|
}
|
|
364
355
|
return { type: 'get', ...action };
|
|
365
356
|
});
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
);
|
|
371
|
-
await act(async () => {
|
|
372
|
-
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
|
373
|
-
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
|
374
|
-
});
|
|
357
|
+
|
|
358
|
+
renderJobWizard({ withGql: false });
|
|
359
|
+
await goToAdvancedStep();
|
|
360
|
+
|
|
375
361
|
expect(
|
|
376
|
-
screen.getByLabelText('description preview', {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
362
|
+
screen.getByLabelText('description preview', { selector: 'input' })
|
|
363
|
+
).toHaveValue('Run Default val');
|
|
364
|
+
|
|
365
|
+
selectors.selectTemplateInputs.mockRestore();
|
|
366
|
+
api.get.mockRestore();
|
|
380
367
|
});
|
|
381
368
|
|
|
382
|
-
it('search
|
|
383
|
-
jest.useFakeTimers();
|
|
384
|
-
mockApi(api);
|
|
369
|
+
it('dispatches resource search when typing in resource select', async () => {
|
|
385
370
|
const newStore = testSetup(selectors, api);
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
await act(async () => {
|
|
392
|
-
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
|
393
|
-
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
|
394
|
-
});
|
|
371
|
+
mockApi(api);
|
|
372
|
+
|
|
373
|
+
renderJobWizard({ customStore: newStore, withGql: false });
|
|
374
|
+
await goToAdvancedStep();
|
|
375
|
+
|
|
395
376
|
const resourceSelectField = screen.getByLabelText(
|
|
396
377
|
'adv resource select typeahead input'
|
|
397
378
|
);
|
|
398
379
|
|
|
380
|
+
await typeIntoField(resourceSelectField, 'some search');
|
|
399
381
|
await act(async () => {
|
|
400
|
-
await fireEvent.change(resourceSelectField, {
|
|
401
|
-
target: { value: 'some search' },
|
|
402
|
-
});
|
|
403
|
-
|
|
404
382
|
jest.advanceTimersByTime(10000);
|
|
405
383
|
});
|
|
384
|
+
|
|
406
385
|
const actions = newStore.getActions();
|
|
407
386
|
const resourceSearchAction = actions.filter(
|
|
408
387
|
action => action.key === 'ForemanTasksTask'
|
|
@@ -1,6 +1,76 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
2
5
|
import HostItem from '../components/HostItem';
|
|
3
6
|
import { HostItemFixtures } from './fixtures';
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
jest.unmock('foremanReact/components/common/ActionButtons/ActionButtons');
|
|
9
|
+
|
|
10
|
+
const renderHostItem = props =>
|
|
11
|
+
render(
|
|
12
|
+
<table>
|
|
13
|
+
<tbody>
|
|
14
|
+
<HostItem {...props} />
|
|
15
|
+
</tbody>
|
|
16
|
+
</table>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
describe('HostItem', () => {
|
|
20
|
+
it('renders the host name as a link with the provided URL', () => {
|
|
21
|
+
renderHostItem(HostItemFixtures.renders);
|
|
22
|
+
|
|
23
|
+
expect(screen.getByRole('link', { name: 'Host1' })).toHaveAttribute(
|
|
24
|
+
'href',
|
|
25
|
+
'/host1'
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('renders the host status', () => {
|
|
30
|
+
renderHostItem(HostItemFixtures.renders);
|
|
31
|
+
|
|
32
|
+
expect(screen.getByText('Succeeded')).toBeInTheDocument();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('renders no action buttons when actions are empty', () => {
|
|
36
|
+
renderHostItem(HostItemFixtures.renders);
|
|
37
|
+
|
|
38
|
+
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('renders a disabled link when link is not provided', () => {
|
|
42
|
+
renderHostItem({
|
|
43
|
+
...HostItemFixtures.renders,
|
|
44
|
+
link: '',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(screen.getByRole('link', { name: 'Host1' })).toHaveAttribute(
|
|
48
|
+
'href',
|
|
49
|
+
'#'
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('renders action buttons and calls action on click', async () => {
|
|
54
|
+
const onClick = jest.fn();
|
|
55
|
+
|
|
56
|
+
renderHostItem({
|
|
57
|
+
...HostItemFixtures.renders,
|
|
58
|
+
actions: [{ title: 'View output', action: { onClick } }],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
await userEvent.click(
|
|
62
|
+
screen.getByRole('button', { name: 'View output' })
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
expect(onClick).toHaveBeenCalledTimes(1);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('renders failed status text for error status', () => {
|
|
69
|
+
renderHostItem({
|
|
70
|
+
...HostItemFixtures.renders,
|
|
71
|
+
status: 'error',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(screen.getByText('Failed')).toBeInTheDocument();
|
|
75
|
+
});
|
|
76
|
+
});
|