Change the sufficiency threshold from a static number of minimum responses to a minimum response rate of 25 percent

pull/1/head
rebuilt 4 years ago
parent d4df7cbc06
commit 2a2777745a

@ -27,3 +27,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Bump ruby version to 3.1.0 - Bump ruby version to 3.1.0
- Add previous year data. - Add previous year data.
- Add scale to framework. Calculations for scores bubble up through the framework. - Add scale to framework. Calculations for scores bubble up through the framework.
- Change the threshold for sufficiency from a static number of responses to a response rate; from a minimum threshold of 17 teacher responses per survey item in a measure to 25 percent response rate in a subcategory and a minimum of 196 student responses per survey item in a measure to 25 percent response rate in a subcategory.

@ -16,7 +16,9 @@ class SqmApplicationController < ApplicationController
@schools = School.includes([:district]).where(district: @district).order(:name) @schools = School.includes([:district]).where(district: @district).order(:name)
@academic_year = AcademicYear.find_by_range params[:year] @academic_year = AcademicYear.find_by_range params[:year]
@academic_years = AcademicYear.all.order(range: :desc) @academic_years = AcademicYear.all.order(range: :desc)
@has_empty_dataset = Measure.all.all? do |measure| measure.none_meet_threshold? school: @school, academic_year: @academic_year end @has_empty_dataset = Measure.all.all? do |measure|
measure.none_meet_threshold? school: @school, academic_year: @academic_year
end
end end
def district_slug def district_slug

@ -83,19 +83,13 @@ class Measure < ActiveRecord::Base
def sufficient_student_data?(school:, academic_year:) def sufficient_student_data?(school:, academic_year:)
return false unless includes_student_survey_items? return false unless includes_student_survey_items?
average_response_count = student_survey_items.map do |survey_item| subcategory.student_response_rate(school:, academic_year:).meets_student_threshold?
survey_item.survey_item_responses.where(school:, academic_year:).count
end.average
average_response_count >= SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD
end end
def sufficient_teacher_data?(school:, academic_year:) def sufficient_teacher_data?(school:, academic_year:)
return false unless includes_teacher_survey_items? return false unless includes_teacher_survey_items?
average_response_count = teacher_survey_items.map do |survey_item| subcategory.teacher_response_rate(school:, academic_year:).meets_teacher_threshold?
survey_item.survey_item_responses.where(school:, academic_year:).count
end.average
average_response_count >= SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD
end end
def sufficient_data?(school:, academic_year:) def sufficient_data?(school:, academic_year:)

@ -1,4 +1,7 @@
module ResponseRate module ResponseRate
TEACHER_RATE_THRESHOLD = 0.25
STUDENT_RATE_THRESHOLD = 0.25
def initialize(subcategory:, school:, academic_year:) def initialize(subcategory:, school:, academic_year:)
@subcategory = subcategory @subcategory = subcategory
@school = school @school = school
@ -14,4 +17,12 @@ module ResponseRate
(average_responses_per_survey_item / total_possible_responses.to_f * 100).round (average_responses_per_survey_item / total_possible_responses.to_f * 100).round
end end
def meets_student_threshold?
rate >= STUDENT_RATE_THRESHOLD * 100
end
def meets_teacher_threshold?
rate >= TEACHER_RATE_THRESHOLD * 100
end
end end

@ -4,11 +4,11 @@ class StudentResponseRate
private private
def survey_item_count def survey_item_count
@student_survey_item_count ||= @subcategory.measures.map { |measure| measure.student_survey_items.count }.sum @survey_item_count ||= @subcategory.measures.map { |measure| measure.student_survey_items.count }.sum
end end
def response_count def response_count
@student_response_count ||= @subcategory.measures.map do |measure| @response_count ||= @subcategory.measures.map do |measure|
measure.student_survey_items.map do |survey_item| measure.student_survey_items.map do |survey_item|
survey_item.survey_item_responses.where(school: @school, academic_year: @academic_year).count survey_item.survey_item_responses.where(school: @school, academic_year: @academic_year).count
end.sum end.sum
@ -16,7 +16,7 @@ class StudentResponseRate
end end
def total_possible_responses def total_possible_responses
@total_possible_student_responses ||= begin @total_possible_responses ||= begin
total_responses = Respondent.where(school: @school, academic_year: @academic_year).first total_responses = Respondent.where(school: @school, academic_year: @academic_year).first
return 0 unless total_responses.present? return 0 unless total_responses.present?

