decidim-forms 0.23.2 → 0.24.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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/decidim/forms/forms.js.es6 +4 -4
- data/app/commands/decidim/forms/admin/update_questionnaire.rb +2 -1
- data/app/commands/decidim/forms/answer_questionnaire.rb +43 -1
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +10 -2
- data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +10 -4
- data/app/forms/decidim/forms/admin/question_form.rb +2 -0
- data/app/forms/decidim/forms/answer_form.rb +27 -0
- data/app/helpers/decidim/forms/admin/application_helper.rb +1 -6
- data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_url_helper.rb +3 -3
- data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +1 -1
- data/app/models/decidim/forms/answer.rb +8 -0
- data/app/models/decidim/forms/question.rb +9 -3
- data/app/models/decidim/forms/questionnaire.rb +2 -0
- data/app/presenters/decidim/forms/admin/questionnaire_answer_presenter.rb +20 -0
- data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +4 -4
- data/app/queries/decidim/forms/questionnaire_user_answers.rb +2 -1
- data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +3 -3
- data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +11 -0
- data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +1 -1
- data/app/views/decidim/forms/questionnaires/_answer.html.erb +1 -1
- data/app/views/decidim/forms/questionnaires/answers/_files.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/answers/_long_answer.html.erb +1 -1
- data/app/views/decidim/forms/questionnaires/answers/_matrix_multiple.html.erb +2 -1
- data/app/views/decidim/forms/questionnaires/answers/_matrix_single.html.erb +2 -1
- data/app/views/decidim/forms/questionnaires/answers/_multiple_option.html.erb +2 -1
- data/app/views/decidim/forms/questionnaires/answers/_short_answer.html.erb +1 -1
- data/app/views/decidim/forms/questionnaires/answers/_single_option.html.erb +2 -1
- data/app/views/decidim/forms/questionnaires/show.html.erb +1 -1
- data/config/initializers/wicked_pdf.rb +2 -0
- data/config/locales/ca.yml +8 -2
- data/config/locales/cs.yml +8 -2
- data/config/locales/de.yml +8 -2
- data/config/locales/el.yml +1 -1
- data/config/locales/en.yml +8 -2
- data/config/locales/es-MX.yml +8 -2
- data/config/locales/es-PY.yml +8 -2
- data/config/locales/es.yml +8 -2
- data/config/locales/fi-plain.yml +8 -2
- data/config/locales/fi.yml +8 -2
- data/config/locales/fr-CA.yml +8 -2
- data/config/locales/fr.yml +9 -3
- data/config/locales/gl.yml +2 -1
- data/config/locales/it.yml +1 -2
- data/config/locales/ja.yml +2 -2
- data/config/locales/lv.yml +1 -1
- data/config/locales/nl.yml +4 -5
- data/config/locales/no.yml +1 -2
- data/config/locales/pl.yml +11 -2
- data/config/locales/pt.yml +1 -2
- data/config/locales/ro-RO.yml +13 -2
- data/config/locales/sv.yml +1 -2
- data/config/locales/tr-TR.yml +2 -2
- data/config/locales/zh-CN.yml +1 -2
- data/db/migrate/20210208094442_add_max_characters_to_decidim_forms_questions.rb +7 -0
- data/lib/decidim/api/answer_option_type.rb +13 -0
- data/lib/decidim/api/question_type.rb +21 -0
- data/lib/decidim/api/questionnaire_entity_interface.rb +5 -5
- data/lib/decidim/api/questionnaire_type.rb +19 -0
- data/lib/decidim/exporters/form_pdf_controller_helper.rb +2 -0
- data/lib/decidim/forms.rb +1 -1
- data/lib/decidim/forms/api.rb +3 -0
- data/lib/decidim/forms/data_portability_user_answers_serializer.rb +7 -1
- data/lib/decidim/forms/test/factories.rb +12 -2
- data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +38 -5
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +5 -4
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +7 -3
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +1 -1
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +5 -0
- data/lib/decidim/forms/user_answers_serializer.rb +9 -1
- data/lib/decidim/forms/version.rb +1 -1
- metadata +15 -13
- data/app/types/decidim/forms/answer_option_type.rb +0 -14
- data/app/types/decidim/forms/question_type.rb +0 -23
- data/app/types/decidim/forms/questionnaire_type.rb +0 -22
data/config/locales/zh-CN.yml
CHANGED
|
@@ -78,7 +78,6 @@ zh-CN:
|
|
|
78
78
|
collapse: 收起所有问题
|
|
79
79
|
expand: 展开所有问题
|
|
80
80
|
preview: 预览
|
|
81
|
-
title: 编辑表单
|
|
82
81
|
unpublished_warning: 表单未发布。您可以修改它的问题,但这样做将删除当前答案。
|
|
83
82
|
matrix_row:
|
|
84
83
|
matrix_row: 行
|
|
@@ -110,7 +109,7 @@ zh-CN:
|
|
|
110
109
|
answer:
|
|
111
110
|
body: 主体不能为空
|
|
112
111
|
files:
|
|
113
|
-
|
|
112
|
+
extension_allowlist: '接受的格式:'
|
|
114
113
|
images:
|
|
115
114
|
dimensions: "%{width} x %{height} px"
|
|
116
115
|
dimensions_info: '这张图片将是:'
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Forms
|
|
5
|
+
class AnswerOptionType < Decidim::Api::Types::BaseObject
|
|
6
|
+
description "An answer option for a multi-choice question in a questionnaire"
|
|
7
|
+
|
|
8
|
+
field :id, GraphQL::Types::ID, "ID of this answer option", null: false
|
|
9
|
+
field :body, Decidim::Core::TranslatedFieldType, "The text answer response option.", null: false
|
|
10
|
+
field :free_text, GraphQL::Types::Boolean, "Whether if this answer accepts any free text from the user.", null: false
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Forms
|
|
5
|
+
class QuestionType < Decidim::Api::Types::BaseObject
|
|
6
|
+
description "A question in a questionnaire"
|
|
7
|
+
|
|
8
|
+
implements Decidim::Core::TimestampsInterface
|
|
9
|
+
|
|
10
|
+
field :id, GraphQL::Types::ID, "ID of this question", null: false
|
|
11
|
+
field :body, Decidim::Core::TranslatedFieldType, "What is being asked in this question.", null: false
|
|
12
|
+
field :description, Decidim::Core::TranslatedFieldType, "The description of this question.", null: true
|
|
13
|
+
field :mandatory, GraphQL::Types::Boolean, "Whether if this question is mandatory.", null: false
|
|
14
|
+
field :position, GraphQL::Types::Int, "Order position of the question in the questionnaire", null: true
|
|
15
|
+
field :max_choices, GraphQL::Types::Int, "On questions with answer options, maximum number of choices the user has", null: true
|
|
16
|
+
field :max_characters, GraphQL::Types::Int, "On questions with free text answers, maximum number of characters the answer can have (0 if no limit)", null: false
|
|
17
|
+
field :question_type, GraphQL::Types::String, "Type of question.", null: true
|
|
18
|
+
field :answer_options, [AnswerOptionType, { null: true }], "List of answer options in multi-choice questions.", null: false
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -4,15 +4,15 @@ module Decidim
|
|
|
4
4
|
module Forms
|
|
5
5
|
# This interface should be implemented by any Type that can be linked to a questionnaire
|
|
6
6
|
# The only requirement is to have an ID and the Type name be the class.name + Type
|
|
7
|
-
QuestionnaireEntityInterface
|
|
8
|
-
|
|
7
|
+
module QuestionnaireEntityInterface
|
|
8
|
+
include Decidim::Api::Types::BaseInterface
|
|
9
9
|
description "An interface that can be used in objects with questionnaires"
|
|
10
10
|
|
|
11
|
-
field :id,
|
|
11
|
+
field :id, GraphQL::Types::ID, "ID of this entity", null: false
|
|
12
12
|
|
|
13
|
-
resolve_type
|
|
13
|
+
def self.resolve_type(obj, _ctx)
|
|
14
14
|
"#{obj.class.name}Type".constantize
|
|
15
|
-
|
|
15
|
+
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Forms
|
|
5
|
+
class QuestionnaireType < Decidim::Api::Types::BaseObject
|
|
6
|
+
description "A questionnaire"
|
|
7
|
+
|
|
8
|
+
implements Decidim::Core::TimestampsInterface
|
|
9
|
+
|
|
10
|
+
field :id, GraphQL::Types::ID, "ID of this questionnaire", null: false
|
|
11
|
+
field :title, Decidim::Core::TranslatedFieldType, "The title of this questionnaire.", null: false
|
|
12
|
+
field :description, Decidim::Core::TranslatedFieldType, "The description of this questionnaire.", null: true
|
|
13
|
+
field :tos, Decidim::Core::TranslatedFieldType, "The Terms of Service for this questionnaire.", null: true
|
|
14
|
+
field :for_type, GraphQL::Types::String, "Type of entity using this questionnaire.", method: :questionnaire_for_type, null: true
|
|
15
|
+
field :for_entity, QuestionnaireEntityInterface, "Entity using this questionnaire.", method: :questionnaire_for, null: true
|
|
16
|
+
field :questions, [Decidim::Forms::QuestionType, { null: true }], "Questions in this questionnaire.", null: false
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module Decidim
|
|
4
4
|
module Exporters
|
|
5
|
+
# rubocop: disable Rails/ApplicationController
|
|
5
6
|
# A dummy controller to render views while exporting questionnaires
|
|
6
7
|
class FormPDFControllerHelper < ActionController::Base
|
|
8
|
+
# rubocop: enable Rails/ApplicationController
|
|
7
9
|
helper Decidim::TranslationsHelper
|
|
8
10
|
helper Decidim::Forms::Admin::QuestionnaireAnswersHelper
|
|
9
11
|
end
|
data/lib/decidim/forms.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "decidim/forms/admin"
|
|
4
|
+
require "decidim/forms/api"
|
|
4
5
|
require "decidim/forms/engine"
|
|
5
6
|
require "decidim/forms/admin_engine"
|
|
6
|
-
require "decidim/forms/api"
|
|
7
7
|
|
|
8
8
|
module Decidim
|
|
9
9
|
# This namespace holds the logic of the `Forms`.
|
data/lib/decidim/forms/api.rb
CHANGED
|
@@ -3,5 +3,8 @@
|
|
|
3
3
|
module Decidim
|
|
4
4
|
module Forms
|
|
5
5
|
autoload :QuestionnaireEntityInterface, "decidim/api/questionnaire_entity_interface"
|
|
6
|
+
autoload :AnswerOptionType, "decidim/api/answer_option_type"
|
|
7
|
+
autoload :QuestionType, "decidim/api/question_type"
|
|
8
|
+
autoload :QuestionnaireType, "decidim/api/questionnaire_type"
|
|
6
9
|
end
|
|
7
10
|
end
|
|
@@ -30,7 +30,13 @@ module Decidim
|
|
|
30
30
|
private
|
|
31
31
|
|
|
32
32
|
def normalize_body(resource)
|
|
33
|
-
resource.body || resource.choices.pluck(:body)
|
|
33
|
+
attachments_for(resource) || resource.body || resource.choices.pluck(:body)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def attachments_for(resource)
|
|
37
|
+
return if resource.attachments.blank?
|
|
38
|
+
|
|
39
|
+
resource.attachments.map(&:url)
|
|
34
40
|
end
|
|
35
41
|
end
|
|
36
42
|
end
|
|
@@ -17,10 +17,13 @@ FactoryBot.define do
|
|
|
17
17
|
|
|
18
18
|
trait :with_questions do
|
|
19
19
|
questions do
|
|
20
|
+
position = 0
|
|
20
21
|
qs = %w(short_answer long_answer).collect do |text_question_type|
|
|
21
|
-
build(:questionnaire_question, question_type: text_question_type)
|
|
22
|
+
q = build(:questionnaire_question, question_type: text_question_type, position: position)
|
|
23
|
+
position += 1
|
|
24
|
+
q
|
|
22
25
|
end
|
|
23
|
-
qs << build(:questionnaire_question, :with_answer_options, question_type: :single_option)
|
|
26
|
+
qs << build(:questionnaire_question, :with_answer_options, question_type: :single_option, position: position)
|
|
24
27
|
qs
|
|
25
28
|
end
|
|
26
29
|
end
|
|
@@ -91,6 +94,13 @@ FactoryBot.define do
|
|
|
91
94
|
question { create(:questionnaire_question, questionnaire: questionnaire) }
|
|
92
95
|
user { create(:user, organization: questionnaire.questionnaire_for.organization) }
|
|
93
96
|
session_token { Digest::MD5.hexdigest(user.id.to_s) }
|
|
97
|
+
|
|
98
|
+
trait :with_attachments do
|
|
99
|
+
after(:create) do |answer, _evaluator|
|
|
100
|
+
create :attachment, :with_image, attached_to: answer
|
|
101
|
+
create :attachment, :with_pdf, attached_to: answer
|
|
102
|
+
end
|
|
103
|
+
end
|
|
94
104
|
end
|
|
95
105
|
|
|
96
106
|
factory :answer_option, class: "Decidim::Forms::AnswerOption" do
|
|
@@ -194,6 +194,28 @@ shared_examples_for "has questionnaire" do
|
|
|
194
194
|
end
|
|
195
195
|
end
|
|
196
196
|
|
|
197
|
+
shared_examples_for "question has a character limit" do
|
|
198
|
+
context "when max_characters value is positive" do
|
|
199
|
+
let(:max_characters) { 30 }
|
|
200
|
+
|
|
201
|
+
it "shows a message indicating number of characters left" do
|
|
202
|
+
visit questionnaire_public_path
|
|
203
|
+
|
|
204
|
+
expect(page).to have_content("30 characters left")
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
context "when max_characters value is 0" do
|
|
209
|
+
let(:max_characters) { 0 }
|
|
210
|
+
|
|
211
|
+
it "doesn't show message indicating number of characters left" do
|
|
212
|
+
visit questionnaire_public_path
|
|
213
|
+
|
|
214
|
+
expect(page).not_to have_content("characters left")
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
197
219
|
describe "leaving a blank question (without js)", driver: :rack_test do
|
|
198
220
|
include_context "when a non multiple choice question is mandatory"
|
|
199
221
|
|
|
@@ -268,12 +290,13 @@ shared_examples_for "has questionnaire" do
|
|
|
268
290
|
|
|
269
291
|
describe "free text options" do
|
|
270
292
|
let(:answer_option_bodies) { Array.new(3) { Decidim::Faker::Localized.sentence } }
|
|
271
|
-
|
|
293
|
+
let(:max_characters) { 0 }
|
|
272
294
|
let!(:question) do
|
|
273
295
|
create(
|
|
274
296
|
:questionnaire_question,
|
|
275
297
|
questionnaire: questionnaire,
|
|
276
298
|
question_type: question_type,
|
|
299
|
+
max_characters: max_characters,
|
|
277
300
|
position: 1,
|
|
278
301
|
options: [
|
|
279
302
|
{ "body" => answer_option_bodies[0] },
|
|
@@ -346,6 +369,8 @@ shared_examples_for "has questionnaire" do
|
|
|
346
369
|
|
|
347
370
|
expect(page).to have_field("questionnaire_responses_0_choices_2_custom_body", with: "Cacatua")
|
|
348
371
|
end
|
|
372
|
+
|
|
373
|
+
it_behaves_like "question has a character limit"
|
|
349
374
|
end
|
|
350
375
|
|
|
351
376
|
context "when question is multiple_option type" do
|
|
@@ -392,27 +417,35 @@ shared_examples_for "has questionnaire" do
|
|
|
392
417
|
|
|
393
418
|
expect(page).to have_field("questionnaire_responses_0_choices_2_custom_body", with: "Cacatua")
|
|
394
419
|
end
|
|
420
|
+
|
|
421
|
+
it_behaves_like "question has a character limit"
|
|
395
422
|
end
|
|
396
423
|
end
|
|
397
424
|
|
|
398
425
|
context "when question type is long answer" do
|
|
399
|
-
let
|
|
426
|
+
let(:max_characters) { 0 }
|
|
427
|
+
let!(:question) { create(:questionnaire_question, questionnaire: questionnaire, question_type: "long_answer", max_characters: max_characters) }
|
|
400
428
|
|
|
401
429
|
it "renders the answer as a textarea" do
|
|
402
430
|
visit questionnaire_public_path
|
|
403
431
|
|
|
404
432
|
expect(page).to have_selector("textarea#questionnaire_responses_0")
|
|
405
433
|
end
|
|
434
|
+
|
|
435
|
+
it_behaves_like "question has a character limit"
|
|
406
436
|
end
|
|
407
437
|
|
|
408
438
|
context "when question type is short answer" do
|
|
409
|
-
let
|
|
439
|
+
let(:max_characters) { 0 }
|
|
440
|
+
let!(:question) { create(:questionnaire_question, questionnaire: questionnaire, question_type: "short_answer", max_characters: max_characters) }
|
|
410
441
|
|
|
411
442
|
it "renders the answer as a text field" do
|
|
412
443
|
visit questionnaire_public_path
|
|
413
444
|
|
|
414
445
|
expect(page).to have_selector("input[type=text]#questionnaire_responses_0")
|
|
415
446
|
end
|
|
447
|
+
|
|
448
|
+
it_behaves_like "question has a character limit"
|
|
416
449
|
end
|
|
417
450
|
|
|
418
451
|
context "when question type is single option" do
|
|
@@ -665,7 +698,7 @@ shared_examples_for "has questionnaire" do
|
|
|
665
698
|
end
|
|
666
699
|
|
|
667
700
|
radio_buttons = page.all(".radio-button-collection input[type=radio]")
|
|
668
|
-
expect(radio_buttons.
|
|
701
|
+
expect(radio_buttons.pluck(:checked)).to eq([nil, "true", nil, nil])
|
|
669
702
|
end
|
|
670
703
|
|
|
671
704
|
context "when the question is mandatory and the answer is not complete" do
|
|
@@ -830,7 +863,7 @@ shared_examples_for "has questionnaire" do
|
|
|
830
863
|
end
|
|
831
864
|
|
|
832
865
|
checkboxes = page.all(".check-box-collection input[type=checkbox]")
|
|
833
|
-
expect(checkboxes.
|
|
866
|
+
expect(checkboxes.pluck(:checked)).to eq(["true", "true", "true", nil, nil, "true"])
|
|
834
867
|
end
|
|
835
868
|
end
|
|
836
869
|
end
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
4
|
|
|
5
|
-
require "decidim/forms/test/shared_examples/manage_questionnaires/add_questions
|
|
6
|
-
require "decidim/forms/test/shared_examples/manage_questionnaires/update_questions
|
|
7
|
-
require "decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions
|
|
8
|
-
require "decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions
|
|
5
|
+
require "decidim/forms/test/shared_examples/manage_questionnaires/add_questions"
|
|
6
|
+
require "decidim/forms/test/shared_examples/manage_questionnaires/update_questions"
|
|
7
|
+
require "decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions"
|
|
8
|
+
require "decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions"
|
|
9
9
|
|
|
10
10
|
shared_examples_for "manage questionnaires" do
|
|
11
11
|
let(:body) do
|
|
@@ -63,6 +63,7 @@ shared_examples_for "manage questionnaires" do
|
|
|
63
63
|
expect(page).to have_selector("input[value='This is the first question'][disabled]")
|
|
64
64
|
expect(page).to have_selector("select[id$=question_type][disabled]")
|
|
65
65
|
expect(page).to have_selector("select[id$=max_choices][disabled]")
|
|
66
|
+
expect(page).to have_selector("input[id$=max_characters][disabled]")
|
|
66
67
|
expect(page).to have_selector(".ql-editor[contenteditable=false]")
|
|
67
68
|
end
|
|
68
69
|
end
|
|
@@ -39,18 +39,21 @@ shared_examples_for "add display conditions" do
|
|
|
39
39
|
context "when questionnaire has more than one question" do
|
|
40
40
|
let!(:question_short_answer) do
|
|
41
41
|
create(:questionnaire_question,
|
|
42
|
+
position: 0,
|
|
42
43
|
questionnaire: questionnaire,
|
|
43
44
|
body: Decidim::Faker::Localized.sentence,
|
|
44
45
|
question_type: "short_answer")
|
|
45
46
|
end
|
|
46
47
|
let!(:question_long_answer) do
|
|
47
48
|
create(:questionnaire_question,
|
|
49
|
+
position: 1,
|
|
48
50
|
questionnaire: questionnaire,
|
|
49
51
|
body: Decidim::Faker::Localized.sentence,
|
|
50
52
|
question_type: "long_answer")
|
|
51
53
|
end
|
|
52
54
|
let!(:question_single_option) do
|
|
53
55
|
create(:questionnaire_question,
|
|
56
|
+
position: 2,
|
|
54
57
|
questionnaire: questionnaire,
|
|
55
58
|
body: Decidim::Faker::Localized.sentence,
|
|
56
59
|
question_type: "single_option",
|
|
@@ -58,6 +61,7 @@ shared_examples_for "add display conditions" do
|
|
|
58
61
|
end
|
|
59
62
|
let!(:question_multiple_option) do
|
|
60
63
|
create(:questionnaire_question,
|
|
64
|
+
position: 3,
|
|
61
65
|
questionnaire: questionnaire,
|
|
62
66
|
body: Decidim::Faker::Localized.sentence,
|
|
63
67
|
question_type: "multiple_option",
|
|
@@ -101,7 +105,7 @@ shared_examples_for "add display conditions" do
|
|
|
101
105
|
|
|
102
106
|
within "select[id$=decidim_condition_question_id]" do
|
|
103
107
|
elements = page.all("option[data-type]")
|
|
104
|
-
expect(elements.map { |element| element[:"data-type"] }).to
|
|
108
|
+
expect(elements.map { |element| element[:"data-type"] }).to match_array(questions.map(&:question_type))
|
|
105
109
|
expect(page.find("option[value='#{questions.last.id}']")).to be_disabled
|
|
106
110
|
end
|
|
107
111
|
end
|
|
@@ -117,7 +121,7 @@ shared_examples_for "add display conditions" do
|
|
|
117
121
|
option_elements = page.all("select[id$=condition_type] option")
|
|
118
122
|
option_elements = option_elements.to_a.reject { |option| option[:style].match? "display: none" }
|
|
119
123
|
|
|
120
|
-
expect(option_elements.map(&:text)).to
|
|
124
|
+
expect(option_elements.map(&:text)).to match_array(options)
|
|
121
125
|
end
|
|
122
126
|
end
|
|
123
127
|
end
|
|
@@ -132,7 +136,7 @@ shared_examples_for "add display conditions" do
|
|
|
132
136
|
option_elements = page.all("select[id$=condition_type] option")
|
|
133
137
|
option_elements = option_elements.to_a.reject { |option| option[:style].match? "display: none" }
|
|
134
138
|
|
|
135
|
-
expect(option_elements.map(&:text)).to
|
|
139
|
+
expect(option_elements.map(&:text)).to match_array(options)
|
|
136
140
|
end
|
|
137
141
|
end
|
|
138
142
|
end
|
|
@@ -41,7 +41,7 @@ shared_examples_for "add questions" do
|
|
|
41
41
|
within ".questionnaire-question" do
|
|
42
42
|
fill_in find_nested_form_field_locator("body_en"), with: "Body"
|
|
43
43
|
|
|
44
|
-
fill_in_editor find_nested_form_field_locator("description_en", visible: false), with: "<
|
|
44
|
+
fill_in_editor find_nested_form_field_locator("description_en", visible: false), with: "<strong>Superkalifragilistic description</strong>"
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
click_button "Save"
|
|
@@ -15,6 +15,7 @@ shared_examples_for "update questions" do
|
|
|
15
15
|
within "form.edit_questionnaire" do
|
|
16
16
|
within ".questionnaire-question" do
|
|
17
17
|
fill_in "questionnaire_questions_#{question.id}_body_en", with: "Modified question"
|
|
18
|
+
fill_in "questionnaire_questions_#{question.id}_max_characters", with: 30
|
|
18
19
|
check "Mandatory"
|
|
19
20
|
select "Long answer", from: "Type"
|
|
20
21
|
end
|
|
@@ -29,6 +30,7 @@ shared_examples_for "update questions" do
|
|
|
29
30
|
expect(page).to have_selector("input[value='Modified question']")
|
|
30
31
|
expect(page).to have_no_selector("input[value='This is the first question']")
|
|
31
32
|
expect(page).to have_selector("input#questionnaire_questions_#{question.id}_mandatory[checked]")
|
|
33
|
+
expect(page).to have_selector("input#questionnaire_questions_#{question.id}_max_characters[value='30']")
|
|
32
34
|
expect(page).to have_selector("select#questionnaire_questions_#{question.id}_question_type option[value='long_answer'][selected]")
|
|
33
35
|
end
|
|
34
36
|
|
|
@@ -39,6 +41,7 @@ shared_examples_for "update questions" do
|
|
|
39
41
|
within ".questionnaire-question" do
|
|
40
42
|
expect(page).to have_content("Statement*")
|
|
41
43
|
fill_in "questionnaire_questions_#{question.id}_body_en", with: ""
|
|
44
|
+
fill_in "questionnaire_questions_#{question.id}_max_characters", with: -3
|
|
42
45
|
check "Mandatory"
|
|
43
46
|
select "Matrix (Multiple option)", from: "Type"
|
|
44
47
|
select "2", from: "Maximum number of choices"
|
|
@@ -51,10 +54,12 @@ shared_examples_for "update questions" do
|
|
|
51
54
|
|
|
52
55
|
expect(page).to have_admin_callout("There was a problem saving")
|
|
53
56
|
expect(page).to have_content("can't be blank", count: 5) # emtpy question, 2 empty default answer options, 2 empty default matrix rows
|
|
57
|
+
expect(page).to have_content("must be greater than or equal to 0", count: 1)
|
|
54
58
|
|
|
55
59
|
expect(page).to have_selector("input[value='']")
|
|
56
60
|
expect(page).to have_no_selector("input[value='This is the first question']")
|
|
57
61
|
expect(page).to have_selector("input#questionnaire_questions_#{question.id}_mandatory[checked]")
|
|
62
|
+
expect(page).to have_selector("input#questionnaire_questions_#{question.id}_max_characters[value='-3']")
|
|
58
63
|
expect(page).to have_select("Maximum number of choices", selected: "2")
|
|
59
64
|
expect(page).to have_selector("select#questionnaire_questions_#{question.id}_question_type option[value='matrix_multiple'][selected]")
|
|
60
65
|
end
|
|
@@ -28,7 +28,15 @@ module Decidim
|
|
|
28
28
|
private
|
|
29
29
|
|
|
30
30
|
def normalize_body(answer)
|
|
31
|
-
answer.body ||
|
|
31
|
+
answer.body ||
|
|
32
|
+
normalize_attachments(answer) ||
|
|
33
|
+
normalize_choices(answer, answer.choices)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def normalize_attachments(answer)
|
|
37
|
+
return if answer.attachments.blank?
|
|
38
|
+
|
|
39
|
+
answer.attachments.map(&:url)
|
|
32
40
|
end
|
|
33
41
|
|
|
34
42
|
def normalize_choices(answer, choices)
|