Finishes #183092367. Adds ui and graphs to show grade level disaggregations

pull/1/head
rebuilt 3 years ago
parent 6ed405d16d
commit 89a7f27b88

@ -2,7 +2,8 @@
class AnalyzeController < SqmApplicationController class AnalyzeController < SqmApplicationController
before_action :assign_categories, :assign_subcategories, :assign_measures, :assign_academic_years, before_action :assign_categories, :assign_subcategories, :assign_measures, :assign_academic_years,
:response_rate_timestamp, :races, :selected_races, :graph, :graphs, :background, :race_score_timestamp, only: [:index] :response_rate_timestamp, :races, :selected_races, :graph, :graphs, :background, :race_score_timestamp,
:sources, :group, :groups, :selected_grades, :grades, :slice, only: [:index]
def index; end def index; end
private private
@ -67,14 +68,15 @@ class AnalyzeController < SqmApplicationController
def graph def graph
graphs.each do |graph| graphs.each do |graph|
@graph = graph if graph.value == params[:graph] @graph = graph if graph.slug == params[:graph]
end end
@graph ||= graphs.first @graph ||= graphs.first
end end
def graphs def graphs
@graphs ||= [Analyze::Graph::StudentsAndTeachers.new, Analyze::Graph::StudentsByGroup.new(races: selected_races)] @graphs ||= [Analyze::Graph::StudentsAndTeachers.new, Analyze::Graph::StudentsByRace.new(races: selected_races),
Analyze::Graph::StudentsByGrade.new(grades: selected_grades)]
end end
def background def background
@ -88,4 +90,61 @@ class AnalyzeController < SqmApplicationController
score.updated_at score.updated_at
end end
end end
def sources
@sources = [Analyze::Source::SurveyData.new(slices:)]
end
def slices
students_and_teachers = Analyze::Slice::StudentsAndTeachers.new
students_by_group = Analyze::Slice::StudentsByGroup.new(races:, grades:)
[students_and_teachers, students_by_group]
end
def group
groups.each do |group|
@group = group if group.slug == params[:group]
end
@group ||= groups.first
end
def groups
@groups = [Analyze::Group::Race.new, Analyze::Group::Grade.new]
end
def selected_grades
@selected_grades ||= begin
grade_params = params[:grades]
return @selected_grades = grades unless grade_params
grade_list = grade_params.split(',') if grade_params
if grade_list
grade_list = grade_list.map do |grade|
grade.to_i
end
end
grade_list
end
end
def grades
@grades ||= SurveyItemResponse.where(school: @school, academic_year: @academic_year)
.where.not(grade: nil)
.group(:grade)
.select(:response_id)
.distinct(:response_id)
.count.reject do |_key, value|
value < 10
end.keys
end
def slice
slice_param = params[:slice]
slices.each do |slice|
@slice = slice if slice.slug == slice_param
end
@slice ||= slices.first
end
end end

@ -10,10 +10,16 @@ export default class extends Controller {
base_url + base_url +
"&academic_years=" + "&academic_years=" +
this.selected_years().join(",") + this.selected_years().join(",") +
"&group=" +
this.selected_group() +
"&slice=" +
this.selected_slice() +
"&graph=" + "&graph=" +
this.selected_graph() + this.selected_graph() +
"&races=" + "&races=" +
this.selected_races().join(","); this.selected_races().join(",") +
"&grades=" +
this.selected_grades().join(",");
this.go_to(url); this.go_to(url);
} }
@ -36,17 +42,50 @@ export default class extends Controller {
return years; return years;
} }
selected_group() {
let groups = [...document.getElementsByName("group-option")];
let selected_group = groups
.filter((item) => {
return item.selected;
})
.map((item) => {
return item.id;
});
return selected_group[0];
}
selected_slice() {
let slices = [...document.getElementsByName("slice")];
let selected_slice = slices
.filter((item) => {
return item.checked;
})
.map((item) => {
return item.id;
});
return selected_slice[0];
}
selected_graph() { selected_graph() {
let graphs = [...document.getElementsByName("graph")]; let graphs = [...document.getElementsByName("slice")];
let selected_graph = graphs let selected_graph = graphs
.filter((item) => { .filter((item) => {
return item.checked; return item.checked;
}) })
.map((item) => { .map((item) => {
return item.id; return item.id;
}); })[0];
if (selected_graph === 'students-and-teachers') {
return selected_graph;
}
return selected_graph[0]; if (this.selected_group() === 'race') {
return 'students-by-race'
} else {
return 'students-by-grade'
}
} }
selected_races() { selected_races() {
@ -61,4 +100,17 @@ export default class extends Controller {
return races; return races;
} }
selected_grades() {
let grade_checkboxes = [...document.getElementsByName("grade-checkbox")]
let grades = grade_checkboxes
.filter((item) => {
return item.checked;
})
.map((item) => {
return item.id.replace('grade-', '');
});
return grades;
}
} }

@ -145,7 +145,7 @@ class Measure < ActiveRecord::Base
meets_student_threshold = sufficient_student_data?(school:, academic_year:) meets_student_threshold = sufficient_student_data?(school:, academic_year:)
meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:) meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:)
meets_admin_data_threshold = any_admin_data_collected?(school:, academic_year:) meets_admin_data_threshold = any_admin_data_collected?(school:, academic_year:)
Score.new(average, meets_teacher_threshold, meets_student_threshold, meets_admin_data_threshold) Score.new(average:, meets_teacher_threshold:, meets_student_threshold:, meets_admin_data_threshold:)
end end
def collect_survey_item_average(survey_items:, school:, academic_year:) def collect_survey_item_average(survey_items:, school:, academic_year:)

@ -1,7 +1,20 @@
# frozen_string_literal: true # frozen_string_literal: true
class Score < Struct.new(:average, :meets_teacher_threshold?, :meets_student_threshold?, :meets_admin_data_threshold?) class Score < ApplicationRecord
NIL_SCORE = Score.new(nil, false, false, false) belongs_to :measure
belongs_to :school
belongs_to :academic_year
belongs_to :race
NIL_SCORE = Score.new(average: nil, meets_teacher_threshold: false, meets_student_threshold: false, meets_admin_data_threshold: false)
enum group: {
all_students: 0,
race: 1,
grade: 2,
gender: 3
}
def in_zone?(zone:) def in_zone?(zone:)
return false if average.nil? || average.is_a?(Float) && average.nan? return false if average.nil? || average.is_a?(Float) && average.nan?

@ -15,4 +15,10 @@ class SurveyItemResponse < ActiveRecord::Base
boston = District.find_by_name('Boston') boston = District.find_by_name('Boston')
where.not(school: boston.schools) if boston.present? where.not(school: boston.schools) if boston.present?
} }
scope :averages_for_grade, ->(survey_items, school, academic_year, grade) {
SurveyItemResponse.where(survey_item: survey_items, school:,
academic_year: , grade:).group(:survey_item).average(:likert_score)
}
end end

@ -0,0 +1,33 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Eight < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 8'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
8
end
end
end
end
end
end

@ -0,0 +1,33 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Eleven < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 11'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
11
end
end
end
end
end
end

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Five < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 5'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
5
end
end
end
end
end
end

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Four < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 4'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
4
end
end
end
end
end
end

@ -0,0 +1,34 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Nine < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 9'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
9
end
end
end
end
end
end

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class One < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 1'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
1
end
end
end
end
end
end

@ -0,0 +1,27 @@
module Analyze
module Graph
module Column
module Grade
module ScoreForGrade
def score(year_index)
averages = SurveyItemResponse.averages_for_grade(measure.student_survey_items, school, academic_years[year_index], grade)
average = bubble_up_averages(averages:)
Score.new(average:,
meets_teacher_threshold: false,
meets_student_threshold: true,
meets_admin_data_threshold: false)
end
def bubble_up_averages(averages:)
measure.student_scales.map do |scale|
scale.survey_items.map do |survey_item|
averages[survey_item]
end.remove_blanks.average
end.remove_blanks.average
end
end
end
end
end
end

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Seven < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 7'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
7
end
end
end
end
end
end

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Six < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 6'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
6
end
end
end
end
end
end

@ -0,0 +1,34 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Ten < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 10'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
10
end
end
end
end
end
end

@ -0,0 +1,32 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Three < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 3'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
3
end
end
end
end
end
end

@ -0,0 +1,34 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Twelve < GroupedBarColumnPresenter
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 12'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
12
end
end
end
end
end
end

