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,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