hssc_surveyor 1.4.1.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. data/.gitignore +28 -0
  2. data/.rspec +1 -0
  3. data/CHANGELOG.md +198 -0
  4. data/Gemfile +5 -0
  5. data/Gemfile.rails_version +19 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +186 -0
  8. data/Rakefile +105 -0
  9. data/app/controllers/surveyor_controller.rb +6 -0
  10. data/app/helpers/results_helper.rb +20 -0
  11. data/app/helpers/survey_form_builder.rb +37 -0
  12. data/app/helpers/surveyor_helper.rb +3 -0
  13. data/app/inputs/quiet_input.rb +5 -0
  14. data/app/inputs/surveyor_check_boxes_input.rb +35 -0
  15. data/app/inputs/surveyor_radio_input.rb +18 -0
  16. data/app/models/answer.rb +4 -0
  17. data/app/models/dependency.rb +4 -0
  18. data/app/models/dependency_condition.rb +4 -0
  19. data/app/models/question.rb +4 -0
  20. data/app/models/question_group.rb +5 -0
  21. data/app/models/response.rb +5 -0
  22. data/app/models/response_set.rb +4 -0
  23. data/app/models/survey.rb +4 -0
  24. data/app/models/survey_section.rb +5 -0
  25. data/app/models/survey_section_sweeper.rb +15 -0
  26. data/app/models/survey_translation.rb +5 -0
  27. data/app/models/validation.rb +4 -0
  28. data/app/models/validation_condition.rb +4 -0
  29. data/app/views/layouts/results.html.erb +13 -0
  30. data/app/views/layouts/surveyor_default.html.erb +12 -0
  31. data/app/views/partials/_answer.html.haml +25 -0
  32. data/app/views/partials/_dependents.html.haml +5 -0
  33. data/app/views/partials/_question.html.haml +41 -0
  34. data/app/views/partials/_question_group.html.haml +44 -0
  35. data/app/views/partials/_section.html.haml +12 -0
  36. data/app/views/partials/_section_menu.html.haml +12 -0
  37. data/app/views/surveyor/edit.html.haml +24 -0
  38. data/app/views/surveyor/export.json.rabl +85 -0
  39. data/app/views/surveyor/new.html.haml +24 -0
  40. data/app/views/surveyor/show.html.haml +74 -0
  41. data/app/views/surveyor/show.json.rabl +15 -0
  42. data/ci-exec.sh +56 -0
  43. data/config/routes.rb +8 -0
  44. data/cucumber.yml +10 -0
  45. data/doc/REPRESENTATIONS.md +34 -0
  46. data/doc/api_id_schema.json +7 -0
  47. data/doc/question types.png +0 -0
  48. data/doc/response_set_schema.json +54 -0
  49. data/doc/surveyor question combinations.png +0 -0
  50. data/doc/surveyor reject or delete decision matrix.png +0 -0
  51. data/doc/surveyor_models.png +0 -0
  52. data/doc/surveyor_models2.png +0 -0
  53. data/doc/surveyor_timestamp_schema.json +9 -0
  54. data/features/ajax_submissions.feature +140 -0
  55. data/features/export_to_json.feature +344 -0
  56. data/features/internationalization.feature +121 -0
  57. data/features/no_duplicates.feature +110 -0
  58. data/features/show_survey.feature +71 -0
  59. data/features/step_definitions/parser_steps.rb +145 -0
  60. data/features/step_definitions/surveyor_steps.rb +325 -0
  61. data/features/step_definitions/ui_steps.rb +25 -0
  62. data/features/step_definitions/web_steps.rb +225 -0
  63. data/features/support/REDCapDemoDatabase_DataDictionary.csv +127 -0
  64. data/features/support/database_cleaner.rb +16 -0
  65. data/features/support/env.rb +56 -0
  66. data/features/support/hooks.rb +4 -0
  67. data/features/support/paths.rb +39 -0
  68. data/features/support/redcap_new_headers.csv +1 -0
  69. data/features/support/redcap_siblings.csv +1 -0
  70. data/features/support/redcap_whitespace.csv +1 -0
  71. data/features/support/selectors.rb +39 -0
  72. data/features/support/simultaneous_ajax.rb +101 -0
  73. data/features/support/single_quit_selenium_driver.rb +23 -0
  74. data/features/support/slow_updates.rb +18 -0
  75. data/features/surveyor.feature +895 -0
  76. data/features/surveyor_dependencies.feature +476 -0
  77. data/features/surveyor_parser.feature +504 -0
  78. data/features/z_redcap_parser.feature +62 -0
  79. data/lib/assets/images/surveyor/next.gif +0 -0
  80. data/lib/assets/images/surveyor/prev.gif +0 -0
  81. data/lib/assets/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  82. data/lib/assets/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  83. data/lib/assets/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  84. data/lib/assets/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  85. data/lib/assets/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  86. data/lib/assets/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  87. data/lib/assets/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  88. data/lib/assets/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  89. data/lib/assets/images/ui-icons_222222_256x240.png +0 -0
  90. data/lib/assets/images/ui-icons_2e83ff_256x240.png +0 -0
  91. data/lib/assets/images/ui-icons_454545_256x240.png +0 -0
  92. data/lib/assets/images/ui-icons_888888_256x240.png +0 -0
  93. data/lib/assets/images/ui-icons_cd0a0a_256x240.png +0 -0
  94. data/lib/assets/javascripts/surveyor/jquery-1.9.0.js +9555 -0
  95. data/lib/assets/javascripts/surveyor/jquery-ui-1.10.0.custom.js +14850 -0
  96. data/lib/assets/javascripts/surveyor/jquery-ui-timepicker-addon.js +1919 -0
  97. data/lib/assets/javascripts/surveyor/jquery.maskedinput.js +338 -0
  98. data/lib/assets/javascripts/surveyor/jquery.selectToUISlider.js +240 -0
  99. data/lib/assets/javascripts/surveyor/jquery.surveyor.js +156 -0
  100. data/lib/assets/stylesheets/surveyor/jquery-ui-1.10.0.custom.css +1174 -0
  101. data/lib/assets/stylesheets/surveyor/jquery-ui-timepicker-addon.css +11 -0
  102. data/lib/assets/stylesheets/surveyor/reset.css +48 -0
  103. data/lib/assets/stylesheets/surveyor/results.css +125 -0
  104. data/lib/assets/stylesheets/surveyor/ui.slider.extras.css +110 -0
  105. data/lib/assets/stylesheets/surveyor.sass +132 -0
  106. data/lib/generators/surveyor/custom_generator.rb +18 -0
  107. data/lib/generators/surveyor/install_generator.rb +102 -0
  108. data/lib/generators/surveyor/templates/app/assets/javascripts/surveyor_all.js +6 -0
  109. data/lib/generators/surveyor/templates/app/assets/stylesheets/surveyor_all.css +9 -0
  110. data/lib/generators/surveyor/templates/app/controllers/surveyor_controller.rb +40 -0
  111. data/lib/generators/surveyor/templates/app/views/layouts/surveyor_custom.html.erb +13 -0
  112. data/lib/generators/surveyor/templates/config/locales/surveyor_en.yml +19 -0
  113. data/lib/generators/surveyor/templates/config/locales/surveyor_es.yml +19 -0
  114. data/lib/generators/surveyor/templates/config/locales/surveyor_he.yml +19 -0
  115. data/lib/generators/surveyor/templates/config/locales/surveyor_ko.yml +19 -0
  116. data/lib/generators/surveyor/templates/db/migrate/add_api_id_to_question_groups.rb +10 -0
  117. data/lib/generators/surveyor/templates/db/migrate/add_api_ids.rb +14 -0
  118. data/lib/generators/surveyor/templates/db/migrate/add_api_ids_to_response_sets_and_responses.rb +12 -0
  119. data/lib/generators/surveyor/templates/db/migrate/add_attachment_to_response.rb +5 -0
  120. data/lib/generators/surveyor/templates/db/migrate/add_correct_answer_id_to_questions.rb +10 -0
  121. data/lib/generators/surveyor/templates/db/migrate/add_default_value_to_answers.rb +10 -0
  122. data/lib/generators/surveyor/templates/db/migrate/add_display_order_to_surveys.rb +10 -0
  123. data/lib/generators/surveyor/templates/db/migrate/add_display_type_to_answers.rb +14 -0
  124. data/lib/generators/surveyor/templates/db/migrate/add_index_to_response_sets.rb +10 -0
  125. data/lib/generators/surveyor/templates/db/migrate/add_index_to_surveys.rb +10 -0
  126. data/lib/generators/surveyor/templates/db/migrate/add_input_mask_attributes_to_answer.rb +12 -0
  127. data/lib/generators/surveyor/templates/db/migrate/add_section_id_to_responses.rb +12 -0
  128. data/lib/generators/surveyor/templates/db/migrate/add_unique_index_on_access_code_and_version_in_surveys.rb +10 -0
  129. data/lib/generators/surveyor/templates/db/migrate/add_unique_indicies.rb +18 -0
  130. data/lib/generators/surveyor/templates/db/migrate/add_version_to_surveys.rb +10 -0
  131. data/lib/generators/surveyor/templates/db/migrate/api_ids_must_be_unique.rb +23 -0
  132. data/lib/generators/surveyor/templates/db/migrate/create_answers.rb +38 -0
  133. data/lib/generators/surveyor/templates/db/migrate/create_dependencies.rb +23 -0
  134. data/lib/generators/surveyor/templates/db/migrate/create_dependency_conditions.rb +30 -0
  135. data/lib/generators/surveyor/templates/db/migrate/create_question_groups.rb +28 -0
  136. data/lib/generators/surveyor/templates/db/migrate/create_questions.rb +37 -0
  137. data/lib/generators/surveyor/templates/db/migrate/create_response_sets.rb +23 -0
  138. data/lib/generators/surveyor/templates/db/migrate/create_responses.rb +34 -0
  139. data/lib/generators/surveyor/templates/db/migrate/create_survey_sections.rb +30 -0
  140. data/lib/generators/surveyor/templates/db/migrate/create_survey_translations.rb +19 -0
  141. data/lib/generators/surveyor/templates/db/migrate/create_surveys.rb +32 -0
  142. data/lib/generators/surveyor/templates/db/migrate/create_validation_conditions.rb +33 -0
  143. data/lib/generators/surveyor/templates/db/migrate/create_validations.rb +21 -0
  144. data/lib/generators/surveyor/templates/db/migrate/drop_unique_index_on_access_code_in_surveys.rb +10 -0
  145. data/lib/generators/surveyor/templates/db/migrate/update_blank_api_ids_on_question_group.rb +22 -0
  146. data/lib/generators/surveyor/templates/db/migrate/update_blank_versions_on_surveys.rb +13 -0
  147. data/lib/generators/surveyor/templates/surveys/EXTENDING_SURVEYOR.md +52 -0
  148. data/lib/generators/surveyor/templates/surveys/MODIFYING_SURVEYOR.md +91 -0
  149. data/lib/generators/surveyor/templates/surveys/date_survey.rb +16 -0
  150. data/lib/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +284 -0
  151. data/lib/generators/surveyor/templates/surveys/languages.rb +14 -0
  152. data/lib/generators/surveyor/templates/surveys/quiz.rb +11 -0
  153. data/lib/generators/surveyor/templates/surveys/translations/languages.es.yml +18 -0
  154. data/lib/generators/surveyor/templates/surveys/translations/languages.he.yml +18 -0
  155. data/lib/generators/surveyor/templates/surveys/translations/languages.ko.yml +18 -0
  156. data/lib/generators/surveyor/templates/vendor/assets/stylesheets/custom.sass +5 -0
  157. data/lib/surveyor/acts_as_response.rb +17 -0
  158. data/lib/surveyor/common.rb +59 -0
  159. data/lib/surveyor/engine.rb +10 -0
  160. data/lib/surveyor/helpers/asset_pipeline.rb +13 -0
  161. data/lib/surveyor/helpers/formtastic_custom_input.rb +13 -0
  162. data/lib/surveyor/helpers/surveyor_helper_methods.rb +103 -0
  163. data/lib/surveyor/models/answer_methods.rb +86 -0
  164. data/lib/surveyor/models/dependency_condition_methods.rb +72 -0
  165. data/lib/surveyor/models/dependency_methods.rb +60 -0
  166. data/lib/surveyor/models/question_group_methods.rb +61 -0
  167. data/lib/surveyor/models/question_methods.rb +115 -0
  168. data/lib/surveyor/models/response_methods.rb +132 -0
  169. data/lib/surveyor/models/response_set_methods.rb +196 -0
  170. data/lib/surveyor/models/survey_methods.rb +103 -0
  171. data/lib/surveyor/models/survey_section_methods.rb +56 -0
  172. data/lib/surveyor/models/survey_translation_methods.rb +33 -0
  173. data/lib/surveyor/models/validation_condition_methods.rb +56 -0
  174. data/lib/surveyor/models/validation_methods.rb +48 -0
  175. data/lib/surveyor/mustache_context.rb +11 -0
  176. data/lib/surveyor/parser.rb +428 -0
  177. data/lib/surveyor/redcap_parser.rb +289 -0
  178. data/lib/surveyor/surveyor_controller_methods.rb +237 -0
  179. data/lib/surveyor/unparser.rb +147 -0
  180. data/lib/surveyor/version.rb +3 -0
  181. data/lib/surveyor.rb +13 -0
  182. data/lib/tasks/surveyor_tasks.rake +88 -0
  183. data/rails/init.rb +1 -0
  184. data/spec/controllers/surveyor_controller_spec.rb +307 -0
  185. data/spec/factories.rb +161 -0
  186. data/spec/helpers/formtastic_custom_input_spec.rb +15 -0
  187. data/spec/helpers/surveyor_helper_spec.rb +118 -0
  188. data/spec/lib/benchmark_spec.rb +22 -0
  189. data/spec/lib/chinese_survey.rb +14 -0
  190. data/spec/lib/common_spec.rb +34 -0
  191. data/spec/lib/parser_spec.rb +204 -0
  192. data/spec/lib/rake_kitchen_sink.rb +40 -0
  193. data/spec/lib/redcap_parser_spec.rb +75 -0
  194. data/spec/lib/tasks_spec.rake +26 -0
  195. data/spec/lib/unparser_spec.rb +126 -0
  196. data/spec/models/answer_spec.rb +175 -0
  197. data/spec/models/dependency_condition_spec.rb +439 -0
  198. data/spec/models/dependency_spec.rb +101 -0
  199. data/spec/models/question_group_spec.rb +93 -0
  200. data/spec/models/question_spec.rb +207 -0
  201. data/spec/models/response_set_spec.rb +477 -0
  202. data/spec/models/response_spec.rb +218 -0
  203. data/spec/models/survey_section_spec.rb +85 -0
  204. data/spec/models/survey_spec.rb +191 -0
  205. data/spec/models/validation_condition_spec.rb +113 -0
  206. data/spec/models/validation_spec.rb +74 -0
  207. data/spec/rcov.opts +2 -0
  208. data/spec/spec.opts +4 -0
  209. data/spec/spec_helper.rb +56 -0
  210. data/stacktests.sh +65 -0
  211. data/surveyor.gemspec +45 -0
  212. metadata +657 -0
