From 30e006ee0d659361b12f401f6a054db2c1c981d5 Mon Sep 17 00:00:00 2001 From: rebuilt Date: Mon, 17 Apr 2023 15:18:10 -0700 Subject: [PATCH] Set a minimum threshold of 10 survey item responses to calculate scores per survey item --- app/models/measure.rb | 16 +++-- spec/models/measure_spec.rb | 68 ++++++++++++++----- .../grouped_bar_column_presenter_spec.rb | 20 +++--- 3 files changed, 72 insertions(+), 32 deletions(-) diff --git a/app/models/measure.rb b/app/models/measure.rb index d063ccf7..00e2fb46 100644 --- a/app/models/measure.rb +++ b/app/models/measure.rb @@ -24,11 +24,15 @@ class Measure < ActiveRecord::Base @student_survey_items ||= survey_items.student_survey_items end - def student_survey_items_by_survey_type(school:, academic_year:) - survey = Survey.where(school:, academic_year:).first - return student_survey_items.short_form_items if survey.form == 'short' - - student_survey_items + def student_survey_items_with_sufficient_responses(school:, academic_year:) + SurveyItem.where(id: SurveyItem.joins('inner join survey_item_responses on survey_item_responses.survey_item_id = survey_items.id') + .student_survey_items + .where("survey_item_responses.school": school, + "survey_item_responses.academic_year": academic_year, + "survey_item_responses.survey_item_id": survey_items.student_survey_items) + .group('survey_items.id') + .having('count(*) >= 10') + .count.keys) end def teacher_scales @@ -244,7 +248,7 @@ class Measure < ActiveRecord::Base def student_average(school:, academic_year:) @student_average ||= Hash.new do |memo, (school, academic_year)| - survey_items = student_survey_items_by_survey_type(school:, academic_year:) + survey_items = student_survey_items_with_sufficient_responses(school:, academic_year:) memo[[school, academic_year]] = collect_survey_item_average(survey_items:, school:, academic_year:) end @student_average[[school, academic_year]] diff --git a/spec/models/measure_spec.rb b/spec/models/measure_spec.rb index bcd1eb35..67b35e45 100644 --- a/spec/models/measure_spec.rb +++ b/spec/models/measure_spec.rb @@ -294,6 +294,46 @@ RSpec.describe Measure, type: :model do let(:short_form_student_survey_item_2) { create(:student_survey_item, scale: student_scale, on_short_form: true) } let(:short_form_student_survey_item_3) { create(:student_survey_item, scale: student_scale, on_short_form: true) } + context "and the number of responses for each of the measure's survey items does not meet the student threshold " do + before :each do + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, + survey_item: student_survey_item_1, academic_year:, school:, likert_score: 3) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, + survey_item: student_survey_item_2, academic_year:, school:, likert_score: 4) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, + survey_item: student_survey_item_3, academic_year:, school:, likert_score: 5) + end + it 'it does not return an average score' do + expect(measure.score(school:, academic_year:).average).to eq nil + end + end + + context 'and one survey item has sufficient responses but other items do not meet the threshold' do + before :each do + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, + survey_item: student_survey_item_1, academic_year:, school:, likert_score: 3) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, + survey_item: student_survey_item_2, academic_year:, school:, likert_score: 4) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, + survey_item: student_survey_item_3, academic_year:, school:, likert_score: 5) + end + it 'it does not return an average score' do + expect(measure.score(school:, academic_year:).average).to eq 3 + end + end + context 'and two survey items have sufficient responses but other items do not meet the threshold' do + before :each do + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, + survey_item: student_survey_item_1, academic_year:, school:, likert_score: 3) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, + survey_item: student_survey_item_2, academic_year:, school:, likert_score: 4) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, + survey_item: student_survey_item_3, academic_year:, school:, likert_score: 5) + end + it 'it does not return an average score' do + expect(measure.score(school:, academic_year:).average).to eq 3.5 + end + end context "and the number of responses for each of the measure's survey items meets the student threshold " do before :each do create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, @@ -316,22 +356,6 @@ RSpec.describe Measure, type: :model do end end - context "and the average number of responses across the measure's survey items meets the student threshold " do - before :each do - create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD + 1, survey_item: student_survey_item_1, academic_year:, - school:, likert_score: 3) - create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: student_survey_item_2, academic_year:, - school:, likert_score: 4) - create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, survey_item: student_survey_item_3, academic_year:, - school:, likert_score: 5) - end - - it 'returns the average of the likert scores of the survey items' do - average_score = 4 - expect(measure.score(school:, academic_year:).average).to be_within(0.001).of(average_score) - end - end - context "and none of the measure's survey items meets the student threshold " do before :each do create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, survey_item: student_survey_item_1, academic_year:, @@ -375,6 +399,18 @@ RSpec.describe Measure, type: :model do let(:teacher_survey_item_1) { create(:teacher_survey_item, scale: teacher_scale) } let(:student_survey_item_1) { create(:student_survey_item, scale: student_scale) } + context 'and there is sufficient teacher data but insufficient student data' do + before :each do + create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, + survey_item: teacher_survey_item_1, academic_year:, school:, likert_score: 3) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, + survey_item: student_survey_item_1, academic_year:, school:, likert_score: 5) + end + + it 'returns the average of the likert scores of the survey items' do + expect(measure.score(school:, academic_year:).average).to eq 3 + end + end context 'and there is sufficient teacher data and sufficient student data' do before :each do create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, diff --git a/spec/presenters/grouped_bar_column_presenter_spec.rb b/spec/presenters/grouped_bar_column_presenter_spec.rb index 749daf60..d1045020 100644 --- a/spec/presenters/grouped_bar_column_presenter_spec.rb +++ b/spec/presenters/grouped_bar_column_presenter_spec.rb @@ -129,10 +129,10 @@ describe GroupedBarColumnPresenter do end context 'when more than one year exists' do before do - create(:survey_item_response, survey_item: student_survey_item_for_composite_measure, school:, - academic_year: another_academic_year, likert_score: 5) - create(:survey_item_response, survey_item: student_survey_item_for_composite_measure, school:, - academic_year: another_academic_year, likert_score: 3) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: student_survey_item_for_composite_measure, school:, + academic_year: another_academic_year, likert_score: 5) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: student_survey_item_for_composite_measure, school:, + academic_year: another_academic_year, likert_score: 3) end it 'returns independent scores for each year of data' do expect(all_data_presenter.score(0).average).to eq 4.5 @@ -205,10 +205,10 @@ describe GroupedBarColumnPresenter do context 'when there is more than one years worth of data to show' do before do - create(:survey_item_response, survey_item: student_survey_item, school:, - academic_year: another_academic_year, likert_score: 3) - create(:survey_item_response, survey_item: student_survey_item, school:, - academic_year: another_academic_year, likert_score: 4) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: student_survey_item, school:, + academic_year: another_academic_year, likert_score: 3) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: student_survey_item, school:, + academic_year: another_academic_year, likert_score: 4) end it 'returns only bars that have a numeric score' do @@ -305,8 +305,8 @@ describe GroupedBarColumnPresenter do end context 'when there are enough responses to calculate a score' do before do - create(:survey_item_response, survey_item: teacher_survey_item, school:, - academic_year:) + create(:survey_item_response, survey_item: teacher_survey_item, school:, + academic_year:) end it 'indicates it should show the insufficient data message' do