surveyor_gui 0.0.3
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 +7 -0
- data/.gitignore +44 -0
- data/.travis.yml +17 -0
- data/Gemfile +7 -0
- data/LICENSE +21 -0
- data/MIT-LICENSE +20 -0
- data/README.md +159 -0
- data/Rakefile +66 -0
- data/app/controllers/answers_controller.rb +3 -0
- data/app/controllers/application_controller.rb +3 -0
- data/app/controllers/dependencys_controller.rb +286 -0
- data/app/controllers/question_groups_controller.rb +84 -0
- data/app/controllers/questions_controller.rb +187 -0
- data/app/controllers/survey_sections_controller.rb +80 -0
- data/app/controllers/surveyforms_controller.rb +4 -0
- data/app/controllers/surveyor_controller.rb +89 -0
- data/app/controllers/surveyor_gui/reports_controller.rb +339 -0
- data/app/controllers/surveyor_gui/responses_controller.rb +39 -0
- data/app/controllers/surveyor_gui/survey_controller.rb +16 -0
- data/app/facades/report_formatter.rb +44 -0
- data/app/facades/report_preview_wrapper.rb +11 -0
- data/app/facades/report_response_generator.rb +147 -0
- data/app/helpers/application_helper.rb +2 -0
- data/app/helpers/dependency_helper.rb +5 -0
- data/app/helpers/question_helper.rb +22 -0
- data/app/helpers/surveyform_helper.rb +179 -0
- data/app/helpers/surveyor_gui/report_helper.rb +19 -0
- data/app/helpers/surveyor_helper.rb +4 -0
- data/app/inputs/currency_input.rb +5 -0
- data/app/inputs/date_picker_input.rb +7 -0
- data/app/inputs/datetime_picker_input.rb +5 -0
- data/app/inputs/percent_input.rb +5 -0
- data/app/inputs/time_picker_input.rb +5 -0
- data/app/mailers/.gitkeep +0 -0
- data/app/models/.gitkeep +0 -0
- data/app/models/answer.rb +4 -0
- data/app/models/column.rb +3 -0
- data/app/models/dependency.rb +4 -0
- data/app/models/dependency_condition.rb +4 -0
- data/app/models/permitted_params_decorator.rb +80 -0
- data/app/models/question.rb +4 -0
- data/app/models/question_group.rb +4 -0
- data/app/models/question_type.rb +7 -0
- data/app/models/response.rb +4 -0
- data/app/models/response_set.rb +4 -0
- data/app/models/row.rb +3 -0
- data/app/models/survey.rb +4 -0
- data/app/models/survey_section.rb +4 -0
- data/app/models/surveyform.rb +103 -0
- data/app/uploaders/blob_uploader.rb +48 -0
- data/app/views/dependencys/_column.html.erb +1 -0
- data/app/views/dependencys/_dependency.html.erb +22 -0
- data/app/views/dependencys/_dependency_condition_fields.html.erb +48 -0
- data/app/views/dependencys/_form.html.erb +20 -0
- data/app/views/dependencys/blank.html.erb +0 -0
- data/app/views/dependencys/edit.html.erb +1 -0
- data/app/views/dependencys/new.html.erb +1 -0
- data/app/views/layouts/application.html.erb +14 -0
- data/app/views/layouts/surveyor_gui_blank.html.erb +12 -0
- data/app/views/layouts/surveyor_gui_default.html.erb +16 -0
- data/app/views/layouts/surveyor_modified.html.erb +14 -0
- data/app/views/partials/_answer.html.haml +33 -0
- data/app/views/partials/_question.html.haml +33 -0
- data/app/views/partials/_question_group.html.haml +73 -0
- data/app/views/partials/_section.html.haml +13 -0
- data/app/views/question_groups/_form.html.erb +56 -0
- data/app/views/question_groups/_group_inline_field.html.erb +21 -0
- data/app/views/question_groups/_group_inline_fields.html.erb +25 -0
- data/app/views/question_groups/blank.html.erb +0 -0
- data/app/views/question_groups/edit.html.erb +1 -0
- data/app/views/question_groups/new.html.erb +1 -0
- data/app/views/questions/_answer_fields.html.erb +23 -0
- data/app/views/questions/_answer_options.html.erb +28 -0
- data/app/views/questions/_form.html.erb +65 -0
- data/app/views/questions/_grid_dropdown_columns.html.erb +10 -0
- data/app/views/questions/_grid_dropdown_fields.html.erb +42 -0
- data/app/views/questions/_grid_fields.html.erb +9 -0
- data/app/views/questions/_no_picks.html.erb +29 -0
- data/app/views/questions/_pick.html +21 -0
- data/app/views/questions/_picks.html.erb +12 -0
- data/app/views/questions/blank.html.erb +0 -0
- data/app/views/questions/edit.html.erb +1 -0
- data/app/views/questions/new.html.erb +1 -0
- data/app/views/survey_sections/_form.html.erb +13 -0
- data/app/views/survey_sections/blank.html.erb +0 -0
- data/app/views/survey_sections/edit.html.erb +1 -0
- data/app/views/survey_sections/new.html.erb +1 -0
- data/app/views/surveyforms/_form.html.erb +50 -0
- data/app/views/surveyforms/_question_field.html.erb +148 -0
- data/app/views/surveyforms/_question_group.html.erb +116 -0
- data/app/views/surveyforms/_question_group_fields.html.erb +3 -0
- data/app/views/surveyforms/_question_name_and_number.html.erb +6 -0
- data/app/views/surveyforms/_question_section.html.erb +15 -0
- data/app/views/surveyforms/_question_wrapper.html.erb +109 -0
- data/app/views/surveyforms/_survey_section_fields.html.erb +138 -0
- data/app/views/surveyforms/clone_survey.html.erb +13 -0
- data/app/views/surveyforms/edit.html.erb +5 -0
- data/app/views/surveyforms/index.html.erb +40 -0
- data/app/views/surveyforms/new.html.erb +1 -0
- data/app/views/surveyforms/show.html.erb +5 -0
- data/app/views/surveyor_gui/reports/_graphs.html.haml +21 -0
- data/app/views/surveyor_gui/reports/_grid.html.haml +42 -0
- data/app/views/surveyor_gui/reports/_grid_dropdown.html.haml +56 -0
- data/app/views/surveyor_gui/reports/_repeater.html.haml +28 -0
- data/app/views/surveyor_gui/reports/_show_report.html.haml +33 -0
- data/app/views/surveyor_gui/reports/_single_question.html.haml +70 -0
- data/app/views/surveyor_gui/reports/show.html.erb +14 -0
- data/app/views/surveyor_gui/responses/_grid.html.haml +20 -0
- data/app/views/surveyor_gui/responses/_grid_dropdown.html.haml +20 -0
- data/app/views/surveyor_gui/responses/_repeater.html.haml +22 -0
- data/app/views/surveyor_gui/responses/_survey_results.html.haml +40 -0
- data/app/views/surveyor_gui/responses/index.html.haml +24 -0
- data/app/views/surveyor_gui/responses/show.html.haml +42 -0
- data/app/views/surveyor_gui/shared/_grid_comments.html.haml +10 -0
- data/app/views/surveyor_gui/shared/_new_line.html.haml +2 -0
- data/app/views/surveyor_gui/shared/_pick_comments.html.haml +15 -0
- data/app/views/surveyor_gui/shared/_question_number.html.haml +9 -0
- data/app/views/surveyor_gui/shared/_report_data.html.haml +24 -0
- data/app/views/surveyor_gui/shared/_stars_report_data.html.haml +14 -0
- data/config.ru +4 -0
- data/config/environment.rb +0 -0
- data/config/routes.rb +71 -0
- data/db/migrate/20140307204049_add_template_to_surveys.rb +5 -0
- data/db/migrate/20140307235607_add_test_data_to_response_sets.rb +5 -0
- data/db/migrate/20140308171947_add_original_choice_to_answers.rb +5 -0
- data/db/migrate/20140308172118_add_blob_to_responses.rb +5 -0
- data/db/migrate/20140308172417_add_modifiable_to_survey_section.rb +5 -0
- data/db/migrate/20140308174532_add_modifiable_to_question.rb +5 -0
- data/db/migrate/20140308175305_add_dynamically_generate_to_questions.rb +5 -0
- data/db/migrate/20140311032923_add_dummy_blob_to_questions.rb +5 -0
- data/db/migrate/20140311160609_add_dynamic_source_to_questions.rb +5 -0
- data/db/migrate/20140311161714_add_report_code_to_questions.rb +5 -0
- data/db/migrate/20140530181134_add_is_comment_to_questions.rb +5 -0
- data/db/migrate/20140531012006_add_is_comment_to_answers.rb +5 -0
- data/db/migrate/20140531225529_create_rows.rb +9 -0
- data/db/migrate/20140601011151_create_columns.rb +11 -0
- data/db/migrate/20140602030330_add_column_id_to_answers.rb +5 -0
- data/db/migrate/20140603155606_add_column_id_to_responses.rb +5 -0
- data/db/migrate/20140606023527_add_column_id_to_dependency_conditions.rb +5 -0
- data/db/migrate/20140815165307_add_user_id_to_survey.rb +5 -0
- data/lib/assets/.gitkeep +0 -0
- data/lib/assets/images/addicon.png +0 -0
- data/lib/assets/images/datepicker.gif +0 -0
- data/lib/assets/images/delete.gif +0 -0
- data/lib/assets/images/delete.png +0 -0
- data/lib/assets/images/images/border.png +0 -0
- data/lib/assets/images/images/controls.png +0 -0
- data/lib/assets/images/images/loading.gif +0 -0
- data/lib/assets/images/images/loading_background.png +0 -0
- data/lib/assets/images/images/overlay.png +0 -0
- data/lib/assets/images/rails.png +0 -0
- data/lib/assets/images/star.gif +0 -0
- data/lib/assets/javascripts/.gitkeep +0 -0
- data/lib/assets/javascripts/surveyor_gui/jquery.MetaData.js +121 -0
- data/lib/assets/javascripts/surveyor_gui/jquery.blockUI.js +619 -0
- data/lib/assets/javascripts/surveyor_gui/jquery.rating.js +377 -0
- data/lib/assets/javascripts/surveyor_gui/jquery.validate.js +1188 -0
- data/lib/assets/javascripts/surveyor_gui/surveyor_add_ons.js +10 -0
- data/lib/assets/javascripts/surveyor_gui/surveyor_gui.js +1417 -0
- data/lib/assets/stylesheets/.gitkeep +0 -0
- data/lib/assets/stylesheets/surveyor_gui/jquery.rating.css +12 -0
- data/lib/assets/stylesheets/surveyor_gui/surveyor_add_ons.css +3 -0
- data/lib/assets/stylesheets/surveyor_gui/surveyor_gui.sass +650 -0
- data/lib/enumerable_extenders.rb +31 -0
- data/lib/generators/surveyor_gui/install_generator.rb +57 -0
- data/lib/generators/surveyor_gui/templates/app/assets/javascripts/surveyor_add_ons.js +2 -0
- data/lib/generators/surveyor_gui/templates/app/assets/javascripts/surveyor_gui_all.js +24 -0
- data/lib/generators/surveyor_gui/templates/app/assets/stylesheets/surveyor_add_ons.css.sass +1 -0
- data/lib/generators/surveyor_gui/templates/app/assets/stylesheets/surveyor_gui_all.css.sass +8 -0
- data/lib/generators/surveyor_gui/templates/app/helpers/surveyor_helper.rb +4 -0
- data/lib/generators/surveyor_gui/templates/app/models/response_set_user.rb +13 -0
- data/lib/generators/surveyor_gui/templates/app/views/layouts/surveyor_gui_default.html.erb +16 -0
- data/lib/generators/surveyor_gui/templates/config/initializers/simple_form.rb +140 -0
- data/lib/generators/surveyor_gui/templates/config/locales/en.yml +5 -0
- data/lib/surveyor_gui.rb +17 -0
- data/lib/surveyor_gui/engine.rb +30 -0
- data/lib/surveyor_gui/helpers/surveyor_helper_methods.rb +19 -0
- data/lib/surveyor_gui/models/answer_methods.rb +24 -0
- data/lib/surveyor_gui/models/column_methods.rb +43 -0
- data/lib/surveyor_gui/models/dependency_condition_methods.rb +53 -0
- data/lib/surveyor_gui/models/dependency_methods.rb +83 -0
- data/lib/surveyor_gui/models/question_and_group_shared_methods.rb +11 -0
- data/lib/surveyor_gui/models/question_group_methods.rb +55 -0
- data/lib/surveyor_gui/models/question_methods.rb +435 -0
- data/lib/surveyor_gui/models/question_type_methods.rb +493 -0
- data/lib/surveyor_gui/models/response_methods.rb +67 -0
- data/lib/surveyor_gui/models/response_set_methods.rb +54 -0
- data/lib/surveyor_gui/models/row_methods.rb +11 -0
- data/lib/surveyor_gui/models/survey_methods.rb +32 -0
- data/lib/surveyor_gui/models/survey_section_methods.rb +32 -0
- data/lib/surveyor_gui/surveyforms_controller_methods.rb +258 -0
- data/lib/surveyor_gui/version.rb +3 -0
- data/lib/tasks/.gitkeep +0 -0
- data/lib/tasks/surveyor_gui_tasks.rake +4 -0
- data/lib/templates/erb/scaffold/_form.html.erb +13 -0
- data/spec/controllers/surveyforms_controller_spec.rb +361 -0
- data/spec/controllers/surveyor_controller_spec.rb +303 -0
- data/spec/factories.rb +181 -0
- data/spec/features/create_survey_spec.rb +418 -0
- data/spec/features/dependencies_spec.rb +61 -0
- data/spec/features/rearrange_survey_spec.rb +118 -0
- data/spec/features/ui_spec.rb +469 -0
- data/spec/fixtures/REDCapDemoDatabase_DataDictionary.csv +127 -0
- data/spec/fixtures/chinese_survey.rb +14 -0
- data/spec/fixtures/everything.rb +215 -0
- data/spec/fixtures/favorites-ish.rb +22 -0
- data/spec/fixtures/favorites.rb +22 -0
- data/spec/fixtures/feelings.rb +38 -0
- data/spec/fixtures/lifestyle.rb +55 -0
- data/spec/fixtures/numbers.rb +21 -0
- data/spec/fixtures/redcap_new_headers.csv +1 -0
- data/spec/fixtures/redcap_siblings.csv +1 -0
- data/spec/fixtures/redcap_whitespace.csv +1 -0
- data/spec/helpers/formtastic_custom_input_spec.rb +15 -0
- data/spec/helpers/surveyor_helper_spec.rb +116 -0
- data/spec/lib/common_spec.rb +37 -0
- data/spec/lib/parser_spec.rb +393 -0
- data/spec/lib/rake_kitchen_sink.rb +42 -0
- data/spec/lib/redcap_parser_spec.rb +129 -0
- data/spec/lib/unparser_spec.rb +126 -0
- data/spec/models/answer_spec.rb +144 -0
- data/spec/models/dependency_condition_spec.rb +428 -0
- data/spec/models/dependency_spec.rb +90 -0
- data/spec/models/question_group_spec.rb +66 -0
- data/spec/models/question_spec.rb +176 -0
- data/spec/models/response_set_spec.rb +452 -0
- data/spec/models/response_spec.rb +208 -0
- data/spec/models/survey_section_spec.rb +58 -0
- data/spec/models/survey_spec.rb +155 -0
- data/spec/models/surveyor_gui/question_spec.rb +60 -0
- data/spec/models/surveyor_gui/question_type_spec.rb +268 -0
- data/spec/models/validation_condition_spec.rb +98 -0
- data/spec/models/validation_spec.rb +64 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +119 -0
- data/spec/support/scenario_outline_helper.rb +39 -0
- data/spec/support/shared.rb +10 -0
- data/spec/support/surveyforms_creation_helpers.rb +312 -0
- data/spec/support/surveyforms_rearrangement_helpers.rb +170 -0
- data/spec/support/surveyor_api_helpers.rb +15 -0
- data/spec/support/surveyor_ui_helpers.rb +108 -0
- data/spec/support/wait_for_ajax.rb +11 -0
- data/spec/views/questions/edit.html.erb_spec.rb +73 -0
- data/spec/views/surveyforms/edit.html.erb_spec.rb +126 -0
- data/surveyor_gui.gemspec +52 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.gitkeep +0 -0
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +59 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/lib/assets/.gitkeep +0 -0
- data/test/dummy/log/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/surveyor-gui_test.rb +7 -0
- data/test/test_helper.rb +15 -0
- data/vendor/assets/stylesheets/.gitkeep +0 -0
- data/vendor/assets/stylesheets/custom.sass +5 -0
- data/vendor/plugins/.gitkeep +0 -0
- metadata +664 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Dependency do
|
4
|
+
before(:each) do
|
5
|
+
@dependency = FactoryGirl.create(:dependency)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be valid" do
|
9
|
+
@dependency.should be_valid
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be invalid without a rule" do
|
13
|
+
@dependency.rule = nil
|
14
|
+
@dependency.should have(2).errors_on(:rule)
|
15
|
+
@dependency.rule = " "
|
16
|
+
@dependency.should have(1).errors_on(:rule)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be invalid without a question_id" do
|
20
|
+
@dependency.question_id = nil
|
21
|
+
@dependency.should have(1).error_on(:question_id)
|
22
|
+
|
23
|
+
@dependency.question_group_id = 1
|
24
|
+
@dependency.should be_valid
|
25
|
+
|
26
|
+
@dependency.question_id.should be_nil
|
27
|
+
@dependency.question_group_id = nil
|
28
|
+
@dependency.should have(1).error_on(:question_group_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should alias question_id as dependent_question_id" do
|
32
|
+
@dependency.question_id = 19
|
33
|
+
@dependency.dependent_question_id.should == 19
|
34
|
+
@dependency.dependent_question_id = 14
|
35
|
+
@dependency.question_id.should == 14
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should be invalid unless rule composed of only references and operators" do
|
39
|
+
@dependency.rule = "foo"
|
40
|
+
@dependency.should have(1).error_on(:rule)
|
41
|
+
@dependency.rule = "1 to 2"
|
42
|
+
@dependency.should have(1).error_on(:rule)
|
43
|
+
@dependency.rule = "a and b"
|
44
|
+
@dependency.should have(1).error_on(:rule)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe Dependency, "when evaluating dependency conditions of a question in a response set" do
|
49
|
+
|
50
|
+
before(:each) do
|
51
|
+
@dep = Dependency.new(:rule => "A", :question_id => 1)
|
52
|
+
@dep2 = Dependency.new(:rule => "A and B", :question_id => 1)
|
53
|
+
@dep3 = Dependency.new(:rule => "A or B", :question_id => 1)
|
54
|
+
@dep4 = Dependency.new(:rule => "!(A and B) and C", :question_id => 1)
|
55
|
+
|
56
|
+
@dep_c = mock_model(DependencyCondition, :id => 1, :rule_key => "A", :to_hash => {:A => true})
|
57
|
+
@dep_c2 = mock_model(DependencyCondition, :id => 2, :rule_key => "B", :to_hash => {:B => false})
|
58
|
+
@dep_c3 = mock_model(DependencyCondition, :id => 3, :rule_key => "C", :to_hash => {:C => true})
|
59
|
+
|
60
|
+
@dep.stub(:dependency_conditions).and_return([@dep_c])
|
61
|
+
@dep2.stub(:dependency_conditions).and_return([@dep_c, @dep_c2])
|
62
|
+
@dep3.stub(:dependency_conditions).and_return([@dep_c, @dep_c2])
|
63
|
+
@dep4.stub(:dependency_conditions).and_return([@dep_c, @dep_c2, @dep_c3])
|
64
|
+
end
|
65
|
+
|
66
|
+
it "knows if the dependencies are met" do
|
67
|
+
@dep.is_met?(@response_set).should be_true
|
68
|
+
@dep2.is_met?(@response_set).should be_false
|
69
|
+
@dep3.is_met?(@response_set).should be_true
|
70
|
+
@dep4.is_met?(@response_set).should be_true
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns the proper keyed pairs from the dependency conditions" do
|
74
|
+
@dep.conditions_hash(@response_set).should == {:A => true}
|
75
|
+
@dep2.conditions_hash(@response_set).should == {:A => true, :B => false}
|
76
|
+
@dep3.conditions_hash(@response_set).should == {:A => true, :B => false}
|
77
|
+
@dep4.conditions_hash(@response_set).should == {:A => true, :B => false, :C => true}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
describe Dependency, "with conditions" do
|
81
|
+
it "should destroy conditions when destroyed" do
|
82
|
+
@dependency = Dependency.new(:rule => "A and B and C", :question_id => 1)
|
83
|
+
FactoryGirl.create(:dependency_condition, :dependency => @dependency, :rule_key => "A")
|
84
|
+
FactoryGirl.create(:dependency_condition, :dependency => @dependency, :rule_key => "B")
|
85
|
+
FactoryGirl.create(:dependency_condition, :dependency => @dependency, :rule_key => "C")
|
86
|
+
dc_ids = @dependency.dependency_conditions.map(&:id)
|
87
|
+
@dependency.destroy
|
88
|
+
dc_ids.each{|id| DependencyCondition.find_by_id(id).should == nil}
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
3
|
+
|
4
|
+
describe QuestionGroup do
|
5
|
+
let(:question_group){ FactoryGirl.create(:question_group) }
|
6
|
+
let(:dependency){ FactoryGirl.create(:dependency) }
|
7
|
+
let(:response_set){ FactoryGirl.create(:response_set) }
|
8
|
+
|
9
|
+
context "when creating" do
|
10
|
+
it { question_group.should be_valid }
|
11
|
+
it "#display_type = inline by default" do
|
12
|
+
question_group.display_type = "inline"
|
13
|
+
question_group.renderer.should == :inline
|
14
|
+
end
|
15
|
+
it "#renderer == 'default' when #display_type = nil" do
|
16
|
+
question_group.display_type = nil
|
17
|
+
question_group.renderer.should == :default
|
18
|
+
end
|
19
|
+
it "interprets symbolizes #display_type to #renderer" do
|
20
|
+
question_group.display_type = "foo"
|
21
|
+
question_group.renderer.should == :foo
|
22
|
+
end
|
23
|
+
it "reports DOM ready #css_class based on dependencies" do
|
24
|
+
question_group.dependency = dependency
|
25
|
+
dependency.should_receive(:is_met?).and_return(true)
|
26
|
+
question_group.css_class(response_set).should == "g_dependent"
|
27
|
+
|
28
|
+
dependency.should_receive(:is_met?).and_return(false)
|
29
|
+
question_group.css_class(response_set).should == "g_dependent g_hidden"
|
30
|
+
|
31
|
+
question_group.custom_class = "foo bar"
|
32
|
+
dependency.should_receive(:is_met?).and_return(false)
|
33
|
+
question_group.css_class(response_set).should == "g_dependent g_hidden foo bar"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "with translations" do
|
38
|
+
require 'yaml'
|
39
|
+
let(:survey){ FactoryGirl.create(:survey) }
|
40
|
+
let(:survey_section){ FactoryGirl.create(:survey_section) }
|
41
|
+
let(:survey_translation){
|
42
|
+
FactoryGirl.create(:survey_translation, :locale => :es, :translation => {
|
43
|
+
:question_groups => {
|
44
|
+
:goodbye => {
|
45
|
+
:text => "¡Adios!"
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}.to_yaml)
|
49
|
+
}
|
50
|
+
let(:question){ FactoryGirl.create(:question) }
|
51
|
+
before do
|
52
|
+
question_group.text = "Goodbye"
|
53
|
+
question_group.reference_identifier = "goodbye"
|
54
|
+
question_group.questions = [question]
|
55
|
+
question.survey_section = survey_section
|
56
|
+
survey_section.survey = survey
|
57
|
+
survey.translations << survey_translation
|
58
|
+
end
|
59
|
+
it "returns its own translation" do
|
60
|
+
question_group.translation(:es)[:text].should == "¡Adios!"
|
61
|
+
end
|
62
|
+
it "returns its own default values" do
|
63
|
+
question_group.translation(:de).should == {"text" => "Goodbye", "help_text" => nil}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
3
|
+
|
4
|
+
describe Question do
|
5
|
+
let(:question){ FactoryGirl.create(:question) }
|
6
|
+
|
7
|
+
context "when creating" do
|
8
|
+
it "is invalid without #text" do
|
9
|
+
question.text = nil
|
10
|
+
question.should have(1).error_on :text
|
11
|
+
end
|
12
|
+
it "#is_mandantory == false by default" do
|
13
|
+
question.mandatory?.should be_false
|
14
|
+
end
|
15
|
+
it "converts #pick to string" do
|
16
|
+
question.pick.should == "none"
|
17
|
+
question.pick = :one
|
18
|
+
question.pick.should == "one"
|
19
|
+
question.pick = nil
|
20
|
+
question.pick.should == nil
|
21
|
+
end
|
22
|
+
it "#renderer == 'default' when #display_type = nil" do
|
23
|
+
question.display_type = nil
|
24
|
+
question.renderer.should == :default
|
25
|
+
end
|
26
|
+
it "has #api_id with 36 characters by default" do
|
27
|
+
question.api_id.length.should == 36
|
28
|
+
end
|
29
|
+
it "#part_of_group? and #solo? are aware of question groups" do
|
30
|
+
question.question_group = FactoryGirl.create(:question_group)
|
31
|
+
question.solo?.should be_false
|
32
|
+
question.part_of_group?.should be_true
|
33
|
+
|
34
|
+
question.question_group = nil
|
35
|
+
question.solo?.should be_true
|
36
|
+
question.part_of_group?.should be_false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with answers" do
|
41
|
+
let(:answer_1){ FactoryGirl.create(:answer, :question => question, :display_order => 3, :text => "blue")}
|
42
|
+
let(:answer_2){ FactoryGirl.create(:answer, :question => question, :display_order => 1, :text => "red")}
|
43
|
+
let(:answer_3){ FactoryGirl.create(:answer, :question => question, :display_order => 2, :text => "green")}
|
44
|
+
before do
|
45
|
+
[answer_1, answer_2, answer_3].each{|a| question.answers << a }
|
46
|
+
end
|
47
|
+
it{ question.should have(3).answers}
|
48
|
+
it "gets answers in order" do
|
49
|
+
question.answers.order("display_order asc").should == [answer_2, answer_3, answer_1]
|
50
|
+
question.answers.order("display_order asc").map(&:display_order).should == [1,2,3]
|
51
|
+
end
|
52
|
+
it "deletes child answers when deleted" do
|
53
|
+
answer_ids = question.answers.map(&:id)
|
54
|
+
question.destroy
|
55
|
+
answer_ids.each{|id| Answer.find_by_id(id).should be_nil}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "with dependencies" do
|
60
|
+
let(:response_set){ FactoryGirl.create(:response_set) }
|
61
|
+
let(:dependency){ FactoryGirl.create(:dependency) }
|
62
|
+
before do
|
63
|
+
question.dependency = dependency
|
64
|
+
dependency.stub(:is_met?).with(response_set).and_return true
|
65
|
+
end
|
66
|
+
it "checks its dependency" do
|
67
|
+
question.triggered?(response_set).should be_true
|
68
|
+
end
|
69
|
+
it "deletes its dependency when deleted" do
|
70
|
+
d_id = question.dependency.id
|
71
|
+
question.destroy
|
72
|
+
Dependency.find_by_id(d_id).should be_nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "with mustache text substitution" do
|
77
|
+
require 'mustache'
|
78
|
+
let(:mustache_context){ Class.new(::Mustache){ def site; "Northwestern"; end; def foo; "bar"; end } }
|
79
|
+
it "subsitutes Mustache context variables" do
|
80
|
+
question.text = "You are in {{site}}"
|
81
|
+
question.in_context(question.text, mustache_context).should == "You are in Northwestern"
|
82
|
+
end
|
83
|
+
it "substitues in views" do
|
84
|
+
question.text = "You are in {{site}}"
|
85
|
+
question.text_for(nil, mustache_context).should == "You are in Northwestern"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "with translations" do
|
90
|
+
require 'yaml'
|
91
|
+
let(:survey){ FactoryGirl.create(:survey) }
|
92
|
+
let(:survey_section){ FactoryGirl.create(:survey_section) }
|
93
|
+
let(:survey_translation){
|
94
|
+
FactoryGirl.create(:survey_translation, :locale => :es, :translation => {
|
95
|
+
:questions => {
|
96
|
+
:hello => {
|
97
|
+
:text => "¡Hola!"
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}.to_yaml)
|
101
|
+
}
|
102
|
+
before do
|
103
|
+
question.reference_identifier = "hello"
|
104
|
+
question.survey_section = survey_section
|
105
|
+
survey_section.survey = survey
|
106
|
+
survey.translations << survey_translation
|
107
|
+
end
|
108
|
+
it "returns its own translation" do
|
109
|
+
YAML.load(survey_translation.translation).should_not be_nil
|
110
|
+
question.translation(:es)[:text].should == "¡Hola!"
|
111
|
+
end
|
112
|
+
it "returns its own default values" do
|
113
|
+
question.translation(:de).should == {"text" => question.text, "help_text" => question.help_text}
|
114
|
+
end
|
115
|
+
it "returns translations in views" do
|
116
|
+
question.text_for(nil, nil, :es).should == "¡Hola!"
|
117
|
+
end
|
118
|
+
it "returns default values in views" do
|
119
|
+
question.text_for(nil, nil, :de).should == question.text
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "handling strings" do
|
124
|
+
it "#split preserves strings" do
|
125
|
+
question.split(question.text).should == "What is your favorite color?"
|
126
|
+
end
|
127
|
+
it "#split(:pre) preserves strings" do
|
128
|
+
question.split(question.text, :pre).should == "What is your favorite color?"
|
129
|
+
end
|
130
|
+
it "#split(:post) preserves strings" do
|
131
|
+
question.split(question.text, :post).should == ""
|
132
|
+
end
|
133
|
+
it "#split splits strings" do
|
134
|
+
question.text = "before|after|extra"
|
135
|
+
question.split(question.text).should == "before|after|extra"
|
136
|
+
end
|
137
|
+
it "#split(:pre) splits strings" do
|
138
|
+
question.text = "before|after|extra"
|
139
|
+
question.split(question.text, :pre).should == "before"
|
140
|
+
end
|
141
|
+
it "#split(:post) splits strings" do
|
142
|
+
question.text = "before|after|extra"
|
143
|
+
question.split(question.text, :post).should == "after|extra"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "for views" do
|
148
|
+
it "#text_for with #display_type == image" do
|
149
|
+
question.text = "rails.png"
|
150
|
+
question.display_type = :image
|
151
|
+
question.text_for.should =~ /<img alt="Rails" src="\/(images|assets)\/rails\.png" \/>/
|
152
|
+
end
|
153
|
+
it "#help_text_for"
|
154
|
+
it "#text_for preserves strings" do
|
155
|
+
question.text_for.should == "What is your favorite color?"
|
156
|
+
end
|
157
|
+
it "#text_for(:pre) preserves strings" do
|
158
|
+
question.text_for(:pre).should == "What is your favorite color?"
|
159
|
+
end
|
160
|
+
it "#text_for(:post) preserves strings" do
|
161
|
+
question.text_for(:post).should == ""
|
162
|
+
end
|
163
|
+
it "#text_for splits strings" do
|
164
|
+
question.text = "before|after|extra"
|
165
|
+
question.text_for.should == "before|after|extra"
|
166
|
+
end
|
167
|
+
it "#text_for(:pre) splits strings" do
|
168
|
+
question.text = "before|after|extra"
|
169
|
+
question.text_for(:pre).should == "before"
|
170
|
+
end
|
171
|
+
it "#text_for(:post) splits strings" do
|
172
|
+
question.text = "before|after|extra"
|
173
|
+
question.text_for(:post).should == "after|extra"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,452 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe ResponseSet do
|
4
|
+
let(:response_set) { FactoryGirl.create(:response_set) }
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@response_set = FactoryGirl.create(:response_set)
|
8
|
+
@radio_response_attributes = HashWithIndifferentAccess.new({"1"=>{"question_id"=>"1", "answer_id"=>"1", "string_value"=>"XXL"}, "2"=>{"question_id"=>"2", "answer_id"=>"6"}, "3"=>{"question_id"=>"3"}})
|
9
|
+
@checkbox_response_attributes = HashWithIndifferentAccess.new({"1"=>{"question_id"=>"9", "answer_id"=>"11"}, "2"=>{"question_id"=>"9", "answer_id"=>"12"}})
|
10
|
+
@other_response_attributes = HashWithIndifferentAccess.new({"6"=>{"question_id"=>"6", "answer_id" => "3", "string_value"=>""}, "7"=>{"question_id"=>"7", "answer_id" => "4", "text_value"=>"Brian is tired"}, "5"=>{"question_id"=>"5", "answer_id" => "5", "string_value"=>""}})
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have a unique code with length 10 that identifies the survey" do
|
14
|
+
@response_set.access_code.should_not be_nil
|
15
|
+
@response_set.access_code.length.should == 10
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#access_code' do
|
19
|
+
let!(:rs1) { FactoryGirl.create(:response_set).tap { |rs| rs.update_attribute(:access_code, 'one') } }
|
20
|
+
let!(:rs2) { FactoryGirl.create(:response_set).tap { |rs| rs.update_attribute(:access_code, 'two') } }
|
21
|
+
|
22
|
+
# Regression test for #263
|
23
|
+
it 'accepts an access code in the constructor' do
|
24
|
+
rs = ResponseSet.new
|
25
|
+
rs.access_code = 'eleven'
|
26
|
+
rs.access_code.should == 'eleven'
|
27
|
+
end
|
28
|
+
|
29
|
+
# Regression test for #263
|
30
|
+
it 'setter accepts a conflicting access code' do
|
31
|
+
rs2.access_code = 'one'
|
32
|
+
rs2.access_code.should == 'one'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'is invalid when conflicting' do
|
36
|
+
rs2.access_code = 'one'
|
37
|
+
rs2.should_not be_valid
|
38
|
+
rs2.should have(1).errors_on(:access_code)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "is completable" do
|
43
|
+
@response_set.completed_at.should be_nil
|
44
|
+
@response_set.complete!
|
45
|
+
@response_set.completed_at.should_not be_nil
|
46
|
+
@response_set.completed_at.is_a?(Time).should be_true
|
47
|
+
@response_set.should be_complete
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'saves its responses' do
|
51
|
+
new_set = ResponseSet.new(:survey => FactoryGirl.create(:survey))
|
52
|
+
new_set.responses.build(:question_id => 1, :answer_id => 1, :string_value => 'XXL')
|
53
|
+
new_set.save!
|
54
|
+
|
55
|
+
ResponseSet.find(new_set.id).responses.should have(1).items
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#update_from_ui_hash' do
|
59
|
+
let(:ui_hash) { {} }
|
60
|
+
let(:api_id) { 'ABCDEF-1234-567890' }
|
61
|
+
|
62
|
+
let(:question_id) { 42 }
|
63
|
+
let(:answer_id) { 137 }
|
64
|
+
|
65
|
+
def ui_response(attrs={})
|
66
|
+
{ 'question_id' => question_id.to_s, 'api_id' => api_id }.merge(attrs)
|
67
|
+
end
|
68
|
+
|
69
|
+
def do_ui_update
|
70
|
+
response_set.update_from_ui_hash(ui_hash)
|
71
|
+
end
|
72
|
+
|
73
|
+
def resulting_response
|
74
|
+
# response_set_id criterion is to make sure a created response is
|
75
|
+
# appropriately associated.
|
76
|
+
Response.where(:api_id => api_id, :response_set_id => response_set).first
|
77
|
+
end
|
78
|
+
|
79
|
+
shared_examples 'pick one or any' do
|
80
|
+
it 'saves an answer alone' do
|
81
|
+
ui_hash['3'] = ui_response('answer_id' => set_answer_id)
|
82
|
+
do_ui_update
|
83
|
+
resulting_response.answer_id.should == answer_id
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'preserves the question' do
|
87
|
+
ui_hash['4'] = ui_response('answer_id' => set_answer_id)
|
88
|
+
do_ui_update
|
89
|
+
resulting_response.question_id.should == question_id
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'interprets a blank answer as no response' do
|
93
|
+
ui_hash['7'] = ui_response('answer_id' => blank_answer_id)
|
94
|
+
do_ui_update
|
95
|
+
resulting_response.should be_nil
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'interprets no answer_id as no response' do
|
99
|
+
ui_hash['8'] = ui_response
|
100
|
+
do_ui_update
|
101
|
+
resulting_response.should be_nil
|
102
|
+
end
|
103
|
+
|
104
|
+
[
|
105
|
+
['string_value', 'foo', '', 'foo'],
|
106
|
+
['datetime_value', '2010-10-01 17:15', '', Time.zone.parse('2010-10-1 17:15')],
|
107
|
+
['date_value', '2010-10-01', '', '2010-10-01'],
|
108
|
+
['time_value', '17:15', '', '17:15'],
|
109
|
+
['integer_value', '9', '', 9],
|
110
|
+
['float_value', '4.0', '', 4.0],
|
111
|
+
['text_value', 'more than foo', '', 'more than foo']
|
112
|
+
].each do |value_type, set_value, blank_value, expected_value|
|
113
|
+
describe "plus #{value_type}" do
|
114
|
+
it 'saves the value' do
|
115
|
+
ui_hash['11'] = ui_response('answer_id' => set_answer_id, value_type => set_value)
|
116
|
+
do_ui_update
|
117
|
+
resulting_response.send(value_type).should == expected_value
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'interprets a blank answer as no response' do
|
121
|
+
ui_hash['18'] = ui_response('answer_id' => blank_answer_id, value_type => set_value)
|
122
|
+
do_ui_update
|
123
|
+
resulting_response.should be_nil
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'interprets a blank value as no response' do
|
127
|
+
ui_hash['29'] = ui_response('answer_id' => set_answer_id, value_type => blank_value)
|
128
|
+
do_ui_update
|
129
|
+
resulting_response.should be_nil
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'interprets no answer_id as no response' do
|
133
|
+
ui_hash['8'] = ui_response(value_type => set_value)
|
134
|
+
do_ui_update
|
135
|
+
resulting_response.should be_nil
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
shared_examples 'response interpretation' do
|
142
|
+
it 'fails when api_id is not provided' do
|
143
|
+
ui_hash['0'] = { 'question_id' => question_id }
|
144
|
+
lambda { do_ui_update }.should raise_error(/api_id missing from response 0/)
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'for a radio button' do
|
148
|
+
let(:set_answer_id) { answer_id.to_s }
|
149
|
+
let(:blank_answer_id) { '' }
|
150
|
+
|
151
|
+
include_examples 'pick one or any'
|
152
|
+
end
|
153
|
+
|
154
|
+
describe 'for a checkbox' do
|
155
|
+
let(:set_answer_id) { ['', answer_id.to_s] }
|
156
|
+
let(:blank_answer_id) { [''] }
|
157
|
+
|
158
|
+
include_examples 'pick one or any'
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe 'with a new response' do
|
163
|
+
include_examples 'response interpretation'
|
164
|
+
|
165
|
+
# After much effort I cannot produce this situation in a test, either with
|
166
|
+
# with threads or separate processes. While SQLite 3 will nominally allow
|
167
|
+
# for some coarse-grained concurrency, it does not appear to work with
|
168
|
+
# simultaneous write transactions the way AR uses SQLite. Instead,
|
169
|
+
# simultaneous write transactions always result in a
|
170
|
+
# SQLite3::BusyException, regardless of the connection's timeout setting.
|
171
|
+
it 'fails predicably when another response with the same api_id is created in a simultaneous open transaction'
|
172
|
+
end
|
173
|
+
|
174
|
+
describe 'with an existing response' do
|
175
|
+
let!(:original_response) {
|
176
|
+
response_set.responses.build(:question_id => question_id, :answer_id => answer_id).tap do |r|
|
177
|
+
r.api_id = api_id # not mass assignable
|
178
|
+
r.save!
|
179
|
+
end
|
180
|
+
}
|
181
|
+
|
182
|
+
include_examples 'response interpretation'
|
183
|
+
|
184
|
+
it 'fails when the existing response is for a different question' do
|
185
|
+
ui_hash['76'] = ui_response('question_id' => '43', 'answer_id' => answer_id.to_s)
|
186
|
+
|
187
|
+
lambda { do_ui_update }.should raise_error(/Illegal attempt to change question for response #{api_id}./)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# clean_with_truncation is necessary because AR 3.0 can't roll back a nested
|
192
|
+
# transaction with SQLite.
|
193
|
+
it 'rolls back all changes on failure', :clean_with_truncation do
|
194
|
+
ui_hash['0'] = ui_response('question_id' => '42', 'answer_id' => answer_id.to_s)
|
195
|
+
ui_hash['1'] = { 'answer_id' => '7' } # no api_id
|
196
|
+
|
197
|
+
begin
|
198
|
+
do_ui_update
|
199
|
+
fail "Expected error did not occur"
|
200
|
+
rescue
|
201
|
+
end
|
202
|
+
|
203
|
+
response_set.reload.responses.should be_empty
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe ResponseSet, "with dependencies" do
|
209
|
+
before(:each) do
|
210
|
+
@section = FactoryGirl.create(:survey_section)
|
211
|
+
# Questions
|
212
|
+
@do_you_like_pie = FactoryGirl.create(:question, :text => "Do you like pie?", :survey_section => @section)
|
213
|
+
@what_flavor = FactoryGirl.create(:question, :text => "What flavor?", :survey_section => @section)
|
214
|
+
@what_bakery = FactoryGirl.create(:question, :text => "What bakery?", :survey_section => @section)
|
215
|
+
# Answers
|
216
|
+
@do_you_like_pie.answers << FactoryGirl.create(:answer, :text => "yes", :question_id => @do_you_like_pie.id)
|
217
|
+
@do_you_like_pie.answers << FactoryGirl.create(:answer, :text => "no", :question_id => @do_you_like_pie.id)
|
218
|
+
@what_flavor.answers << FactoryGirl.create(:answer, :response_class => :string, :question_id => @what_flavor.id)
|
219
|
+
@what_bakery.answers << FactoryGirl.create(:answer, :response_class => :string, :question_id => @what_bakery.id)
|
220
|
+
# Dependency
|
221
|
+
@what_flavor_dep = FactoryGirl.create(:dependency, :rule => "A", :question_id => @what_flavor.id)
|
222
|
+
FactoryGirl.create(:dependency_condition, :rule_key => "A", :question_id => @do_you_like_pie.id, :operator => "==", :answer_id => @do_you_like_pie.answers.first.id, :dependency_id => @what_flavor_dep.id)
|
223
|
+
@what_bakery_dep = FactoryGirl.create(:dependency, :rule => "B", :question_id => @what_bakery.id)
|
224
|
+
FactoryGirl.create(:dependency_condition, :rule_key => "B", :question_id => @do_you_like_pie.id, :operator => "==", :answer_id => @do_you_like_pie.answers.first.id, :dependency_id => @what_bakery_dep.id)
|
225
|
+
# Responses
|
226
|
+
@response_set = FactoryGirl.create(:response_set)
|
227
|
+
@response_set.responses << FactoryGirl.create(:response, :question_id => @do_you_like_pie.id, :answer_id => @do_you_like_pie.answers.first.id, :response_set_id => @response_set.id)
|
228
|
+
@response_set.responses << FactoryGirl.create(:response, :string_value => "pecan pie", :question_id => @what_flavor.id, :answer_id => @what_flavor.answers.first.id, :response_set_id => @response_set.id)
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should list unanswered dependencies to show at the top of the next page (javascript turned off)" do
|
232
|
+
@response_set.unanswered_dependencies.should == [@what_bakery]
|
233
|
+
end
|
234
|
+
it "should list answered and unanswered dependencies to show inline (javascript turned on)" do
|
235
|
+
@response_set.all_dependencies[:show].should == ["q_#{@what_flavor.id}", "q_#{@what_bakery.id}"]
|
236
|
+
end
|
237
|
+
it "should list group as dependency" do
|
238
|
+
# Question Group
|
239
|
+
crust_group = FactoryGirl.create(:question_group, :text => "Favorite Crusts")
|
240
|
+
|
241
|
+
# Question
|
242
|
+
what_crust = FactoryGirl.create(:question, :text => "What is your favorite curst type?", :survey_section => @section)
|
243
|
+
crust_group.questions << what_crust
|
244
|
+
|
245
|
+
# Answers
|
246
|
+
what_crust.answers << FactoryGirl.create(:answer, :response_class => :string, :question_id => what_crust.id)
|
247
|
+
|
248
|
+
# Dependency
|
249
|
+
crust_group_dep = FactoryGirl.create(:dependency, :rule => "C", :question_group_id => crust_group.id, :question => nil)
|
250
|
+
FactoryGirl.create(:dependency_condition, :rule_key => "C", :question_id => @do_you_like_pie.id, :operator => "==", :answer_id => @do_you_like_pie.answers.first.id, :dependency_id => crust_group_dep.id)
|
251
|
+
|
252
|
+
@response_set.unanswered_dependencies.should == [@what_bakery, crust_group]
|
253
|
+
end
|
254
|
+
end
|
255
|
+
describe ResponseSet, "dependency_conditions" do
|
256
|
+
before do
|
257
|
+
@section = FactoryGirl.create(:survey_section)
|
258
|
+
# Questions
|
259
|
+
@like_pie = FactoryGirl.create(:question, :text => "Do you like pie?", :survey_section => @section)
|
260
|
+
@like_jam = FactoryGirl.create(:question, :text => "Do you like jam?", :survey_section => @section)
|
261
|
+
@what_is_wrong_with_you = FactoryGirl.create(:question, :text => "What's wrong with you?", :survey_section => @section)
|
262
|
+
# Answers
|
263
|
+
@like_pie.answers << FactoryGirl.create(:answer, :text => "yes", :question_id => @like_pie.id)
|
264
|
+
@like_pie.answers << FactoryGirl.create(:answer, :text => "no", :question_id => @like_pie.id)
|
265
|
+
@like_jam.answers << FactoryGirl.create(:answer, :text => "yes", :question_id => @like_jam.id)
|
266
|
+
@like_jam.answers << FactoryGirl.create(:answer, :text => "no", :question_id => @like_jam.id)
|
267
|
+
# Dependency
|
268
|
+
@what_is_wrong_with_you = FactoryGirl.create(:dependency, :rule => "A or B", :question_id => @what_is_wrong_with_you.id)
|
269
|
+
@dep_a = FactoryGirl.create(:dependency_condition, :rule_key => "A", :question_id => @like_pie.id, :operator => "==", :answer_id => @like_pie.answers.first.id, :dependency_id => @what_is_wrong_with_you.id)
|
270
|
+
@dep_b = FactoryGirl.create(:dependency_condition, :rule_key => "B", :question_id => @like_jam.id, :operator => "==", :answer_id => @like_jam.answers.first.id, :dependency_id => @what_is_wrong_with_you.id)
|
271
|
+
# Responses
|
272
|
+
@response_set = FactoryGirl.create(:response_set)
|
273
|
+
@response_set.responses << FactoryGirl.create(:response, :question_id => @like_pie.id, :answer_id => @like_pie.answers.last.id, :response_set_id => @response_set.id)
|
274
|
+
end
|
275
|
+
it "should list all dependencies for answered questions" do
|
276
|
+
dependency_conditions = @response_set.send(:dependencies).last.dependency_conditions
|
277
|
+
dependency_conditions.size.should == 2
|
278
|
+
dependency_conditions.should include(@dep_a)
|
279
|
+
dependency_conditions.should include(@dep_b)
|
280
|
+
|
281
|
+
end
|
282
|
+
it "should list all dependencies for passed question_id" do
|
283
|
+
# Questions
|
284
|
+
like_ice_cream = FactoryGirl.create(:question, :text => "Do you like ice_cream?", :survey_section => @section)
|
285
|
+
what_flavor = FactoryGirl.create(:question, :text => "What flavor?", :survey_section => @section)
|
286
|
+
# Answers
|
287
|
+
like_ice_cream.answers << FactoryGirl.create(:answer, :text => "yes", :question_id => like_ice_cream.id)
|
288
|
+
like_ice_cream.answers << FactoryGirl.create(:answer, :text => "no", :question_id => like_ice_cream.id)
|
289
|
+
what_flavor.answers << FactoryGirl.create(:answer, :response_class => :string, :question_id => what_flavor.id)
|
290
|
+
# Dependency
|
291
|
+
flavor_dependency = FactoryGirl.create(:dependency, :rule => "C", :question_id => what_flavor.id)
|
292
|
+
flavor_dependency_condition = FactoryGirl.create(:dependency_condition, :rule_key => "A", :question_id => like_ice_cream.id, :operator => "==",
|
293
|
+
:answer_id => like_ice_cream.answers.first.id, :dependency_id => flavor_dependency.id)
|
294
|
+
# Responses
|
295
|
+
dependency_conditions = @response_set.send(:dependencies, like_ice_cream.id).should == [flavor_dependency]
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
describe ResponseSet, "as a quiz" do
|
300
|
+
before(:each) do
|
301
|
+
@survey = FactoryGirl.create(:survey)
|
302
|
+
@section = FactoryGirl.create(:survey_section, :survey => @survey)
|
303
|
+
@response_set = FactoryGirl.create(:response_set, :survey => @survey)
|
304
|
+
end
|
305
|
+
def generate_responses(count, quiz = nil, correct = nil)
|
306
|
+
count.times do |i|
|
307
|
+
q = FactoryGirl.create(:question, :survey_section => @section)
|
308
|
+
a = FactoryGirl.create(:answer, :question => q, :response_class => "answer")
|
309
|
+
x = FactoryGirl.create(:answer, :question => q, :response_class => "answer")
|
310
|
+
q.correct_answer = (quiz == "quiz" ? a : nil)
|
311
|
+
@response_set.responses << FactoryGirl.create(:response, :question => q, :answer => (correct == "correct" ? a : x))
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
it "should report correctness if it is a quiz" do
|
316
|
+
generate_responses(3, "quiz", "correct")
|
317
|
+
@response_set.correct?.should be_true
|
318
|
+
@response_set.correctness_hash.should == {:questions => 3, :responses => 3, :correct => 3}
|
319
|
+
end
|
320
|
+
it "should report incorrectness if it is a quiz" do
|
321
|
+
generate_responses(3, "quiz", "incorrect")
|
322
|
+
@response_set.correct?.should be_false
|
323
|
+
@response_set.correctness_hash.should == {:questions => 3, :responses => 3, :correct => 0}
|
324
|
+
end
|
325
|
+
it "should report correct if it isn't a quiz" do
|
326
|
+
generate_responses(3, "non-quiz")
|
327
|
+
@response_set.correct?.should be_true
|
328
|
+
@response_set.correctness_hash.should == {:questions => 3, :responses => 3, :correct => 3}
|
329
|
+
end
|
330
|
+
end
|
331
|
+
describe ResponseSet, "with mandatory questions" do
|
332
|
+
before(:each) do
|
333
|
+
@survey = FactoryGirl.create(:survey)
|
334
|
+
@section = FactoryGirl.create(:survey_section, :survey => @survey)
|
335
|
+
@response_set = FactoryGirl.create(:response_set, :survey => @survey)
|
336
|
+
end
|
337
|
+
def generate_responses(count, mandatory = nil, responded = nil)
|
338
|
+
count.times do |i|
|
339
|
+
q = FactoryGirl.create(:question, :survey_section => @section, :is_mandatory => (mandatory == "mandatory"))
|
340
|
+
a = FactoryGirl.create(:answer, :question => q, :response_class => "answer")
|
341
|
+
if responded == "responded"
|
342
|
+
@response_set.responses << FactoryGirl.create(:response, :question => q, :answer => a)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
it "should report progress without mandatory questions" do
|
347
|
+
generate_responses(3)
|
348
|
+
@response_set.mandatory_questions_complete?.should be_true
|
349
|
+
@response_set.progress_hash.should == {:questions => 3, :triggered => 3, :triggered_mandatory => 0, :triggered_mandatory_completed => 0}
|
350
|
+
end
|
351
|
+
it "should report progress with mandatory questions" do
|
352
|
+
generate_responses(3, "mandatory", "responded")
|
353
|
+
@response_set.mandatory_questions_complete?.should be_true
|
354
|
+
@response_set.progress_hash.should == {:questions => 3, :triggered => 3, :triggered_mandatory => 3, :triggered_mandatory_completed => 3}
|
355
|
+
end
|
356
|
+
it "should report progress with mandatory questions" do
|
357
|
+
generate_responses(3, "mandatory", "not-responded")
|
358
|
+
@response_set.mandatory_questions_complete?.should be_false
|
359
|
+
@response_set.progress_hash.should == {:questions => 3, :triggered => 3, :triggered_mandatory => 3, :triggered_mandatory_completed => 0}
|
360
|
+
end
|
361
|
+
it "should ignore labels and images" do
|
362
|
+
generate_responses(3, "mandatory", "responded")
|
363
|
+
FactoryGirl.create(:question, :survey_section => @section, :display_type => "label", :is_mandatory => true)
|
364
|
+
FactoryGirl.create(:question, :survey_section => @section, :display_type => "image", :is_mandatory => true)
|
365
|
+
@response_set.mandatory_questions_complete?.should be_true
|
366
|
+
@response_set.progress_hash.should == {:questions => 5, :triggered => 5, :triggered_mandatory => 5, :triggered_mandatory_completed => 5}
|
367
|
+
end
|
368
|
+
end
|
369
|
+
describe ResponseSet, "with mandatory, dependent questions" do
|
370
|
+
before(:each) do
|
371
|
+
@survey = FactoryGirl.create(:survey)
|
372
|
+
@section = FactoryGirl.create(:survey_section, :survey => @survey)
|
373
|
+
Qstruct = Struct.new(:q, :a) unless defined?(Qstruct)
|
374
|
+
end
|
375
|
+
def generate_responses(count, mandatory = nil, dependent = nil, triggered = nil)
|
376
|
+
dq = FactoryGirl.create(:question, :survey_section => @section, :is_mandatory => (mandatory == "mandatory"))
|
377
|
+
da = FactoryGirl.create(:answer, :question => dq, :response_class => "answer")
|
378
|
+
dx = FactoryGirl.create(:answer, :question => dq, :response_class => "answer")
|
379
|
+
qary = []
|
380
|
+
count.times do |i|
|
381
|
+
q = FactoryGirl.create(:question, :survey_section => @section, :is_mandatory => (mandatory == "mandatory"))
|
382
|
+
a = FactoryGirl.create(:answer, :question => q, :response_class => "answer")
|
383
|
+
if dependent == "dependent"
|
384
|
+
d = FactoryGirl.create(:dependency, :question => q)
|
385
|
+
dc = FactoryGirl.create(:dependency_condition, :dependency => d, :question_id => dq.id, :answer_id => da.id)
|
386
|
+
end
|
387
|
+
qary << Qstruct.new(q, a)
|
388
|
+
end
|
389
|
+
@response_set = FactoryGirl.create(:response_set, :survey => @survey)
|
390
|
+
@response_set.responses << FactoryGirl.create(:response, :response_set => @response_set, :question => dq, :answer => (triggered == "triggered" ? da : dx))
|
391
|
+
qary.each do |q|
|
392
|
+
@response_set.responses << FactoryGirl.create(:response, :response_set => @response_set, :question => q.q, :answer => q.a)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
it "should report progress without mandatory questions" do
|
396
|
+
generate_responses(3, "mandatory", "dependent")
|
397
|
+
@response_set.mandatory_questions_complete?.should be_true
|
398
|
+
@response_set.progress_hash.should == {:questions => 4, :triggered => 1, :triggered_mandatory => 1, :triggered_mandatory_completed => 1}
|
399
|
+
end
|
400
|
+
it "should report progress with mandatory questions" do
|
401
|
+
generate_responses(3, "mandatory", "dependent", "triggered")
|
402
|
+
@response_set.mandatory_questions_complete?.should be_true
|
403
|
+
@response_set.progress_hash.should == {:questions => 4, :triggered => 4, :triggered_mandatory => 4, :triggered_mandatory_completed => 4}
|
404
|
+
end
|
405
|
+
end
|
406
|
+
describe ResponseSet, "exporting csv" do
|
407
|
+
before(:each) do
|
408
|
+
@section = FactoryGirl.create(:survey_section)
|
409
|
+
# Questions
|
410
|
+
@do_you_like_pie = FactoryGirl.create(:question, :text => "Do you like pie?", :survey_section => @section)
|
411
|
+
@what_flavor = FactoryGirl.create(:question, :text => "What flavor?", :survey_section => @section)
|
412
|
+
@what_bakery = FactoryGirl.create(:question, :text => "What bakery?", :survey_section => @section)
|
413
|
+
# Answers
|
414
|
+
@do_you_like_pie.answers << FactoryGirl.create(:answer, :text => "yes", :question_id => @do_you_like_pie.id)
|
415
|
+
@do_you_like_pie.answers << FactoryGirl.create(:answer, :text => "no", :question_id => @do_you_like_pie.id)
|
416
|
+
@what_flavor.answers << FactoryGirl.create(:answer, :response_class => :string, :question_id => @what_flavor.id)
|
417
|
+
@what_bakery.answers << FactoryGirl.create(:answer, :response_class => :string, :question_id => @what_bakery.id)
|
418
|
+
# Responses
|
419
|
+
@response_set = FactoryGirl.create(:response_set)
|
420
|
+
@response_set.responses << FactoryGirl.create(:response, :question_id => @do_you_like_pie.id, :answer_id => @do_you_like_pie.answers.first.id, :response_set_id => @response_set.id)
|
421
|
+
@response_set.responses << FactoryGirl.create(:response, :string_value => "pecan pie", :question_id => @what_flavor.id, :answer_id => @what_flavor.answers.first.id, :response_set_id => @response_set.id)
|
422
|
+
end
|
423
|
+
it "should export a string with responses" do
|
424
|
+
@response_set.responses.size.should == 2
|
425
|
+
csv = @response_set.to_csv
|
426
|
+
csv.is_a?(String).should be_true
|
427
|
+
csv.should match "question.short_text"
|
428
|
+
csv.should match "What flavor?"
|
429
|
+
csv.should match /pecan pie/
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
describe ResponseSet, "#as_json" do
|
434
|
+
let(:rs) {
|
435
|
+
FactoryGirl.create(:response_set, :responses => [
|
436
|
+
FactoryGirl.create(:response, :question => FactoryGirl.create(:question), :answer => FactoryGirl.create(:answer), :string_value => '2')])
|
437
|
+
}
|
438
|
+
|
439
|
+
let(:js) {rs.as_json}
|
440
|
+
|
441
|
+
it "should include uuid, survey_id" do
|
442
|
+
js[:uuid].should == rs.api_id
|
443
|
+
end
|
444
|
+
|
445
|
+
it "should include responses with uuid, question_id, answer_id, value" do
|
446
|
+
r0 = rs.responses[0]
|
447
|
+
js[:responses][0][:uuid].should == r0.api_id
|
448
|
+
js[:responses][0][:answer_id].should == r0.answer.api_id
|
449
|
+
js[:responses][0][:question_id].should == r0.question.api_id
|
450
|
+
js[:responses][0][:value].should == r0.string_value
|
451
|
+
end
|
452
|
+
end
|