@ -0,0 +1,34 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Grade
class Two < GroupedBarColumnPresenter
attr_reader :sufficient_responses
include Analyze::Graph::Column::Grade::ScoreForGrade
def label
'Grade 2'
end
def basis
'student'
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def grade
2
end
end
end
end
end
end

@ -8,7 +8,10 @@ module Analyze
average ||= 0 average ||= 0
meets_student_threshold = s.meets_student_threshold? unless s.nil? meets_student_threshold = s.meets_student_threshold? unless s.nil?
meets_student_threshold ||= false meets_student_threshold ||= false
Score.new(average, false, meets_student_threshold, false) Score.new(average:,
meets_teacher_threshold: false,
meets_student_threshold:,
meets_admin_data_threshold: false)
end end
end end
end end

@ -8,7 +8,7 @@ module Analyze
'Students & Teachers' 'Students & Teachers'
end end
def value def slug
'students-and-teachers' 'students-and-teachers'
end end

@ -0,0 +1,50 @@
module Analyze
module Graph
class StudentsByGrade
include Analyze::Graph::Column::Grade
attr_reader :grades
def initialize(grades:)
@grades = grades
end
def to_s
'Students by Grade'
end
def slug
'students-by-grade'
end
def columns
[].tap do |array|
grades.each do |grade|
array << column_for_grade_code(code: grade)
end
array << Analyze::Graph::Column::AllStudent
end
end
private
def column_for_grade_code(code:)
CFR[code]
end
CFR = {
1 => One,
2 => Two,
3 => Three,
4 => Four,
5 => Five,
6 => Six,
7 => Seven,
8 => Eight,
9 => Nine,
10 => Ten,
11 => Eleven,
12 => Twelve,
}.freeze
end
end
end

@ -1,6 +1,6 @@
module Analyze module Analyze
module Graph module Graph
class StudentsByGroup class StudentsByRace
attr_reader :races attr_reader :races
def initialize(races:) def initialize(races:)
@ -8,11 +8,11 @@ module Analyze
end end
def to_s def to_s
'Students by Group' 'Students by Race'
end end
def value def slug
'students-by-group' 'students-by-race'
end end
def columns def columns
@ -39,7 +39,7 @@ module Analyze
'8' => Analyze::Graph::Column::MiddleEastern, '8' => Analyze::Graph::Column::MiddleEastern,
'99' => Analyze::Graph::Column::Unknown, '99' => Analyze::Graph::Column::Unknown,
'100' => Analyze::Graph::Column::Multiracial '100' => Analyze::Graph::Column::Multiracial
} }.freeze
end end
end end
end end

@ -0,0 +1,13 @@
module Analyze
module Group
class Grade
def name
'Grade'
end
def slug
'grade'
end
end
end
end

@ -0,0 +1,13 @@
module Analyze
module Group
class Race
def name
'Race'
end
def slug
'race'
end
end
end
end

@ -0,0 +1,17 @@
module Analyze
module Slice
class StudentsAndTeachers
def to_s
'Students & Teachers'
end
def slug
'students-and-teachers'
end
def graphs
[Analyze::Graph::StudentsAndTeachers.new]
end
end
end
end

@ -0,0 +1,24 @@
module Analyze
module Slice
class StudentsByGroup
attr_reader :races, :grades
def initialize(races:, grades:)
@races = races
@grades = grades
end
def to_s
'Students by Group'
end
def slug
'students-by-group'
end
def graphs
[Analyze::Graph::StudentsByRace.new(races:), Analyze::Graph::StudentsByGrade.new(grades:)]
end
end
end
end

@ -0,0 +1,20 @@
module Analyze
module Source
class SurveyData
attr_reader :slices
include Analyze::Slice
def initialize(slices:)
@slices = slices
end
# def to_s
# 'Survey Data Only'
# end
# def value
# 'survey-data-only'
# end
end
end
end

@ -42,6 +42,6 @@ class Zones
end end
def zone_for_score(score) def zone_for_score(score)
all_zones.find { |zone| Score.new(score).in_zone?(zone:) } || insufficient_data all_zones.find { |zone| Score.new(average: score).in_zone?(zone:) } || insufficient_data
end end
end end

@ -45,15 +45,13 @@ class RaceScoreLoader
def self.race_score(measure:, school:, academic_year:, race:) def self.race_score(measure:, school:, academic_year:, race:)
rate = response_rate(school:, academic_year:, measure:) rate = response_rate(school:, academic_year:, measure:)
return Score.new(0, false, false, false) unless rate.meets_student_threshold return Score.new(average: 0, meets_teacher_threshold: false, meets_student_threshold: false, meets_admin_data_threshold: false) unless rate.meets_student_threshold
survey_items = measure.student_survey_items survey_items = measure.student_survey_items
# students = StudentRace.where(race:).pluck(:student_id).uniq
averages = grouped_responses(school:, academic_year:, survey_items:, race:) averages = grouped_responses(school:, academic_year:, survey_items:, race:)
meets_student_threshold = sufficient_responses(school:, academic_year:, race:) meets_student_threshold = sufficient_responses(school:, academic_year:, race:)
scorify(responses: averages, meets_student_threshold:, measure:) scorify(responses: averages, meets_student_threshold:, measure:)
# binding.break
end end
def self.grouped_responses(school:, academic_year:, survey_items:, race:) def self.grouped_responses(school:, academic_year:, survey_items:, race:)
@ -83,7 +81,7 @@ class RaceScoreLoader
average = 0 unless meets_student_threshold average = 0 unless meets_student_threshold
Score.new(average, false, meets_student_threshold, false) Score.new(average:, meets_teacher_threshold: false, meets_student_threshold:, meets_admin_data_threshold: false)
end end
def self.sufficient_responses(school:, academic_year:, race:) def self.sufficient_responses(school:, academic_year:, race:)

@ -6,11 +6,10 @@ class SurveyResponsesDataLoader
def self.load_data(filepath:) def self.load_data(filepath:)
File.open(filepath) do |file| File.open(filepath) do |file|
headers = file.first headers = file.first
survey_items = SurveyItem.where(survey_item_id: get_survey_item_ids_from_headers(headers:))
file.lazy.each_slice(1000) do |lines| file.lazy.each_slice(1000) do |lines|
survey_item_responses = CSV.parse(lines.join, headers:).map do |row| survey_item_responses = CSV.parse(lines.join, headers:).map do |row|
process_row row: row, survey_items: survey_items process_row row: Values.new(row:, headers:)
end end
SurveyItemResponse.import survey_item_responses.compact.flatten, batch_size: 1000 SurveyItemResponse.import survey_item_responses.compact.flatten, batch_size: 1000
@ -20,89 +19,102 @@ class SurveyResponsesDataLoader
private private
def self.process_row(row:, survey_items:) def self.process_row(row:)
id = dese_id(row) return unless row.dese_id?
return unless dese_id?(id) return unless row.school.present?
school = School.find_by_dese_id(id) process_survey_items(row:)
return unless school.present?
process_survey_items(row:, survey_items:, school:)
end end
def self.process_survey_items(row:, survey_items:, school:) def self.process_survey_items(row:)
id = response_id(row) row.survey_items.map do |survey_item|
survey_items.map do |survey_item| likert_score = row.likert_score(survey_item_id: survey_item.survey_item_id) || next
likert_score = row[survey_item.survey_item_id] || next
unless likert_score.valid_likert_score? unless likert_score.valid_likert_score?
puts "Response ID: #{id}, Likert score: #{likert_score} rejected" unless likert_score == 'NA' puts "Response ID: #{row.response_id}, Likert score: #{likert_score} rejected" unless likert_score == 'NA'
next next
end end
response = survey_item_response(response_id: id, survey_item:) response = row.survey_item_response(survey_item:)
create_or_update_response(survey_item_response: response, likert_score:, school:, row:, survey_item:) create_or_update_response(survey_item_response: response, likert_score:, row:, survey_item:)
end.compact end.compact
end end
def self.create_or_update_response(survey_item_response:, likert_score:, school:, row:, survey_item:) def self.create_or_update_response(survey_item_response:, likert_score:, row:, survey_item:)
if survey_item_response.present? if survey_item_response.present?
survey_item_response.update!(likert_score:) if survey_item_response.likert_score != likert_score survey_item_response.update!(likert_score:)
[] []
else else
SurveyItemResponse.new(response_id: response_id(row), academic_year: academic_year(row), school:, survey_item:, SurveyItemResponse.new(response_id: row.response_id, academic_year: row.academic_year, school: row.school, survey_item:,
likert_score:) likert_score:, grade: row.grade)
end end
end end
def self.get_survey_item_ids_from_headers(headers:) private_class_method :process_row
CSV.parse(headers, headers: true).headers private_class_method :process_survey_items
.filter(&:present?) private_class_method :create_or_update_response
.filter { |header| header.start_with? 't-' or header.start_with? 's-' } end
class Values
attr_reader :row, :headers
def initialize(row:, headers:)
@row = row
@headers = headers
end end
def self.dese_id?(dese_id) def dese_id?
dese_id.present? dese_id.present?
end end
def self.response_date(row) def response_date
Date.parse(row['Recorded Date'] || row['RecordedDate']) @response_date ||= Date.parse(row['Recorded Date'] || row['RecordedDate'])
end end
def self.academic_year(row) def academic_year
AcademicYear.find_by_date response_date(row) @academic_year ||= AcademicYear.find_by_date response_date
end end
def self.survey_item_response(response_id:, survey_item:) def survey_item_response(survey_item:)
SurveyItemResponse.find_by(response_id:, survey_item:) SurveyItemResponse.find_by(response_id:, survey_item:)
end end
def self.response_id(row) def response_id
row['Response ID'] || row['ResponseId'] || row['ResponseID'] @response_id ||= row['Response ID'] || row['ResponseId'] || row['ResponseID']
end end
def self.dese_id(row) def dese_id
row['DESE ID' || 'Dese ID'] || row['DeseId'] || row['DeseID'] @dese_id ||= (row['DESE ID' || 'Dese ID'] || row['DeseId'] || row['DeseID']).to_i
end end
private_class_method :process_row def likert_score(survey_item_id:)
private_class_method :process_survey_items row[survey_item_id]
private_class_method :get_survey_item_ids_from_headers end
private_class_method :dese_id?
private_class_method :create_or_update_response
private_class_method :response_date
private_class_method :academic_year
private_class_method :survey_item_response
private_class_method :response_id
private_class_method :dese_id
end
module StringMonkeyPatches def school
def integer? @school ||= School.find_by_dese_id(dese_id)
to_i.to_s == self end
def survey_items
@survey_items ||= SurveyItem.where(survey_item_id: get_survey_item_ids_from_headers(headers:))
end
def get_survey_item_ids_from_headers(headers:)
CSV.parse(headers, headers: true).headers
.filter(&:present?)
.filter { |header| header.start_with? 't-' or header.start_with? 's-' }
end end
def grade
@grade ||= begin
raw_grade = (row['grade'] || row['Grade'] || row['What grade are you in?']).to_i
raw_grade == 0 ? nil : raw_grade
end
end
end
module StringMonkeyPatches
def valid_likert_score? def valid_likert_score?
integer? and to_i.between? 1, 5 to_i.between? 1, 5
end end
end end