data/lib/surveyor.rb ADDED
@@ -0,0 +1,13 @@
1
+ module Surveyor
2
+ require 'surveyor/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
3
+ autoload :VERSION, 'surveyor/version'
4
+ autoload :ParserError, 'surveyor/parser'
5
+ end
6
+ require 'surveyor/common'
7
+ require 'surveyor/acts_as_response'
8
+ # require 'surveyor/surveyor_controller_methods'
9
+ # require 'surveyor/models/survey_methods'
10
+ require 'formtastic'
11
+ Formtastic::FormBuilder.default_text_area_height = 5
12
+ Formtastic::FormBuilder.default_text_area_width = 50
13
+ Formtastic::FormBuilder.all_fields_required_by_default = false
@@ -0,0 +1,88 @@
1
+ desc "generate and load survey (specify FILE=surveys/your_survey.rb)"
2
+ task :surveyor => :"surveyor:parse"
3
+
4
+ namespace :surveyor do
5
+ task :parse => :environment do
6
+ raise "USAGE: file name required e.g. 'FILE=surveys/kitchen_sink_survey.rb'" if ENV["FILE"].blank?
7
+ file = File.join(Rails.root, ENV["FILE"])
8
+ raise "File does not exist: #{file}" unless FileTest.exists?(file)
9
+ puts "--- Parsing #{file} ---"
10
+ Surveyor::Parser.parse_file(file, {:trace => Rake.application.options.trace})
11
+ puts "--- Done #{file} ---"
12
+ end
13
+ desc "generate and load survey from REDCap Data Dictionary (specify FILE=surveys/redcap.csv)"
14
+ task :redcap => :environment do
15
+ raise "USAGE: file name required e.g. 'FILE=surveys/redcap_demo_survey.csv'" if ENV["FILE"].blank?
16
+ file = File.join(Rails.root, ENV["FILE"])
17
+ raise "File does not exist: #{file}" unless FileTest.exists?(file)
18
+ puts "--- Parsing #{file} ---"
19
+ Surveyor::RedcapParser.parse File.read(file), File.basename(file, ".csv"), {:trace => Rake.application.options.trace}
20
+ puts "--- Done #{file} ---"
21
+ end
22
+ desc "generate a surveyor DSL file from a survey"
23
+ task :unparse => :environment do
24
+ surveys = Survey.all
25
+ if surveys
26
+ puts "The following surveys are available"
27
+ surveys.each do |survey|
28
+ puts "#{survey.id} #{survey.title}"
29
+ end
30
+ print "Which survey would you like to unparse? "
31
+ id = $stdin.gets.to_i
32
+ if survey_to_unparse = surveys.detect{|s| s.id == id}
33
+ filename = "surveys/#{survey_to_unparse.access_code}_#{Date.today.to_s(:db)}.rb"
34
+ puts "unparsing #{survey_to_unparse.title} to #{filename}"
35
+ File.open(filename, 'w') {|f| f.write(Surveyor::Unparser.unparse(survey_to_unparse))}
36
+ else
37
+ puts "not found"
38
+ end
39
+ else
40
+ puts "There are no surveys available"
41
+ end
42
+ end
43
+ desc "remove surveys (that don't have response sets)"
44
+ task :remove => :environment do
45
+ surveys = Survey.all.delete_if{|s| !s.response_sets.blank?}
46
+ if surveys
47
+ puts "The following surveys do not have any response sets"
48
+ surveys.each do |survey|
49
+ puts "#{survey.id} #{survey.title}"
50
+ end
51
+ print "Which survey would you like to remove? "
52
+ id = $stdin.gets.to_i
53
+ if survey_to_delete = surveys.detect{|s| s.id == id}
54
+ puts "removing #{survey_to_delete.title}"
55
+ survey_to_delete.destroy
56
+ else
57
+ put "not found"
58
+ end
59
+ else
60
+ puts "There are no surveys without response sets"
61
+ end
62
+ end
63
+ desc "dump all responses to a given survey"
64
+ task :dump => :environment do
65
+ require 'fileutils.rb'
66
+ survey_version = ENV["SURVEY_VERSION"]
67
+ access_code = ENV["SURVEY_ACCESS_CODE"]
68
+
69
+ raise "USAGE: rake surveyor:dump SURVEY_ACCESS_CODE=<access_code> [OUTPUT_DIR=<dir>] [SURVEY_VERSION=<survey_version>]" unless access_code
70
+ params_string = "code #{access_code}"
71
+
72
+ surveys = Survey.where(:access_code => access_code).order("survey_version ASC")
73
+ if survey_version.blank?
74
+ survey = surveys.last
75
+ else
76
+ params_string += " and survey_version #{survey_version}"
77
+ survey = surveys.where(:survey_version => survey_version).first
78
+ end
79
+
80
+ raise "No Survey found with #{params_string}" unless survey
81
+ dir = ENV["OUTPUT_DIR"] || Rails.root
82
+ mkpath(dir) # Create all non-existent directories
83
+ full_path = File.join(dir,"#{survey.access_code}_v#{survey.survey_version}_#{Time.now.to_i}.csv")
84
+ File.open(full_path, 'w') do |f|
85
+ survey.response_sets.each_with_index{|r,i| f.write(r.to_csv(true, i == 0)) } # print access code every time, print_header first time
86
+ end
87
+ end
88
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'surveyor'
@@ -0,0 +1,307 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe SurveyorController do
4
+ include Surveyor::Engine.routes.url_helpers
5
+ before do
6
+ @routes = Surveyor::Engine.routes
7
+ end
8
+
9
+ let!(:survey) { Factory(:survey, :title => "Alphabet", :access_code => "alpha", :survey_version => 0)}
10
+ let!(:survey_beta) { Factory(:survey, :title => "Alphabet", :access_code => "alpha", :survey_version => 1)}
11
+ let!(:response_set) { Factory(:response_set, :survey => survey, :access_code => "pdq")}
12
+ let!(:response_set_beta) { Factory(:response_set, :survey => survey_beta, :access_code => "rst")}
13
+ before { ResponseSet.stub!(:create).and_return(response_set) }
14
+
15
+ # match '/', :to => 'surveyor#new', :as => 'available_surveys', :via => :get
16
+ # match '/:survey_code', :to => 'surveyor#create', :as => 'take_survey', :via => :post
17
+ # match '/:survey_code', :to => 'surveyor#export', :as => 'export_survey', :via => :get
18
+ # match '/:survey_code/:response_set_code', :to => 'surveyor#show', :as => 'view_my_survey', :via => :get
19
+ # match '/:survey_code/:response_set_code/take', :to => 'surveyor#edit', :as => 'edit_my_survey', :via => :get
20
+ # match '/:survey_code/:response_set_code', :to => 'surveyor#update', :as => 'update_my_survey', :via => :put
21
+
22
+ context "#new" do
23
+ def do_get
24
+ get :new
25
+ end
26
+ it "renders new" do
27
+ do_get
28
+ response.should be_success
29
+ response.should render_template('new')
30
+ end
31
+ it "assigns surveys_by_access_code" do
32
+ do_get
33
+ assigns(:surveys_by_access_code).should == {"alpha" => [survey_beta,survey]}
34
+ end
35
+ end
36
+
37
+ context "#create" do
38
+ def do_post(params = {})
39
+ post :create, {:survey_code => "alpha"}.merge(params)
40
+ end
41
+ it "finds latest version" do
42
+ do_post
43
+ assigns(:survey).should == survey_beta
44
+ end
45
+ it "finds specified survey_version" do
46
+ do_post :survey_version => 0
47
+ assigns(:survey).should == survey
48
+ end
49
+ it "creates a new response_set" do
50
+ ResponseSet.should_receive(:create)
51
+ do_post
52
+ end
53
+ it "should redirects to the new response_set" do
54
+ do_post
55
+ response.should redirect_to( edit_my_survey_path(:survey_code => "alpha", :response_set_code => "pdq"))
56
+ end
57
+
58
+ context "with failures" do
59
+ it "redirect to #new on failed ResponseSet#create" do
60
+ ResponseSet.should_receive(:create).and_return(false)
61
+ do_post
62
+ response.should redirect_to(available_surveys_path)
63
+ end
64
+ it "redirect to #new on failed Survey#find" do
65
+ do_post :survey_code => "missing"
66
+ response.should redirect_to(available_surveys_path)
67
+ end
68
+ end
69
+
70
+ context "with javascript check, assigned in session" do
71
+ it "enabled" do
72
+ do_post :surveyor_javascript_enabled => "true"
73
+ session[:surveyor_javascript].should_not be_nil
74
+ session[:surveyor_javascript].should == "enabled"
75
+ end
76
+ it "disabled" do
77
+ post :create, :survey_code => "xyz", :surveyor_javascript_enabled => "not_true"
78
+ session[:surveyor_javascript].should_not be_nil
79
+ session[:surveyor_javascript].should == "not_enabled"
80
+ end
81
+ end
82
+ end
83
+
84
+ context "#show" do
85
+ def do_get(params = {})
86
+ get :show, {:survey_code => "alpha", :response_set_code => "pdq"}.merge(params)
87
+ end
88
+ it "renders show" do
89
+ do_get
90
+ response.should be_success
91
+ response.should render_template('show')
92
+ end
93
+ it "finds ResponseSet with includes" do
94
+ ResponseSet.should_receive(:find_by_access_code).with("pdq",{:include=>{:responses=>[:question, :answer]}})
95
+ do_get
96
+ end
97
+ it "redirects for missing response set" do
98
+ do_get :response_set_code => "DIFFERENT"
99
+ response.should redirect_to(available_surveys_path)
100
+ end
101
+ it "assigns earlier survey_version" do
102
+ response_set
103
+ do_get
104
+ assigns[:response_set].should == response_set
105
+ assigns[:survey].should == survey
106
+ end
107
+ it "assigns later survey_version" do
108
+ response_set_beta
109
+ do_get :response_set_code => "rst"
110
+ assigns[:response_set].should == response_set_beta
111
+ assigns[:survey].should == survey_beta
112
+ end
113
+ end
114
+
115
+ context "#edit" do
116
+ def do_get(params = {})
117
+ survey.sections = [Factory(:survey_section, :survey => survey)]
118
+ get :edit, {:survey_code => "alpha", :response_set_code => "pdq"}.merge(params)
119
+ end
120
+ it "renders edit" do
121
+ do_get
122
+ response.should be_success
123
+ response.should render_template('edit')
124
+ end
125
+ it "assigns survey and response set" do
126
+ do_get
127
+ assigns[:survey].should == survey
128
+ assigns[:response_set].should == response_set
129
+ end
130
+ it "redirects for missing response set" do
131
+ do_get :response_set_code => "DIFFERENT"
132
+ response.should redirect_to(available_surveys_path)
133
+ end
134
+ it "assigns dependents if javascript not enabled" do
135
+ controller.stub!(:get_unanswered_dependencies_minus_section_questions).and_return([Factory(:question)])
136
+ session[:surveyor_javascript].should be_nil
137
+ do_get
138
+ assigns[:dependents].should_not be_empty
139
+ end
140
+ it "does not assign dependents if javascript is enabled" do
141
+ controller.stub!(:get_unanswered_dependencies_minus_section_questions).and_return([Factory(:question)])
142
+ session[:surveyor_javascript] = "enabled"
143
+ do_get
144
+ assigns[:dependents].should be_empty
145
+ end
146
+ it "assigns earlier survey_version" do
147
+ do_get
148
+ assigns[:response_set].should == response_set
149
+ assigns[:survey].should == survey
150
+ end
151
+ it "assigns later survey_version" do
152
+ survey_beta.sections = [Factory(:survey_section, :survey => survey_beta)]
153
+ do_get :response_set_code => "rst"
154
+ assigns[:survey].should == survey_beta
155
+ assigns[:response_set].should == response_set_beta
156
+
157
+ end
158
+ end
159
+
160
+ context "#update" do
161
+ let(:responses_ui_hash) { {} }
162
+ let(:update_params) {
163
+ {
164
+ :survey_code => "alpha",
165
+ :response_set_code => "pdq"
166
+ }
167
+ }
168
+ shared_examples "#update action" do
169
+ before do
170
+ ResponseSet.stub!(:find_by_access_code).and_return(response_set)
171
+ responses_ui_hash['11'] = {'api_id' => 'something', 'answer_id' => '56', 'question_id' => '9'}
172
+ end
173
+ it "finds a response set" do
174
+ ResponseSet.should_receive(:find_by_access_code).and_return(response_set)
175
+ do_put
176
+ end
177
+ it "saves responses" do
178
+ response_set.should_receive(:update_from_ui_hash).with(responses_ui_hash)
179
+
180
+ do_put(:r => responses_ui_hash)
181
+ end
182
+ it "does not fail when there are no responses" do
183
+ lambda { do_put }.should_not raise_error
184
+ end
185
+ context "with update exceptions" do
186
+ it 'retries the update on a constraint violation' do
187
+ response_set.should_receive(:update_from_ui_hash).ordered.with(responses_ui_hash).and_raise(ActiveRecord::StatementInvalid)
188
+ response_set.should_receive(:update_from_ui_hash).ordered.with(responses_ui_hash)
189
+
190
+ expect { do_put(:r => responses_ui_hash) }.to_not raise_error
191
+ end
192
+
193
+ it 'only retries three times' do
194
+ response_set.should_receive(:update_from_ui_hash).exactly(3).times.with(responses_ui_hash).and_raise(ActiveRecord::StatementInvalid)
195
+
196
+ expect { do_put(:r => responses_ui_hash) }.to raise_error(ActiveRecord::StatementInvalid)
197
+ end
198
+
199
+ it 'does not retry for other errors' do
200
+ response_set.should_receive(:update_from_ui_hash).once.with(responses_ui_hash).and_raise('Bad news')
201
+
202
+ expect { do_put(:r => responses_ui_hash) }.to raise_error('Bad news')
203
+ end
204
+ end
205
+ end
206
+
207
+ context "with form submission" do
208
+ def do_put(extra_params = {})
209
+ put :update, update_params.merge(extra_params)
210
+ end
211
+
212
+ it_behaves_like "#update action"
213
+ it "redirects to #edit without params" do
214
+ do_put
215
+ response.should redirect_to(edit_my_survey_path(:survey_code => "alpha", :response_set_code => "pdq"))
216
+ end
217
+ it "completes the found response set on finish" do
218
+ do_put :finish => 'finish'
219
+ response_set.reload.should be_complete
220
+ end
221
+ it 'flashes completion' do
222
+ do_put :finish => 'finish'
223
+ flash[:notice].should == "Completed survey"
224
+ end
225
+ it "redirects for missing response set" do
226
+ do_put :response_set_code => "DIFFERENT"
227
+ response.should redirect_to(available_surveys_path)
228
+ flash[:notice].should == "Unable to find your responses to the survey"
229
+ end
230
+ end
231
+
232
+ context 'with ajax' do
233
+ def do_put(extra_params = {})
234
+ xhr :put, :update, update_params.merge(extra_params)
235
+ end
236
+
237
+ it_behaves_like "#update action"
238
+ it "returns dependencies" do
239
+ ResponseSet.stub!(:find_by_access_code).and_return(response_set)
240
+ response_set.should_receive(:all_dependencies).and_return({"show" => ['q_1'], "hide" => ['q_2']})
241
+
242
+ do_put
243
+ JSON.parse(response.body).should == {"show" => ['q_1'], "hide" => ["q_2"]}
244
+ end
245
+ it "returns 404 for missing response set" do
246
+ do_put :response_set_code => "DIFFERENT"
247
+ response.status.should == 404
248
+ end
249
+ end
250
+ end
251
+
252
+ context "#export" do
253
+ render_views
254
+
255
+ let(:json) {
256
+ get :export, :survey_code => survey.access_code, :format => 'json'
257
+ JSON.parse(response.body)
258
+ }
259
+
260
+ context "question inside and outside a question group" do
261
+ def question_text(refid)
262
+ <<-SURVEY
263
+ q "Where is a foo?", :pick => :one, :help_text => 'Look around.', :reference_identifier => #{refid.inspect},
264
+ :data_export_identifier => 'X.FOO', :common_namespace => 'F', :common_identifier => 'f'
265
+ a_L 'To the left', :data_export_identifier => 'X.L', :common_namespace => 'F', :common_identifier => 'l'
266
+ a_R 'To the right', :data_export_identifier => 'X.R', :common_namespace => 'F', :common_identifier => 'r'
267
+ a_O 'Elsewhere', :string
268
+
269
+ dependency :rule => 'R'
270
+ condition_R :q_bar, "==", :a_1
271
+ SURVEY
272
+ end
273
+ let(:survey_text) {
274
+ <<-SURVEY
275
+ survey 'xyz' do
276
+ section 'Sole' do
277
+ q_bar "Should that other question show up?", :pick => :one
278
+ a_1 'Yes'
279
+ a_2 'No'
280
+
281
+ #{question_text('foo_solo')}
282
+
283
+ group do
284
+ #{question_text('foo_grouped')}
285
+ end
286
+ end
287
+ end
288
+ SURVEY
289
+ }
290
+ let(:survey) { Surveyor::Parser.new.parse(survey_text) }
291
+ let(:solo_question_json) { json['sections'][0]['questions_and_groups'][1] }
292
+ let(:grouped_question_json) { json['sections'][0]['questions_and_groups'][2]['questions'][0] }
293
+
294
+ it "produces identical JSON except for API IDs and question reference identifers" do
295
+ solo_question_json['answers'].to_json.should be_json_eql( grouped_question_json['answers'].to_json).excluding("uuid", "reference_identifier")
296
+ solo_question_json['dependency'].to_json.should be_json_eql( grouped_question_json['dependency'].to_json).excluding("uuid", "reference_identifier")
297
+ solo_question_json.to_json.should be_json_eql( grouped_question_json.to_json).excluding("uuid", "reference_identifier")
298
+ end
299
+ it "produces the expected reference identifier for the solo question" do
300
+ solo_question_json['reference_identifier'].should == 'foo_solo'
301
+ end
302
+ it "produces the expected reference identifer for the question in the group" do
303
+ grouped_question_json['reference_identifier'].should == 'foo_grouped'
304
+ end
305
+ end
306
+ end
307
+ end
data/spec/factories.rb ADDED
@@ -0,0 +1,161 @@
1
+ # encoding: utf-8
2
+ # http://github.com/thoughtbot/factory_girl/tree/master
3
+ require 'rubygems'
4
+ require 'factory_girl'
5
+
6
+ Factory.sequence(:unique_survey_access_code){|n| "simple survey #{UUIDTools::UUID.random_create.to_s}" }
7
+
8
+ Factory.define :survey do |s|
9
+ s.title "Simple survey"
10
+ s.description "A simple survey for testing"
11
+ s.access_code { Factory.next :unique_survey_access_code }
12
+ s.survey_version 0
13
+ end
14
+
15
+ Factory.define :survey_translation do |t|
16
+ t.locale "es"
17
+ t.translation %(title: "Un idioma nunca es suficiente"
18
+ survey_sections:
19
+ one:
20
+ title: "Uno"
21
+ questions:
22
+ hello:
23
+ text: "¡Hola!"
24
+ name:
25
+ text: "¿Cómo se llama Usted?"
26
+ answers:
27
+ name:
28
+ help_text: "Mi nombre es...")
29
+ end
30
+
31
+ Factory.sequence(:survey_section_display_order){|n| n }
32
+
33
+ Factory.define :survey_section do |s|
34
+ s.association :survey # s.survey_id {}
35
+ s.title {"Demographics"}
36
+ s.description {"Asking you about your personal data"}
37
+ s.display_order {Factory.next :survey_section_display_order}
38
+ s.reference_identifier {"demographics"}
39
+ s.data_export_identifier {"demographics"}
40
+ end
41
+
42
+ Factory.sequence(:question_display_order){|n| n }
43
+
44
+ Factory.define :question do |q|
45
+ q.association :survey_section # s.survey_section_id {}
46
+ # q.question_group_id {}
47
+ q.text "What is your favorite color?"
48
+ q.short_text "favorite_color"
49
+ q.help_text "just write it in the box"
50
+ q.pick :none
51
+ q.reference_identifier {|me| "q_#{me.object_id}"}
52
+ # q.data_export_identifier {}
53
+ # q.common_namespace {}
54
+ # q.common_identifier {}
55
+ q.display_order Factory.next :question_display_order
56
+ # q.display_type {} # nil is default
57
+ q.is_mandatory false
58
+ # q.display_width {}
59
+ q.correct_answer_id nil
60
+ end
61
+
62
+ Factory.define :question_group do |g|
63
+ g.text {"Describe your family"}
64
+ g.help_text {}
65
+ g.reference_identifier {|me| "g_#{me.object_id}"}
66
+ g.data_export_identifier {}
67
+ g.common_namespace {}
68
+ g.common_identifier {}
69
+ g.display_type {}
70
+ g.custom_class {}
71
+ g.custom_renderer {}
72
+ end
73
+
74
+ Factory.sequence(:answer_display_order){|n| n }
75
+
76
+ Factory.define :answer do |a|
77
+ a.association :question # a.question_id {}
78
+ a.text "My favorite color is clear"
79
+ a.short_text "clear"
80
+ a.help_text "Clear is the absense of color"
81
+ # a.weight
82
+ a.response_class "string"
83
+ # a.reference_identifier {}
84
+ # a.data_export_identifier {}
85
+ # a.common_namespace {}
86
+ # a.common_identifier {}
87
+ a.display_order {Factory.next :answer_display_order}
88
+ # a.is_exclusive {}
89
+ a.display_type "default"
90
+ # a.display_length {}
91
+ # a.custom_class {}
92
+ # a.custom_renderer {}
93
+ end
94
+
95
+ Factory.define :dependency do |d|
96
+ # the dependent question
97
+ d.association :question # d.question_id {}
98
+ d.question_group_id {}
99
+ d.rule {"A"}
100
+ end
101
+
102
+ Factory.define :dependency_condition do |d|
103
+ d.association :dependency # d.dependency_id {}
104
+ d.rule_key {"A"}
105
+ # the conditional question
106
+ d.question_id {}
107
+ d.operator {"=="}
108
+ d.answer_id {}
109
+ d.datetime_value {}
110
+ d.integer_value {}
111
+ d.float_value {}
112
+ d.unit {}
113
+ d.text_value {}
114
+ d.string_value {}
115
+ d.response_other {}
116
+ end
117
+
118
+ Factory.define :response_set do |r|
119
+ r.user_id {}
120
+ r.association :survey # r.survey_id {}
121
+ r.access_code {Surveyor::Common.make_tiny_code}
122
+ r.started_at {Time.now}
123
+ r.completed_at {}
124
+ end
125
+
126
+ Factory.define :response do |r|
127
+ r.association :response_set # r.response_set_id {}
128
+ r.survey_section_id {}
129
+ r.question_id {}
130
+ r.answer_id {}
131
+ r.datetime_value {}
132
+ r.integer_value {}
133
+ r.float_value {}
134
+ r.unit {}
135
+ r.text_value {}
136
+ r.string_value {}
137
+ r.response_other {}
138
+ r.response_group {}
139
+ end
140
+
141
+ Factory.define :validation do |v|
142
+ v.association :answer # v.answer_id {}
143
+ v.rule {"A"}
144
+ v.message {}
145
+ end
146
+
147
+ Factory.define :validation_condition do |v|
148
+ v.association :validation # v.validation_id {}
149
+ v.rule_key {"A"}
150
+ v.question_id {}
151
+ v.operator {"=="}
152
+ v.answer_id {}
153
+ v.datetime_value {}
154
+ v.integer_value {}
155
+ v.float_value {}
156
+ v.unit {}
157
+ v.text_value {}
158
+ v.string_value {}
159
+ v.response_other {}
160
+ v.regexp {}
161
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/surveyor/helpers/formtastic_custom_input')
3
+
4
+ describe Surveyor::Helpers::FormtasticCustomInput do
5
+ context "input helpers" do
6
+ it "should translate response class into attribute" do
7
+ helper.response_class_to_method(:string).should == :string_value
8
+ helper.response_class_to_method(:integer).should == :integer_value
9
+ helper.response_class_to_method(:float).should == :float_value
10
+ helper.response_class_to_method(:datetime).should == :datetime_value
11
+ helper.response_class_to_method(:date).should == :date_value
12
+ helper.response_class_to_method(:time).should == :time_value
13
+ end
14
+ end
15
+ end