@ -10,4 +10,20 @@ class Subcategory < ActiveRecord::Base
scores = scores.reject(&:nil?) scores = scores.reject(&:nil?)
scores.average scores.average
end end
def student_response_rate(school:, academic_year:)
@student_response_rate ||= Hash.new do |memo|
memo[[school, academic_year]] = StudentResponseRate.new(subcategory: self, school:, academic_year:)
end
@student_response_rate[[school, academic_year]]
end
def teacher_response_rate(school:, academic_year:)
@teacher_response_rate ||= Hash.new do |memo|
memo[[school, academic_year]] = TeacherResponseRate.new(subcategory: self, school:, academic_year:)
end
@teacher_response_rate[[school, academic_year]]
end
end end

@ -1,6 +1,6 @@
class SurveyItemResponse < ActiveRecord::Base class SurveyItemResponse < ActiveRecord::Base
TEACHER_RESPONSE_THRESHOLD = 17 TEACHER_RESPONSE_THRESHOLD = 2
STUDENT_RESPONSE_THRESHOLD = 196 STUDENT_RESPONSE_THRESHOLD = 2
belongs_to :academic_year belongs_to :academic_year
belongs_to :school belongs_to :school

@ -12,11 +12,11 @@ class TeacherResponseRate
end end
def survey_item_count def survey_item_count
@teacher_survey_item_count ||= @subcategory.measures.map { |measure| measure.teacher_survey_items.count }.sum @survey_item_count ||= @subcategory.measures.map { |measure| measure.teacher_survey_items.count }.sum
end end
def response_count def response_count
@teacher_response_count ||= @subcategory.measures.map do |measure| @response_count ||= @subcategory.measures.map do |measure|
measure.teacher_survey_items.map do |survey_item| measure.teacher_survey_items.map do |survey_item|
survey_item.survey_item_responses.where(school: @school, academic_year: @academic_year).count survey_item.survey_item_responses.where(school: @school, academic_year: @academic_year).count
end.sum end.sum
@ -24,7 +24,7 @@ class TeacherResponseRate
end end
def total_possible_responses def total_possible_responses
@total_possible_teacher_responses ||= begin @total_possible_responses ||= begin
total_responses = Respondent.where(school: @school, academic_year: @academic_year).first total_responses = Respondent.where(school: @school, academic_year: @academic_year).first
return 0 unless total_responses.present? return 0 unless total_responses.present?

@ -3,10 +3,6 @@ class SubcategoryPresenter
@subcategory = subcategory @subcategory = subcategory
@academic_year = academic_year @academic_year = academic_year
@school = school @school = school
@student_response_rate = StudentResponseRate.new(subcategory: @subcategory, school: @school,
academic_year: @academic_year)
@teacher_response_rate = TeacherResponseRate.new(subcategory: @subcategory, school: @school,
academic_year: @academic_year)
end end
def id def id
@ -34,11 +30,11 @@ class SubcategoryPresenter
end end
def student_response_rate def student_response_rate
@student_response_rate.rate @subcategory.student_response_rate(school: @school, academic_year: @academic_year).rate
end end
def teacher_response_rate def teacher_response_rate
@teacher_response_rate.rate @subcategory.teacher_response_rate(school: @school, academic_year: @academic_year).rate
end end
def admin_collection_rate def admin_collection_rate

@ -0,0 +1,19 @@
# Decision record 3
# Change the response rate threshold from a static number to a response rate percentage
## Status
Completed
## Context
We do not show responses if there is insufficient data. We only show a graph if it's statistically meaningful. Previously, the minimum number of responses was set to 17 per teacher survey item and 196 per student survey item. This was calculated at the measure level.
## Decision
We have changed the minumim threshold to be a 25 percent response rate at the subcategory level.
## Consequences
This story, in combination with the story for marking short-form only schools, means that small population elementary schools will be able to see the responses visualized on the dashboard where before, that data would have been filtered out.

