decidim-forms 0.22.0 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
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,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples_for "update display conditions" do
6
+ context "when loading a saved display condition" do
7
+ let!(:condition_question_type) { "short_answer" }
8
+ let!(:condition_question) { create(:questionnaire_question, questionnaire: questionnaire, question_type: condition_question_type, position: 1) }
9
+ let!(:question) { create(:questionnaire_question, questionnaire: questionnaire, question_type: "short_answer", position: 2) }
10
+ let!(:condition_type) { :answered }
11
+ let!(:answer_option) { nil }
12
+
13
+ let!(:display_condition) do
14
+ create(:display_condition,
15
+ question: question,
16
+ condition_question: condition_question,
17
+ condition_type: condition_type,
18
+ answer_option: answer_option)
19
+ end
20
+
21
+ before do
22
+ visit_questionnaire_edit_path_and_expand_all
23
+ end
24
+
25
+ it "the related form appears" do
26
+ expect(page).to have_selector(".questionnaire-question-display-condition")
27
+ end
28
+
29
+ it "loads condition_question in select" do
30
+ within ".questionnaire-question-display-condition" do
31
+ expect(page).to have_select("Question", selected: condition_question.body["en"])
32
+ end
33
+ end
34
+
35
+ it "loads condition_type in select" do
36
+ within ".questionnaire-question-display-condition" do
37
+ expect(page).to have_select("Condition", selected: "Answered")
38
+ end
39
+ end
40
+
41
+ context "when condition_type is :equal" do
42
+ let!(:condition_question_type) { "single_option" }
43
+ let!(:answer_options) { create_list(:answer_option, 3, question: condition_question) }
44
+ let!(:answer_option) { answer_options.third }
45
+ let!(:condition_type) { :equal }
46
+
47
+ it "loads answer_option in select" do
48
+ within ".questionnaire-question-display-condition" do
49
+ expect(page).to have_select("Condition", selected: "Equal")
50
+ expect(page).to have_select("Answer option", selected: answer_option.body["en"])
51
+ end
52
+ end
53
+ end
54
+
55
+ it "can be removed" do
56
+ within ".questionnaire-question-display-condition:last-of-type" do
57
+ click_button "Remove"
58
+ end
59
+
60
+ click_button "Save"
61
+
62
+ visit_questionnaire_edit_path_and_expand_all
63
+
64
+ expect(page).to have_selector(".questionnaire-question-display-condition", count: 0)
65
+ end
66
+
67
+ it "still removes the question even if previous editions rendered the conditions invalid" do
68
+ within "form.edit_questionnaire" do
69
+ expect(page).to have_selector(".questionnaire-question", count: 2)
70
+
71
+ within ".questionnaire-question-display-condition:first-of-type" do
72
+ select condition_question.body["en"], from: "Question"
73
+ select "Includes text", from: "Condition"
74
+ fill_in find_nested_form_field_locator("condition_value_en"), with: ""
75
+ end
76
+
77
+ within ".questionnaire-question:last-of-type" do
78
+ click_button "Remove", match: :first
79
+ end
80
+
81
+ click_button "Save"
82
+ end
83
+
84
+ expect(page).to have_admin_callout("successfully")
85
+
86
+ visit_questionnaire_edit_path_and_expand_all
87
+
88
+ within "form.edit_questionnaire" do
89
+ expect(page).to have_selector(".questionnaire-question", count: 1)
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,461 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples_for "update questions" do
6
+ context "when a questionnaire has an existing question" do
7
+ let!(:question) { create(:questionnaire_question, questionnaire: questionnaire, body: body) }
8
+
9
+ before do
10
+ visit questionnaire_edit_path
11
+ expand_all_questions
12
+ end
13
+
14
+ it "modifies the question when the information is valid" do
15
+ within "form.edit_questionnaire" do
16
+ within ".questionnaire-question" do
17
+ fill_in "questionnaire_questions_#{question.id}_body_en", with: "Modified question"
18
+ check "Mandatory"
19
+ select "Long answer", from: "Type"
20
+ end
21
+
22
+ click_button "Save"
23
+ end
24
+
25
+ expect(page).to have_admin_callout("successfully")
26
+
27
+ visit_questionnaire_edit_path_and_expand_all
28
+
29
+ expect(page).to have_selector("input[value='Modified question']")
30
+ expect(page).to have_no_selector("input[value='This is the first question']")
31
+ expect(page).to have_selector("input#questionnaire_questions_#{question.id}_mandatory[checked]")
32
+ expect(page).to have_selector("select#questionnaire_questions_#{question.id}_question_type option[value='long_answer'][selected]")
33
+ end
34
+
35
+ it "re-renders the form when the information is invalid and displays errors" do
36
+ expand_all_questions
37
+
38
+ within "form.edit_questionnaire" do
39
+ within ".questionnaire-question" do
40
+ expect(page).to have_content("Statement*")
41
+ fill_in "questionnaire_questions_#{question.id}_body_en", with: ""
42
+ check "Mandatory"
43
+ select "Matrix (Multiple option)", from: "Type"
44
+ select "2", from: "Maximum number of choices"
45
+ end
46
+
47
+ click_button "Save"
48
+ end
49
+
50
+ expand_all_questions
51
+
52
+ expect(page).to have_admin_callout("There was a problem saving")
53
+ expect(page).to have_content("can't be blank", count: 5) # emtpy question, 2 empty default answer options, 2 empty default matrix rows
54
+
55
+ expect(page).to have_selector("input[value='']")
56
+ expect(page).to have_no_selector("input[value='This is the first question']")
57
+ expect(page).to have_selector("input#questionnaire_questions_#{question.id}_mandatory[checked]")
58
+ expect(page).to have_select("Maximum number of choices", selected: "2")
59
+ expect(page).to have_selector("select#questionnaire_questions_#{question.id}_question_type option[value='matrix_multiple'][selected]")
60
+ end
61
+
62
+ it "preserves deleted status across submission failures" do
63
+ within "form.edit_questionnaire" do
64
+ within ".questionnaire-question" do
65
+ click_button "Remove"
66
+ end
67
+ end
68
+
69
+ click_button "Add question"
70
+
71
+ click_button "Save"
72
+
73
+ expect(page).to have_selector(".questionnaire-question", count: 1)
74
+
75
+ within ".questionnaire-question" do
76
+ expect(page).to have_selector(".card-title", text: "#1")
77
+ expect(page).to have_no_button("Up")
78
+ end
79
+ end
80
+
81
+ it "removes the question" do
82
+ within "form.edit_questionnaire" do
83
+ within ".questionnaire-question" do
84
+ click_button "Remove"
85
+ end
86
+
87
+ click_button "Save"
88
+ end
89
+
90
+ expect(page).to have_admin_callout("successfully")
91
+
92
+ visit questionnaire_edit_path
93
+
94
+ within "form.edit_questionnaire" do
95
+ expect(page).to have_selector(".questionnaire-question", count: 0)
96
+ end
97
+ end
98
+
99
+ it "cannot be moved up" do
100
+ within "form.edit_questionnaire" do
101
+ within ".questionnaire-question" do
102
+ expect(page).to have_no_button("Up")
103
+ end
104
+ end
105
+ end
106
+
107
+ it "cannot be moved down" do
108
+ within "form.edit_questionnaire" do
109
+ within ".questionnaire-question" do
110
+ expect(page).to have_no_button("Down")
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ context "when a questionnaire has an existing question with answer options" do
117
+ let!(:question) do
118
+ create(
119
+ :questionnaire_question,
120
+ questionnaire: questionnaire,
121
+ body: body,
122
+ question_type: "single_option",
123
+ options: [
124
+ { "body" => { "en" => "cacatua" } },
125
+ { "body" => { "en" => "cat" } },
126
+ { "body" => { "en" => "dog" } }
127
+
128
+ ]
129
+ )
130
+ end
131
+
132
+ before do
133
+ visit questionnaire_edit_path
134
+ end
135
+
136
+ it "allows deleting answer options" do
137
+ expand_all_questions
138
+
139
+ within ".questionnaire-question-answer-option:last-of-type" do
140
+ click_button "Remove"
141
+ end
142
+
143
+ click_button "Save"
144
+
145
+ visit_questionnaire_edit_path_and_expand_all
146
+
147
+ expect(page).to have_selector(".questionnaire-question-answer-option", count: 2)
148
+ end
149
+
150
+ it "still removes the question even if previous editions rendered the options invalid" do
151
+ within "form.edit_questionnaire" do
152
+ expect(page).to have_selector(".questionnaire-question", count: 1)
153
+
154
+ expand_all_questions
155
+
156
+ within ".questionnaire-question-answer-option:first-of-type" do
157
+ fill_in find_nested_form_field_locator("body_en"), with: ""
158
+ end
159
+
160
+ within ".questionnaire-question" do
161
+ click_button "Remove", match: :first
162
+ end
163
+
164
+ click_button "Save"
165
+ end
166
+
167
+ expect(page).to have_admin_callout("successfully")
168
+
169
+ visit_questionnaire_edit_path_and_expand_all
170
+
171
+ within "form.edit_questionnaire" do
172
+ expect(page).to have_selector(".questionnaire-question", count: 0)
173
+ end
174
+ end
175
+ end
176
+
177
+ context "when a questionnaire has an existing question with matrix rows" do
178
+ let!(:other_question) { create(:questionnaire_question, questionnaire: questionnaire, position: 1) }
179
+ let!(:question) do
180
+ create(
181
+ :questionnaire_question,
182
+ questionnaire: questionnaire,
183
+ body: body,
184
+ question_type: "matrix_single",
185
+ position: 2,
186
+ options: [
187
+ { "body" => { "en" => "cacatua" } },
188
+ { "body" => { "en" => "cat" } },
189
+ { "body" => { "en" => "dog" } }
190
+ ],
191
+ rows: [
192
+ { "body" => { "en" => "cute" } },
193
+ { "body" => { "en" => "ugly" } },
194
+ { "body" => { "en" => "meh" } }
195
+ ]
196
+ )
197
+ end
198
+
199
+ before do
200
+ visit_questionnaire_edit_path_and_expand_all
201
+ end
202
+
203
+ it "allows deleting matrix rows" do
204
+ within ".questionnaire-question-matrix-row:last-of-type" do
205
+ click_button "Remove"
206
+ end
207
+
208
+ click_button "Save"
209
+
210
+ visit_questionnaire_edit_path_and_expand_all
211
+
212
+ within ".questionnaire-question:last-of-type" do
213
+ expect(page).to have_selector(".questionnaire-question-matrix-row", count: 2)
214
+ expect(page).to have_selector(".questionnaire-question-answer-option", count: 3)
215
+ end
216
+ end
217
+
218
+ it "still removes the question even if previous editions rendered the rows invalid" do
219
+ within "form.edit_questionnaire" do
220
+ expect(page).to have_selector(".questionnaire-question", count: 2)
221
+
222
+ within ".questionnaire-question-matrix-row:first-of-type" do
223
+ fill_in find_nested_form_field_locator("body_en"), with: ""
224
+ end
225
+
226
+ within ".questionnaire-question:last-of-type" do
227
+ click_button "Remove", match: :first
228
+ end
229
+
230
+ click_button "Save"
231
+ end
232
+
233
+ expect(page).to have_admin_callout("successfully")
234
+
235
+ visit_questionnaire_edit_path_and_expand_all
236
+
237
+ within "form.edit_questionnaire" do
238
+ expect(page).to have_selector(".questionnaire-question", count: 1)
239
+ end
240
+ end
241
+ end
242
+
243
+ context "when a questionnaire has multiple existing questions" do
244
+ let!(:question_1) do
245
+ create(:questionnaire_question, questionnaire: questionnaire, body: first_body, position: 0)
246
+ end
247
+
248
+ let!(:question_2) do
249
+ create(:questionnaire_question, questionnaire: questionnaire, body: second_body, position: 1)
250
+ end
251
+
252
+ let(:first_body) do
253
+ { en: "First", ca: "Primera", es: "Primera" }
254
+ end
255
+
256
+ let(:second_body) do
257
+ { en: "Second", ca: "Segona", es: "Segunda" }
258
+ end
259
+
260
+ before do
261
+ visit questionnaire_edit_path
262
+ expand_all_questions
263
+ end
264
+
265
+ shared_examples_for "switching questions order" do
266
+ it "properly reorders the questions" do
267
+ within ".questionnaire-question:first-of-type" do
268
+ expect(page).to have_nested_field("body_en", with: "Second")
269
+ expect(page).to look_like_first_question
270
+ end
271
+
272
+ within ".questionnaire-question:last-of-type" do
273
+ expect(page).to have_nested_field("body_en", with: "First")
274
+ expect(page).to look_like_last_question
275
+ end
276
+ end
277
+ end
278
+
279
+ context "when moving a question up" do
280
+ before do
281
+ within ".questionnaire-question:last-of-type" do
282
+ click_button "Up"
283
+ end
284
+ end
285
+
286
+ it_behaves_like "switching questions order"
287
+ end
288
+
289
+ context "when moving a question down" do
290
+ before do
291
+ within ".questionnaire-question:first-of-type" do
292
+ click_button "Down"
293
+ end
294
+ end
295
+
296
+ it_behaves_like "switching questions order"
297
+ end
298
+
299
+ describe "collapsible questions" do
300
+ context "when clicking on Expand all button" do
301
+ it "expands all questions" do
302
+ click_button "Expand all questions"
303
+ expect(page).to have_selector(".collapsible", visible: :all)
304
+ expect(page).to have_selector(".question--collapse .icon-collapse", count: questionnaire.questions.count)
305
+ end
306
+ end
307
+
308
+ context "when clicking on Collapse all button" do
309
+ it "collapses all questions" do
310
+ click_button "Collapse all questions"
311
+ expect(page).not_to have_selector(".collapsible", visible: :visible)
312
+ expect(page).to have_selector(".question--collapse .icon-expand", count: questionnaire.questions.count)
313
+ end
314
+ end
315
+
316
+ shared_examples_for "collapsing a question" do
317
+ it "changes the toggle button" do
318
+ within ".questionnaire-question:last-of-type" do
319
+ expect(page).to have_selector(".icon-expand")
320
+ end
321
+ end
322
+
323
+ it "hides the question card section" do
324
+ within ".questionnaire-question:last-of-type" do
325
+ expect(page).not_to have_selector(".collapsible", visible: :visible)
326
+ end
327
+ end
328
+ end
329
+
330
+ shared_examples_for "uncollapsing a question" do
331
+ it "changes the toggle button" do
332
+ within ".questionnaire-question:last-of-type" do
333
+ expect(page).to have_selector(".icon-collapse")
334
+ end
335
+ end
336
+
337
+ it "shows the question card section" do
338
+ expect(page).to have_selector(".collapsible", visible: :visible)
339
+ end
340
+ end
341
+
342
+ context "when collapsing an existing question" do
343
+ before do
344
+ expand_all_questions
345
+ within ".questionnaire-question:last-of-type" do
346
+ page.find(".question--collapse").click
347
+ end
348
+ end
349
+
350
+ it_behaves_like "collapsing a question"
351
+ end
352
+
353
+ context "when adding a new question" do
354
+ before do
355
+ click_button "Add question"
356
+ expand_all_questions
357
+
358
+ within ".questionnaire-question:last-of-type" do
359
+ page.find(".question--collapse").click
360
+ end
361
+ end
362
+
363
+ it_behaves_like "collapsing a question"
364
+ end
365
+
366
+ context "when submitting a new question with an error" do
367
+ before do
368
+ click_button "Add question"
369
+ click_button "Save"
370
+
371
+ within ".questionnaire-question:last-of-type" do
372
+ page.find(".question--collapse").click
373
+ end
374
+ end
375
+
376
+ it_behaves_like "collapsing a question"
377
+
378
+ it "can be expanded" do
379
+ within ".questionnaire-question:last-of-type" do
380
+ page.find(".question--collapse").click
381
+ end
382
+
383
+ within ".questionnaire-question:last-of-type" do
384
+ expect(page).to have_selector(".icon-collapse")
385
+ end
386
+ end
387
+ end
388
+ end
389
+
390
+ it "properly decides which button to show after adding/removing questions" do
391
+ click_button "Add question"
392
+ expand_all_questions
393
+
394
+ expect(page.find(".questionnaire-question:nth-of-type(1)")).to look_like_first_question
395
+ expect(page.find(".questionnaire-question:nth-of-type(2)")).to look_like_intermediate_question
396
+ expect(page.find(".questionnaire-question:nth-of-type(3)")).to look_like_last_question
397
+
398
+ within ".questionnaire-question:first-of-type" do
399
+ click_button "Remove"
400
+ end
401
+
402
+ expect(page.all(".questionnaire-question").first).to look_like_first_question
403
+ expect(page.all(".questionnaire-question").last).to look_like_last_question
404
+ end
405
+
406
+ it "does not duplicate editors when adding new questions" do
407
+ expect do
408
+ click_button "Add question"
409
+ expand_all_questions
410
+ end.to change { page.all(".ql-toolbar").size }.by(1)
411
+ end
412
+
413
+ it "properly decides which button to show after adding/removing answer options" do
414
+ click_button "Add question"
415
+ expand_all_questions
416
+
417
+ within ".questionnaire-question:last-of-type" do
418
+ select "Single option", from: "Type"
419
+
420
+ within ".questionnaire-question-answer-options-list" do
421
+ expect(page).to have_no_button("Remove")
422
+ end
423
+
424
+ click_button "Add answer option"
425
+
426
+ expect(page.all(".questionnaire-question-answer-option")).to all(have_button("Remove"))
427
+
428
+ within ".questionnaire-question-answer-option:first-of-type" do
429
+ click_button "Remove"
430
+ end
431
+
432
+ within ".questionnaire-question-answer-options-list" do
433
+ expect(page).to have_no_button("Remove")
434
+ end
435
+ end
436
+
437
+ click_button "Save"
438
+ expand_all_questions
439
+
440
+ within ".questionnaire-question:last-of-type" do
441
+ within ".questionnaire-question-answer-options-list" do
442
+ expect(page).to have_no_button("Remove")
443
+ end
444
+ end
445
+ end
446
+
447
+ private
448
+
449
+ def look_like_first_question
450
+ have_no_button("Up").and have_button("Down")
451
+ end
452
+
453
+ def look_like_intermediate_question
454
+ have_button("Up").and have_button("Down")
455
+ end
456
+
457
+ def look_like_last_question
458
+ have_button("Up").and have_no_button("Down")
459
+ end
460
+ end
461
+ end