@ -1,23 +1,28 @@
<%# TODO Hook up the buttons so that only the selected races are shown for each column %>
<h3 class="sub-header-4 mt-5">Data Filters</h3> <h3 class="sub-header-4 mt-5">Data Filters</h3>
<div class="bg-gray p-3" data-controller="analyze"> <div class="bg-gray p-3" data-controller="analyze">
<% @graphs.each do |graph| %> <% @sources.first.slices.each do |slice| %>
<div> <div>
<input type="radio" <input type="radio"
id="<%= graph.value %>" id="<%= slice.slug %>"
class="form-check-input" class="form-check-input"
name="graph" name="slice"
value="<%= base_url %>" value="<%= base_url %>"
data-action="click->analyze#refresh" data-action="click->analyze#refresh"
<%= graph.value == @graph.value ? "checked" : "" %>> <%= slice.slug == @slice.slug ? "checked" : "" %>>
<label for="<%= graph.value %>"><%= graph.to_s %></label> <label for="<%= slice.slug %>"><%= slice.to_s %></label>
</div> </div>
<% end %>
<select id="select-group" class="mx-3 form-select" data-id="group-dropdown" data-action="analyze#refresh">
<% @groups.each do |group| %>
<option id="<%= group.slug %>" name="group-option" value="<%= base_url %>" <%= group.slug == @group.slug ? "Selected": "" %>><%= group.name %> </option>
<% end %> <% end %>
</select>
<p class="sub-header-5 mt-3 font-size-14"> Select a group </p> <p class="sub-header-5 mt-3 font-size-14"> Select a group </p>
<% @races.each do |race | %> <% @races.each do |race | %>
<div class="d-flex align-items-center <%= race.slug %>"> <div class="d-flex align-items-center">
<input <input
id="<%= race.slug %>" id="<%= race.slug %>"
class="m-3 race-checkbox form-check-input" class="m-3 race-checkbox form-check-input"
@ -26,9 +31,33 @@
value="<%= base_url %>" value="<%= base_url %>"
data-action="click->analyze#refresh" data-action="click->analyze#refresh"
<%= @selected_races.map(&:slug).include?(race.slug) ? "checked" : "" %> <%= @selected_races.map(&:slug).include?(race.slug) ? "checked" : "" %>
<%= @graph.value == 'students-and-teachers' ? "disabled" : "" %>> <%= @graph.slug == 'students-and-teachers' ? "disabled" : "" %>
<%= @group.slug == 'race' ? "" : "hidden" %>>
<label for="<%= race.qualtrics_code %>"
<%= @group.slug == 'race' ? "" : "hidden" %>>
<%= race.designation %>
</label>
</div>
<% end %>
<% @grades.each do |grade | %>
<div class="d-flex align-items-center">
<input
id="grade-<%= grade %>"
class="m-3 grade-checkbox form-check-input"
type="checkbox"
name="grade-checkbox"
value="<%= base_url %>"
data-action="click->analyze#refresh"
<%= @selected_grades.include?(grade) ? "checked" : "" %>
<%= @graph.slug == 'students-and-teachers' ? "disabled" : "" %>
<%= @group.slug == 'grade' ? "" : "hidden" %>>
<label for="<%= race.qualtrics_code %>"><%= race.designation %></label> <label for="grade-<%= grade %>"
<%= @group.slug == 'grade' ? "" : "hidden" %>>
<%= grade %>
</label>
</div> </div>
<% end %> <% end %>
</div> </div>

@ -1,6 +1,7 @@
<% content_for :title do %> <% content_for :title do %>
<h1 class="sub-header-2 color-white m-0"> Analysis of <%= @school.name %> </h1> <h1 class="sub-header-2 color-white m-0"> Analysis of <%= @school.name %> </h1>
<% end %> <% end %>
<div class="graph-content"> <div class="graph-content">
<div class="breadcrumbs sub-header-4"> <div class="breadcrumbs sub-header-4">
<%= @category.category_id %>:<%= @category.name %> > <%= @subcategory.subcategory_id %>:<%= @subcategory.name %> <%= @category.category_id %>:<%= @category.name %> > <%= @subcategory.subcategory_id %>:<%= @subcategory.name %>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,5 @@
class AddGradeToSurveyItemResponse < ActiveRecord::Migration[7.0]
def change
add_column :survey_item_responses, :grade, :integer
end
end

@ -0,0 +1,18 @@
class CreateScores < ActiveRecord::Migration[7.0]
def change
create_table :scores do |t|
t.float :average
t.boolean :meets_teacher_threshold
t.boolean :meets_student_threshold
t.boolean :meets_admin_data_threshold
t.integer :group
t.references :measure, null: false, foreign_key: true
t.references :school, null: false, foreign_key: true
t.references :academic_year, null: false, foreign_key: true
t.integer :grade
t.references :race, null: false, foreign_key: true
t.timestamps
end
end
end