@ -36,7 +36,7 @@ FactoryBot.define do
end end
after(:create) do |subcategory, evaluator| after(:create) do |subcategory, evaluator|
create_list(:measure, evaluator.measures_count, subcategory:).each do |measure| create_list(:measure, evaluator.measures_count, subcategory:).each do |measure|
scale = create(:scale, measure: measure) scale = create(:scale, measure:)
survey_item = create(:teacher_survey_item, scale:) survey_item = create(:teacher_survey_item, scale:)
create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item:) create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item:)
end end
@ -59,10 +59,10 @@ FactoryBot.define do
measure measure
scale_id { "A Scale #{rand}" } scale_id { "A Scale #{rand}" }
factory :teacher_scale do factory :teacher_scale do
scale_id {"t-#{rand}"} scale_id { "t-#{rand}" }
end end
factory :student_scale do factory :student_scale do
scale_id {"s-#{rand}"} scale_id { "s-#{rand}" }
end end
end end
@ -102,5 +102,7 @@ FactoryBot.define do
factory :respondent do factory :respondent do
school school
academic_year academic_year
total_students { SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD * 4 }
total_teachers { SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD * 4 }
end end
end end

@ -1,7 +0,0 @@
require 'rails_helper'
module Legacy
RSpec.describe Student, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end
end

