-<% cache [@district, @school, @academic_year] do %>
<% if @district == District.find_by_name("Boston") %>
<%= render partial: 'layouts/boston_modal' %>
<% elsif @has_empty_dataset %>
diff --git a/lib/tasks/data.rake b/lib/tasks/data.rake
index 836fd93e..84bff1d1 100644
--- a/lib/tasks/data.rake
+++ b/lib/tasks/data.rake
@@ -42,6 +42,17 @@ namespace :data do
SurveyResponsesDataLoader.load_data filepath:
end
puts "=====================> Completed loading #{SurveyItemResponse.count} survey responses"
+
+ puts 'Refreshing response rates'
+ ResponseRateLoader.refresh
+ puts "=====================> Completed loading #{ResponseRate.count} survey responses"
+ end
+
+ desc 'refresh response rate values'
+ task refresh_response_rates: :environment do
+ puts 'Refreshing response rates'
+ ResponseRateLoader.refresh
+ puts "=====================> Completed loading #{ResponseRate.count} survey responses"
end
desc 'load admin_data'
diff --git a/lib/tasks/one_off.rake b/lib/tasks/one_off.rake
index 3add2619..e390ea81 100644
--- a/lib/tasks/one_off.rake
+++ b/lib/tasks/one_off.rake
@@ -51,6 +51,9 @@ namespace :one_off do
puts "=====================> Loading data from csv at path: #{filepath}"
SurveyResponsesDataLoader.load_data filepath: filepath
puts "=====================> Completed loading #{SurveyItemResponse.count} survey responses"
+ puts 'Refreshing response rates'
+ ResponseRateLoader.refresh
+ puts "=====================> Completed loading #{ResponseRate.count} survey responses"
end
desc 'load winchester results for 2021-22'
@@ -61,6 +64,9 @@ namespace :one_off do
puts "=====================> Loading data from csv at path: #{filepath}"
SurveyResponsesDataLoader.load_data filepath:
end
+ puts 'Refreshing response rates'
+ ResponseRateLoader.refresh
+ puts "=====================> Completed loading #{ResponseRate.count} survey responses"
end
desc 'list scales that have no survey responses'
diff --git a/spec/models/response_rate_calculator_spec.rb b/spec/models/response_rate_calculator_spec.rb
index b33ddf42..ed7cc1bd 100644
--- a/spec/models/response_rate_calculator_spec.rb
+++ b/spec/models/response_rate_calculator_spec.rb
@@ -3,6 +3,9 @@ require 'rails_helper'
describe ResponseRateCalculator, type: :model do
let(:school) { create(:school) }
let(:academic_year) { create(:academic_year) }
+ let(:survey) { create(:survey, school:, academic_year:) }
+ let(:short_form_survey) { create(:survey, form: :short, school:, academic_year:) }
+ let(:respondent) { create(:respondent, school:, academic_year:) }
describe StudentResponseRateCalculator do
let(:subcategory) { create(:subcategory) }
@@ -23,13 +26,14 @@ describe ResponseRateCalculator, type: :model do
create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: sufficient_student_survey_item_2,
academic_year:, school:, likert_score: 4)
end
- context 'when a students take a regular survey' do
- before :each do
- create(:respondent, school:, academic_year:)
- create(:survey, school:, academic_year:)
- end
+ context 'when a students take a regular survey' do
context 'when the average number of student responses per question in a subcategory is equal to the student response threshold' do
+ before :each do
+ respondent
+ survey
+ end
+
it 'returns a response rate equal to the response threshold' do
expect(StudentResponseRateCalculator.new(subcategory:, school:,
academic_year:).rate).to eq 25
@@ -39,8 +43,8 @@ describe ResponseRateCalculator, type: :model do
context 'when students take the short form survey' do
before :each do
- create(:respondent, school:, academic_year:)
- create(:survey, form: :short, school:, academic_year:)
+ respondent
+ short_form_survey
end
context 'when the average number of student responses per question in a subcategory is equal to the student response threshold' do
@@ -49,19 +53,19 @@ describe ResponseRateCalculator, type: :model do
sufficient_student_survey_item_2.update! on_short_form: true
end
- it 'returns 100 percent' do
+ it 'takes into account the responses from both survey items' do
expect(StudentResponseRateCalculator.new(subcategory:, school:,
academic_year:).rate).to eq 25
end
- context 'for the same number of responses, if only one of the questions is a short form question, the response rate will be half' do
+ context 'and only one of the survey items is on the short form' do
before do
sufficient_student_survey_item_2.update! on_short_form: false
end
- it 'returns 100 percent' do
+ it 'the response rate ignores the responses in the non-short form item' do
expect(StudentResponseRateCalculator.new(subcategory:, school:,
- academic_year:).rate).to eq 50
+ academic_year:).rate).to eq 25
end
end
end
@@ -69,8 +73,8 @@ describe ResponseRateCalculator, type: :model do
context 'when the average number of teacher responses is greater than the total possible responses' do
before do
- create(:respondent, school:, academic_year:)
- create(:survey, school:, academic_year:)
+ respondent
+ survey
create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD * 11, survey_item: sufficient_student_survey_item_2,
academic_year:, school:, likert_score: 1)
end
@@ -124,8 +128,8 @@ describe ResponseRateCalculator, type: :model do
context 'when the average number of teacher responses per question in a subcategory is at the threshold' do
before :each do
- create(:respondent, school:, academic_year:)
- create(:survey, school:, academic_year:)
+ respondent
+ survey
end
it 'returns 25 percent' do
expect(TeacherResponseRateCalculator.new(subcategory:, school:,
@@ -135,8 +139,8 @@ describe ResponseRateCalculator, type: :model do
context 'when the teacher response rate is not a whole number. eg 29.166%' do
before do
- create(:respondent, school:, academic_year:)
- create(:survey, school:, academic_year:)
+ respondent
+ survey
create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD + 1, survey_item: sufficient_teacher_survey_item_3,
academic_year:, school:, likert_score: 1)
end
@@ -148,8 +152,8 @@ describe ResponseRateCalculator, type: :model do
context 'when the average number of teacher responses is greater than the total possible responses' do
before do
- create(:respondent, school:, academic_year:)
- create(:survey, school:, academic_year:)
+ respondent
+ survey
create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD * 11, survey_item: sufficient_teacher_survey_item_3,
academic_year:, school:, likert_score: 1)
end
@@ -169,8 +173,8 @@ describe ResponseRateCalculator, type: :model do
context 'when there is an imbalance in the response rate of the teacher items' do
context 'and one of the teacher items has no associated survey item responses' do
before do
- create(:respondent, school:, academic_year:)
- create(:survey, school:, academic_year:)
+ respondent
+ survey
insufficient_teacher_survey_item_4
end
it 'ignores the empty survey item and returns only the average response rate of teacher survey items with responses' do
diff --git a/spec/services/response_rate_loader_spec.rb b/spec/services/response_rate_loader_spec.rb
new file mode 100644
index 00000000..4b6e49ae
--- /dev/null
+++ b/spec/services/response_rate_loader_spec.rb
@@ -0,0 +1,140 @@
+require 'rails_helper'
+
+describe ResponseRateLoader do
+ let(:school) { School.find_by_slug 'milford-high-school' }
+ let(:academic_year) { AcademicYear.find_by_range '2020-21' }
+ let(:respondents) do
+ respondents = Respondent.where(school:, academic_year:).first
+ respondents.total_students = 10
+ respondents.total_teachers = 10
+ respondents.save
+ end
+
+ let(:short_form_survey) do
+ survey = Survey.find_by(school:, academic_year:)
+ survey.form = :short
+ survey.save
+ survey
+ end
+
+ let(:subcategory) { Subcategory.find_by_subcategory_id '5D' }
+
+ let(:s_acst_q1) { SurveyItem.find_by_survey_item_id 's-acst-q1' }
+ let(:s_acst_q2) { SurveyItem.find_by_survey_item_id 's-acst-q2' } # short form
+ let(:s_acst_q3) { SurveyItem.find_by_survey_item_id 's-acst-q3' }
+ let(:s_poaf_q1) { SurveyItem.find_by_survey_item_id 's-poaf-q1' }
+ let(:s_poaf_q2) { SurveyItem.find_by_survey_item_id 's-poaf-q2' }
+ let(:s_poaf_q3) { SurveyItem.find_by_survey_item_id 's-poaf-q3' } # short form
+ let(:s_poaf_q4) { SurveyItem.find_by_survey_item_id 's-poaf-q4' }
+ let(:t_phya_q2) { SurveyItem.find_by_survey_item_id 't-phya-q2' }
+ let(:t_phya_q3) { SurveyItem.find_by_survey_item_id 't-phya-q3' }
+
+ let(:s_acst) { Scale.find_by_scale_id 's-acst' }
+ let(:s_poaf) { Scale.find_by_scale_id 's-poaf' }
+ let(:t_phya) { Scale.find_by_scale_id 't-phya' }
+
+ let(:response_rate) { ResponseRate.find_by(subcategory:, school:, academic_year:) }
+
+ before :each do
+ Rails.application.load_seed
+ respondents
+ end
+
+ after :each do
+ DatabaseCleaner.clean
+ end
+
+ describe 'self.refresh' do
+ context 'When refreshing response rates' do
+ context 'and half the students responded to each question' do
+ before :each do
+ create_list(:survey_item_response, 5, survey_item: s_acst_q1, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: s_acst_q2, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: s_acst_q3, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: s_poaf_q1, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: s_poaf_q2, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: s_poaf_q3, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: s_poaf_q4, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: t_phya_q2, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: t_phya_q3, likert_score: 3, school:, academic_year:)
+
+ ResponseRateLoader.refresh
+ end
+
+ it 'populates the database with response rates' do
+ expect(s_acst_q1.survey_item_id).to eq 's-acst-q1'
+ expect(subcategory.subcategory_id).to eq '5D'
+ expect(subcategory.name).to eq 'Health'
+ expect(s_acst.score(school:, academic_year:)).to eq 3
+ expect(s_poaf.score(school:, academic_year:)).to eq 3
+ expect(t_phya.score(school:, academic_year:)).to eq 3
+ expect(response_rate.student_response_rate).to eq 50
+ expect(response_rate.teacher_response_rate).to eq 50
+ expect(response_rate.meets_student_threshold).to be true
+ expect(response_rate.meets_teacher_threshold).to be true
+ end
+ context 'when running the loader a second time' do
+ it 'is idempotent' do
+ response_count = ResponseRate.count
+ ResponseRateLoader.refresh
+ second_count = ResponseRate.count
+
+ expect(response_count).to eq second_count
+ end
+ end
+ end
+
+ context 'and only the first question for each scale was asked; e.g. like on a short form' do
+ before :each do
+ create_list(:survey_item_response, 5, survey_item: s_acst_q1, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: s_poaf_q1, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: t_phya_q2, likert_score: 3, school:, academic_year:)
+
+ ResponseRateLoader.refresh
+ end
+
+ it 'only takes into account the first question and ignores the other questions in the scale' do
+ expect(response_rate.student_response_rate).to eq 50
+ expect(response_rate.teacher_response_rate).to eq 50
+ end
+ end
+
+ context 'and no respondent entry exists for the school and year' do
+ before do
+ Respondent.destroy_all
+ create_list(:survey_item_response, 5, survey_item: s_acst_q1, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: s_poaf_q1, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 5, survey_item: t_phya_q2, likert_score: 3, school:, academic_year:)
+
+ ResponseRateLoader.refresh
+ end
+
+ it 'since no score can be calculated, it returns a default of 100' do
+ expect(response_rate.student_response_rate).to eq 100
+ expect(response_rate.teacher_response_rate).to eq 100
+ end
+ end
+
+ context 'and the school took the short form student survey' do
+ before :each do
+ create_list(:survey_item_response, 1, survey_item: s_acst_q1, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 6, survey_item: s_acst_q2, likert_score: 3, school:, academic_year:) # short form
+ create_list(:survey_item_response, 1, survey_item: s_acst_q3, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 1, survey_item: s_poaf_q1, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 1, survey_item: s_poaf_q2, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 6, survey_item: s_poaf_q3, likert_score: 3, school:, academic_year:) # short form
+ create_list(:survey_item_response, 1, survey_item: s_poaf_q4, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 1, survey_item: t_phya_q2, likert_score: 3, school:, academic_year:)
+ create_list(:survey_item_response, 1, survey_item: t_phya_q3, likert_score: 3, school:, academic_year:)
+ short_form_survey
+
+ ResponseRateLoader.refresh
+ end
+
+ it 'only counts responses from survey items on the short form' do
+ expect(response_rate.student_response_rate).to eq 60
+ end
+ end
+ end
+ end
+end
diff --git a/spec/system/sqm_application_spec.rb b/spec/system/sqm_application_spec.rb
index 2647da45..8cb6cdc1 100644
--- a/spec/system/sqm_application_spec.rb
+++ b/spec/system/sqm_application_spec.rb
@@ -12,6 +12,7 @@ describe 'SQM Application' do
driven_by :rack_test
page.driver.browser.basic_authorize(username, password)
create(:respondent, school:, academic_year:)
+ create(:survey, school:, academic_year:)
end
context 'when no measures meet their threshold' do
diff --git a/spec/views/analyze/index.html.erb_spec.rb b/spec/views/analyze/index.html.erb_spec.rb
index e961d232..4a49dc94 100644
--- a/spec/views/analyze/index.html.erb_spec.rb
+++ b/spec/views/analyze/index.html.erb_spec.rb
@@ -5,6 +5,8 @@ describe 'analyze/index' do
subject { Nokogiri::HTML(rendered) }
let(:category) { create(:category) }
let(:subcategory) { create(:subcategory, category:) }
+ let(:school) { create(:school) }
+ let(:academic_year) { create(:academic_year) }
let(:support_for_teaching) do
measure = create(:measure, name: 'Support For Teaching Development & Growth', measure_id: '1A-I', subcategory:)
@@ -41,22 +43,20 @@ describe 'analyze/index' do
ideal_low_benchmark: 4.5)
measure
end
- let(:academic_year) { create(:academic_year) }
before :each do
- # assign :category_presenters, []
- # assign :grouped_bar_column_presenters, grouped_bar_column_presenters
assign :academic_year, academic_year
assign :available_academic_years, [academic_year]
assign :selected_academic_years, [academic_year]
- # assign :academic_years, [academic_year]
assign :district, create(:district)
- assign :school, create(:school)
+ assign :school, school
assign :category, category
assign :categories, [category]
assign :subcategory, subcategory
assign :subcategories, category.subcategories
assign :measures, [support_for_teaching, effective_leadership, professional_qualifications]
+ create(:respondent, school:, academic_year:)
+ create(:survey, school:, academic_year:)
render
end
@@ -107,7 +107,10 @@ describe 'analyze/index' do
end
it 'displays disabled checkboxes for years that dont have data' do
+ ResponseRateLoader.refresh
year_checkbox = subject.css("##{academic_year.range}").first
+ expect(year_checkbox.name).to eq 'input'
+ expect(academic_year.range).to eq '2050-51'
expect(year_checkbox).to have_attribute 'disabled'
end
end