jakewendt-surveyor 0.11.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +285 -0
  3. data/Rakefile +54 -0
  4. data/VERSION +1 -0
  5. data/app/controllers/surveyor_controller.rb +142 -0
  6. data/app/helpers/survey_form_builder.rb +37 -0
  7. data/app/helpers/surveyor_helper.rb +67 -0
  8. data/app/models/answer.rb +23 -0
  9. data/app/models/dependency.rb +50 -0
  10. data/app/models/dependency_condition.rb +47 -0
  11. data/app/models/question.rb +54 -0
  12. data/app/models/question_group.rb +33 -0
  13. data/app/models/response.rb +94 -0
  14. data/app/models/response_set.rb +316 -0
  15. data/app/models/survey.rb +172 -0
  16. data/app/models/survey_section.rb +18 -0
  17. data/app/models/validation.rb +38 -0
  18. data/app/models/validation_condition.rb +47 -0
  19. data/app/views/layouts/surveyor_default.html.erb +13 -0
  20. data/app/views/partials/_answer.html.haml +58 -0
  21. data/app/views/partials/_question.html.haml +80 -0
  22. data/app/views/partials/_question_group.html.haml +39 -0
  23. data/app/views/surveyor/edit.html.haml +38 -0
  24. data/app/views/surveyor/new.html.haml +16 -0
  25. data/app/views/surveyor/show.html.haml +12 -0
  26. data/config/routes.rb +11 -0
  27. data/features/step_definitions/surveyor_steps.rb +7 -0
  28. data/features/step_definitions/web_steps.rb +273 -0
  29. data/features/support/env.rb +57 -0
  30. data/features/support/paths.rb +25 -0
  31. data/features/surveyor.feature +11 -0
  32. data/generators/extend_surveyor/extend_surveyor_generator.rb +22 -0
  33. data/generators/extend_surveyor/templates/EXTENDING_SURVEYOR +17 -0
  34. data/generators/extend_surveyor/templates/extensions/survey_extensions.rb +24 -0
  35. data/generators/extend_surveyor/templates/extensions/surveyor_controller_extensions.rb +28 -0
  36. data/generators/extend_surveyor/templates/extensions/surveyor_custom.html.erb +13 -0
  37. data/generators/extend_surveyor/templates/extensions/surveyor_helper_extensions.rb +17 -0
  38. data/generators/surveyor/surveyor_generator.rb +67 -0
  39. data/generators/surveyor/templates/README +10 -0
  40. data/generators/surveyor/templates/assets/images/222222_11x11_icon_arrows_leftright.gif +0 -0
  41. data/generators/surveyor/templates/assets/images/222222_11x11_icon_arrows_updown.gif +0 -0
  42. data/generators/surveyor/templates/assets/images/222222_11x11_icon_close.gif +0 -0
  43. data/generators/surveyor/templates/assets/images/222222_11x11_icon_doc.gif +0 -0
  44. data/generators/surveyor/templates/assets/images/222222_11x11_icon_folder_closed.gif +0 -0
  45. data/generators/surveyor/templates/assets/images/222222_11x11_icon_folder_open.gif +0 -0
  46. data/generators/surveyor/templates/assets/images/222222_11x11_icon_minus.gif +0 -0
  47. data/generators/surveyor/templates/assets/images/222222_11x11_icon_plus.gif +0 -0
  48. data/generators/surveyor/templates/assets/images/222222_11x11_icon_resize_se.gif +0 -0
  49. data/generators/surveyor/templates/assets/images/222222_35x9_colorpicker_indicator.gif.gif +0 -0
  50. data/generators/surveyor/templates/assets/images/222222_7x7_arrow_down.gif +0 -0
  51. data/generators/surveyor/templates/assets/images/222222_7x7_arrow_left.gif +0 -0
  52. data/generators/surveyor/templates/assets/images/222222_7x7_arrow_right.gif +0 -0
  53. data/generators/surveyor/templates/assets/images/222222_7x7_arrow_up.gif +0 -0
  54. data/generators/surveyor/templates/assets/images/454545_11x11_icon_arrows_leftright.gif +0 -0
  55. data/generators/surveyor/templates/assets/images/454545_11x11_icon_arrows_updown.gif +0 -0
  56. data/generators/surveyor/templates/assets/images/454545_11x11_icon_close.gif +0 -0
  57. data/generators/surveyor/templates/assets/images/454545_11x11_icon_doc.gif +0 -0
  58. data/generators/surveyor/templates/assets/images/454545_11x11_icon_folder_closed.gif +0 -0
  59. data/generators/surveyor/templates/assets/images/454545_11x11_icon_folder_open.gif +0 -0
  60. data/generators/surveyor/templates/assets/images/454545_11x11_icon_minus.gif +0 -0
  61. data/generators/surveyor/templates/assets/images/454545_11x11_icon_plus.gif +0 -0
  62. data/generators/surveyor/templates/assets/images/454545_7x7_arrow_down.gif +0 -0
  63. data/generators/surveyor/templates/assets/images/454545_7x7_arrow_left.gif +0 -0
  64. data/generators/surveyor/templates/assets/images/454545_7x7_arrow_right.gif +0 -0
  65. data/generators/surveyor/templates/assets/images/454545_7x7_arrow_up.gif +0 -0
  66. data/generators/surveyor/templates/assets/images/888888_11x11_icon_arrows_leftright.gif +0 -0
  67. data/generators/surveyor/templates/assets/images/888888_11x11_icon_arrows_updown.gif +0 -0
  68. data/generators/surveyor/templates/assets/images/888888_11x11_icon_close.gif +0 -0
  69. data/generators/surveyor/templates/assets/images/888888_11x11_icon_doc.gif +0 -0
  70. data/generators/surveyor/templates/assets/images/888888_11x11_icon_folder_closed.gif +0 -0
  71. data/generators/surveyor/templates/assets/images/888888_11x11_icon_folder_open.gif +0 -0
  72. data/generators/surveyor/templates/assets/images/888888_11x11_icon_minus.gif +0 -0
  73. data/generators/surveyor/templates/assets/images/888888_11x11_icon_plus.gif +0 -0
  74. data/generators/surveyor/templates/assets/images/888888_7x7_arrow_down.gif +0 -0
  75. data/generators/surveyor/templates/assets/images/888888_7x7_arrow_left.gif +0 -0
  76. data/generators/surveyor/templates/assets/images/888888_7x7_arrow_right.gif +0 -0
  77. data/generators/surveyor/templates/assets/images/888888_7x7_arrow_up.gif +0 -0
  78. data/generators/surveyor/templates/assets/images/dadada_40x100_textures_02_glass_75.png +0 -0
  79. data/generators/surveyor/templates/assets/images/e6e6e6_40x100_textures_02_glass_75.png +0 -0
  80. data/generators/surveyor/templates/assets/images/ffffff_40x100_textures_01_flat_0.png +0 -0
  81. data/generators/surveyor/templates/assets/images/ffffff_40x100_textures_02_glass_65.png +0 -0
  82. data/generators/surveyor/templates/assets/javascripts/accessibleUISlider.jQuery.js +201 -0
  83. data/generators/surveyor/templates/assets/javascripts/jquery-1.2.6.js +3549 -0
  84. data/generators/surveyor/templates/assets/javascripts/jquery-ui-personalized-1.5.3.js +7616 -0
  85. data/generators/surveyor/templates/assets/javascripts/jquery.form.js +637 -0
  86. data/generators/surveyor/templates/assets/javascripts/surveyor.js +47 -0
  87. data/generators/surveyor/templates/assets/stylesheets/jquery-ui-slider-additions.css +71 -0
  88. data/generators/surveyor/templates/assets/stylesheets/reset.css +50 -0
  89. data/generators/surveyor/templates/assets/stylesheets/sass/surveyor.sass +243 -0
  90. data/generators/surveyor/templates/assets/stylesheets/surveyor.css +235 -0
  91. data/generators/surveyor/templates/assets/stylesheets/ui.theme.css +851 -0
  92. data/generators/surveyor/templates/initializers/haml.rb +8 -0
  93. data/generators/surveyor/templates/initializers/surveyor.rb +10 -0
  94. data/generators/surveyor/templates/migrate/add_correct_answer_id_to_questions.rb +9 -0
  95. data/generators/surveyor/templates/migrate/add_display_order_to_surveys.rb +9 -0
  96. data/generators/surveyor/templates/migrate/add_index_to_response_sets.rb +9 -0
  97. data/generators/surveyor/templates/migrate/add_index_to_surveys.rb +9 -0
  98. data/generators/surveyor/templates/migrate/add_manual_numbering.rb +11 -0
  99. data/generators/surveyor/templates/migrate/add_unique_indicies.rb +17 -0
  100. data/generators/surveyor/templates/migrate/create_answers.rb +37 -0
  101. data/generators/surveyor/templates/migrate/create_dependencies.rb +22 -0
  102. data/generators/surveyor/templates/migrate/create_dependency_conditions.rb +29 -0
  103. data/generators/surveyor/templates/migrate/create_question_groups.rb +27 -0
  104. data/generators/surveyor/templates/migrate/create_questions.rb +36 -0
  105. data/generators/surveyor/templates/migrate/create_response_sets.rb +22 -0
  106. data/generators/surveyor/templates/migrate/create_responses.rb +33 -0
  107. data/generators/surveyor/templates/migrate/create_survey_sections.rb +29 -0
  108. data/generators/surveyor/templates/migrate/create_surveys.rb +31 -0
  109. data/generators/surveyor/templates/migrate/create_validation_conditions.rb +32 -0
  110. data/generators/surveyor/templates/migrate/create_validations.rb +20 -0
  111. data/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +218 -0
  112. data/generators/surveyor/templates/tasks/surveyor.rb +4 -0
  113. data/generators/test_surveyor/templates/TESTING_SURVEYOR +0 -0
  114. data/generators/test_surveyor/templates/environments/cucumber.rb +21 -0
  115. data/generators/test_surveyor/test_surveyor_generator.rb +15 -0
  116. data/jakewendt-surveyor.gemspec +212 -0
  117. data/lib/fixtures_extensions.rb +6 -0
  118. data/lib/jakewendt-surveyor.rb +1 -0
  119. data/lib/surveyor.rb +44 -0
  120. data/lib/surveyor/acts_as_response.rb +33 -0
  121. data/lib/surveyor/config.rb +45 -0
  122. data/lib/tasks/surveyor_tasks.rake +33 -0
  123. data/lib/xml_formatter.rb +12 -0
  124. data/rails/init.rb +1 -0
  125. data/script/surveyor/answer.rb +54 -0
  126. data/script/surveyor/base.rb +77 -0
  127. data/script/surveyor/dependency.rb +13 -0
  128. data/script/surveyor/dependency_condition.rb +40 -0
  129. data/script/surveyor/parser.rb +207 -0
  130. data/script/surveyor/question.rb +37 -0
  131. data/script/surveyor/question_group.rb +26 -0
  132. data/script/surveyor/specs/answer_spec.rb +29 -0
  133. data/script/surveyor/specs/question_spec.rb +63 -0
  134. data/script/surveyor/specs/spec_helper.rb +7 -0
  135. data/script/surveyor/specs/survey_section_spec.rb +23 -0
  136. data/script/surveyor/specs/validation_condition_spec.rb +20 -0
  137. data/script/surveyor/specs/validation_spec.rb +20 -0
  138. data/script/surveyor/survey.rb +35 -0
  139. data/script/surveyor/survey_section.rb +21 -0
  140. data/script/surveyor/validation.rb +21 -0
  141. data/script/surveyor/validation_condition.rb +21 -0
  142. data/script/surveyor/whr_dsl.tmproj +244 -0
  143. data/spec/controllers/surveyor_controller_spec.rb +193 -0
  144. data/spec/factories.rb +145 -0
  145. data/spec/lib/surveyor_spec.rb +44 -0
  146. data/spec/models/answer_spec.rb +29 -0
  147. data/spec/models/dependency_condition_spec.rb +321 -0
  148. data/spec/models/dependency_spec.rb +81 -0
  149. data/spec/models/question_group_spec.rb +35 -0
  150. data/spec/models/question_spec.rb +75 -0
  151. data/spec/models/response_set_spec.rb +245 -0
  152. data/spec/models/response_spec.rb +76 -0
  153. data/spec/models/survey_section_spec.rb +32 -0
  154. data/spec/models/survey_spec.rb +71 -0
  155. data/spec/models/validation_condition_spec.rb +105 -0
  156. data/spec/models/validation_spec.rb +59 -0
  157. data/spec/rcov.opts +2 -0
  158. data/spec/spec.opts +4 -0
  159. data/spec/spec_helper.rb +12 -0
  160. metadata +254 -0