@ -23,6 +23,10 @@ RSpec.describe Measure, type: :model do
let(:teacher_approval_low_benchmark) { 3.2 } let(:teacher_approval_low_benchmark) { 3.2 }
let(:teacher_ideal_low_benchmark) { 4.2 } let(:teacher_ideal_low_benchmark) { 4.2 }
before do
create(:respondent, school:, academic_year:)
create(:respondent, school:, academic_year:)
end
describe 'benchmarks' do describe 'benchmarks' do
context 'when a measure includes only one admin data item' do context 'when a measure includes only one admin data item' do
before do before do
@ -194,7 +198,7 @@ RSpec.describe Measure, type: :model do
let(:teacher_survey_item_2) { create(:teacher_survey_item, scale: teacher_scale) } let(:teacher_survey_item_2) { create(:teacher_survey_item, scale: teacher_scale) }
let(:teacher_survey_item_3) { create(:teacher_survey_item, scale: teacher_scale) } let(:teacher_survey_item_3) { create(:teacher_survey_item, scale: teacher_scale) }
context "and the number of responses for each of the measure's survey items meets the teacher threshold of 17" do context "and the number of responses for each of the measure's survey items meets the teacher threshold " do
before :each do before :each do
create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD,
survey_item: teacher_survey_item_1, academic_year:, school:, likert_score: 3) survey_item: teacher_survey_item_1, academic_year:, school:, likert_score: 3)
@ -217,14 +221,14 @@ RSpec.describe Measure, type: :model do
end end
end end
context "and the average number of responses across the measure's survey items meets the teacher threshold of 17" do context "and the average number of responses across the measure's survey items meets the teacher threshold " do
before :each do before :each do
create_list(:survey_item_response, 19, survey_item: teacher_survey_item_1, academic_year:, school:, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD + 1, survey_item: teacher_survey_item_1, academic_year:, school:,
likert_score: 3) likert_score: 3)
create_list(:survey_item_response, 16, survey_item: teacher_survey_item_2, academic_year:, school:, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item: teacher_survey_item_2, academic_year:, school:,
likert_score: 4) likert_score: 4)
create_list(:survey_item_response, 16, survey_item: teacher_survey_item_3, academic_year:, school:, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1, survey_item: teacher_survey_item_3, academic_year:, school:,
likert_score: 5) likert_score: 5)
end end
it 'returns the average of the likert scores of the survey items' do it 'returns the average of the likert scores of the survey items' do
@ -233,14 +237,14 @@ RSpec.describe Measure, type: :model do
end end
end end
context "and none of the measure's survey items meets the teacher threshold of 17" do context "and none of the measure's survey items meets the teacher threshold " do
before :each do before :each do
create_list(:survey_item_response, 16, survey_item: teacher_survey_item_1, academic_year:, school:, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1, survey_item: teacher_survey_item_1, academic_year:, school:,
likert_score: rand) likert_score: rand)
create_list(:survey_item_response, 16, survey_item: teacher_survey_item_2, academic_year:, school:, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1, survey_item: teacher_survey_item_2, academic_year:, school:,
likert_score: rand) likert_score: rand)
create_list(:survey_item_response, 16, survey_item: teacher_survey_item_3, academic_year:, school:, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1, survey_item: teacher_survey_item_3, academic_year:, school:,
likert_score: rand) likert_score: rand)
end end
it 'returns nil' do it 'returns nil' do
@ -252,14 +256,14 @@ RSpec.describe Measure, type: :model do
end end
end end
context "and the average number of responses across the measure's survey items does not meet the teacher threshold of 17" do context "and the average number of responses across the measure's survey items does not meet the teacher threshold " do
before :each do before :each do
create_list(:survey_item_response, 18, survey_item: teacher_survey_item_1, academic_year:, school:, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item: teacher_survey_item_1, academic_year:, school:,
likert_score: rand) likert_score: rand)
create_list(:survey_item_response, 16, survey_item: teacher_survey_item_2, academic_year:, school:, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1, survey_item: teacher_survey_item_2, academic_year:, school:,
likert_score: rand) likert_score: rand)
create_list(:survey_item_response, 16, survey_item: teacher_survey_item_3, academic_year:, school:, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1, survey_item: teacher_survey_item_3, academic_year:, school:,
likert_score: rand) likert_score: rand)
end end
it 'returns nil' do it 'returns nil' do
@ -277,7 +281,7 @@ RSpec.describe Measure, type: :model do
let(:student_survey_item_2) { create(:student_survey_item, scale: student_scale) } let(:student_survey_item_2) { create(:student_survey_item, scale: student_scale) }
let(:student_survey_item_3) { create(:student_survey_item, scale: student_scale) } let(:student_survey_item_3) { create(:student_survey_item, scale: student_scale) }
context "and the number of responses for each of the measure's survey items meets the student threshold of 196" do context "and the number of responses for each of the measure's survey items meets the student threshold " do
before :each do before :each do
create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD,
survey_item: student_survey_item_1, academic_year:, school:, likert_score: 3) survey_item: student_survey_item_1, academic_year:, school:, likert_score: 3)
@ -299,14 +303,14 @@ RSpec.describe Measure, type: :model do
end end
end end
context "and the average number of responses across the measure's survey items meets the student threshold of 196" do context "and the average number of responses across the measure's survey items meets the student threshold " do
before :each do before :each do
create_list(:survey_item_response, 200, survey_item: student_survey_item_1, academic_year:, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD + 1, survey_item: student_survey_item_1, academic_year:,
school:, likert_score: 3) school:, likert_score: 3)
create_list(:survey_item_response, 195, survey_item: student_survey_item_2, academic_year:, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: student_survey_item_2, academic_year:,
school:, likert_score: 4) school:, likert_score: 4)
create_list(:survey_item_response, 193, survey_item: student_survey_item_3, academic_year:, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, survey_item: student_survey_item_3, academic_year:,
school:, likert_score: 5) school:, likert_score: 5)
end end
it 'returns the average of the likert scores of the survey items' do it 'returns the average of the likert scores of the survey items' do
@ -315,14 +319,14 @@ RSpec.describe Measure, type: :model do
end end
end end
context "and none of the measure's survey items meets the student threshold of 196" do context "and none of the measure's survey items meets the student threshold " do
before :each do before :each do
create_list(:survey_item_response, 195, survey_item: student_survey_item_1, academic_year:, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, survey_item: student_survey_item_1, academic_year:,
school:, likert_score: rand) school:, likert_score: rand)
create_list(:survey_item_response, 195, survey_item: student_survey_item_2, academic_year:, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, survey_item: student_survey_item_2, academic_year:,
school:, likert_score: rand) school:, likert_score: rand)
create_list(:survey_item_response, 195, survey_item: student_survey_item_3, academic_year:, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, survey_item: student_survey_item_3, academic_year:,
school:, likert_score: rand) school:, likert_score: rand)
end end
it 'returns nil' do it 'returns nil' do
@ -334,14 +338,14 @@ RSpec.describe Measure, type: :model do
end end
end end
context "and the average number of responses across the measure's survey items does not meet the student threshold of 196" do context "and the average number of responses across the measure's survey items does not meet the student threshold " do
before :each do before :each do
create_list(:survey_item_response, 200, survey_item: student_survey_item_1, academic_year:, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, survey_item: student_survey_item_1, academic_year:,
school:, likert_score: rand) school:, likert_score: rand)
create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1,
survey_item: student_survey_item_2, academic_year:, school:, likert_score: rand) survey_item: student_survey_item_2, academic_year:, school:, likert_score: rand)
create_list(:survey_item_response, 191, survey_item: student_survey_item_3, academic_year:, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: student_survey_item_3, academic_year:,
school:, likert_score: rand) school:, likert_score: rand)
end end
it 'returns nil' do it 'returns nil' do