@ -0,0 +1,5 @@
class AddGradeIndexToSurveyItemResponse < ActiveRecord::Migration[7.0]
def change
add_index :survey_item_responses, [:school_id, :survey_item_id, :academic_year_id, :grade], name: "index_survey_responses_on_grade"
end
end

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2022_08_22_214951) do ActiveRecord::Schema[7.0].define(version: 2022_10_15_023621) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements" enable_extension "pg_stat_statements"
enable_extension "plpgsql" enable_extension "plpgsql"
@ -339,7 +339,6 @@ ActiveRecord::Schema[7.0].define(version: 2022_08_22_214951) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.index ["academic_year_id"], name: "index_response_rates_on_academic_year_id" t.index ["academic_year_id"], name: "index_response_rates_on_academic_year_id"
t.index ["school_id", "subcategory_id"], name: "index_response_rates_on_school_id_and_subcategory_id" t.index ["school_id", "subcategory_id"], name: "index_response_rates_on_school_id_and_subcategory_id"
t.index ["school_id"], name: "index_response_rates_on_school_id"
t.index ["subcategory_id"], name: "index_response_rates_on_subcategory_id" t.index ["subcategory_id"], name: "index_response_rates_on_subcategory_id"
end end
@ -366,6 +365,25 @@ ActiveRecord::Schema[7.0].define(version: 2022_08_22_214951) do
t.index ["dese_id"], name: "index_schools_on_dese_id", unique: true t.index ["dese_id"], name: "index_schools_on_dese_id", unique: true
end end
create_table "scores", force: :cascade do |t|
t.float "average"
t.boolean "meets_teacher_threshold"
t.boolean "meets_student_threshold"
t.boolean "meets_admin_data_threshold"
t.integer "group"
t.bigint "measure_id", null: false
t.bigint "school_id", null: false
t.bigint "academic_year_id", null: false
t.integer "grade"
t.bigint "race_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["academic_year_id"], name: "index_scores_on_academic_year_id"
t.index ["measure_id"], name: "index_scores_on_measure_id"
t.index ["race_id"], name: "index_scores_on_race_id"
t.index ["school_id"], name: "index_scores_on_school_id"
end
create_table "student_races", force: :cascade do |t| create_table "student_races", force: :cascade do |t|
t.bigint "student_id", null: false t.bigint "student_id", null: false
t.bigint "race_id", null: false t.bigint "race_id", null: false
@ -403,10 +421,11 @@ ActiveRecord::Schema[7.0].define(version: 2022_08_22_214951) do
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.bigint "student_id" t.bigint "student_id"
t.integer "grade"
t.index ["academic_year_id"], name: "index_survey_item_responses_on_academic_year_id" t.index ["academic_year_id"], name: "index_survey_item_responses_on_academic_year_id"
t.index ["response_id"], name: "index_survey_item_responses_on_response_id" t.index ["response_id"], name: "index_survey_item_responses_on_response_id"
t.index ["school_id", "academic_year_id"], name: "index_survey_item_responses_on_school_id_and_academic_year_id" t.index ["school_id", "academic_year_id"], name: "index_survey_item_responses_on_school_id_and_academic_year_id"
t.index ["school_id"], name: "index_survey_item_responses_on_school_id" t.index ["school_id", "survey_item_id", "academic_year_id", "grade"], name: "index_survey_responses_on_grade"
t.index ["student_id"], name: "index_survey_item_responses_on_student_id" t.index ["student_id"], name: "index_survey_item_responses_on_student_id"
t.index ["survey_item_id"], name: "index_survey_item_responses_on_survey_item_id" t.index ["survey_item_id"], name: "index_survey_item_responses_on_survey_item_id"
end end
@ -457,6 +476,10 @@ ActiveRecord::Schema[7.0].define(version: 2022_08_22_214951) do
add_foreign_key "response_rates", "subcategories" add_foreign_key "response_rates", "subcategories"
add_foreign_key "scales", "measures" add_foreign_key "scales", "measures"
add_foreign_key "schools", "districts" add_foreign_key "schools", "districts"
add_foreign_key "scores", "academic_years"
add_foreign_key "scores", "measures"
add_foreign_key "scores", "races"
add_foreign_key "scores", "schools"
add_foreign_key "student_races", "races" add_foreign_key "student_races", "races"
add_foreign_key "student_races", "students" add_foreign_key "student_races", "students"
add_foreign_key "subcategories", "categories" add_foreign_key "subcategories", "categories"

File diff suppressed because it is too large Load Diff

@ -40,14 +40,10 @@ namespace :one_off do
end end
end end
task change_overall_performance_measure_id: :environment do
measure_4aii = Measure.where(name: 'Overall Performance')[0]
measure_4aii.update! measure_id: '4A-i'
end
desc 'load a single file' desc 'load a single file'
task load_single_file: :environment do task load_single_file: :environment do
filepath = Rails.root.join('data', 'survey_responses', '2016-17_student_survey_responses.csv') filepath = Rails.root.join('data', 'survey_responses',
'2021-22_revere_somerville_wareham_student_survey_responses.csv')
puts "=====================> Loading data from csv at path: #{filepath}" puts "=====================> Loading data from csv at path: #{filepath}"
SurveyResponsesDataLoader.load_data filepath: filepath SurveyResponsesDataLoader.load_data filepath: filepath
puts "=====================> Completed loading #{SurveyItemResponse.count} survey responses" puts "=====================> Completed loading #{SurveyItemResponse.count} survey responses"
@ -78,44 +74,6 @@ namespace :one_off do
puts "=====================> Completed loading #{Student.count} survey responses" puts "=====================> Completed loading #{Student.count} survey responses"
end end
desc 'load revere somerville warehame results for 2021-22'
task load_revere: :environment do
['2021-22_revere_somerville_wareham_student_survey_responses.csv',
'2021-22_revere_somerville_wareham_teacher_survey_responses.csv'].each do |filepath|
filepath = Rails.root.join('data', 'survey_responses', filepath)
puts "=====================> Loading data from csv at path: #{filepath}"
SurveyResponsesDataLoader.load_data filepath:
end
puts 'Resetting response rates'
revere = District.find_by_name 'Revere'
somerville = District.find_by_name 'Somerville'
wareham = District.find_by_name 'Wareham'
academic_year = AcademicYear.find_by_range '2021-22'
ResponseRateLoader.reset(schools: revere.schools, academic_years: [academic_year])
ResponseRateLoader.reset(schools: somerville.schools, academic_years: [academic_year])
ResponseRateLoader.reset(schools: wareham.schools, academic_years: [academic_year])
Rails.cache.clear
puts "=====================> Completed recalculating #{ResponseRate.count} response rates"
end
desc 'load lowell and milford results for 2021-22'
task load_lowell: :environment do
['2021-22_lowell_milford_student_survey_responses.csv',
'2021-22_lowell_milford_teacher_survey_responses.csv'].each do |filepath|
filepath = Rails.root.join('data', 'survey_responses', filepath)
puts "=====================> Loading data from csv at path: #{filepath}"
SurveyResponsesDataLoader.load_data filepath:
end
puts 'Resetting response rates'
lowell = District.find_by_name 'Lowell'
milford = District.find_by_name 'Milford'
academic_year = AcademicYear.find_by_range '2021-22'
ResponseRateLoader.reset(schools: lowell.schools, academic_years: [academic_year])
ResponseRateLoader.reset(schools: milford.schools, academic_years: [academic_year])
Rails.cache.clear
puts "=====================> Completed recalculating #{ResponseRate.count} response rates"
end
desc 'reset race score calculations' desc 'reset race score calculations'
task reset_race_scores_2021: :environment do task reset_race_scores_2021: :environment do
puts 'Resetting race scores' puts 'Resetting race scores'
@ -125,51 +83,6 @@ namespace :one_off do
puts "=====================> Completed loading #{RaceScore.count} race scores" puts "=====================> Completed loading #{RaceScore.count} race scores"
end end
desc 'reset race score calculations'
task reset_race_scores_2020: :environment do
puts 'Resetting race scores'
academic_years = [AcademicYear.find_by_range('2020-21')]
RaceScoreLoader.reset(academic_years:, fast_processing: false)
Rails.cache.clear
puts "=====================> Completed loading #{RaceScore.count} race scores"
end
desc 'reset race score calculations'
task reset_race_scores_2019: :environment do
puts 'Resetting race scores'
academic_years = [AcademicYear.find_by_range('2019-20')]
RaceScoreLoader.reset(academic_years:, fast_processing: false)
Rails.cache.clear
puts "=====================> Completed loading #{RaceScore.count} race scores"
end
desc 'reset race score calculations'
task reset_race_scores_2018: :environment do
puts 'Resetting race scores'
academic_years = [AcademicYear.find_by_range('2018-19')]
RaceScoreLoader.reset(academic_years:, fast_processing: false)
Rails.cache.clear
puts "=====================> Completed loading #{RaceScore.count} race scores"
end
desc 'reset race score calculations'
task reset_race_scores_2017: :environment do
puts 'Resetting race scores'
academic_years = [AcademicYear.find_by_range('2017-18')]
RaceScoreLoader.reset(academic_years:, fast_processing: false)
Rails.cache.clear
puts "=====================> Completed loading #{RaceScore.count} race scores"
end
desc 'reset race score calculations'
task reset_race_scores_2016: :environment do
puts 'Resetting race scores'
academic_years = [AcademicYear.find_by_range('2016-17')]
RaceScoreLoader.reset(academic_years:, fast_processing: false)
Rails.cache.clear
puts "=====================> Completed loading #{RaceScore.count} race scores"
end
desc 'list scales that have no survey responses' desc 'list scales that have no survey responses'
task list_scales_that_lack_survey_responses: :environment do task list_scales_that_lack_survey_responses: :environment do
output = AcademicYear.all.map do |academic_year| output = AcademicYear.all.map do |academic_year|
@ -202,24 +115,4 @@ namespace :one_off do
end end
pp output pp output
end end
desc 'delete invalid scale'
task delete_s_grmi_scale_from_2016_17: :environment do
academic_year = AcademicYear.find_by_range '2016-17'
survey_items = SurveyItem.where('survey_item_id LIKE ?', 's-grmi%')
SurveyItemResponse.joins(:survey_item).where(academic_year:, survey_item: survey_items).delete_all
end
desc 'reset admin data values'
task reset_admin_data_values: :environment do
puts "Initial count of admin data values #{AdminDataValue.all.count}"
AdminDataValue.delete_all
puts 'Deleted all admin data values'
Dir.glob(Rails.root.join('data', 'admin_data', '*.csv')).each do |filepath|
puts "=====================> Loading data from csv at path: #{filepath}"
AdminDataLoader.load_data filepath:
end
puts "=====================> Completed loading #{AdminDataValue.count} survey responses"
end
end end

