diff --git a/Gemfile b/Gemfile index d4352ce40..2f0514f39 100644 --- a/Gemfile +++ b/Gemfile @@ -4,7 +4,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '3.3.4' # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" -gem 'rails', '~> 8.0' +gem 'rails', '~> 8.0', '>= 8.0.2.1' # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] gem 'sprockets-rails' @@ -15,11 +15,10 @@ gem 'pg' # Use the Puma web server [https://github.com/puma/puma] gem 'puma' - -gem "importmap-rails", ">= 2.2.0" +gem 'importmap-rails', '>= 2.2.0' # Hotwire"s SPA-like page accelerator [https://turbo.hotwired.dev] -gem "turbo-rails", ">= 2.0.14" +gem 'turbo-rails', '>= 2.0.14' # Hotwire"s modest JavaScript framework [https://stimulus.hotwired.dev] gem 'stimulus-rails' @@ -64,10 +63,6 @@ gem 'omniauth-rails_csrf_protection' gem 'rack-attack' gem 'rack-cors', '>= 3.0.0', require: 'rack/cors' # Use Redis to cache Touchpoints in all envs= -gem 'redis-client' -gem 'redis-namespace' -gem 'sidekiq', '>= 8.0.4' -gem 'json-jwt' gem 'aasm' gem 'acts-as-taggable-on' gem 'json-jwt' @@ -76,7 +71,7 @@ gem 'paper_trail' gem 'redis-client' gem 'redis-namespace' gem 'rolify' -gem 'sidekiq', '>= 6.5.0' +gem 'sidekiq', '>= 8.0.4' group :development, :test do gem 'dotenv' @@ -94,8 +89,8 @@ group :development do gem 'bundler-audit' gem 'listen' gem 'rails-erd' - gem "rubocop-rails", ">= 2.32.0" - gem "rubocop-rspec" + gem 'rubocop-rails', '>= 2.32.0' + gem 'rubocop-rspec' gem 'web-console' end diff --git a/Gemfile.lock b/Gemfile.lock index 2f9c31343..8bf7a073f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -18,29 +18,29 @@ GEM aasm-diagram (0.1.3) aasm (~> 5.0, >= 4.12) ruby-graphviz (~> 1.2) - actioncable (8.0.2) - actionpack (= 8.0.2) - activesupport (= 8.0.2) + actioncable (8.0.2.1) + actionpack (= 8.0.2.1) + activesupport (= 8.0.2.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (8.0.2) - actionpack (= 8.0.2) - activejob (= 8.0.2) - activerecord (= 8.0.2) - activestorage (= 8.0.2) - activesupport (= 8.0.2) + actionmailbox (8.0.2.1) + actionpack (= 8.0.2.1) + activejob (= 8.0.2.1) + activerecord (= 8.0.2.1) + activestorage (= 8.0.2.1) + activesupport (= 8.0.2.1) mail (>= 2.8.0) - actionmailer (8.0.2) - actionpack (= 8.0.2) - actionview (= 8.0.2) - activejob (= 8.0.2) - activesupport (= 8.0.2) + actionmailer (8.0.2.1) + actionpack (= 8.0.2.1) + actionview (= 8.0.2.1) + activejob (= 8.0.2.1) + activesupport (= 8.0.2.1) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (8.0.2) - actionview (= 8.0.2) - activesupport (= 8.0.2) + actionpack (8.0.2.1) + actionview (= 8.0.2.1) + activesupport (= 8.0.2.1) nokogiri (>= 1.8.5) rack (>= 2.2.4) rack-session (>= 1.0.1) @@ -48,15 +48,15 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (8.0.2) - actionpack (= 8.0.2) - activerecord (= 8.0.2) - activestorage (= 8.0.2) - activesupport (= 8.0.2) + actiontext (8.0.2.1) + actionpack (= 8.0.2.1) + activerecord (= 8.0.2.1) + activestorage (= 8.0.2.1) + activesupport (= 8.0.2.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (8.0.2) - activesupport (= 8.0.2) + actionview (8.0.2.1) + activesupport (= 8.0.2.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) @@ -66,22 +66,22 @@ GEM activemodel (>= 4.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (8.0.2) - activesupport (= 8.0.2) + activejob (8.0.2.1) + activesupport (= 8.0.2.1) globalid (>= 0.3.6) - activemodel (8.0.2) - activesupport (= 8.0.2) - activerecord (8.0.2) - activemodel (= 8.0.2) - activesupport (= 8.0.2) + activemodel (8.0.2.1) + activesupport (= 8.0.2.1) + activerecord (8.0.2.1) + activemodel (= 8.0.2.1) + activesupport (= 8.0.2.1) timeout (>= 0.4.0) - activestorage (8.0.2) - actionpack (= 8.0.2) - activejob (= 8.0.2) - activerecord (= 8.0.2) - activesupport (= 8.0.2) + activestorage (8.0.2.1) + actionpack (= 8.0.2.1) + activejob (= 8.0.2.1) + activerecord (= 8.0.2.1) + activesupport (= 8.0.2.1) marcel (~> 1.0) - activesupport (8.0.2) + activesupport (8.0.2.1) base64 benchmark (>= 0.3) bigdecimal @@ -437,20 +437,20 @@ GEM rack (>= 1.3) rackup (2.2.1) rack (>= 3) - rails (8.0.2) - actioncable (= 8.0.2) - actionmailbox (= 8.0.2) - actionmailer (= 8.0.2) - actionpack (= 8.0.2) - actiontext (= 8.0.2) - actionview (= 8.0.2) - activejob (= 8.0.2) - activemodel (= 8.0.2) - activerecord (= 8.0.2) - activestorage (= 8.0.2) - activesupport (= 8.0.2) + rails (8.0.2.1) + actioncable (= 8.0.2.1) + actionmailbox (= 8.0.2.1) + actionmailer (= 8.0.2.1) + actionpack (= 8.0.2.1) + actiontext (= 8.0.2.1) + actionview (= 8.0.2.1) + activejob (= 8.0.2.1) + activemodel (= 8.0.2.1) + activerecord (= 8.0.2.1) + activestorage (= 8.0.2.1) + activesupport (= 8.0.2.1) bundler (>= 1.15.0) - railties (= 8.0.2) + railties (= 8.0.2.1) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -467,9 +467,9 @@ GEM rails-html-sanitizer (1.6.2) loofah (~> 2.21) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - railties (8.0.2) - actionpack (= 8.0.2) - activesupport (= 8.0.2) + railties (8.0.2.1) + actionpack (= 8.0.2.1) + activesupport (= 8.0.2.1) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) @@ -685,8 +685,8 @@ DEPENDENCIES pry puma rack-attack - rack-cors - rails (~> 8.0) + rack-cors (>= 3.0.0) + rails (~> 8.0, >= 8.0.2.1) rails-controller-testing rails-erd redis-client @@ -694,11 +694,11 @@ DEPENDENCIES rolify rspec-rails (>= 8.0.1) rspec_junit_formatter - rubocop-rails + rubocop-rails (>= 2.32.0) rubocop-rspec sassc-rails selenium-webdriver - sidekiq (>= 6.5.0) + sidekiq (>= 8.0.4) simplecov sprockets-rails stimulus-rails diff --git a/app/models/form.rb b/app/models/form.rb index dc1af4ae7..7cd49660f 100644 --- a/app/models/form.rb +++ b/app/models/form.rb @@ -570,27 +570,83 @@ def to_a11_v2_array(start_date: nil, end_date: nil) .order('created_at') return nil if non_flagged_submissions.blank? - answer_02_options = self.questions.where(answer_field: "answer_02").first.question_options.collect(&:value) - answer_03_options = self.questions.where(answer_field: "answer_03").first.question_options.collect(&:value) + answer_02_options = questions.where(answer_field: 'answer_02').first.question_options.collect(&:value) + answer_03_options = questions.where(answer_field: 'answer_03').first.question_options.collect(&:value) non_flagged_submissions.map do |submission| { id: submission.id, answer_01: submission.answer_01, - answer_02_effectiveness: submission.answer_02 && submission.answer_02.split(",").include?("effectiveness") ? 1 :(answer_02_options.include?("effectiveness") ? 0 : 'null'), - answer_02_ease: submission.answer_02 && submission.answer_02.split(",").include?("ease") ? 1 : (answer_02_options.include?("ease") ? 0 : 'null'), - answer_02_efficiency: submission.answer_02 && submission.answer_02.split(",").include?("efficiency") ? 1 : (answer_02_options.include?("efficiency") ? 0 : 'null'), - answer_02_transparency: submission.answer_02 && submission.answer_02.split(",").include?("transparency") ? 1 : (answer_02_options.include?("transparency") ? 0 : 'null'), - answer_02_humanity: submission.answer_02 && submission.answer_02.split(",").include?("humanity") ? 1 : (answer_02_options.include?("humanity") ? 0 : 'null'), - answer_02_employee: submission.answer_02 && submission.answer_02.split(",").include?("employee") ? 1 : (answer_02_options.include?("employee") ? 0 : 'null'), - answer_02_other: submission.answer_02 && submission.answer_02.split(",").include?("other") ? 1 : (answer_02_options.include?("other") ? 0 : 'null'), - answer_03_effectiveness: submission.answer_03 && submission.answer_03.split(",").include?("effectiveness") ? 1 : (answer_03_options.include?("effectiveness") ? 0 : 'null'), - answer_03_ease: submission.answer_03 && submission.answer_03.split(",").include?("ease") ? 1 : (answer_03_options.include?("ease") ? 0 : 'null'), - answer_03_efficiency: submission.answer_03 && submission.answer_03.split(",").include?("efficiency") ? 1 : (answer_03_options.include?("efficiency") ? 0 : 'null'), - answer_03_transparency: submission.answer_03 && submission.answer_03.split(",").include?("transparency") ? 1 : (answer_03_options.include?("transparency") ? 0 : 'null'), - answer_03_humanity: submission.answer_03 && submission.answer_03.split(",").include?("humanity") ? 1 : (answer_03_options.include?("humanity") ? 0 : 'null'), - answer_03_employee: submission.answer_03 && submission.answer_03.split(",").include?("employee") ? 1 : (answer_03_options.include?("employee") ? 0 : 'null'), - answer_03_other: submission.answer_03 && submission.answer_03.split(",").include?("other") ? 1 : (answer_03_options.include?("other") ? 0 : 'null'), + answer_02_effectiveness: if submission.answer_02 && submission.answer_02.split(',').include?('effectiveness') + 1 + else + (answer_02_options.include?('effectiveness') ? 0 : 'null') + end, + answer_02_ease: if submission.answer_02 && submission.answer_02.split(',').include?('ease') + 1 + else + (answer_02_options.include?('ease') ? 0 : 'null') + end, + answer_02_efficiency: if submission.answer_02 && submission.answer_02.split(',').include?('efficiency') + 1 + else + (answer_02_options.include?('efficiency') ? 0 : 'null') + end, + answer_02_transparency: if submission.answer_02 && submission.answer_02.split(',').include?('transparency') + 1 + else + (answer_02_options.include?('transparency') ? 0 : 'null') + end, + answer_02_humanity: if submission.answer_02 && submission.answer_02.split(',').include?('humanity') + 1 + else + (answer_02_options.include?('humanity') ? 0 : 'null') + end, + answer_02_employee: if submission.answer_02 && submission.answer_02.split(',').include?('employee') + 1 + else + (answer_02_options.include?('employee') ? 0 : 'null') + end, + answer_02_other: if submission.answer_02 && submission.answer_02.split(',').include?('other') + 1 + else + (answer_02_options.include?('other') ? 0 : 'null') + end, + answer_03_effectiveness: if submission.answer_03 && submission.answer_03.split(',').include?('effectiveness') + 1 + else + (answer_03_options.include?('effectiveness') ? 0 : 'null') + end, + answer_03_ease: if submission.answer_03 && submission.answer_03.split(',').include?('ease') + 1 + else + (answer_03_options.include?('ease') ? 0 : 'null') + end, + answer_03_efficiency: if submission.answer_03 && submission.answer_03.split(',').include?('efficiency') + 1 + else + (answer_03_options.include?('efficiency') ? 0 : 'null') + end, + answer_03_transparency: if submission.answer_03 && submission.answer_03.split(',').include?('transparency') + 1 + else + (answer_03_options.include?('transparency') ? 0 : 'null') + end, + answer_03_humanity: if submission.answer_03 && submission.answer_03.split(',').include?('humanity') + 1 + else + (answer_03_options.include?('humanity') ? 0 : 'null') + end, + answer_03_employee: if submission.answer_03 && submission.answer_03.split(',').include?('employee') + 1 + else + (answer_03_options.include?('employee') ? 0 : 'null') + end, + answer_03_other: if submission.answer_03 && submission.answer_03.split(',').include?('other') + 1 + else + (answer_03_options.include?('other') ? 0 : 'null') + end, answer_04: submission.answer_04, } end @@ -900,9 +956,7 @@ def ensure_a11_v2_radio_format end def warn_about_not_too_many_questions - if questions.size >= 30 - errors.add(:base, "Touchpoints supports a maximum of 30 questions. There are currently #{questions_count} questions. Fewer questions tend to yield higher response rates.") - end + errors.add(:base, "Touchpoints supports a maximum of 30 questions. There are currently #{questions_count} questions. Fewer questions tend to yield higher response rates.") if questions.size > 20 end def contains_elements?(array, required_elements) diff --git a/spec/features/touchpoints_spec.rb b/spec/features/touchpoints_spec.rb index 31bb0b1af..4f9823446 100644 --- a/spec/features/touchpoints_spec.rb +++ b/spec/features/touchpoints_spec.rb @@ -30,14 +30,14 @@ visit touchpoint_path(two_question_form) end - it "enters text, refreshes to ensure it still there, submits, and ensures it has been cleared" do - expect(find("#" + two_question_form.ordered_questions.first.ui_selector).value).to eq('Question one') - expect(find("#" + two_question_form.ordered_questions.last.ui_selector).value).to eq('Question two') + it 'enters text, refreshes to ensure it still there, submits, and ensures it has been cleared' do + expect(find('#' + two_question_form.ordered_questions.first.ui_selector).value).to eq('Question one') + expect(find('#' + two_question_form.ordered_questions.last.ui_selector).value).to eq('Question two') click_button 'Submit' expect(page).to have_content('Thank you. Your feedback has been received.') visit touchpoint_path(two_question_form) - expect(find("#" + two_question_form.ordered_questions.first.ui_selector).value).to be_blank - expect(find("#" + two_question_form.ordered_questions.last.ui_selector).value).to be_blank + expect(find('#' + two_question_form.ordered_questions.first.ui_selector).value).to be_blank + expect(find('#' + two_question_form.ordered_questions.last.ui_selector).value).to be_blank end end @@ -73,7 +73,7 @@ end context 'form.verify_csrf=true, but with invalid authenticity_token' do - before do + before do expect(form.verify_csrf).to be true visit touchpoint_path(form) page.execute_script("document.getElementById('authenticity_token').value = 'an invalid csrf token'") @@ -88,11 +88,11 @@ end context 'form.verify_csrf=true, but without authenticity_token' do - before do + before do expect(form.verify_csrf).to be true visit touchpoint_path(form) page.execute_script("document.getElementById('authenticity_token').remove()") - expect(page).to_not have_css("#authenticity_token", visible: false) + expect(page).to_not have_css('#authenticity_token', visible: false) click_button 'Submit' end @@ -104,12 +104,12 @@ end context 'form.verify_csrf=false' do - before do + before do form.update!(verify_csrf: false) expect(form.verify_csrf).to be false visit touchpoint_path(form) - expect(page).to_not have_css("#authenticity_token", visible: false) + expect(page).to_not have_css('#authenticity_token', visible: false) click_button 'Submit' end @@ -127,7 +127,7 @@ end it 'displays the form title in an h1' do - within("h1") do + within('h1') do expect(page).to have_text(form.title) end end @@ -135,12 +135,12 @@ context 'with blank/empty form title' do before do - form.update(title: "") + form.update(title: '') visit touchpoint_path(form) end it 'in h1 does not render a title but does render text for screen reader' do - expect(find("h1").text).to be_empty + expect(find('h1').text).to be_empty expect(page).to have_css('h1 .usa-sr-only', text: 'Feedback form', visible: :all) end end @@ -274,27 +274,27 @@ describe 'rich text question' do let(:rich_text_form) { FactoryBot.create(:form, organization:) } - let!(:rich_text_question_1) { FactoryBot.create(:question, form: rich_text_form, position: 1, form_section: rich_text_form.form_sections.first, question_type: "rich_textarea", answer_field: 'answer_01', text: "Q1" ) } - let!(:rich_text_question_2) { FactoryBot.create(:question, form: rich_text_form, position: 2, form_section: rich_text_form.form_sections.first, question_type: "rich_textarea", answer_field: 'answer_02', text: "Q2", is_required: true) } - let!(:rich_text_question_3) { FactoryBot.create(:question, form: rich_text_form, position: 3, form_section: rich_text_form.form_sections.first, question_type: "rich_textarea", answer_field: 'answer_03', text: "Q3", character_limit: 300) } + let!(:rich_text_question_1) { FactoryBot.create(:question, form: rich_text_form, position: 1, form_section: rich_text_form.form_sections.first, question_type: 'rich_textarea', answer_field: 'answer_01', text: 'Q1') } + let!(:rich_text_question_2) { FactoryBot.create(:question, form: rich_text_form, position: 2, form_section: rich_text_form.form_sections.first, question_type: 'rich_textarea', answer_field: 'answer_02', text: 'Q2', is_required: true) } + let!(:rich_text_question_3) { FactoryBot.create(:question, form: rich_text_form, position: 3, form_section: rich_text_form.form_sections.first, question_type: 'rich_textarea', answer_field: 'answer_03', text: 'Q3', character_limit: 300) } before do visit touchpoint_path(rich_text_form) - find("##{rich_text_question_1.ui_selector} .ql-editor").send_keys("some text goes here") + find("##{rich_text_question_1.ui_selector} .ql-editor").send_keys('some text goes here') find("##{rich_text_question_2.ui_selector}").click end it 'persists rich text values from localStorage' do - expect(find("#hidden-#{rich_text_question_1.ui_selector}", visible: false).value).to eq("