@ -2,103 +2,86 @@ require 'rails_helper'
describe ResponseRate, type: :model do describe ResponseRate, type: :model do
let(:school) { create(:school) } let(:school) { create(:school) }
let(:ay) { create(:academic_year) } let(:academic_year) { create(:academic_year) }
let(:survey_respondents) do let(:survey_respondents) do
create(:respondent, school: school, total_students: SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, create(:respondent, school:, academic_year:)
total_teachers: SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, academic_year: ay)
end end
describe StudentResponseRate do describe StudentResponseRate do
let(:subcategory) { create(:subcategory) } let(:subcategory) { create(:subcategory) }
let(:sufficient_measure_1) { create(:measure, subcategory: subcategory) } let(:sufficient_measure_1) { create(:measure, subcategory:) }
let(:sufficient_scale_1) { create(:scale, measure: sufficient_measure_1) } let(:sufficient_scale_1) { create(:scale, measure: sufficient_measure_1) }
let(:sufficient_measure_2) { create(:measure, subcategory: subcategory) } let(:sufficient_measure_2) { create(:measure, subcategory:) }
let(:sufficient_scale_2) { create(:scale, measure: sufficient_measure_2) } let(:sufficient_scale_2) { create(:scale, measure: sufficient_measure_2) }
let(:insufficient_measure) { create(:measure, subcategory: subcategory) }
let(:insufficient_scale) { create(:scale, measure: insufficient_measure) }
let(:sufficient_teacher_survey_item) { create(:teacher_survey_item, scale: sufficient_scale_1) } let(:sufficient_teacher_survey_item) { create(:teacher_survey_item, scale: sufficient_scale_1) }
let(:sufficient_student_survey_item_1) { create(:student_survey_item, scale: sufficient_scale_1) } let(:sufficient_student_survey_item_1) { create(:student_survey_item, scale: sufficient_scale_1) }
let(:insufficient_teacher_survey_item) { create(:teacher_survey_item, scale: insufficient_scale) }
let(:sufficient_student_survey_item_2) { create(:student_survey_item, scale: sufficient_scale_2) } let(:sufficient_student_survey_item_2) { create(:student_survey_item, scale: sufficient_scale_2) }
let(:insufficient_student_survey_item) { create(:student_survey_item, scale: insufficient_scale) }
before :each do before :each do
survey_respondents survey_respondents
create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item: sufficient_teacher_survey_item, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item: sufficient_teacher_survey_item,
academic_year: ay, school: school, likert_score: 1) academic_year:, school:, likert_score: 1)
create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: sufficient_student_survey_item_1, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: sufficient_student_survey_item_1,
academic_year: ay, school: school, likert_score: 4) academic_year:, school:, likert_score: 4)
create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD + 1, survey_item: sufficient_student_survey_item_2, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: sufficient_student_survey_item_2,
academic_year: ay, school: school, likert_score: 4) academic_year:, school:, likert_score: 4)
create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1,
survey_item: insufficient_teacher_survey_item, academic_year: ay, school: school, likert_score: 1)
create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1,
survey_item: insufficient_student_survey_item, academic_year: ay, school: school, likert_score: 1)
end end
context 'when the average number of student responses per question in a subcategory is equal to the student response threshold' do context 'when the average number of student responses per question in a subcategory is equal to the student response threshold' do
it 'returns 100 percent' do it 'returns 100 percent' do
expect(StudentResponseRate.new(subcategory: subcategory, school: school, expect(StudentResponseRate.new(subcategory:, school:,
academic_year: ay).rate).to eq 100 academic_year:).rate).to eq 25
end end
end end
end end
describe TeacherResponseRate do describe TeacherResponseRate do
let(:subcategory) { create(:subcategory) } let(:subcategory) { create(:subcategory) }
let(:sufficient_measure_1) { create(:measure, subcategory: subcategory) } let(:sufficient_measure_1) { create(:measure, subcategory:) }
let(:sufficient_scale_1) { create(:scale, measure: sufficient_measure_1) } let(:sufficient_scale_1) { create(:scale, measure: sufficient_measure_1) }
let(:sufficient_measure_2) { create(:measure, subcategory: subcategory) } let(:sufficient_measure_2) { create(:measure, subcategory:) }
let(:sufficient_scale_2) { create(:scale, measure: sufficient_measure_2) } let(:sufficient_scale_2) { create(:scale, measure: sufficient_measure_2) }
let(:insufficient_measure) { create(:measure, subcategory: subcategory) }
let(:insufficient_scale) { create(:scale, measure: insufficient_measure) }
let(:sufficient_teacher_survey_item_1) { create(:teacher_survey_item, scale: sufficient_scale_1) } let(:sufficient_teacher_survey_item_1) { create(:teacher_survey_item, scale: sufficient_scale_1) }
let(:sufficient_teacher_survey_item_2) { create(:teacher_survey_item, scale: sufficient_scale_1) } let(:sufficient_teacher_survey_item_2) { create(:teacher_survey_item, scale: sufficient_scale_1) }
let(:sufficient_teacher_survey_item_3) { create(:teacher_survey_item, scale: sufficient_scale_1) } let(:sufficient_teacher_survey_item_3) { create(:teacher_survey_item, scale: sufficient_scale_1) }
let(:sufficient_student_survey_item_1) { create(:student_survey_item, scale: sufficient_scale_1) } let(:sufficient_student_survey_item_1) { create(:student_survey_item, scale: sufficient_scale_1) }
let(:insufficient_teacher_survey_item) { create(:teacher_survey_item, scale: insufficient_scale) }
let(:insufficient_student_survey_item) { create(:student_survey_item, scale: insufficient_scale) }
before :each do before :each do
survey_respondents survey_respondents
create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item: sufficient_teacher_survey_item_1, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item: sufficient_teacher_survey_item_1,
academic_year: ay, school: school, likert_score: 1) academic_year:, school:, likert_score: 1)
create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD + 1, survey_item: sufficient_teacher_survey_item_2, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item: sufficient_teacher_survey_item_2,
academic_year: ay, school: school, likert_score: 1) academic_year:, school:, likert_score: 1)
create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: sufficient_student_survey_item_1, create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: sufficient_student_survey_item_1,
academic_year: ay, school: school, likert_score: 4) academic_year:, school:, likert_score: 4)
create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1,
survey_item: insufficient_teacher_survey_item, academic_year: ay, school: school, likert_score: 1)
create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1,
survey_item: insufficient_student_survey_item, academic_year: ay, school: school, likert_score: 1)
end end
context 'when the average number of teacher responses per question in a subcategory is equal to the total possible responses' do context 'when the average number of teacher responses per question in a subcategory is at the threshold' do
it 'returns 100 percent' do it 'returns 25 percent' do
expect(TeacherResponseRate.new(subcategory: subcategory, school: school, expect(TeacherResponseRate.new(subcategory:, school:,
academic_year: ay).rate).to eq 100 academic_year:).rate).to eq 25
end end
end end
context 'when the average number of teacher responses is 77.9, the response rate averages up to 78 percent' do context 'when the teacher response rate is not a whole number. eg 29.166%' do
before do before do
create_list(:survey_item_response, 2, survey_item: sufficient_teacher_survey_item_3, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD + 1, survey_item: sufficient_teacher_survey_item_3,
academic_year: ay, school: school, likert_score: 1) academic_year:, school:, likert_score: 1)
end end
it 'returns 10 percent' do it 'it will return the nearest whole number' do
expect(TeacherResponseRate.new(subcategory: subcategory, school: school, expect(TeacherResponseRate.new(subcategory:, school:,
academic_year: ay).rate).to eq 78 academic_year:).rate).to eq 29
end end
end end
context 'when the average number of teacher responses is greater than the total possible responses' do context 'when the average number of teacher responses is greater than the total possible responses' do
before do before do
create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD + 1, survey_item: sufficient_teacher_survey_item_3, create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD * 11, survey_item: sufficient_teacher_survey_item_3,
academic_year: ay, school: school, likert_score: 1) academic_year:, school:, likert_score: 1)
end end
it 'returns 100 percent' do it 'returns 100 percent' do
expect(TeacherResponseRate.new(subcategory: subcategory, school: school, expect(TeacherResponseRate.new(subcategory:, school:,
academic_year: ay).rate).to eq 100 academic_year:).rate).to eq 100
end end
end end
end end