@@ -0,0 +1,81 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Dependency do
4
+ before(:each) do
5
+ @dependency = Factory(: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
+
47
+ end
48
+
49
+ describe Dependency, "when evaluating dependency conditions of a question in a response set" do
50
+
51
+ before(:each) do
52
+ @dep = Dependency.new(:rule => "A", :question_id => 1)
53
+ @dep2 = Dependency.new(:rule => "A and B", :question_id => 1)
54
+ @dep3 = Dependency.new(:rule => "A or B", :question_id => 1)
55
+ @dep4 = Dependency.new(:rule => "!(A and B) and C", :question_id => 1)
56
+
57
+ @dep_c = mock_model(DependencyCondition, :id => 1, :rule_key => "A", :to_hash => {:A => true})
58
+ @dep_c2 = mock_model(DependencyCondition, :id => 2, :rule_key => "B", :to_hash => {:B => false})
59
+ @dep_c3 = mock_model(DependencyCondition, :id => 3, :rule_key => "C", :to_hash => {:C => true})
60
+
61
+ @dep.stub!(:dependency_conditions).and_return([@dep_c])
62
+ @dep2.stub!(:dependency_conditions).and_return([@dep_c, @dep_c2])
63
+ @dep3.stub!(:dependency_conditions).and_return([@dep_c, @dep_c2])
64
+ @dep4.stub!(:dependency_conditions).and_return([@dep_c, @dep_c2, @dep_c3])
65
+ end
66
+
67
+ it "knows if the dependencies are met" do
68
+ @dep.is_met?(@response_set).should be_true
69
+ @dep2.is_met?(@response_set).should be_false
70
+ @dep3.is_met?(@response_set).should be_true
71
+ @dep4.is_met?(@response_set).should be_true
72
+ end
73
+
74
+ it "returns the proper keyed pairs from the dependency conditions" do
75
+ @dep.conditions_hash(@response_set).should == {:A => true}
76
+ @dep2.conditions_hash(@response_set).should == {:A => true, :B => false}
77
+ @dep3.conditions_hash(@response_set).should == {:A => true, :B => false}
78
+ @dep4.conditions_hash(@response_set).should == {:A => true, :B => false, :C => true}
79
+ end
80
+
81
+ end
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe QuestionGroup do
4
+ before(:each) do
5
+ @question_group = Factory(:question_group)
6
+ end
7
+
8
+ it "should be valid" do
9
+ @question_group.should be_valid
10
+ end
11
+ it "should have defaults" do
12
+ @question_group = QuestionGroup.new
13
+ @question_group.display_type.should == "inline"
14
+ @question_group.renderer.should == :inline
15
+ @question_group.display_type = nil
16
+ @question_group.renderer.should == :default
17
+ end
18
+ it "should return its custom css class" do
19
+ @question_group.custom_class = "foo bar"
20
+ @question_group.css_class(Factory(:response_set)).should == "foo bar"
21
+ end
22
+ it "should return its dependency class" do
23
+ @dependency = Factory(:dependency)
24
+ @question_group.dependency = @dependency
25
+ @dependency.should_receive(:is_met?).and_return(true)
26
+ @question_group.css_class(Factory(:response_set)).should == "dependent"
27
+
28
+ @dependency.should_receive(:is_met?).and_return(false)
29
+ @question_group.css_class(Factory(:response_set)).should == "dependent hidden"
30
+
31
+ @question_group.custom_class = "foo bar"
32
+ @dependency.should_receive(:is_met?).and_return(false)
33
+ @question_group.css_class(Factory(:response_set)).should == "dependent hidden foo bar"
34
+ end
35
+ end
@@ -0,0 +1,75 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Question, "when creating a new question" do
4
+ before(:each) do
5
+ @ss = mock_model(SurveySection)
6
+ @question = Question.new(:text => "What is your favorite color?", :survey_section => @ss, :is_mandatory => true, :display_order => 1)
7
+ end
8
+
9
+ it "should be valid" do
10
+ @question.should be_valid
11
+ end
12
+
13
+ it "should be invalid without text" do
14
+ @question.text = nil
15
+ @question.should have(1).error_on(:text)
16
+ end
17
+
18
+ it "should have a parent survey section" do
19
+ @question.survey_section = nil
20
+ @question.should have(1).error_on(:survey_section_id)
21
+ end
22
+
23
+ it "should be mandatory by default" do
24
+ @question.mandatory?.should be_true
25
+ end
26
+
27
+ end
28
+
29
+ describe Question, "that has answers" do
30
+ before(:each) do
31
+ @question = Factory(:question, :text => "What is your favorite color?")
32
+ Factory(:answer, :question => @question, :display_order => 3, :text => "blue")
33
+ Factory(:answer, :question => @question, :display_order => 1, :text => "red")
34
+ Factory(:answer, :question => @question, :display_order => 2, :text => "green")
35
+ end
36
+
37
+ it "should have answers" do
38
+ @question.answers.should have(3).answers
39
+ end
40
+
41
+ it "should retrieve those answers in display_order" do
42
+ @question.answers.map(&:display_order).should == [1,2,3]
43
+ end
44
+
45
+ end
46
+
47
+ describe Question, "when interacting with an instance" do
48
+
49
+ before(:each) do
50
+ @ss = mock_model(SurveySection)
51
+ @question = Question.new(:text => "What is your favorite color?", :survey_section => @ss)
52
+ end
53
+
54
+ it "should return 'default' for nil display type" do
55
+ @question.display_type = nil
56
+ @question.renderer.should == :default
57
+ end
58
+
59
+ end
60
+
61
+ describe Question, "with dependencies" do
62
+ before(:each) do
63
+ @ss = mock_model(SurveySection)
64
+ @rs = mock_model(ResponseSet)
65
+ @question = Question.new(:text => "Which island?", :survey_section => @ss)
66
+ end
67
+
68
+ it "should check its dependency" do
69
+ @dependency = mock_model(Dependency)
70
+ @dependency.stub!(:is_met?).with(@rs).and_return(true)
71
+ @question.stub!(:dependency).and_return(@dependency)
72
+ @question.triggered?(@rs).should == true
73
+ end
74
+
75
+ end
@@ -0,0 +1,245 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe ResponseSet do
4
+ before(:each) do
5
+ @response_set = Factory(:response_set)
6
+ end
7
+ it "should have a unique code with length 10 that identifies the survey" do
8
+ @response_set.access_code.should_not be_nil
9
+ @response_set.access_code.length.should == 10
10
+ end
11
+ it "is completable" do
12
+ @response_set.completed_at.should be_nil
13
+ @response_set.complete!
14
+ @response_set.completed_at.should_not be_nil
15
+ @response_set.completed_at.is_a?(Time).should be_true
16
+ end
17
+ it "does not allow completion through mass assignment" do
18
+ @response_set.completed_at.should be_nil
19
+ @response_set.update_attributes(:completed_at => Time.now)
20
+ @response_set.completed_at.should be_nil
21
+ end
22
+ end
23
+ describe ResponseSet, "Updating the response set" do
24
+ before(:each) do
25
+ @response_set = Factory(:response_set)
26
+ # {"responses"=>{
27
+ # "6"=>{"question_id"=>"6", "20"=>{"string_value"=>""}},
28
+ # "7"=>{"question_id"=>"7", "21"=>{"text_value"=>"Brian is tired"}},
29
+ # "1"=>{"question_id"=>"1", "answer_id"=>"1", "4"=>{"string_value"=>"XXL"}},
30
+ # "2"=>{"question_id"=>"2", "answer_id"=>"6"},
31
+ # "3"=>{"question_id"=>"3"},
32
+ # "4"=>{"question_id"=>"4"},
33
+ # "5"=>{"question_id"=>"5", "19"=>{"string_value"=>""}}},
34
+ # "survey_code"=>"test_survey",
35
+ # "commit"=>"Next Section (Utensiles and you!) >>",
36
+ # "authenticity_token"=>"d03bc1b52fa9669e1ed87c313b939836e7b93e34",
37
+ # "_method"=>"put",
38
+ # "action"=>"update",
39
+ # "controller"=>"app",
40
+ # "response_set_code"=>"cIFn0DnxlU",
41
+ # "section"=>"2"}
42
+
43
+ #TODO test views to produce these params. e.g., blank responses should still have a hash with question_id
44
+ @radio_response_attributes = HashWithIndifferentAccess.new({
45
+ "1"=>{"question_id"=>"1", "answer_id"=>"1", "4"=>{"string_value"=>"XXL"}},
46
+ "2"=>{"question_id"=>"2", "answer_id"=>"6"},
47
+ "3"=>{"question_id"=>"3"}
48
+ })
49
+ @other_response_attributes = HashWithIndifferentAccess.new({
50
+ "6"=>{"question_id"=>"6", "20"=>{"string_value"=>""}},
51
+ "7"=>{"question_id"=>"7", "21"=>{"text_value"=>"Brian is tired"}},
52
+ "5"=>{"question_id"=>"5", "19"=>{"string_value"=>""}}
53
+ })
54
+ end
55
+
56
+ it "should save new responses from radio buttons, ignoring blanks" do
57
+ @response_set.update_attributes(:response_attributes => @radio_response_attributes)
58
+ @response_set.responses.should have(2).items
59
+ @response_set.responses.detect{|r| r.question_id == 2}.answer_id.should == 6
60
+ end
61
+ it "should save new responses from other types, ignoring blanks" do
62
+ @response_set.update_attributes(:response_attributes => @other_response_attributes)
63
+ @response_set.responses.should have(1).items
64
+ @response_set.responses.detect{|r| r.question_id == 7}.text_value.should == "Brian is tired"
65
+ end
66
+ it "should ignore data if corresponding radio button is not selected" do
67
+ @response_set.update_attributes(:response_attributes => @radio_response_attributes)
68
+ @response_set.responses.select{|r| r.question_id == 2}.should have(1).item
69
+ @response_set.responses.detect{|r| r.question_id == 2}.string_value.should == nil
70
+ end
71
+ it "should preserve data in checkboxes regardless of selection" do
72
+ pending
73
+ end
74
+
75
+ it "should give convenient access to responses through response_for" do
76
+ @response_set.save #need to save for the associated models to build/save
77
+ @response_set.attributes = {:response_attributes => @radio_response_attributes}
78
+ @response_set.save.should be_true
79
+ @response_set.responses.should have(2).items
80
+
81
+ pending
82
+ end
83
+ end
84
+
85
+ describe ResponseSet, "with dependencies" do
86
+ before(:each) do
87
+ @section = Factory(:survey_section)
88
+ # Questions
89
+ @do_you_like_pie = Factory(:question, :text => "Do you like pie?", :survey_section => @section)
90
+ @what_flavor = Factory(:question, :text => "What flavor?", :survey_section => @section)
91
+ @what_bakery = Factory(:question, :text => "What bakery?", :survey_section => @section)
92
+ # Answers
93
+ @do_you_like_pie.answers << Factory(:answer, :text => "yes", :question_id => @do_you_like_pie.id)
94
+ @do_you_like_pie.answers << Factory(:answer, :text => "no", :question_id => @do_you_like_pie.id)
95
+ @what_flavor.answers << Factory(:answer, :response_class => :string, :question_id => @what_flavor.id)
96
+ @what_bakery.answers << Factory(:answer, :response_class => :string, :question_id => @what_bakery.id)
97
+ # Dependency
98
+ @what_flavor_dep = Factory(:dependency, :rule => "A", :question_id => @what_flavor.id)
99
+ Factory(: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)
100
+ @what_bakery_dep = Factory(:dependency, :rule => "B", :question_id => @what_bakery.id)
101
+ Factory(: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)
102
+ # Responses
103
+ @response_set = Factory(:response_set)
104
+ @response_set.current_section_id = @section.id
105
+ @response_set.responses << Factory(:response, :question_id => @do_you_like_pie.id, :answer_id => @do_you_like_pie.answers.first.id, :response_set_id => @response_set.id)
106
+ @response_set.responses << Factory(:response, :string_value => "pecan pie", :question_id => @what_flavor.id, :answer_id => @what_flavor.answers.first.id, :response_set_id => @response_set.id)
107
+ end
108
+
109
+ it "should list unanswered dependencies to show at the top of the next page (javascript turned off)" do
110
+ @response_set.unanswered_dependencies.should == [@what_bakery]
111
+ end
112
+ it "should list answered and unanswered dependencies to show inline (javascript turned on)" do
113
+ @response_set.all_dependencies[:show].should == ["question_#{@what_flavor.id}", "question_#{@what_bakery.id}"]
114
+ end
115
+
116
+ end
117
+ describe ResponseSet, "as a quiz" do
118
+ before(:each) do
119
+ @survey = Factory(:survey)
120
+ @section = Factory(:survey_section, :survey => @survey)
121
+ @response_set = Factory(:response_set, :survey => @survey)
122
+ end
123
+ def generate_responses(count, quiz = nil, correct = nil)
124
+ count.times do |i|
125
+ q = Factory(:question, :survey_section => @section)
126
+ a = Factory(:answer, :question => q, :response_class => "answer")
127
+ x = Factory(:answer, :question => q, :response_class => "answer")
128
+ q.correct_answer_id = (quiz == "quiz" ? a.id : nil)
129
+ @response_set.responses << Factory(:response, :question => q, :answer => (correct == "correct" ? a : x))
130
+ end
131
+ end
132
+
133
+ it "should report correctness if it is a quiz" do
134
+ generate_responses(3, "quiz", "correct")
135
+ @response_set.correct?.should be_true
136
+ @response_set.correctness_hash.should == {:questions => 3, :responses => 3, :correct => 3}
137
+ end
138
+ it "should report incorrectness if it is a quiz" do
139
+ generate_responses(3, "quiz", "incorrect")
140
+ @response_set.correct?.should be_false
141
+ @response_set.correctness_hash.should == {:questions => 3, :responses => 3, :correct => 0}
142
+ end
143
+ it "should report correct if it isn't a quiz" do
144
+ generate_responses(3, "non-quiz")
145
+ @response_set.correct?.should be_true
146
+ @response_set.correctness_hash.should == {:questions => 3, :responses => 3, :correct => 3}
147
+ end
148
+ end
149
+ describe ResponseSet, "with mandatory questions" do
150
+ before(:each) do
151
+ @survey = Factory(:survey)
152
+ @section = Factory(:survey_section, :survey => @survey)
153
+ @response_set = Factory(:response_set, :survey => @survey)
154
+ end
155
+ def generate_responses(count, mandatory = nil, responded = nil)
156
+ count.times do |i|
157
+ q = Factory(:question, :survey_section => @section, :is_mandatory => (mandatory == "mandatory"))
158
+ a = Factory(:answer, :question => q, :response_class => "answer")
159
+ if responded == "responded"
160
+ @response_set.responses << Factory(:response, :question => q, :answer => a)
161
+ end
162
+ end
163
+ end
164
+ it "should report progress without mandatory questions" do
165
+ generate_responses(3)
166
+ @response_set.mandatory_questions_complete?.should be_true
167
+ @response_set.progress_hash.should == {:questions => 3, :triggered => 3, :triggered_mandatory => 0, :triggered_mandatory_completed => 0}
168
+ end
169
+ it "should report progress with mandatory questions" do
170
+ generate_responses(3, "mandatory", "responded")
171
+ @response_set.mandatory_questions_complete?.should be_true
172
+ @response_set.progress_hash.should == {:questions => 3, :triggered => 3, :triggered_mandatory => 3, :triggered_mandatory_completed => 3}
173
+ end
174
+ it "should report progress with mandatory questions" do
175
+ generate_responses(3, "mandatory", "not-responded")
176
+ @response_set.mandatory_questions_complete?.should be_false
177
+ @response_set.progress_hash.should == {:questions => 3, :triggered => 3, :triggered_mandatory => 3, :triggered_mandatory_completed => 0}
178
+ end
179
+ it "should ignore labels and images" do
180
+ generate_responses(3, "mandatory", "responded")
181
+ Factory(:question, :survey_section => @section, :display_type => "label", :is_mandatory => true)
182
+ Factory(:question, :survey_section => @section, :display_type => "image", :is_mandatory => true)
183
+ @response_set.mandatory_questions_complete?.should be_true
184
+ @response_set.progress_hash.should == {:questions => 5, :triggered => 5, :triggered_mandatory => 5, :triggered_mandatory_completed => 5}
185
+ end
186
+ end
187
+ describe ResponseSet, "with mandatory, dependent questions" do
188
+ before(:each) do
189
+ @survey = Factory(:survey)
190
+ @section = Factory(:survey_section, :survey => @survey)
191
+ @response_set = Factory(:response_set, :survey => @survey)
192
+ end
193
+ def generate_responses(count, mandatory = nil, dependent = nil, triggered = nil)
194
+ dq = Factory(:question, :survey_section => @section, :is_mandatory => (mandatory == "mandatory"))
195
+ da = Factory(:answer, :question => dq, :response_class => "answer")
196
+ dx = Factory(:answer, :question => dq, :response_class => "answer")
197
+ count.times do |i|
198
+ q = Factory(:question, :survey_section => @section, :is_mandatory => (mandatory == "mandatory"))
199
+ a = Factory(:answer, :question => q, :response_class => "answer")
200
+ if dependent == "dependent"
201
+ d = Factory(:dependency, :question => q)
202
+ dc = Factory(:dependency_condition, :dependency => d, :question_id => dq.id, :answer_id => da.id)
203
+ end
204
+ @response_set.responses << Factory(:response, :question => dq, :answer => (triggered == "triggered" ? da : dx))
205
+ @response_set.responses << Factory(:response, :question => q, :answer => a)
206
+ end
207
+ end
208
+ it "should report progress without mandatory questions" do
209
+ generate_responses(3, "mandatory", "dependent")
210
+ @response_set.mandatory_questions_complete?.should be_true
211
+ @response_set.progress_hash.should == {:questions => 4, :triggered => 1, :triggered_mandatory => 1, :triggered_mandatory_completed => 1}
212
+ end
213
+ it "should report progress with mandatory questions" do
214
+ generate_responses(3, "mandatory", "dependent", "triggered")
215
+ @response_set.mandatory_questions_complete?.should be_true
216
+ @response_set.progress_hash.should == {:questions => 4, :triggered => 4, :triggered_mandatory => 4, :triggered_mandatory_completed => 4}
217
+ end
218
+ end
219
+ describe ResponseSet, "exporting csv" do
220
+ before(:each) do
221
+ @section = Factory(:survey_section)
222
+ # Questions
223
+ @do_you_like_pie = Factory(:question, :text => "Do you like pie?", :survey_section => @section)
224
+ @what_flavor = Factory(:question, :text => "What flavor?", :survey_section => @section)
225
+ @what_bakery = Factory(:question, :text => "What bakery?", :survey_section => @section)
226
+ # Answers
227
+ @do_you_like_pie.answers << Factory(:answer, :text => "yes", :question_id => @do_you_like_pie.id)
228
+ @do_you_like_pie.answers << Factory(:answer, :text => "no", :question_id => @do_you_like_pie.id)
229
+ @what_flavor.answers << Factory(:answer, :response_class => :string, :question_id => @what_flavor.id)
230
+ @what_bakery.answers << Factory(:answer, :response_class => :string, :question_id => @what_bakery.id)
231
+ # Responses
232
+ @response_set = Factory(:response_set)
233
+ @response_set.current_section_id = @section.id
234
+ @response_set.responses << Factory(:response, :question_id => @do_you_like_pie.id, :answer_id => @do_you_like_pie.answers.first.id, :response_set_id => @response_set.id)
235
+ @response_set.responses << Factory(:response, :string_value => "pecan pie", :question_id => @what_flavor.id, :answer_id => @what_flavor.answers.first.id, :response_set_id => @response_set.id)
236
+ end
237
+ it "should export a string with responses" do
238
+ @response_set.responses.size.should == 2
239
+ csv = @response_set.to_csv
240
+ csv.is_a?(String).should be_true
241
+ csv.should match "question.short_text"
242
+ csv.should match "What flavor?"
243
+ csv.should match /pecan pie/
244
+ end
245
+ end
@@ -0,0 +1,76 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Response, "when saving a response" do
4
+ before(:each) do
5
+ # @response = Response.new(:question_id => 314, :response_set_id => 159, :answer_id => 1)
6
+ @response = Factory(:response, :question => Factory(:question), :answer => Factory(:answer))
7
+ end
8
+
9
+ it "should be valid" do
10
+ @response.should be_valid
11
+ end
12
+
13
+ it "should be invalid without a parent response set and question" do
14
+ @response.response_set_id = nil
15
+ @response.should have(1).error_on(:response_set_id)
16
+
17
+ @response.question_id = nil
18
+ @response.should have(1).error_on(:question_id)
19
+ end
20
+
21
+ it "should be correct if the question has no correct_answer_id" do
22
+ @response.question.correct_answer_id.should be_nil
23
+ @response.correct?.should be_true
24
+ end
25
+ it "should be correct if the answer's response class != answer" do
26
+ @response.answer.response_class.should_not == "answer"
27
+ @response.correct?.should be_true
28
+ end
29
+ it "should be (in)correct if answer_id is (not) equal to question's correct_answer_id" do
30
+ @answer = Factory(:answer, :response_class => "answer")
31
+ @question = Factory(:question, :correct_answer_id => @answer.id)
32
+ @response = Factory(:response, :question => @question, :answer => @answer)
33
+ @response.correct?.should be_true
34
+ @response.answer_id = 143
35
+ @response.correct?.should be_false
36
+ end
37
+ describe "returns the response as the type requested" do
38
+
39
+ it "returns 'string'" do
40
+ @response.string_value = "blah"
41
+ @response.as("string").should == "blah"
42
+ @response.as(:string).should == "blah"
43
+ end
44
+
45
+ it "returns 'integer'" do
46
+ @response.integer_value = 1001
47
+ @response.as(:integer).should == 1001
48
+ end
49
+
50
+ it "returns 'float'" do
51
+ @response.float_value = 3.14
52
+ @response.as(:float).should == 3.14
53
+ end
54
+
55
+ it "returns 'answer'" do
56
+ @response.answer_id = 14
57
+ @response.as(:answer).should == 14
58
+ end
59
+
60
+ it "default returns answer type if not specified" do
61
+ @response.answer_id =18
62
+ @response.as(:stuff).should == 18
63
+ end
64
+
65
+ it "returns empty elements if the response is cast as a type that is not present" do
66
+ resp = Response.new(:question_id => 314, :response_set_id => 156)
67
+ resp.as(:string).should == nil
68
+ resp.as(:integer).should == nil
69
+ resp.as(:float).should == nil
70
+ resp.as(:answer).should == nil
71
+ resp.as(:stuff).should == nil
72
+ end
73
+
74
+ end
75
+
76
+ end