decidim-forms 0.19.1 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/config/admin/decidim_forms_manifest.css +3 -0
  4. data/app/assets/config/admin/decidim_forms_manifest.js +1 -0
  5. data/app/assets/config/decidim_forms_manifest.css +1 -0
  6. data/app/assets/images/decidim/surveys/icon.svg +1 -19
  7. data/app/assets/javascripts/decidim/forms/admin/auto_select_options_from_url.component.js.es6 +40 -0
  8. data/app/assets/javascripts/decidim/forms/admin/collapsible_questions.js.es6 +13 -0
  9. data/app/assets/javascripts/decidim/forms/admin/forms.js.es6 +260 -16
  10. data/app/assets/javascripts/decidim/forms/admin/live_text_update.component.js.es6 +52 -0
  11. data/app/assets/javascripts/decidim/forms/autosortable_checkboxes.component.js.es6 +54 -34
  12. data/app/assets/javascripts/decidim/forms/display_conditions.component.js.es6 +204 -0
  13. data/app/assets/javascripts/decidim/forms/forms.js.es6 +49 -1
  14. data/app/assets/javascripts/decidim/forms/max_choices_alert.component.js.es6 +44 -0
  15. data/app/assets/stylesheets/decidim/forms/forms.scss +39 -0
  16. data/app/assets/stylesheets/decidim/forms/questionnaire-answers-pdf.scss +69 -0
  17. data/app/cells/decidim/forms/matrix_readonly/show.erb +5 -0
  18. data/app/cells/decidim/forms/matrix_readonly_cell.rb +12 -0
  19. data/app/cells/decidim/forms/question_readonly/show.erb +5 -1
  20. data/app/cells/decidim/forms/question_readonly_cell.rb +5 -0
  21. data/app/cells/decidim/forms/step_navigation/show.erb +35 -0
  22. data/app/cells/decidim/forms/step_navigation_cell.rb +46 -0
  23. data/app/commands/decidim/forms/admin/update_questionnaire.rb +33 -1
  24. data/app/commands/decidim/forms/answer_questionnaire.rb +7 -2
  25. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +52 -2
  26. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire_answers.rb +97 -0
  27. data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +58 -2
  28. data/app/forms/decidim/forms/admin/display_condition_form.rb +100 -0
  29. data/app/forms/decidim/forms/admin/question_form.rb +21 -1
  30. data/app/forms/decidim/forms/admin/question_matrix_row_form.rb +26 -0
  31. data/app/forms/decidim/forms/answer_choice_form.rb +1 -0
  32. data/app/forms/decidim/forms/answer_form.rb +31 -2
  33. data/app/forms/decidim/forms/questionnaire_form.rb +33 -3
  34. data/app/helpers/decidim/forms/admin/application_helper.rb +37 -0
  35. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_pagination_helper.rb +49 -0
  36. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_url_helper.rb +40 -0
  37. data/app/helpers/decidim/forms/admin/questionnaire_answers_helper.rb +27 -0
  38. data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +19 -0
  39. data/app/models/decidim/forms/answer.rb +2 -5
  40. data/app/models/decidim/forms/answer_choice.rb +7 -0
  41. data/app/models/decidim/forms/answer_option.rb +14 -0
  42. data/app/models/decidim/forms/display_condition.rb +51 -0
  43. data/app/models/decidim/forms/question.rb +52 -2
  44. data/app/models/decidim/forms/question_matrix_row.rb +15 -0
  45. data/app/models/decidim/forms/questionnaire.rb +13 -2
  46. data/app/presenters/decidim/forms/admin/questionnaire_answer_presenter.rb +43 -0
  47. data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +60 -0
  48. data/app/presenters/decidim/forms/answer_option_presenter.rb +20 -0
  49. data/app/presenters/decidim/forms/question_presenter.rb +16 -0
  50. data/app/queries/decidim/forms/questionnaire_participant.rb +35 -0
  51. data/app/queries/decidim/forms/questionnaire_participants.rb +43 -0
  52. data/app/queries/decidim/forms/questionnaire_user_answers.rb +1 -1
  53. data/app/types/decidim/forms/answer_option_type.rb +14 -0
  54. data/app/types/decidim/forms/question_type.rb +23 -0
  55. data/app/types/decidim/forms/questionnaire_type.rb +22 -0
  56. data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +1 -1
  57. data/app/views/decidim/forms/admin/questionnaires/_display_condition.html.erb +88 -0
  58. data/app/views/decidim/forms/admin/questionnaires/_display_condition_template.html.erb +7 -0
  59. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +67 -8
  60. data/app/views/decidim/forms/admin/questionnaires/_matrix_row.html.erb +34 -0
  61. data/app/views/decidim/forms/admin/questionnaires/_matrix_row_template.html.erb +7 -0
  62. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +45 -6
  63. data/app/views/decidim/forms/admin/questionnaires/_separator.html.erb +41 -0
  64. data/app/views/decidim/forms/admin/questionnaires/answers/export/_answer.html.erb +31 -0
  65. data/app/views/decidim/forms/admin/questionnaires/answers/export/pdf.html.erb +13 -0
  66. data/app/views/decidim/forms/admin/questionnaires/answers/index.html.erb +53 -0
  67. data/app/views/decidim/forms/admin/questionnaires/answers/show.html.erb +48 -0
  68. data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +9 -5
  69. data/app/views/decidim/forms/questionnaires/_answer.html.erb +28 -99
  70. data/app/views/decidim/forms/questionnaires/answers/_long_answer.html.erb +1 -0
  71. data/app/views/decidim/forms/questionnaires/answers/_matrix_multiple.html.erb +43 -0
  72. data/app/views/decidim/forms/questionnaires/answers/_matrix_single.html.erb +43 -0
  73. data/app/views/decidim/forms/questionnaires/answers/_multiple_option.html.erb +23 -0
  74. data/app/views/decidim/forms/questionnaires/answers/_separator.html.erb +1 -0
  75. data/app/views/decidim/forms/questionnaires/answers/_short_answer.html.erb +1 -0
  76. data/app/views/decidim/forms/questionnaires/answers/_single_option.html.erb +30 -0
  77. data/app/views/decidim/forms/questionnaires/answers/_sorting.html.erb +23 -0
  78. data/app/views/decidim/forms/questionnaires/show.html.erb +81 -28
  79. data/app/views/layouts/decidim/forms/admin/questionnaires/questionnaire_answers.html.erb +12 -0
  80. data/config/initializers/wicked_pdf.rb +25 -0
  81. data/config/locales/am-ET.yml +1 -0
  82. data/config/locales/ar.yml +12 -4
  83. data/config/locales/bg-BG.yml +14 -0
  84. data/config/locales/bg.yml +14 -0
  85. data/config/locales/ca.yml +98 -8
  86. data/config/locales/cs.yml +94 -4
  87. data/config/locales/da-DK.yml +1 -0
  88. data/config/locales/da.yml +1 -0
  89. data/config/locales/de.yml +92 -4
  90. data/config/locales/el-GR.yml +1 -0
  91. data/config/locales/el.yml +118 -0
  92. data/config/locales/en.yml +94 -4
  93. data/config/locales/eo.yml +1 -0
  94. data/config/locales/es-MX.yml +94 -4
  95. data/config/locales/es-PY.yml +94 -4
  96. data/config/locales/es.yml +94 -4
  97. data/config/locales/et-EE.yml +1 -0
  98. data/config/locales/et.yml +1 -0
  99. data/config/locales/eu.yml +7 -4
  100. data/config/locales/fi-plain.yml +94 -4
  101. data/config/locales/fi.yml +94 -4
  102. data/config/locales/fr-CA.yml +172 -0
  103. data/config/locales/fr.yml +94 -4
  104. data/config/locales/ga-IE.yml +1 -0
  105. data/config/locales/gl.yml +7 -4
  106. data/config/locales/hr-HR.yml +1 -0
  107. data/config/locales/hr.yml +1 -0
  108. data/config/locales/hu.yml +16 -4
  109. data/config/locales/id-ID.yml +7 -4
  110. data/config/locales/is-IS.yml +1 -0
  111. data/config/locales/is.yml +1 -0
  112. data/config/locales/it.yml +95 -5
  113. data/config/locales/ja-JP.yml +170 -0
  114. data/config/locales/ja.yml +170 -0
  115. data/config/locales/ko-KR.yml +1 -0
  116. data/config/locales/ko.yml +1 -0
  117. data/config/locales/lt-LT.yml +1 -0
  118. data/config/locales/lt.yml +1 -0
  119. data/config/locales/lv.yml +118 -0
  120. data/config/locales/mt-MT.yml +1 -0
  121. data/config/locales/mt.yml +1 -0
  122. data/config/locales/nl.yml +97 -7
  123. data/config/locales/no.yml +98 -1
  124. data/config/locales/om-ET.yml +1 -0
  125. data/config/locales/pl.yml +113 -26
  126. data/config/locales/pt-BR.yml +8 -5
  127. data/config/locales/pt.yml +111 -24
  128. data/config/locales/ro-RO.yml +167 -0
  129. data/config/locales/ru.yml +4 -2
  130. data/config/locales/sk-SK.yml +88 -0
  131. data/config/locales/sk.yml +90 -0
  132. data/config/locales/sl.yml +12 -0
  133. data/config/locales/so-SO.yml +1 -0
  134. data/config/locales/sr-CS.yml +1 -0
  135. data/config/locales/sv.yml +91 -4
  136. data/config/locales/ti-ER.yml +1 -0
  137. data/config/locales/tr-TR.yml +7 -4
  138. data/config/locales/vi-VN.yml +1 -0
  139. data/config/locales/vi.yml +1 -0
  140. data/config/locales/zh-CN.yml +172 -0
  141. data/config/locales/zh-TW.yml +1 -0
  142. data/db/migrate/20190315203056_add_session_token_to_decidim_forms_answers.rb +17 -0
  143. data/db/migrate/20190930094710_add_ip_hash_to_decidim_form_answers.rb +12 -0
  144. data/db/migrate/20200130194123_create_decidim_forms_display_conditions.rb +20 -0
  145. data/db/migrate/20200225123810_create_decidim_forms_question_matrix_rows.rb +11 -0
  146. data/db/migrate/20200304152939_add_matrix_row_id_to_decidim_forms_answer_choices.rb +11 -0
  147. data/lib/decidim/api/questionnaire_entity_interface.rb +18 -0
  148. data/lib/decidim/exporters/form_pdf.rb +33 -0
  149. data/lib/decidim/exporters/form_pdf_controller_helper.rb +11 -0
  150. data/lib/decidim/forms.rb +6 -0
  151. data/lib/decidim/forms/admin_engine.rb +1 -1
  152. data/lib/decidim/forms/api.rb +7 -0
  153. data/lib/decidim/forms/test.rb +6 -0
  154. data/lib/decidim/forms/test/factories.rb +80 -6
  155. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +924 -66
  156. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +108 -0
  157. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +33 -575
  158. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +179 -0
  159. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +463 -0
  160. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +93 -0
  161. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +461 -0
  162. data/lib/decidim/forms/user_answers_serializer.rb +23 -4
  163. data/lib/decidim/forms/version.rb +1 -1
  164. metadata +136 -9
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples_for "add display conditions" do
6
+ context "when adding display conditions to a question" do
7
+ let!(:answer_options) do
8
+ 3.times.to_a.map do |x|
9
+ {
10
+ "body" => Decidim::Faker::Localized.sentence,
11
+ "free_text" => x == 2
12
+ }
13
+ end
14
+ end
15
+
16
+ context "when questionnaire has only one question" do
17
+ let!(:question) { create(:questionnaire_question, questionnaire: questionnaire, body: body, question_type: "short_answer") }
18
+
19
+ before do
20
+ visit_questionnaire_edit_path_and_expand_all
21
+ end
22
+
23
+ it "doesn't display an add display condition button" do
24
+ expect(page).to have_no_button("Add display condition")
25
+ end
26
+
27
+ context "when creating a new question" do
28
+ it "disables the add display condition button if the question hasn't been saved" do
29
+ within "form.edit_questionnaire" do
30
+ click_button "Add question"
31
+ expand_all_questions
32
+
33
+ expect(page).to have_button("Add display condition", disabled: true)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ context "when questionnaire has more than one question" do
40
+ let!(:question_short_answer) do
41
+ create(:questionnaire_question,
42
+ questionnaire: questionnaire,
43
+ body: Decidim::Faker::Localized.sentence,
44
+ question_type: "short_answer")
45
+ end
46
+ let!(:question_long_answer) do
47
+ create(:questionnaire_question,
48
+ questionnaire: questionnaire,
49
+ body: Decidim::Faker::Localized.sentence,
50
+ question_type: "long_answer")
51
+ end
52
+ let!(:question_single_option) do
53
+ create(:questionnaire_question,
54
+ questionnaire: questionnaire,
55
+ body: Decidim::Faker::Localized.sentence,
56
+ question_type: "single_option",
57
+ options: answer_options)
58
+ end
59
+ let!(:question_multiple_option) do
60
+ create(:questionnaire_question,
61
+ questionnaire: questionnaire,
62
+ body: Decidim::Faker::Localized.sentence,
63
+ question_type: "multiple_option",
64
+ options: answer_options)
65
+ end
66
+
67
+ let(:questions) { [question_short_answer, question_long_answer, question_single_option, question_multiple_option] }
68
+
69
+ before do
70
+ visit_questionnaire_edit_path_and_expand_all
71
+ end
72
+
73
+ context "when clicking add display condition button" do
74
+ it "adds a new display condition form with all correct elements" do
75
+ within "form.edit_questionnaire" do
76
+ within_add_display_condition do
77
+ expect(page).to have_select("Question")
78
+ expect(page).to have_select("Condition")
79
+ expect(page).to have_selector("[id$=mandatory]")
80
+
81
+ select question_single_option.body["en"], from: "Question"
82
+ select "Answered", from: "Condition"
83
+
84
+ expect(page).to have_no_select("Answer option")
85
+ expect(page).to have_no_css("[id$=condition_value_en]", visible: :visible)
86
+
87
+ select question_single_option.body["en"], from: "Question"
88
+ select "Equal", from: "Condition"
89
+
90
+ expect(page).to have_select("Answer option")
91
+ expect(page).to have_no_css("[id$=condition_value_en]", visible: :visible)
92
+ end
93
+ end
94
+ end
95
+
96
+ it "fills condition_question select with saved questions from questionnaire" do
97
+ within_add_display_condition do
98
+ options = questions.map { |question| question["body"]["en"] }
99
+ options << "Select a question"
100
+ expect(page).to have_select("Question", options: options)
101
+
102
+ within "select[id$=decidim_condition_question_id]" do
103
+ elements = page.all("option[data-type]")
104
+ expect(elements.map { |element| element[:"data-type"] }).to eq(questions.map(&:question_type))
105
+ expect(page.find("option[value='#{questions.last.id}']")).to be_disabled
106
+ end
107
+ end
108
+ end
109
+
110
+ context "when a text question is selected" do
111
+ it "fills condition_type select with correct options" do
112
+ within_add_display_condition do
113
+ select question_short_answer.body["en"], from: "Question"
114
+
115
+ options = ["Select a condition type", "Answered", "Not answered", "Includes text"]
116
+
117
+ option_elements = page.all("select[id$=condition_type] option")
118
+ option_elements = option_elements.to_a.reject { |option| option[:style].match? "display: none" }
119
+
120
+ expect(option_elements.map(&:text)).to eq(options)
121
+ end
122
+ end
123
+ end
124
+
125
+ context "when an options question is selected" do
126
+ it "fills condition_type select with correct options" do
127
+ within_add_display_condition do
128
+ select question_single_option.body["en"], from: "Question"
129
+
130
+ options = ["Select a condition type", "Answered", "Not answered", "Equal", "Not equal", "Includes text"]
131
+
132
+ option_elements = page.all("select[id$=condition_type] option")
133
+ option_elements = option_elements.to_a.reject { |option| option[:style].match? "display: none" }
134
+
135
+ expect(option_elements.map(&:text)).to eq(options)
136
+ end
137
+ end
138
+ end
139
+
140
+ it "fills answer_options select with correct options" do
141
+ within_add_display_condition do
142
+ select question_single_option.body["en"], from: "Question"
143
+ select "Equal", from: "Condition"
144
+
145
+ options = answer_options.map { |option| option["body"]["en"] }
146
+ options << "Select answer option"
147
+
148
+ expect(page).to have_select("Answer option", options: options, wait: 5)
149
+ end
150
+ end
151
+
152
+ it "loads an empty value field" do
153
+ within_add_display_condition do
154
+ select question_single_option.body["en"], from: "Question"
155
+ select "Includes text", from: "Condition"
156
+ expect(page).to have_nested_field("condition_value_en", with: "")
157
+ end
158
+ end
159
+
160
+ it "loads a mandatory field with false value" do
161
+ within_add_display_condition do
162
+ expect(page).to have_selector("[id$=mandatory]")
163
+ expect(page).to have_no_selector("[id$=mandatory][checked]")
164
+ end
165
+ end
166
+
167
+ it "can be removed" do
168
+ within_add_display_condition do
169
+ click_button "Remove"
170
+ end
171
+
172
+ click_button "Save"
173
+
174
+ expect(page).to have_admin_callout("successfully")
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,463 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples_for "add questions" do
6
+ it "adds a few questions and separators to the questionnaire" do
7
+ questions_body = ["This is the first question", "This is the second question"]
8
+
9
+ within "form.edit_questionnaire" do
10
+ click_button "Add question"
11
+ click_button "Add separator"
12
+ click_button "Add question"
13
+
14
+ expect(page).to have_selector(".questionnaire-question", count: 3)
15
+
16
+ expand_all_questions
17
+
18
+ page.all(".questionnaire-question .collapsible").each_with_index do |question, idx|
19
+ within question do
20
+ fill_in find_nested_form_field_locator("body_en"), with: questions_body[idx]
21
+ end
22
+ end
23
+
24
+ click_button "Save"
25
+ end
26
+
27
+ expect(page).to have_admin_callout("successfully")
28
+
29
+ visit_questionnaire_edit_path_and_expand_all
30
+
31
+ expect(page).to have_selector("input[value='This is the first question']")
32
+ expect(page).to have_selector("input[value='This is the second question']")
33
+ expect(page).to have_content("Separator #2")
34
+ end
35
+
36
+ it "adds a question with a rich text description" do
37
+ within "form.edit_questionnaire" do
38
+ click_button "Add question"
39
+ expand_all_questions
40
+
41
+ within ".questionnaire-question" do
42
+ fill_in find_nested_form_field_locator("body_en"), with: "Body"
43
+
44
+ fill_in_editor find_nested_form_field_locator("description_en", visible: false), with: "<b>Superkalifragilistic description</b>"
45
+ end
46
+
47
+ click_button "Save"
48
+ end
49
+
50
+ expect(page).to have_admin_callout("successfully")
51
+
52
+ component.update!(
53
+ step_settings: {
54
+ component.participatory_space.active_step.id => {
55
+ allow_answers: true
56
+ }
57
+ }
58
+ )
59
+
60
+ visit questionnaire_public_path
61
+
62
+ expect(page).to have_selector("strong", text: "Superkalifragilistic description")
63
+ end
64
+
65
+ it "adds a question with answer options" do
66
+ question_body = ["This is the first question", "This is the second question"]
67
+ answer_options_body = [
68
+ [
69
+ "This is the Q1 first option",
70
+ "This is the Q1 second option",
71
+ "This is the Q1 third option"
72
+ ],
73
+ [
74
+ "This is the Q2 first option",
75
+ "This is the Q2 second option",
76
+ "This is the Q2 third option"
77
+ ]
78
+ ]
79
+
80
+ within "form.edit_questionnaire" do
81
+ click_button "Add question"
82
+ click_button "Add question"
83
+ expand_all_questions
84
+
85
+ page.all(".questionnaire-question").each_with_index do |question, idx|
86
+ within question do
87
+ fill_in find_nested_form_field_locator("body_en"), with: question_body[idx]
88
+ end
89
+ end
90
+
91
+ expect(page).to have_no_content "Add answer option"
92
+
93
+ page.all(".questionnaire-question").each do |question|
94
+ within question do
95
+ select "Single option", from: "Type"
96
+ click_button "Add answer option"
97
+ end
98
+ end
99
+
100
+ page.all(".questionnaire-question").each_with_index do |question, question_idx|
101
+ question.all(".questionnaire-question-answer-option").each_with_index do |question_answer_option, answer_option_idx|
102
+ within question_answer_option do
103
+ fill_in find_nested_form_field_locator("body_en"), with: answer_options_body[question_idx][answer_option_idx]
104
+ end
105
+ end
106
+ end
107
+
108
+ click_button "Save"
109
+ end
110
+
111
+ expect(page).to have_admin_callout("successfully")
112
+
113
+ visit_questionnaire_edit_path_and_expand_all
114
+
115
+ expect(page).to have_selector("input[value='This is the first question']")
116
+ expect(page).to have_selector("input[value='This is the Q1 first option']")
117
+ expect(page).to have_selector("input[value='This is the Q1 second option']")
118
+ expect(page).to have_selector("input[value='This is the Q1 third option']")
119
+ expect(page).to have_selector("input[value='This is the second question']")
120
+ expect(page).to have_selector("input[value='This is the Q2 first option']")
121
+ expect(page).to have_selector("input[value='This is the Q2 second option']")
122
+ expect(page).to have_selector("input[value='This is the Q2 third option']")
123
+ end
124
+
125
+ it "adds a sane number of options for each attribute type" do
126
+ click_button "Add question"
127
+ expand_all_questions
128
+
129
+ select "Long answer", from: "Type"
130
+ expect(page).to have_no_selector(".questionnaire-question-answer-option")
131
+ expect(page).to have_no_selector(".questionnaire-question-matrix-row")
132
+
133
+ select "Single option", from: "Type"
134
+ expect(page).to have_selector(".questionnaire-question-answer-option", count: 2)
135
+ expect(page).to have_no_selector(".questionnaire-question-matrix-row")
136
+
137
+ select "Multiple option", from: "Type"
138
+ expect(page).to have_selector(".questionnaire-question-answer-option", count: 2)
139
+ expect(page).to have_no_selector(".questionnaire-question-matrix-row")
140
+
141
+ select "Matrix (Multiple option)", from: "Type"
142
+ expect(page).to have_selector(".questionnaire-question-answer-option", count: 2)
143
+ expect(page).to have_selector(".questionnaire-question-matrix-row", count: 2)
144
+
145
+ select "Short answer", from: "Type"
146
+ expect(page).to have_no_selector(".questionnaire-question-answer-option")
147
+ expect(page).to have_no_selector(".questionnaire-question-matrix-row")
148
+
149
+ select "Matrix (Single option)", from: "Type"
150
+ expect(page).to have_selector(".questionnaire-question-answer-option", count: 2)
151
+ expect(page).to have_selector(".questionnaire-question-matrix-row", count: 2)
152
+ end
153
+
154
+ it "does not incorrectly reorder when clicking answer options" do
155
+ click_button "Add question"
156
+ expand_all_questions
157
+
158
+ select "Single option", from: "Type"
159
+ 2.times { click_button "Add answer option" }
160
+
161
+ within ".questionnaire-question-answer-option:first-of-type" do
162
+ fill_in find_nested_form_field_locator("body_en"), with: "Something"
163
+ end
164
+
165
+ within ".questionnaire-question-answer-option:last-of-type" do
166
+ fill_in find_nested_form_field_locator("body_en"), with: "Else"
167
+ end
168
+
169
+ # If JS events for option reordering are incorrectly bound, clicking on
170
+ # the field to gain focus can cause the options to get inverted... :S
171
+ within ".questionnaire-question-answer-option:first-of-type" do
172
+ find_nested_form_field("body_en").click
173
+ end
174
+
175
+ within ".questionnaire-question-answer-option:first-of-type" do
176
+ expect(page).to have_nested_field("body_en", with: "Something")
177
+ end
178
+
179
+ within ".questionnaire-question-answer-option:last-of-type" do
180
+ expect(page).to have_nested_field("body_en", with: "Else")
181
+ end
182
+ end
183
+
184
+ it "does not incorrectly reorder when clicking matrix rows" do
185
+ click_button "Add question"
186
+ expand_all_questions
187
+
188
+ select "Matrix (Multiple option)", from: "Type"
189
+ 2.times { click_button "Add row" }
190
+
191
+ within ".questionnaire-question-matrix-row:first-of-type" do
192
+ fill_in find_nested_form_field_locator("body_en"), with: "Something"
193
+ end
194
+
195
+ within ".questionnaire-question-matrix-row:last-of-type" do
196
+ fill_in find_nested_form_field_locator("body_en"), with: "Else"
197
+ end
198
+
199
+ # If JS events for option reordering are incorrectly bound, clicking on
200
+ # the field to gain focus can cause the options to get inverted... :S
201
+ within ".questionnaire-question-matrix-row:first-of-type" do
202
+ find_nested_form_field("body_en").click
203
+ end
204
+
205
+ within ".questionnaire-question-matrix-row:first-of-type" do
206
+ expect(page).to have_nested_field("body_en", with: "Something")
207
+ end
208
+
209
+ within ".questionnaire-question-matrix-row:last-of-type" do
210
+ expect(page).to have_nested_field("body_en", with: "Else")
211
+ end
212
+ end
213
+
214
+ it "preserves question form across submission failures" do
215
+ click_button "Add question"
216
+ expand_all_questions
217
+
218
+ select "Long answer", from: "Type"
219
+ click_button "Save"
220
+
221
+ expand_all_questions
222
+ expect(page).to have_select("Type", selected: "Long answer")
223
+ end
224
+
225
+ it "does not preserve spurious answer options from previous type selections" do
226
+ click_button "Add question"
227
+ expand_all_questions
228
+
229
+ select "Single option", from: "Type"
230
+
231
+ within ".questionnaire-question-answer-option:first-of-type" do
232
+ fill_in find_nested_form_field_locator("body_en"), with: "Something"
233
+ end
234
+
235
+ select "Long answer", from: "Type"
236
+
237
+ click_button "Save"
238
+ expand_all_questions
239
+
240
+ select "Single option", from: "Type"
241
+
242
+ within ".questionnaire-question-answer-option:first-of-type" do
243
+ expect(page).to have_no_nested_field("body_en", with: "Something")
244
+ end
245
+ end
246
+
247
+ it "does not preserve spurious matrix rows from previous type selections" do
248
+ click_button "Add question"
249
+ expand_all_questions
250
+
251
+ select "Matrix (Single option)", from: "Type"
252
+
253
+ within ".questionnaire-question-matrix-row:first-of-type" do
254
+ fill_in find_nested_form_field_locator("body_en"), with: "Something"
255
+ end
256
+
257
+ select "Long answer", from: "Type"
258
+
259
+ click_button "Save"
260
+ expand_all_questions
261
+
262
+ select "Matrix (Single option)", from: "Type"
263
+
264
+ within ".questionnaire-question-matrix-row:first-of-type" do
265
+ expect(page).to have_no_nested_field("body_en", with: "Something")
266
+ end
267
+ end
268
+
269
+ it "preserves answer options form across submission failures" do
270
+ click_button "Add question"
271
+ expand_all_questions
272
+
273
+ select "Multiple option", from: "Type"
274
+
275
+ within ".questionnaire-question-answer-option:first-of-type" do
276
+ fill_in find_nested_form_field_locator("body_en"), with: "Something"
277
+ end
278
+
279
+ click_button "Add answer option"
280
+
281
+ within ".questionnaire-question-answer-option:last-of-type" do
282
+ fill_in find_nested_form_field_locator("body_en"), with: "Else"
283
+ end
284
+
285
+ select "3", from: "Maximum number of choices"
286
+
287
+ click_button "Save"
288
+ expand_all_questions
289
+
290
+ within ".questionnaire-question-answer-option:first-of-type" do
291
+ expect(page).to have_nested_field("body_en", with: "Something")
292
+ end
293
+
294
+ within ".questionnaire-question-answer-option:last-of-type" do
295
+ fill_in find_nested_form_field_locator("body_en"), with: "Else"
296
+ end
297
+
298
+ expect(page).to have_select("Maximum number of choices", selected: "3")
299
+ end
300
+
301
+ it "preserves matrix rows form across submission failures" do
302
+ click_button "Add question"
303
+ expand_all_questions
304
+
305
+ select "Matrix (Multiple option)", from: "Type"
306
+
307
+ within ".questionnaire-question-matrix-row:first-of-type" do
308
+ fill_in find_nested_form_field_locator("body_en"), with: "Something"
309
+ end
310
+
311
+ click_button "Add row"
312
+
313
+ click_button "Save"
314
+ expand_all_questions
315
+
316
+ within ".questionnaire-question-matrix-row:first-of-type" do
317
+ expect(page).to have_nested_field("body_en", with: "Something")
318
+ end
319
+ end
320
+
321
+ it "allows switching translated field tabs after form failures" do
322
+ click_button "Add question"
323
+ click_button "Save"
324
+
325
+ expand_all_questions
326
+
327
+ within ".questionnaire-question:first-of-type" do
328
+ fill_in find_nested_form_field_locator("body_en"), with: "Bye"
329
+ click_link "Català", match: :first
330
+
331
+ fill_in find_nested_form_field_locator("body_ca"), with: "Adeu"
332
+ click_link "English", match: :first
333
+
334
+ expect(page).to have_nested_field("body_en", with: "Bye")
335
+ expect(page).to have_no_selector(nested_form_field_selector("body_ca"))
336
+ expect(page).to have_no_content("Adeu")
337
+ end
338
+ end
339
+
340
+ context "when adding a multiple option question" do
341
+ before do
342
+ visit questionnaire_edit_path
343
+
344
+ within "form.edit_questionnaire" do
345
+ click_button "Add question"
346
+
347
+ expand_all_questions
348
+
349
+ within ".questionnaire-question" do
350
+ fill_in find_nested_form_field_locator("body_en"), with: "This is the first question"
351
+ end
352
+
353
+ expect(page).to have_no_content "Add answer option"
354
+ expect(page).to have_no_select("Maximum number of choices")
355
+ end
356
+ end
357
+
358
+ it "updates the free text option selector according to the selected question type" do
359
+ expect(page).to have_no_selector("input[type=checkbox][id$=_free_text]")
360
+
361
+ select "Multiple option", from: "Type"
362
+ expect(page).to have_selector("input[type=checkbox][id$=_free_text]")
363
+
364
+ select "Short answer", from: "Type"
365
+ expect(page).to have_no_selector("input[type=checkbox][id$=_free_text]")
366
+
367
+ select "Single option", from: "Type"
368
+ expect(page).to have_selector("input[type=checkbox][id$=_free_text]")
369
+ end
370
+
371
+ it "updates the max choices selector according to the configured options" do
372
+ expect(page).to have_no_select("Maximum number of choices")
373
+
374
+ select "Multiple option", from: "Type"
375
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2))
376
+
377
+ click_button "Add answer option"
378
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2 3))
379
+
380
+ click_button "Add answer option"
381
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2 3 4))
382
+
383
+ within(".questionnaire-question-answer-option:last-of-type") { click_button "Remove" }
384
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2 3))
385
+
386
+ within(".questionnaire-question-answer-option:last-of-type") { click_button "Remove" }
387
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2))
388
+
389
+ click_button "Add question"
390
+ expand_all_questions
391
+
392
+ within(".questionnaire-question:last-of-type") do
393
+ select "Multiple option", from: "Type"
394
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2))
395
+
396
+ select "Single option", from: "Type"
397
+ expect(page).to have_no_select("Maximum number of choices")
398
+ end
399
+ end
400
+ end
401
+
402
+ context "when adding a matrix question" do
403
+ before do
404
+ visit questionnaire_edit_path
405
+
406
+ within "form.edit_questionnaire" do
407
+ click_button "Add question"
408
+ expand_all_questions
409
+
410
+ within ".questionnaire-question" do
411
+ fill_in find_nested_form_field_locator("body_en"), with: "This is the first question"
412
+ end
413
+
414
+ expect(page).to have_no_content "Add answer option"
415
+ expect(page).to have_no_content "Add row"
416
+ expect(page).to have_no_select("Maximum number of choices")
417
+ end
418
+ end
419
+
420
+ it "updates the free text option selector according to the selected question type" do
421
+ expect(page).to have_no_selector("input[type=checkbox][id$=_free_text]")
422
+
423
+ select "Matrix (Multiple option)", from: "Type"
424
+ expect(page).to have_selector("input[type=checkbox][id$=_free_text]")
425
+
426
+ select "Short answer", from: "Type"
427
+ expect(page).to have_no_selector("input[type=checkbox][id$=_free_text]")
428
+
429
+ select "Matrix (Single option)", from: "Type"
430
+ expect(page).to have_selector("input[type=checkbox][id$=_free_text]")
431
+ end
432
+
433
+ it "updates the max choices selector according to the configured options" do
434
+ expect(page).to have_no_select("Maximum number of choices")
435
+
436
+ select "Matrix (Multiple option)", from: "Type"
437
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2))
438
+
439
+ click_button "Add answer option"
440
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2 3))
441
+
442
+ click_button "Add answer option"
443
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2 3 4))
444
+
445
+ within(".questionnaire-question-answer-option:last-of-type") { click_button "Remove" }
446
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2 3))
447
+
448
+ within(".questionnaire-question-answer-option:last-of-type") { click_button "Remove" }
449
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2))
450
+
451
+ click_button "Add question"
452
+ expand_all_questions
453
+
454
+ within(".questionnaire-question:last-of-type") do
455
+ select "Matrix (Multiple option)", from: "Type"
456
+ expect(page).to have_select("Maximum number of choices", options: %w(Any 2))
457
+
458
+ select "Matrix (Single option)", from: "Type"
459
+ expect(page).to have_no_select("Maximum number of choices")
460
+ end
461
+ end
462
+ end
463
+ end