@ -4,10 +4,13 @@ RSpec.describe Subcategory, type: :model do
let(:school) { create(:school) } let(:school) { create(:school) }
let(:academic_year) { create(:academic_year) } let(:academic_year) { create(:academic_year) }
let(:subcategory) { create(:subcategory) } let(:subcategory) { create(:subcategory) }
let(:measure_1) { create(:measure, subcategory: subcategory) } let(:measure_1) { create(:measure, subcategory:) }
let(:teacher_scale) { create(:teacher_scale, measure: measure_1) } let(:teacher_scale) { create(:teacher_scale, measure: measure_1) }
let(:measure_2) { create(:measure, subcategory: subcategory) } let(:measure_2) { create(:measure, subcategory:) }
let(:student_scale) { create(:student_scale, measure: measure_2) } let(:student_scale) { create(:student_scale, measure: measure_2) }
before do
create(:respondent, school:, academic_year:)
end
describe '.score' do describe '.score' do
let(:teacher_survey_item_1) { create(:teacher_survey_item, scale: teacher_scale) } let(:teacher_survey_item_1) { create(:teacher_survey_item, scale: teacher_scale) }

@ -8,6 +8,9 @@ describe MeasurePresenter do
let(:student_scale) { create(:student_scale, measure:) } let(:student_scale) { create(:student_scale, measure:) }
let(:admin_scale) { create(:scale, measure:) } let(:admin_scale) { create(:scale, measure:) }
let(:measure_presenter) { MeasurePresenter.new(measure:, academic_year:, school:) } let(:measure_presenter) { MeasurePresenter.new(measure:, academic_year:, school:) }
before do
create(:respondent, school:, academic_year:)
end
it 'returns the id of the measure' do it 'returns the id of the measure' do
expect(measure_presenter.id).to eq 'measure-id' expect(measure_presenter.id).to eq 'measure-id'