@ -1,8 +1,8 @@
Start Date,End Date,Response Type,IP Address,Progress,Duration (in seconds),Finished,RecordedDate,ResponseId,LASID,Recipient Last Name,Recipient First Name,Recipient Email,External Data Reference,Location Latitude,Location Longitude,Distribution Channel,User Language,district,school,DESE ID,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,s-emsa-q1,s-emsa-q2,s-emsa-q3,s-tint-q1,s-tint-q2,#N/A,s-tint-q4,s-tint-q5,s-acpr-q1,s-acpr-q2,s-acpr-q3,s-acpr-q4,#N/A,#N/A,s-cure-q3,s-cure-q4,#N/A,s-sten-q2,s-sten-q3,s-sper-q1,s-sper-q2,s-sper-q3,s-sper-q4,s-civp-q1,s-civp-q2,s-civp-q3,s-civp-q4,s-grmi-q1,#N/A,#N/A,s-grmi-q4,s-appa-q1,s-appa-q2,#N/A,s-peff-q1,s-peff-q2,s-peff-q3,s-peff-q4,s-peff-q5,s-peff-q6,s-sbel-q1,s-sbel-q2,s-sbel-q3,s-sbel-q4,s-sbel-q5,s-phys-q1,s-phys-q2,s-phys-q3,s-phys-q4,s-vale-q1,#N/A,#N/A,s-vale-q4,#N/A,s-acst-q2,s-acst-q3,#N/A,#N/A,s-grit-q1,s-grit-q2,s-grit-q3,s-grit-q4,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,race,What is your race/ethnicity?(Please select all that apply) - Selected Choice Start Date,End Date,Response Type,IP Address,Progress,Duration (in seconds),Finished,RecordedDate,ResponseId,LASID,Recipient Last Name,Recipient First Name,Recipient Email,External Data Reference,Location Latitude,Location Longitude,Distribution Channel,User Language,district,school,DESE ID,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,s-emsa-q1,s-emsa-q2,s-emsa-q3,s-tint-q1,s-tint-q2,#N/A,s-tint-q4,s-tint-q5,s-acpr-q1,s-acpr-q2,s-acpr-q3,s-acpr-q4,#N/A,#N/A,s-cure-q3,s-cure-q4,#N/A,s-sten-q2,s-sten-q3,s-sper-q1,s-sper-q2,s-sper-q3,s-sper-q4,s-civp-q1,s-civp-q2,s-civp-q3,s-civp-q4,s-grmi-q1,#N/A,#N/A,s-grmi-q4,s-appa-q1,s-appa-q2,#N/A,s-peff-q1,s-peff-q2,s-peff-q3,s-peff-q4,s-peff-q5,s-peff-q6,s-sbel-q1,s-sbel-q2,s-sbel-q3,s-sbel-q4,s-sbel-q5,s-phys-q1,s-phys-q2,s-phys-q3,s-phys-q4,s-vale-q1,#N/A,#N/A,s-vale-q4,#N/A,s-acst-q2,s-acst-q3,#N/A,#N/A,s-grit-q1,s-grit-q2,s-grit-q3,s-grit-q4,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,#N/A,race,What is your race/ethnicity?(Please select all that apply) - Selected Choice,grade
2020-09-29 18:28:41,2020-09-29 18:48:28,0,73.249.89.226,6,1186,0,2020-09-30T18:48:50,student_survey_response_1,123456,,,,,,,anonymous,EN,1,8,160505,,,,dddd,4,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,some non-integer response,6,,,,5,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,EN,,,,,1,888 2020-09-29 18:28:41,2020-09-29 18:48:28,0,73.249.89.226,6,1186,0,2020-09-30T18:48:50,student_survey_response_1,123456,,,,,,,anonymous,EN,1,8,160505,,,,dddd,4,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0,some non-integer response,6,,,,5,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,EN,,,,,1,888,11th
2021-02-23 15:12:58,2021-02-23 15:13:17,0,50.207.254.114,0,19,0,2021-02-24T15:13:19,student_survey_response_2,234567,,,,,,,anonymous,EN,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,NA,,,,,,,,,,,,,,,,,,,,,EN,,,,,"2,3,4",888 2021-02-23 15:12:58,2021-02-23 15:13:17,0,50.207.254.114,0,19,0,2021-02-24T15:13:19,student_survey_response_2,234567,,,,,,,anonymous,EN,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,NA,,,,,,,,,,,,,,,,,,,,,EN,,,,,"2,3,4",888,10
2021-03-31 9:50:19,2021-03-31 9:59:01,0,108.7.17.250,100,522,1,2021-03-31T09:59:02,student_survey_response_3,345678,,,,,42.53340149,-70.96530151,anonymous,EN,3,2,1600310,12,4,108,3300,7,1,,,,,,,,,,,,,,2,4,2,1,4,3,3,,,,,3,3,3,3,,,,,NA,,,,,,,,,3,2,3,3,2,1,3,4,1,3,3,4,4,2,4,3,3,4,3,3,3,4,3,3,3,3,3,,,,,,,,,,3,4,4,2,3,3,1,,3,,EN,Math teacher,,,,6,888 2021-03-31 9:50:19,2021-03-31 9:59:01,0,108.7.17.250,100,522,1,2021-03-31T09:59:02,student_survey_response_3,345678,,,,,42.53340149,-70.96530151,anonymous,EN,3,2,1600310,12,4,108,3300,7,1,,,,,,,,,,,,,,2,4,2,1,4,3,3,,,,,3,3,3,3,,,,,NA,,,,,,,,,3,2,3,3,2,1.00,3,4,1,3,3,4,4,2,4,3,3,4,3,3,3,4,3,3,3,3,3,,,,,,,,,,3,4,4,2,3,3,1,,3,,EN,Math teacher,,,,6,888,8
2021-03-31 9:50:09,2021-03-31 10:00:16,0,67.186.188.168,100,607,1,2021-03-31T10:00:17,student_survey_response_4,456789,,,,,42.63510132,-71.30139923,anonymous,EN,3,2,1600310,12,18,108,2064,7,1,,2,2,1,,,,,,,,,,,,,,,,,,,,,,,,,3,5,3,3,,,,,,,,,,4,4,3,4,5,1,1,5,1,3,2,4,4,1,2,1,3,2,3,3,3,4,2,5,3,4,5,5,3,3,4,3,,,,,4,4,4,4,3,5,2,,2,,EN,,,,English teacher,7,888 2021-03-31 9:50:09,2021-03-31 10:00:16,0,67.186.188.168,100,607,1,2021-03-31T10:00:17,student_survey_response_4,456789,,,,,42.63510132,-71.30139923,anonymous,EN,3,2,1600310,12,18,108,2064,7,1,,2,2,1,,,,,,,,,,,,,,,,,,,,,,,,,3,5,3,3,,,,,,,,,,4,4,3,4,5,1,1,5,1,3,2,4,4,1,2,1,3,2,3,3,3,4,2,5,3,4,5,5,3,3,4,3,,,,,4,4,4,4,3,5,2,,2,,EN,,,,English teacher,7,888,8
2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:36,student_survey_response_5,567890,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1600310,6,15,109,3710,7,1,,2,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,"1,2,3,4,5,8,6,7",888 2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:36,student_survey_response_5,567890,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1600310,6,15,109,3710,7,1,,2,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,"1,2,3,4,5,8,6,7",888,7
2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:36,student_survey_response_6,,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1600310,6,15,109,3710,7,1,,2,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,"1,2,3,4,5,8",888 2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:36,student_survey_response_6,,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1600310,6,15,109,3710,7,1,,2,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,"1,2,3,4,5,8",888,3
2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:36,student_survey_response_7,,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1600310,6,15,109,3710,7,1,,2,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,, 2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:36,student_survey_response_7,,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1600310,6,15,109,3710,7,1,,2.0,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,,,4

