decidim-forms 0.22.0 → 0.23.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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/admin/decidim_forms_manifest.css +3 -0
  3. data/app/assets/config/decidim_forms_manifest.css +1 -0
  4. data/app/assets/javascripts/decidim/forms/admin/auto_select_options_from_url.component.js.es6 +40 -0
  5. data/app/assets/javascripts/decidim/forms/admin/forms.js.es6 +181 -25
  6. data/app/assets/javascripts/decidim/forms/autosortable_checkboxes.component.js.es6 +54 -34
  7. data/app/assets/javascripts/decidim/forms/display_conditions.component.js.es6 +204 -0
  8. data/app/assets/javascripts/decidim/forms/forms.js.es6 +8 -1
  9. data/app/assets/stylesheets/decidim/forms/questionnaire-answers-pdf.scss +69 -0
  10. data/app/commands/decidim/forms/admin/update_questionnaire.rb +25 -1
  11. data/app/commands/decidim/forms/answer_questionnaire.rb +1 -1
  12. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +47 -1
  13. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire_answers.rb +97 -0
  14. data/app/forms/decidim/forms/admin/display_condition_form.rb +100 -0
  15. data/app/forms/decidim/forms/admin/question_form.rb +1 -0
  16. data/app/forms/decidim/forms/answer_form.rb +15 -0
  17. data/app/helpers/decidim/forms/admin/application_helper.rb +21 -0
  18. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_pagination_helper.rb +49 -0
  19. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_url_helper.rb +40 -0
  20. data/app/helpers/decidim/forms/admin/questionnaire_answers_helper.rb +27 -0
  21. data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +19 -0
  22. data/app/models/decidim/forms/answer.rb +0 -3
  23. data/app/models/decidim/forms/answer_option.rb +14 -0
  24. data/app/models/decidim/forms/display_condition.rb +51 -0
  25. data/app/models/decidim/forms/question.rb +34 -0
  26. data/app/models/decidim/forms/question_matrix_row.rb +3 -0
  27. data/app/models/decidim/forms/questionnaire.rb +11 -1
  28. data/app/presenters/decidim/forms/admin/questionnaire_answer_presenter.rb +43 -0
  29. data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +60 -0
  30. data/app/presenters/decidim/forms/answer_option_presenter.rb +20 -0
  31. data/app/presenters/decidim/forms/question_presenter.rb +16 -0
  32. data/app/queries/decidim/forms/questionnaire_participant.rb +35 -0
  33. data/app/queries/decidim/forms/questionnaire_participants.rb +43 -0
  34. data/app/views/decidim/forms/admin/questionnaires/_display_condition.html.erb +88 -0
  35. data/app/views/decidim/forms/admin/questionnaires/_display_condition_template.html.erb +7 -0
  36. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +30 -4
  37. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +19 -3
  38. data/app/views/decidim/forms/admin/questionnaires/answers/export/_answer.html.erb +31 -0
  39. data/app/views/decidim/forms/admin/questionnaires/answers/export/pdf.html.erb +13 -0
  40. data/app/views/decidim/forms/admin/questionnaires/answers/index.html.erb +53 -0
  41. data/app/views/decidim/forms/admin/questionnaires/answers/show.html.erb +48 -0
  42. data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +9 -5
  43. data/app/views/decidim/forms/questionnaires/_answer.html.erb +1 -1
  44. data/app/views/decidim/forms/questionnaires/show.html.erb +22 -2
  45. data/app/views/layouts/decidim/forms/admin/questionnaires/questionnaire_answers.html.erb +12 -0
  46. data/config/initializers/wicked_pdf.rb +25 -0
  47. data/config/locales/am-ET.yml +1 -0
  48. data/config/locales/ar.yml +0 -1
  49. data/config/locales/bg-BG.yml +0 -2
  50. data/config/locales/bg.yml +14 -0
  51. data/config/locales/ca.yml +56 -4
  52. data/config/locales/cs.yml +54 -2
  53. data/config/locales/da.yml +1 -0
  54. data/config/locales/de.yml +51 -1
  55. data/config/locales/el.yml +0 -2
  56. data/config/locales/en.yml +54 -2
  57. data/config/locales/eo.yml +1 -0
  58. data/config/locales/es-MX.yml +53 -1
  59. data/config/locales/es-PY.yml +53 -1
  60. data/config/locales/es.yml +54 -2
  61. data/config/locales/et.yml +1 -0
  62. data/config/locales/eu.yml +0 -1
  63. data/config/locales/fi-plain.yml +53 -1
  64. data/config/locales/fi.yml +53 -1
  65. data/config/locales/fr-CA.yml +54 -2
  66. data/config/locales/fr.yml +54 -2
  67. data/config/locales/gl.yml +0 -1
  68. data/config/locales/hr.yml +1 -0
  69. data/config/locales/hu.yml +0 -2
  70. data/config/locales/id-ID.yml +0 -1
  71. data/config/locales/is.yml +1 -0
  72. data/config/locales/it.yml +53 -1
  73. data/config/locales/ja-JP.yml +51 -1
  74. data/config/locales/ja.yml +170 -0
  75. data/config/locales/ko-KR.yml +1 -0
  76. data/config/locales/ko.yml +1 -0
  77. data/config/locales/lt.yml +1 -0
  78. data/config/locales/{lv-LV.yml → lv.yml} +0 -1
  79. data/config/locales/mt.yml +1 -0
  80. data/config/locales/nl.yml +59 -7
  81. data/config/locales/no.yml +47 -2
  82. data/config/locales/om-ET.yml +1 -0
  83. data/config/locales/pl.yml +52 -3
  84. data/config/locales/pt-BR.yml +0 -1
  85. data/config/locales/pt.yml +51 -2
  86. data/config/locales/ro-RO.yml +51 -2
  87. data/config/locales/ru.yml +0 -1
  88. data/config/locales/sk.yml +0 -2
  89. data/config/locales/sl.yml +7 -0
  90. data/config/locales/so-SO.yml +1 -0
  91. data/config/locales/sv.yml +51 -2
  92. data/config/locales/ti-ER.yml +1 -0
  93. data/config/locales/tr-TR.yml +0 -1
  94. data/config/locales/vi-VN.yml +1 -0
  95. data/config/locales/vi.yml +1 -0
  96. data/config/locales/zh-CN.yml +172 -0
  97. data/config/locales/zh-TW.yml +1 -0
  98. data/db/migrate/20200130194123_create_decidim_forms_display_conditions.rb +20 -0
  99. data/lib/decidim/exporters/form_pdf.rb +33 -0
  100. data/lib/decidim/exporters/form_pdf_controller_helper.rb +11 -0
  101. data/lib/decidim/forms.rb +5 -0
  102. data/lib/decidim/forms/admin_engine.rb +1 -1
  103. data/lib/decidim/forms/test.rb +6 -0
  104. data/lib/decidim/forms/test/factories.rb +30 -0
  105. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +619 -38
  106. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +108 -0
  107. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +21 -894
  108. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +179 -0
  109. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +463 -0
  110. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +93 -0
  111. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +461 -0
  112. data/lib/decidim/forms/version.rb +1 -1
  113. metadata +91 -11
@@ -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