some text goes here

") + expect(find("#hidden-#{rich_text_question_1.ui_selector}", visible: false).value).to eq('

some text goes here

') visit touchpoint_path(rich_text_form) - expect(find("#hidden-#{rich_text_question_1.ui_selector}", visible: false).value).to eq("

some text goes here

") - find("##{rich_text_question_3.ui_selector} .ql-editor").send_keys("some more text goes here") - expect(page).to have_content("269 characters left") - click_on "Submit" - expect(page).to have_content("A response is required: Q2") - find("##{rich_text_question_2.ui_selector} .ql-editor").send_keys("okay now") - click_on "Submit" - expect(page).to have_content("Thank you. Your feedback has been received.") + expect(find("#hidden-#{rich_text_question_1.ui_selector}", visible: false).value).to eq('

some text goes here

') + find("##{rich_text_question_3.ui_selector} .ql-editor").send_keys('some more text goes here') + expect(page).to have_content('269 characters left') + click_on 'Submit' + expect(page).to have_content('A response is required: Q2') + find("##{rich_text_question_2.ui_selector} .ql-editor").send_keys('okay now') + click_on 'Submit' + expect(page).to have_content('Thank you. Your feedback has been received.') end end @@ -334,15 +334,15 @@ end it 'not-successful, less than 10 digit phone number' do - fill_in("question_#{phone_question.id}_answer_01", with: "123456789") + fill_in("question_#{phone_question.id}_answer_01", with: '123456789') click_on 'Submit' - expect(page).to have_content("Please enter a valid value: Phone Number") + expect(page).to have_content('Please enter a valid value: Phone Number') end it 'successful, 10 digit phone number' do - fill_in("question_#{phone_question.id}_answer_01", with: "1234567890") + fill_in("question_#{phone_question.id}_answer_01", with: '1234567890') click_on 'Submit' - expect(page).to have_content("Thank you. Your feedback has been received.") + expect(page).to have_content('Thank you. Your feedback has been received.') end end @@ -515,7 +515,7 @@ # An alternative is to send location_code back to the client and assert against it latest_submission = Submission.ordered.first expect(latest_submission.location_code).to eq('TEST_LOCATION_CODE') - expect(latest_submission.query_string).to eq("?location_code=TEST_LOCATION_CODE") + expect(latest_submission.query_string).to eq('?location_code=TEST_LOCATION_CODE') end end end @@ -529,13 +529,13 @@ it 'submits successfully' do expect(page).to have_content(a11_v2_form.title) - expect(page).to have_content("This is help text.") - find("svg[aria-labelledby='thumbs-up-icon']").click # the thumbs up - expect(page).to have_content("Positive indicators") - expect(page).to have_content("effectiveness") - expect(page).to have_content("ease") - expect(page).to have_content("efficiency") - expect(page).to have_content("transparency") + expect(page).to have_content('This is help text.') + find("label[for*='_yes']").click # the thumbs up + expect(page).to have_content('Positive indicators') + expect(page).to have_content('effectiveness') + expect(page).to have_content('ease') + expect(page).to have_content('efficiency') + expect(page).to have_content('transparency') find("label[for='question_option_1']").click find("label[for='question_option_4']").click click_button 'Submit' @@ -545,7 +545,7 @@ expect(latest_submission.answer_01).to eq '1' expect(latest_submission.answer_02).to eq 'effectiveness,transparency' expect(latest_submission.answer_03).to eq nil - expect(latest_submission.answer_04).to eq "" + expect(latest_submission.answer_04).to eq '' end end @@ -558,29 +558,29 @@ it 'toggles positive and negative indicators and submits successfully' do expect(page).to have_content(a11_v2_radio_form.title) - expect(page).to_not have_content("Negative indicators") - expect(page).to_not have_content("Positive indicators") + expect(page).to_not have_content('Negative indicators') + expect(page).to_not have_content('Positive indicators') - find_all("label")[0].click # option 1 - expect(page).to have_content("Negative indicators") + find_all('label')[0].click # option 1 + expect(page).to have_content('Negative indicators') - find_all("label")[3].click # option 4 - expect(page).to have_content("Positive indicators") + find_all('label')[3].click # option 4 + expect(page).to have_content('Positive indicators') - find_all("label")[1].click # option 2 - expect(page).to have_content("Negative indicators") + find_all('label')[1].click # option 2 + expect(page).to have_content('Negative indicators') - find_all("label")[4].click # option 5 - expect(page).to have_content("Positive indicators") + find_all('label')[4].click # option 5 + expect(page).to have_content('Positive indicators') - find_all("label")[2].click # option 3 - expect(page).to have_content("Negative indicators") + find_all('label')[2].click # option 3 + expect(page).to have_content('Negative indicators') - expect(page).to have_content("This is help text.") - expect(page).to have_content("effectiveness") - expect(page).to have_content("ease") - expect(page).to have_content("efficiency") - expect(page).to have_content("transparency") + expect(page).to have_content('This is help text.') + expect(page).to have_content('effectiveness') + expect(page).to have_content('ease') + expect(page).to have_content('efficiency') + expect(page).to have_content('transparency') click_button 'Submit' expect(page).to have_content('Thank you. Your feedback has been received.') @@ -589,7 +589,7 @@ expect(latest_submission.answer_01).to eq '3' expect(latest_submission.answer_02).to eq nil expect(latest_submission.answer_03).to eq nil - expect(latest_submission.answer_04).to eq "" + expect(latest_submission.answer_04).to eq '' end end @@ -598,7 +598,7 @@ before do visit submit_touchpoint_path(custom_form) - expect(page).to have_content("This is help text.") + expect(page).to have_content('This is help text.') find("label[for='question_option_2_yes']").click click_button 'Submit' end