1 Start Date End Date Response Type IP Address Progress Duration (in seconds) Finished RecordedDate ResponseId LASID Recipient Last Name Recipient First Name Recipient Email External Data Reference Location Latitude Location Longitude Distribution Channel User Language district school DESE ID #N/A #N/A #N/A #N/A #N/A #N/A #N/A s-emsa-q1 s-emsa-q2 s-emsa-q3 s-tint-q1 s-tint-q2 #N/A s-tint-q4 s-tint-q5 s-acpr-q1 s-acpr-q2 s-acpr-q3 s-acpr-q4 #N/A #N/A s-cure-q3 s-cure-q4 #N/A s-sten-q2 s-sten-q3 s-sper-q1 s-sper-q2 s-sper-q3 s-sper-q4 s-civp-q1 s-civp-q2 s-civp-q3 s-civp-q4 s-grmi-q1 #N/A #N/A s-grmi-q4 s-appa-q1 s-appa-q2 #N/A s-peff-q1 s-peff-q2 s-peff-q3 s-peff-q4 s-peff-q5 s-peff-q6 s-sbel-q1 s-sbel-q2 s-sbel-q3 s-sbel-q4 s-sbel-q5 s-phys-q1 s-phys-q2 s-phys-q3 s-phys-q4 s-vale-q1 #N/A #N/A s-vale-q4 #N/A s-acst-q2 s-acst-q3 #N/A #N/A s-grit-q1 s-grit-q2 s-grit-q3 s-grit-q4 #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A #N/A race What is your race/ethnicity?(Please select all that apply) - Selected Choice grade
2 2020-09-29 18:28:41 2020-09-29 18:48:28 0 73.249.89.226 6 1186 0 2020-09-30T18:48:50 student_survey_response_1 123456 anonymous EN 1 8 160505 dddd 4 3 0 some non-integer response 6 5 1 EN 1 888 11th
3 2021-02-23 15:12:58 2021-02-23 15:13:17 0 50.207.254.114 0 19 0 2021-02-24T15:13:19 student_survey_response_2 234567 anonymous EN NA EN 2,3,4 888 10
4 2021-03-31 9:50:19 2021-03-31 9:59:01 0 108.7.17.250 100 522 1 2021-03-31T09:59:02 student_survey_response_3 345678 42.53340149 -70.96530151 anonymous EN 3 2 1600310 12 4 108 3300 7 1 2 4 2 1 4 3 3 3 3 3 3 NA 3 2 3 3 2 1 1.00 3 4 1 3 3 4 4 2 4 3 3 4 3 3 3 4 3 3 3 3 3 3 4 4 2 3 3 1 3 EN Math teacher 6 888 8
5 2021-03-31 9:50:09 2021-03-31 10:00:16 0 67.186.188.168 100 607 1 2021-03-31T10:00:17 student_survey_response_4 456789 42.63510132 -71.30139923 anonymous EN 3 2 1600310 12 18 108 2064 7 1 2 2 1 3 5 3 3 4 4 3 4 5 1 1 5 1 3 2 4 4 1 2 1 3 2 3 3 3 4 2 5 3 4 5 5 3 3 4 3 4 4 4 4 3 5 2 2 EN English teacher 7 888 8
6 2021-03-31 9:51:39 2021-03-31 10:01:36 0 73.47.153.77 100 596 1 2021-03-31T10:01:36 student_survey_response_5 567890 42.65820313 -71.30580139 anonymous EN 3 2 1600310 6 15 109 3710 7 1 2 2 2 3 3 4 3 3 3 3 4 3 4 3 4 4 5 4 3 4 3 5 2 2 3 1 2 5 1 3 3 2 4 3 5 4 5 4 3 4 4 4 4 4 4 2 2 EN Social Studies teacher 1,2,3,4,5,8,6,7 888 7
7 2021-03-31 9:51:39 2021-03-31 10:01:36 0 73.47.153.77 100 596 1 2021-03-31T10:01:36 student_survey_response_6 42.65820313 -71.30580139 anonymous EN 3 2 1600310 6 15 109 3710 7 1 2 2 2 3 3 4 3 3 3 3 4 3 4 3 4 4 5 4 3 4 3 5 2 2 3 1 2 5 1 3 3 2 4 3 5 4 5 4 3 4 4 4 4 4 4 2 2 EN Social Studies teacher 1,2,3,4,5,8 888 3
8 2021-03-31 9:51:39 2021-03-31 10:01:36 0 73.47.153.77 100 596 1 2021-03-31T10:01:36 student_survey_response_7 42.65820313 -71.30580139 anonymous EN 3 2 1600310 6 15 109 3710 7 1 2 2.0 2 2 3 3 4 3 3 3 3 4 3 4 3 4 4 5 4 3 4 3 5 2 2 3 1 2 5 1 3 3 2 4 3 5 4 5 4 3 4 4 4 4 4 4 2 2 EN Social Studies teacher 4

@ -0,0 +1,58 @@
require 'rails_helper'
RSpec.describe Score, type: :model do
let(:zones) do
Zones.new(watch_low_benchmark: 1.5, growth_low_benchmark: 2, approval_low_benchmark: 3,
ideal_low_benchmark: 4)
end
let(:warning) do
zones.warning_zone
end
let(:watch) do
zones.watch_zone
end
let(:growth) do
zones.growth_zone
end
let(:approval) do
zones.approval_zone
end
let(:ideal) do
zones.ideal_zone
end
context '.in_zone?' do
it('returns true if the score is in the warning zone') do
score = Score.new(average: 1)
expect(score.in_zone?(zone: warning)).to eq true
expect(score.in_zone?(zone: watch)).to eq false
expect(score.in_zone?(zone: growth)).to eq false
expect(score.in_zone?(zone: approval)).to eq false
expect(score.in_zone?(zone: ideal)).to eq false
end
it('returns true if the score is in the watch zone') do
score = Score.new(average: 1.5)
expect(score.in_zone?(zone: warning)).to eq true
expect(score.in_zone?(zone: watch)).to eq true
expect(score.in_zone?(zone: growth)).to eq false
expect(score.in_zone?(zone: approval)).to eq false
expect(score.in_zone?(zone: ideal)).to eq false
end
end
context '.blank?' do
it 'returns true if the average is nil zero or not a number' do
expect(Score.new(average: 0).blank?).to eq true
expect(Score.new(average: nil).blank?).to eq true
nan = Float::NAN
expect(Score.new(average: nan).blank?).to eq true
end
it 'returns false if the average is a non-zero float' do
expect(Score.new(average: 1).blank?).to eq false
expect(Score.new(average: 0.1).blank?).to eq false
expect(Score.new(average: -0.1).blank?).to eq false
end
end
end

@ -1,7 +1,7 @@
require 'rails_helper' require 'rails_helper'
include Analyze::Graph include Analyze::Graph
include Analyze::Graph::Column include Analyze::Graph::Column
describe StudentsByGroup do describe StudentsByRace do
let(:american_indian) { create(:race, qualtrics_code: 1) } let(:american_indian) { create(:race, qualtrics_code: 1) }
let(:asian) { create(:race, qualtrics_code: 2) } let(:asian) { create(:race, qualtrics_code: 2) }
let(:black) { create(:race, qualtrics_code: 3) } let(:black) { create(:race, qualtrics_code: 3) }
@ -12,11 +12,11 @@ describe StudentsByGroup do
context 'when initialized with a list of races' do context 'when initialized with a list of races' do
it 'generates corresponding race columns' do it 'generates corresponding race columns' do
races = [american_indian] races = [american_indian]
expect(StudentsByGroup.new(races:).columns).to eq [AmericanIndian, AllStudent] expect(StudentsByRace.new(races:).columns).to eq [AmericanIndian, AllStudent]
races = [american_indian, asian] races = [american_indian, asian]
expect(StudentsByGroup.new(races:).columns).to eq [AmericanIndian, Asian, AllStudent] expect(StudentsByRace.new(races:).columns).to eq [AmericanIndian, Asian, AllStudent]
races = [black, hispanic, multiracial] races = [black, hispanic, multiracial]
expect(StudentsByGroup.new(races:).columns).to eq [Black, Hispanic, Multiracial, AllStudent] expect(StudentsByRace.new(races:).columns).to eq [Black, Hispanic, Multiracial, AllStudent]
end end
end end
end end