@ -7,8 +7,7 @@ describe SubcategoryPresenter do
create(:subcategory, name: 'A great subcategory', subcategory_id: 'A', description: 'A great description') create(:subcategory, name: 'A great subcategory', subcategory_id: 'A', description: 'A great description')
end end
let(:survey_respondents) do let(:survey_respondents) do
create(:respondent, school:, total_students: SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, create(:respondent, school:, academic_year:)
total_teachers: 10.0, academic_year:)
end end
let(:subcategory_presenter) do let(:subcategory_presenter) do
survey_respondents survey_respondents
@ -68,11 +67,11 @@ describe SubcategoryPresenter do
end end
it 'returns the student response rate' do it 'returns the student response rate' do
expect(subcategory_presenter.student_response_rate).to eq 100.0 expect(subcategory_presenter.student_response_rate).to eq 25
end end
it 'returns the teacher response rate' do it 'returns the teacher response rate' do
expect(subcategory_presenter.teacher_response_rate).to eq 100 expect(subcategory_presenter.teacher_response_rate).to eq 50
end end
it 'returns the admin collection rate' do it 'returns the admin collection rate' do

@ -9,30 +9,36 @@ describe 'District Admin', js: true do
let(:category) { Category.find_by_name('Teachers & Leadership') } let(:category) { Category.find_by_name('Teachers & Leadership') }
let(:subcategory) { Subcategory.find_by_name('Teachers & The Teaching Environment') } let(:subcategory) { Subcategory.find_by_name('Teachers & The Teaching Environment') }
let(:measures_for_subcategory) { Measure.where(subcategory:) } let(:measures_for_subcategory) { Measure.where(subcategory:) }
let(:scales_for_subcategory) {Scale.where(measure: measures_for_subcategory)} let(:scales_for_subcategory) { Scale.where(measure: measures_for_subcategory) }
let(:survey_items_for_subcategory) { SurveyItem.where(scale: scales_for_subcategory) } let(:survey_items_for_subcategory) { SurveyItem.where(scale: scales_for_subcategory) }
let(:measure_1A_i) { Measure.find_by_measure_id('1A-i') } let(:measure_1A_i) { Measure.find_by_measure_id('1A-i') }
let(:measure_2A_i) { Measure.find_by_measure_id('2A-i') } let(:measure_2A_i) { Measure.find_by_measure_id('2A-i') }
let(:measure_2A_ii) { Measure.find_by_measure_id('2A-ii') }
let(:measure_4C_i) { Measure.find_by_measure_id('4C-i') } let(:measure_4C_i) { Measure.find_by_measure_id('4C-i') }
let(:measure_with_no_survey_responses) { Measure.find_by_measure_id('3A-i') } let(:measure_with_no_survey_responses) { Measure.find_by_measure_id('3A-i') }
let(:survey_item_1_for_measure_1A_i) { SurveyItem.create scale: measure_1A_i.scales.first, survey_item_id: rand.to_s }
let(:survey_item_2_for_measure_1A_i) { SurveyItem.create scale: measure_1A_i.scales.first, survey_item_id: rand.to_s }
let(:survey_items_for_measure_1A_i) { measure_1A_i.survey_items } let(:survey_items_for_measure_1A_i) { measure_1A_i.survey_items }
let(:survey_items_for_measure_2A_i) { measure_2A_i.survey_items } let(:survey_items_for_measure_2A_i) { measure_2A_i.survey_items }
let(:survey_items_for_measure_2A_ii) { measure_2A_ii.survey_items }
let(:survey_items_for_measure_4C_i) { measure_4C_i.survey_items } let(:survey_items_for_measure_4C_i) { measure_4C_i.survey_items }
let(:ay_2020_21) { AcademicYear.find_by_range '2020-21' } let(:ay_2020_21) { AcademicYear.find_by_range '2020-21' }
let(:ay_2019_20) { AcademicYear.find_by_range '2019-20' } # let(:ay_2019_20) { AcademicYear.find_by_range '2019-20' }
let(:username) { 'winchester' } let(:username) { 'winchester' }
let(:password) { 'winchester!' } let(:password) { 'winchester!' }
let(:respondents) do
respondents = Respondent.where(school:).first
respondents.total_students = 8
respondents.total_teachers = 8
respondents.save
end
before :each do before :each do
Rails.application.load_seed Rails.application.load_seed
respondents
survey_item_responses = [] survey_item_responses = []
survey_items_for_measure_1A_i.each do |survey_item| survey_items_for_measure_1A_i.each do |survey_item|
@ -49,6 +55,13 @@ describe 'District Admin', js: true do
end end
end end
survey_items_for_measure_2A_ii.each do |survey_item|
SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD.times do
survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2020_21,
school:, survey_item:, likert_score: 5)
end
end
survey_items_for_measure_4C_i.each do |survey_item| survey_items_for_measure_4C_i.each do |survey_item|
SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD.times do SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD.times do
survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2020_21, survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2020_21,
@ -57,7 +70,7 @@ describe 'District Admin', js: true do
end end
survey_items_for_subcategory.each do |survey_item| survey_items_for_subcategory.each do |survey_item|
200.times do 2.times do
survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2020_21, survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2020_21,
school:, survey_item:, likert_score: 4) school:, survey_item:, likert_score: 4)
end end
@ -108,6 +121,7 @@ end
def district_admin_sees_student_physical_safety def district_admin_sees_student_physical_safety
expect(page).to have_text('Student Physical Safety') expect(page).to have_text('Student Physical Safety')
expect(page).to have_css("[data-for-measure-id='2A-i'][width='40.0%'][x='60%']") expect(page).to have_css("[data-for-measure-id='2A-i'][width='40.0%'][x='60%']")
end end
@ -159,7 +173,7 @@ def district_admin_sees_overview_content
district_admin_sees_student_physical_safety district_admin_sees_student_physical_safety
district_admin_sees_problem_solving_emphasis district_admin_sees_problem_solving_emphasis
page.assert_selector('.measure-row-bar', count: 5) page.assert_selector('.measure-row-bar', count: 6)
end end
def district_admin_sees_browse_content def district_admin_sees_browse_content

