Skip to content

Commit 9cca4c0

Browse files
committed
Refs #39167 - add tests for job wizard templates
1 parent 0588a71 commit 9cca4c0

File tree

1 file changed

+224
-0
lines changed

1 file changed

+224
-0
lines changed
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
# frozen_string_literal: true
2+
3+
require File.expand_path('../test_plugin_helper', __dir__)
4+
require 'integration_test_helper'
5+
require 'securerandom'
6+
7+
class JobWizardCategoryJsTest < IntegrationTestWithJavascript
8+
WIZARD_INPUT_NAME_BASE = 'wizard_integration_input'
9+
WIZARD_FEATURE_INPUT_NAME_BASE = 'wizard_integration_feature_input'
10+
11+
setup do
12+
unique_suffix = SecureRandom.hex(6)
13+
@wizard_input_name = "#{WIZARD_INPUT_NAME_BASE}_#{unique_suffix}"
14+
@wizard_feature_input_name = "#{WIZARD_FEATURE_INPUT_NAME_BASE}_#{unique_suffix}"
15+
default_template_name = "Integration Default REX Form Template #{unique_suffix}"
16+
feature_template_name = "Integration Feature REX Template #{unique_suffix}"
17+
18+
# Prevent real Dynflow proxy calls in CI while planning jobs.
19+
ProxyAPI::ForemanDynflow::DynflowProxy.any_instance.stubs(:tasks_count).returns(0)
20+
21+
@original_rex_form_template = Setting[:remote_execution_form_job_template]
22+
as_admin do
23+
@default_job_template = FactoryBot.create(
24+
:job_template,
25+
:name => default_template_name,
26+
:job_category => 'Default Form Category'
27+
)
28+
@feature_job_template = FactoryBot.create(
29+
:job_template,
30+
:name => feature_template_name,
31+
:job_category => 'Feature Linked Category'
32+
)
33+
add_plain_template_input!(@default_job_template, :name => @wizard_input_name)
34+
add_plain_template_input!(@feature_job_template, :name => @wizard_feature_input_name)
35+
Setting[:remote_execution_form_job_template] = @default_job_template.name
36+
@remote_execution_feature = FactoryBot.create(
37+
:remote_execution_feature,
38+
:label => 'integration_rex_category_feature',
39+
:name => 'Integration REX Category Feature',
40+
:job_template => @feature_job_template
41+
)
42+
@rex_host = FactoryBot.create(:host, :with_execution)
43+
end
44+
end
45+
46+
teardown do
47+
Setting[:remote_execution_form_job_template] = @original_rex_form_template
48+
end
49+
50+
test 'job wizard shows feature template job category when feature query param is present' do
51+
visit new_job_invocation_path(:feature => @remote_execution_feature.label)
52+
assert_text 'Category and template', :wait => 30
53+
wait_for_ajax
54+
assert_selector(:ouia_component_id, 'job_category', :text => 'Feature Linked Category', :wait => 30)
55+
end
56+
57+
test 'job wizard shows default form category when no feature query param' do
58+
visit new_job_invocation_path
59+
assert_text 'Category and template', :wait => 30
60+
wait_for_ajax
61+
assert_selector(:ouia_component_id, 'job_category', :text => 'Default Form Category', :wait => 30)
62+
end
63+
64+
test 'job wizard prefills template input from inputs query param' do
65+
visit new_job_invocation_path(
66+
:inputs => { @wizard_input_name => 'from_query_string' },
67+
:search => ''
68+
)
69+
go_to_target_hosts_and_inputs_step!
70+
assert_selector "textarea##{@wizard_input_name}", :wait => 30
71+
assert_equal 'from_query_string', find("textarea##{@wizard_input_name}").value
72+
end
73+
74+
test 'job wizard does not prefill template input when inputs query param is omitted' do
75+
visit new_job_invocation_path(:search => '')
76+
go_to_target_hosts_and_inputs_step!
77+
assert_selector "textarea##{@wizard_input_name}", :wait => 30
78+
assert_equal '', find("textarea##{@wizard_input_name}").value
79+
end
80+
81+
test 'job wizard prefills template input when feature and inputs query params are present' do
82+
visit new_job_invocation_path(
83+
:feature => @remote_execution_feature.label,
84+
:inputs => { @wizard_feature_input_name => 'feature_and_inputs' },
85+
:search => ''
86+
)
87+
go_to_target_hosts_and_inputs_step!
88+
assert_selector "textarea##{@wizard_feature_input_name}", :wait => 30
89+
assert_equal 'feature_and_inputs', find("textarea##{@wizard_feature_input_name}").value
90+
end
91+
92+
test 'job wizard run on selected hosts is enabled on review and posts to job invocations API' do
93+
posted_to_job_invocations_create = false
94+
subscriber = ActiveSupport::Notifications.subscribe('start_processing.action_controller') do |_n, _s, _f, _i, payload|
95+
if payload[:controller].to_s.end_with?('JobInvocationsController') && payload[:action].to_s == 'create'
96+
posted_to_job_invocations_create = true
97+
end
98+
end
99+
100+
begin
101+
visit new_job_invocation_path(:search => "id = #{@rex_host.id}")
102+
navigate_job_wizard_to_review_step!
103+
104+
assert_selector(:ouia_component_id, 'run-on-selected-hosts-footer', :wait => 30)
105+
run_on_hosts = find(:ouia_component_id, 'run-on-selected-hosts-footer')
106+
assert_includes [nil, 'false'], run_on_hosts[:'aria-disabled']
107+
assert_text 'Run on selected hosts'
108+
find(:ouia_component_id, 'run-on-selected-hosts-footer').click
109+
wait_for_ajax
110+
assert posted_to_job_invocations_create, 'expected Api::V2::JobInvocationsController#create to run'
111+
assert_match(%r{\A/job_invocations/\d+\z}, page.current_path)
112+
ensure
113+
ActiveSupport::Notifications.unsubscribe(subscriber)
114+
end
115+
end
116+
117+
test 'job wizard create API request sends job_template_id and inputs for default template' do
118+
input_value = 'api_payload_default_template'
119+
job_inv_params = capture_api_job_invocation_params_during do
120+
visit new_job_invocation_path(
121+
:search => "id = #{@rex_host.id}",
122+
:inputs => { @wizard_input_name => input_value }
123+
)
124+
navigate_job_wizard_to_review_step!
125+
find(:ouia_component_id, 'run-on-selected-hosts-footer').click
126+
wait_for_ajax
127+
end
128+
129+
assert job_inv_params, 'expected job_invocation key in POST /api/job_invocations'
130+
assert job_inv_params[:job_template_id].present?, 'expected job_template_id to be present'
131+
assert_equal @default_job_template.id, job_inv_params[:job_template_id].to_i
132+
assert job_inv_params[:feature].blank?
133+
assert_equal input_value, hash_from_params_object(job_inv_params[:inputs])[@wizard_input_name]
134+
job_invocation_id = page.current_path.split('/').last.to_i
135+
assert_equal @default_job_template.job_category, JobInvocation.find(job_invocation_id).job_category, 'expected job category to be the default template category'
136+
end
137+
138+
test 'job wizard create API request sends feature label and inputs without job_template_id' do
139+
input_value = 'api_payload_feature_template'
140+
job_inv_params = capture_api_job_invocation_params_during do
141+
visit new_job_invocation_path(
142+
:feature => @remote_execution_feature.label,
143+
:search => "id = #{@rex_host.id}",
144+
:inputs => { @wizard_feature_input_name => input_value }
145+
)
146+
navigate_job_wizard_to_review_step!
147+
find(:ouia_component_id, 'run-on-selected-hosts-footer').click
148+
wait_for_ajax
149+
end
150+
151+
assert job_inv_params, 'expected job_invocation key in POST /api/job_invocations'
152+
assert_not job_inv_params[:job_template_id].present?
153+
assert_equal @remote_execution_feature.label, job_inv_params[:feature]
154+
assert_equal input_value, hash_from_params_object(job_inv_params[:inputs])[@wizard_feature_input_name]
155+
job_invocation_id = page.current_path.split('/').last.to_i
156+
assert_equal @feature_job_template.job_category, JobInvocation.find(job_invocation_id).job_category, 'expected job category to be the feature template category'
157+
end
158+
159+
private
160+
161+
def capture_api_job_invocation_params_during
162+
captured = nil
163+
subscriber = ActiveSupport::Notifications.subscribe('start_processing.action_controller') do |_n, _s, _f, _i, payload|
164+
next unless payload[:controller].to_s.end_with?('JobInvocationsController') && payload[:action].to_s == 'create'
165+
root = payload[:params]
166+
root = root.to_unsafe_h if root.respond_to?(:to_unsafe_h)
167+
job_inv_params = root[:job_invocation] || root['job_invocation']
168+
next unless job_inv_params
169+
job_inv_params = job_inv_params.to_unsafe_h if job_inv_params.respond_to?(:to_unsafe_h)
170+
captured = job_inv_params.with_indifferent_access
171+
end
172+
begin
173+
yield
174+
ensure
175+
ActiveSupport::Notifications.unsubscribe(subscriber)
176+
end
177+
captured
178+
end
179+
180+
def hash_from_params_object(obj)
181+
return {}.with_indifferent_access if obj.blank?
182+
h = obj.respond_to?(:to_unsafe_h) ? obj.to_unsafe_h : obj.to_h
183+
h.with_indifferent_access
184+
end
185+
186+
def add_plain_template_input!(job_template, name:)
187+
job_template.template_inputs << FactoryBot.build(
188+
:template_input,
189+
:name => name,
190+
:input_type => 'user',
191+
:value_type => 'plain',
192+
:required => false
193+
)
194+
job_template.save!
195+
end
196+
197+
def job_wizard_click_next!
198+
wait_for_ajax
199+
find(:ouia_component_id, 'next-footer').click
200+
wait_for_ajax
201+
end
202+
203+
def go_to_target_hosts_and_inputs_step!
204+
assert_text 'Category and template', :wait => 30
205+
wait_for_ajax
206+
job_wizard_click_next!
207+
assert_text 'Target hosts and inputs', :wait => 30
208+
wait_for_ajax
209+
end
210+
211+
def navigate_job_wizard_to_review_step!
212+
assert_text 'Category and template', :wait => 30
213+
wait_for_ajax
214+
job_wizard_click_next!
215+
assert_text 'Target hosts and inputs', :wait => 30
216+
job_wizard_click_next!
217+
assert_text 'Advanced fields', :wait => 30
218+
job_wizard_click_next!
219+
assert_text 'Immediate execution', :wait => 30
220+
job_wizard_click_next!
221+
assert_text 'Review details', :wait => 30
222+
wait_for_ajax
223+
end
224+
end

0 commit comments

Comments
 (0)