@ -40,7 +40,7 @@ describe VarianceChartRowPresenter do
end end
context 'when the score is in the Ideal zone' do context 'when the score is in the Ideal zone' do
let(:score) { Score.new(4.4, true, true) } let(:score) { Score.new(average: 4.4, meets_teacher_threshold: true, meets_student_threshold: true) }
it_behaves_like 'measure_name' it_behaves_like 'measure_name'
@ -58,7 +58,7 @@ describe VarianceChartRowPresenter do
end end
context 'when the score is in the Approval zone' do context 'when the score is in the Approval zone' do
let(:score) { Score.new(3.7, true, true) } let(:score) { Score.new(average: 3.7, meets_teacher_threshold: true, meets_student_threshold: true) }
it_behaves_like 'measure_name' it_behaves_like 'measure_name'
@ -76,7 +76,7 @@ describe VarianceChartRowPresenter do
end end
context 'when the score is in the Growth zone' do context 'when the score is in the Growth zone' do
let(:score) { Score.new(3.2, true, true) } let(:score) { Score.new(average: 3.2, meets_teacher_threshold: true, meets_student_threshold: true) }
it_behaves_like 'measure_name' it_behaves_like 'measure_name'
@ -96,7 +96,7 @@ describe VarianceChartRowPresenter do
end end
context 'when the score is in the Watch zone' do context 'when the score is in the Watch zone' do
let(:score) { Score.new(2.9, true, true) } let(:score) { Score.new(average: 2.9, meets_teacher_threshold: true, meets_student_threshold: true) }
it_behaves_like 'measure_name' it_behaves_like 'measure_name'
@ -116,7 +116,7 @@ describe VarianceChartRowPresenter do
end end
context 'when the score is in the Warning zone' do context 'when the score is in the Warning zone' do
let(:score) { Score.new(1.0, true, true) } let(:score) { Score.new(average: 1.0, meets_teacher_threshold: true, meets_student_threshold: true) }
it_behaves_like 'measure_name' it_behaves_like 'measure_name'
@ -136,7 +136,7 @@ describe VarianceChartRowPresenter do
end end
context 'when a measure does not contain admin data items' do context 'when a measure does not contain admin data items' do
let(:score) { Score.new(nil, false, false) } let(:score) { Score.new(average: nil, meets_teacher_threshold: false, meets_student_threshold: false) }
it 'it does not show a partial data indicator' do it 'it does not show a partial data indicator' do
presenter_without_admin_data = VarianceChartRowPresenter.new measure: measure_without_admin_data_items, presenter_without_admin_data = VarianceChartRowPresenter.new measure: measure_without_admin_data_items,
@ -149,7 +149,7 @@ describe VarianceChartRowPresenter do
before :each do before :each do
end end
let(:score) { Score.new(nil, false, false) } let(:score) { Score.new(average: nil, meets_teacher_threshold: false, meets_student_threshold: false) }
it 'shows a partial data indicator' do it 'shows a partial data indicator' do
measure_with_admin_data = create( measure_with_admin_data = create(
@ -165,7 +165,7 @@ describe VarianceChartRowPresenter do
ideal_low_benchmark: ideal_low_benchmark ideal_low_benchmark: ideal_low_benchmark
admin_data_presenter = VarianceChartRowPresenter.new measure: measure_with_admin_data, admin_data_presenter = VarianceChartRowPresenter.new measure: measure_with_admin_data,
score: Score.new( score: Score.new(
3.7, true, true average: 3.7, meets_teacher_threshold: true, meets_student_threshold: true
) )
expect(admin_data_presenter.show_partial_data_indicator?).to be true expect(admin_data_presenter.show_partial_data_indicator?).to be true
expect(admin_data_presenter.partial_data_sources).to eq ['administrative data'] expect(admin_data_presenter.partial_data_sources).to eq ['administrative data']
@ -179,7 +179,7 @@ describe VarianceChartRowPresenter do
end end
context 'when there are insufficient teacher survey item responses' do context 'when there are insufficient teacher survey item responses' do
let(:score) { Score.new(nil, false, true) } let(:score) { Score.new(average: nil, meets_teacher_threshold: false, meets_student_threshold: true) }
it 'shows a partial data indicator' do it 'shows a partial data indicator' do
expect(presenter.show_partial_data_indicator?).to be true expect(presenter.show_partial_data_indicator?).to be true
expect(presenter.partial_data_sources).to eq ['teacher survey results'] expect(presenter.partial_data_sources).to eq ['teacher survey results']
@ -187,7 +187,7 @@ describe VarianceChartRowPresenter do
end end
context 'when there are sufficient teacher survey item responses' do context 'when there are sufficient teacher survey item responses' do
let(:score) { Score.new(nil, true, true) } let(:score) { Score.new(average: nil, meets_teacher_threshold: true, meets_student_threshold: true) }
it 'does not show a partial data indicator' do it 'does not show a partial data indicator' do
expect(presenter.show_partial_data_indicator?).to be false expect(presenter.show_partial_data_indicator?).to be false
end end
@ -201,7 +201,7 @@ describe VarianceChartRowPresenter do
end end
context 'when there are insufficient student survey item responses' do context 'when there are insufficient student survey item responses' do
let(:score) { Score.new(nil, true, false) } let(:score) { Score.new(average: nil, meets_teacher_threshold: true, meets_student_threshold: false) }
it 'shows a partial data indicator' do it 'shows a partial data indicator' do
expect(presenter.show_partial_data_indicator?).to be true expect(presenter.show_partial_data_indicator?).to be true
expect(presenter.partial_data_sources).to eq ['student survey results'] expect(presenter.partial_data_sources).to eq ['student survey results']
@ -220,7 +220,7 @@ describe VarianceChartRowPresenter do
end end
context 'When there are sufficient student survey item responses' do context 'When there are sufficient student survey item responses' do
let(:score) { Score.new(nil, true, true) } let(:score) { Score.new(average: nil, meets_teacher_threshold: true, meets_student_threshold: true) }
it 'does not show a partial data indicator' do it 'does not show a partial data indicator' do
expect(presenter.show_partial_data_indicator?).to be false expect(presenter.show_partial_data_indicator?).to be false
end end
@ -236,15 +236,15 @@ describe VarianceChartRowPresenter do
growth_low_benchmark:, growth_low_benchmark:,
approval_low_benchmark:, approval_low_benchmark:,
ideal_low_benchmark:) ideal_low_benchmark:)
approval_presenter = VarianceChartRowPresenter.new measure: measure, score: Score.new(3.7, true, true) approval_presenter = VarianceChartRowPresenter.new measure: measure, score: Score.new(average: 3.7, meets_teacher_threshold: true,meets_student_threshold: true)
ideal_presenter = VarianceChartRowPresenter.new measure: measure, score: Score.new(4.4, true, true) ideal_presenter = VarianceChartRowPresenter.new measure: measure, score: Score.new(average: 4.4, meets_teacher_threshold: true, meets_student_threshold: true)
expect(ideal_presenter <=> approval_presenter).to be < 0 expect(ideal_presenter <=> approval_presenter).to be < 0
expect([approval_presenter, ideal_presenter].sort).to eq [ideal_presenter, approval_presenter] expect([approval_presenter, ideal_presenter].sort).to eq [ideal_presenter, approval_presenter]
end end
it 'selects a warning bar below a ideal bar' do it 'selects a warning bar below a ideal bar' do
warning_presenter = VarianceChartRowPresenter.new measure: measure, score: Score.new(1.0, true, true) warning_presenter = VarianceChartRowPresenter.new measure: measure, score: Score.new(average: 1.0, meets_teacher_threshold: true, meets_student_threshold: true)
ideal_presenter = VarianceChartRowPresenter.new measure: measure, score: Score.new(5.0, true, true) ideal_presenter = VarianceChartRowPresenter.new measure: measure, score: Score.new(average: 5.0, meets_teacher_threshold: true, meets_student_threshold: true)
expect(warning_presenter <=> ideal_presenter).to be > 0 expect(warning_presenter <=> ideal_presenter).to be > 0
expect([warning_presenter, ideal_presenter].sort).to eq [ideal_presenter, warning_presenter] expect([warning_presenter, ideal_presenter].sort).to eq [ideal_presenter, warning_presenter]
end end