@ -11,6 +11,7 @@ describe 'SQM Application' do
before :each do before :each do
driven_by :rack_test driven_by :rack_test
page.driver.browser.basic_authorize(username, password) page.driver.browser.basic_authorize(username, password)
create(:respondent, school:, academic_year:)
end end
context 'when no measures meet their threshold' do context 'when no measures meet their threshold' do

@ -10,8 +10,8 @@ describe 'categories/show' do
subcategory1 = create(:subcategory, category:, name: 'A subcategory', subcategory1 = create(:subcategory, category:, name: 'A subcategory',
description: 'Some description of the subcategory') description: 'Some description of the subcategory')
subcategory2 = create(:subcategory_with_measures, category:, name: 'Another subcategory', subcategory2 = create(:subcategory, category:, name: 'Another subcategory',
description: 'Another description of the subcategory') description: 'Another description of the subcategory')
measure1 = create(:measure, subcategory: subcategory1) measure1 = create(:measure, subcategory: subcategory1)
scale1 = create(:student_scale, measure: measure1) scale1 = create(:student_scale, measure: measure1)
@ -44,6 +44,7 @@ describe 'categories/show' do
assign :academic_year, academic_year assign :academic_year, academic_year
assign :academic_years, [academic_year] assign :academic_years, [academic_year]
create(:respondent, school:, academic_year:)
render render
end end

Loading…
Cancel
Save