@ -29,15 +29,10 @@ describe SurveyResponsesDataLoader do
end end
it 'ensures teacher responses load correctly' do it 'ensures teacher responses load correctly' do
assigns_academic_year_to_survey_item_responses assigns_academic_year_to_survey_item_responses
assigns_school_to_the_survey_item_responses assigns_school_to_the_survey_item_responses
loads_survey_item_responses_for_a_given_survey_response loads_survey_item_responses_for_a_given_survey_response
loads_all_survey_item_responses_for_a_given_survey_item loads_all_survey_item_responses_for_a_given_survey_item
captures_likert_scores_for_survey_item_responses captures_likert_scores_for_survey_item_responses
is_idempotent is_idempotent
end end
end end
@ -53,16 +48,23 @@ describe SurveyResponsesDataLoader do
loads_student_survey_item_response_values loads_student_survey_item_response_values
student_survey_item_response_count_matches_expected student_survey_item_response_count_matches_expected
captures_likert_scores_for_student_survey_item_responses captures_likert_scores_for_student_survey_item_responses
assigns_grade_level_to_responses
is_idempotent_for_students is_idempotent_for_students
end end
context 'when updating student survey responses from another csv file' do context 'when updating student survey responses from another csv file' do
it 'updates the likert score to the score on the new csv file' do before do
SurveyResponsesDataLoader.load_data filepath: Rails.root.join('spec', 'fixtures', SurveyResponsesDataLoader.load_data filepath: Rails.root.join('spec', 'fixtures',
'secondary_test_2020-21_student_survey_responses.csv') 'secondary_test_2020-21_student_survey_responses.csv')
expect(SurveyItemResponse.joins(:survey_item).where(response_id: 'student_survey_response_3').where("survey_item.survey_item_id": 's-emsa-q1').first.likert_score).to eq 1 end
expect(SurveyItemResponse.joins(:survey_item).where(response_id: 'student_survey_response_4').where("survey_item.survey_item_id": 's-emsa-q1').first.likert_score).to eq 1 it 'updates the likert score to the score on the new csv file' do
expect(SurveyItemResponse.joins(:survey_item).where(response_id: 'student_survey_response_5').where("survey_item.survey_item_id": 's-emsa-q1').first.likert_score).to eq 1 s_emsa_q1 = SurveyItem.find_by_survey_item_id 's-emsa-q1'
expect(SurveyItemResponse.where(response_id: 'student_survey_response_3',
survey_item: s_emsa_q1).first.likert_score).to eq 1
expect(SurveyItemResponse.where(response_id: 'student_survey_response_4',
survey_item: s_emsa_q1).first.likert_score).to eq 1
expect(SurveyItemResponse.where(response_id: 'student_survey_response_5',
survey_item: s_emsa_q1).first.likert_score).to eq 1
end end
end end
end end
@ -160,3 +162,17 @@ def is_idempotent_for_students
expect(SurveyItemResponse.count).to eq number_of_survey_item_responses expect(SurveyItemResponse.count).to eq number_of_survey_item_responses
end end
def assigns_grade_level_to_responses
results = { 'student_survey_response_1' => 11,
'student_survey_response_3' => 8,
'student_survey_response_4' => 8,
'student_survey_response_5' => 7,
'student_survey_response_6' => 3,
'student_survey_response_7' => 4 }
results.each do |key, value|
expect(SurveyItemResponse.where(response_id: key).all? do |response|
response.grade == value
end).to eq true
end
end

@ -13,7 +13,7 @@ describe 'analyze/index' do
end end
let(:graph) { StudentsAndTeachers.new } let(:graph) { StudentsAndTeachers.new }
let(:graphs) do let(:graphs) do
[StudentsAndTeachers.new, StudentsByGroup.new(races:)] [StudentsAndTeachers.new, StudentsByRace.new(races:)]
end end
let(:background) { BackgroundPresenter.new(num_of_columns: graph.columns.count) } let(:background) { BackgroundPresenter.new(num_of_columns: graph.columns.count) }
let(:selected_races) { races } let(:selected_races) { races }
@ -54,6 +54,36 @@ describe 'analyze/index' do
measure measure
end end
let(:sources) do
[Analyze::Source::SurveyData.new(slices:)]
end
let(:slices) do
students_and_teachers = Analyze::Slice::StudentsAndTeachers.new
students_by_group = Analyze::Slice::StudentsByGroup.new(races:, grades:)
[students_and_teachers, students_by_group]
end
let(:slice) do
slices.first
end
let(:groups) do
[Analyze::Group::Race.new, Analyze::Group::Grade.new]
end
let(:group) do
groups.first
end
let(:grades) do
(1..12).to_a
end
let(:selected_grades) do
grades
end
before :each do before :each do
assign :races, races assign :races, races
assign :selected_races, selected_races assign :selected_races, selected_races
@ -70,6 +100,12 @@ describe 'analyze/index' do
assign :subcategory, subcategory assign :subcategory, subcategory
assign :subcategories, category.subcategories assign :subcategories, category.subcategories
assign :measures, [support_for_teaching, effective_leadership, professional_qualifications] assign :measures, [support_for_teaching, effective_leadership, professional_qualifications]
assign :sources, sources
assign :groups, groups
assign :group, group
assign :slice, slice
assign :grades, grades
assign :selected_grades, selected_grades
create(:respondent, school:, academic_year:) create(:respondent, school:, academic_year:)
create(:survey, school:, academic_year:) create(:survey, school:, academic_year:)
end end
@ -88,7 +124,7 @@ describe 'analyze/index' do
# ideal_low_benchmark: 4.5) # ideal_low_benchmark: 4.5)
# [ # [
# GroupedBarColumnPresenter.new(measure:, # GroupedBarColumnPresenter.new(measure:,
# score: Score.new(rand)) # score: Score.new(average: rand))
# ] # ]
# end # end

@ -58,7 +58,7 @@ describe 'overview/index' do
let(:variance_chart_row_presenters) do let(:variance_chart_row_presenters) do
[ [
VarianceChartRowPresenter.new(measure: support_for_teaching, score: Score.new), VarianceChartRowPresenter.new(measure: support_for_teaching, score: Score.new),
VarianceChartRowPresenter.new(measure: effective_leadership, score: Score.new(rand)), VarianceChartRowPresenter.new(measure: effective_leadership, score: Score.new(average: rand)),
VarianceChartRowPresenter.new(measure: professional_qualifications, score: Score.new) VarianceChartRowPresenter.new(measure: professional_qualifications, score: Score.new)
] ]
end end
@ -90,7 +90,7 @@ describe 'overview/index' do
ideal_low_benchmark: 4.5) ideal_low_benchmark: 4.5)
[ [
VarianceChartRowPresenter.new(measure:, VarianceChartRowPresenter.new(measure:,
score: Score.new(rand)) score: Score.new(average: rand))
] ]
end end

@ -27,8 +27,8 @@ describe 'overview/_variance_chart.html.erb' do
before :each do before :each do
presenters = [ presenters = [
VarianceChartRowPresenter.new(measure: lower_scoring_measure, score: Score.new(1)), VarianceChartRowPresenter.new(measure: lower_scoring_measure, score: Score.new(average: 1)),
VarianceChartRowPresenter.new(measure: higher_scoring_measure, score: Score.new(5)) VarianceChartRowPresenter.new(measure: higher_scoring_measure, score: Score.new(average: 5))
] ]
render partial: 'variance_chart', locals: { presenters: } render partial: 'variance_chart', locals: { presenters: }
@ -53,8 +53,8 @@ describe 'overview/_variance_chart.html.erb' do
measure_lacking_score = create(:measure) measure_lacking_score = create(:measure)
another_measure_lacking_score = create(:measure) another_measure_lacking_score = create(:measure)
presenters = [ presenters = [
VarianceChartRowPresenter.new(measure: measure_lacking_score, score: Score.new(nil)), VarianceChartRowPresenter.new(measure: measure_lacking_score, score: Score.new(average: nil)),
VarianceChartRowPresenter.new(measure: another_measure_lacking_score, score: Score.new(nil)) VarianceChartRowPresenter.new(measure: another_measure_lacking_score, score: Score.new(average: nil))
] ]
render partial: 'variance_chart', locals: { presenters: } render partial: 'variance_chart', locals: { presenters: }

Loading…
Cancel
Save