feat: Add income table to the database. Add seeder for income. Add a reference to income from survey item response. Update the loader to import income data from the survey response csv. Refactor analyze controller to extract presenter. Add corresponding specs. Add income graph to analyze page

pull/1/head
rebuilt 3 years ago
parent 7e1be4860c
commit 4f035f6a63

@ -12,4 +12,4 @@ Style/Documentation:
Enabled: false
Style/StringLiterals:
EnforcedStyle: single_quotes
EnforcedStyle: double_quotes

@ -1,172 +1,8 @@
# frozen_string_literal: true
class AnalyzeController < SqmApplicationController
before_action :assign_categories, :assign_subcategories, :assign_measures, :assign_academic_years,
:races, :selected_races, :graph, :graphs, :background, :race_score_timestamp,
:source, :sources, :group, :groups, :selected_grades, :grades, :slice, :selected_genders, :genders, only: [:index]
def index; end
private
def assign_categories
@category ||= Category.find_by_category_id(params[:category])
@category ||= Category.order(:category_id).first
@categories = Category.all.order(:category_id)
end
def assign_subcategories
@subcategories = @category.subcategories.order(:subcategory_id)
@subcategory ||= Subcategory.find_by_subcategory_id(params[:subcategory])
@subcategory ||= @subcategories.first
end
def assign_measures
@measures = @subcategory.measures.order(:measure_id).includes(%i[admin_data_items subcategory])
end
def assign_academic_years
@available_academic_years = AcademicYear.order(:range).all
year_params = params[:academic_years]
@academic_year_params = year_params.split(',') if year_params
@selected_academic_years = []
@academic_year_params ||= []
@academic_year_params.each do |year|
@selected_academic_years << AcademicYear.find_by_range(year)
end
end
def races
@races ||= Race.all.order(designation: :ASC)
end
def selected_races
@selected_races ||= begin
race_params = params[:races]
return @selected_races = races unless race_params
race_list = race_params.split(',') if race_params
if race_list
race_list = race_list.map do |race|
Race.find_by_slug race
end
end
race_list
end
end
def graph
graphs.each do |graph|
@graph = graph if graph.slug == params[:graph]
end
@graph ||= graphs.first
end
def graphs
@graphs ||= [Analyze::Graph::AllData.new, Analyze::Graph::StudentsAndTeachers.new, Analyze::Graph::StudentsByRace.new(races: selected_races),
Analyze::Graph::StudentsByGrade.new(grades: selected_grades), Analyze::Graph::StudentsByGender.new(genders: selected_genders)]
end
def background
@background ||= BackgroundPresenter.new(num_of_columns: graph.columns.count)
end
def race_score_timestamp
@race_score_timestamp ||= begin
score = RaceScore.where(school: @school,
academic_year: @academic_year).order(updated_at: :DESC).first || Today.new
score.updated_at
end
end
def source
source_param = params[:source]
sources.each do |source|
@source = source if source.slug == source_param
end
@source ||= sources.first
end
def sources
all_data_slices = [Analyze::Slice::AllData.new]
all_data_source = Analyze::Source::AllData.new(slices: all_data_slices)
students_and_teachers = Analyze::Slice::StudentsAndTeachers.new
students_by_group = Analyze::Slice::StudentsByGroup.new(races:, grades:)
survey_data_slices = [students_and_teachers, students_by_group]
survey_data_source = Analyze::Source::SurveyData.new(slices: survey_data_slices)
@sources = [all_data_source, survey_data_source]
end
def slice
slice_param = params[:slice]
slices.each do |slice|
@slice = slice if slice.slug == slice_param
end
@slice ||= slices.first
end
def slices
source.slices
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, Analyze::Group::Gender.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 selected_genders
@selected_genders ||= begin
gender_params = params[:genders]
return @selected_genders = genders unless gender_params
gender_list = gender_params.split(',') if gender_params
if gender_list
gender_list = gender_list.map do |gender|
Gender.find_by_designation(gender)
end
end
gender_list
end
end
def genders
@genders ||= Gender.all
def index
@presenter = Analyze::Presenter.new(params:, school: @school, academic_year: @academic_year)
@background ||= BackgroundPresenter.new(num_of_columns: @presenter.graph.columns.count)
end
end

@ -62,7 +62,7 @@ module AnalyzeHelper
end
def base_url
analyze_subcategory_link(district: @district, school: @school, academic_year: @academic_year, category: @category,
subcategory: @subcategory)
analyze_subcategory_link(district: @district, school: @school, academic_year: @academic_year, category: @presenter.category,
subcategory: @presenter.subcategory)
end
end

@ -22,16 +22,17 @@ export default class extends Controller {
"&graph=" +
this.selected_graph(target) +
"&races=" +
this.selected_races().join(",") +
this.selected_items("race").join(",") +
"&genders=" +
this.selected_genders().join(",") +
this.selected_items("gender").join(",") +
"&incomes=" +
this.selected_items("income").join(",") +
"&grades=" +
this.selected_grades().join(",");
this.selected_items("grade").join(",");
this.go_to(url);
}
go_to(location) {
window.location = location;
}
@ -121,58 +122,34 @@ export default class extends Controller {
return item.id;
})[0];
const groups = new Map([
['gender', 'students-by-gender'],
['grade', 'students-by-grade'],
['income', 'students-by-income'],
['race', 'students-by-race']
])
if (target.name === 'slice' || target.name === 'group') {
if (selected_slice === 'students-and-teachers') {
return 'students-and-teachers';
} else if (this.selected_group() === 'race') {
return 'students-by-race';
} else if (this.selected_group() === 'gender') {
return 'students-by-gender';
} else if (this.selected_group() === 'grade') {
return 'students-by-grade';
}
return groups.get(this.selected_group());
}
return window.graph;
}
selected_races() {
let race_checkboxes = [...document.getElementsByName("race-checkbox")]
let races = race_checkboxes
.filter((item) => {
return item.checked;
})
.map((item) => {
return item.id;
});
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;
}
selected_genders() {
let gender_checkboxes = [...document.getElementsByName("gender-checkbox")]
let genders = gender_checkboxes
selected_items(type) {
let checkboxes = [...document.getElementsByName(`${type}-checkbox`)]
let items = checkboxes
.filter((item) => {
return item.checked;
})
.map((item) => {
return item.id.replace('gender-', '');
return item.id.replace(`${type}-`, '');
});
return genders;
return items;
}
}

@ -0,0 +1,7 @@
class Income < ApplicationRecord
scope :by_designation, -> { all.map { |income| [income.designation, income] }.to_h }
include FriendlyId
friendly_id :designation, use: [:slugged]
end

@ -9,6 +9,7 @@ class SurveyItemResponse < ActiveRecord::Base
belongs_to :survey_item, counter_cache: true
belongs_to :student, foreign_key: :student_id, optional: true
belongs_to :gender
belongs_to :income
has_one :measure, through: :survey_item
@ -25,4 +26,9 @@ class SurveyItemResponse < ActiveRecord::Base
SurveyItemResponse.where(survey_item: survey_items, school:,
academic_year:, gender:).group(:survey_item).average(:likert_score)
}
scope :averages_for_income, lambda { |survey_items, school, academic_year, income|
SurveyItemResponse.where(survey_item: survey_items, school:,
academic_year:, income:).group(:survey_item).average(:likert_score)
}
end

@ -0,0 +1,85 @@
# frozen_string_literal: true
module Analyze
class BarPresenter
include AnalyzeHelper
attr_reader :score, :x_position, :academic_year, :measure_id, :measure, :color
MINIMUM_BAR_HEIGHT = 2
def initialize(measure:, academic_year:, score:, x_position:, color:)
@score = score
@x_position = x_position
@academic_year = academic_year
@measure = measure
@measure_id = measure.measure_id
@color = color
end
def y_offset
benchmark_height = analyze_zone_height * 2
case zone.type
when :ideal, :approval
benchmark_height - bar_height_percentage
else
benchmark_height
end
end
def bar_color
"fill-#{zone.type}"
end
def bar_height_percentage
bar_height = send("#{zone.type}_bar_height_percentage") || 0
enforce_minimum_height(bar_height:)
end
def percentage
low_benchmark = zone.low_benchmark
(score.average - low_benchmark) / (zone.high_benchmark - low_benchmark)
end
def zone
zones = Zones.new(
watch_low_benchmark: measure.watch_low_benchmark,
growth_low_benchmark: measure.growth_low_benchmark,
approval_low_benchmark: measure.approval_low_benchmark,
ideal_low_benchmark: measure.ideal_low_benchmark
)
zones.zone_for_score(score.average)
end
def average
average = score.average || 0
average.round(6)
end
private
def enforce_minimum_height(bar_height:)
bar_height < MINIMUM_BAR_HEIGHT ? MINIMUM_BAR_HEIGHT : bar_height
end
def ideal_bar_height_percentage
(percentage * zone_height_percentage + zone_height_percentage) * 100
end
def approval_bar_height_percentage
(percentage * zone_height_percentage) * 100
end
def growth_bar_height_percentage
((1 - percentage) * zone_height_percentage) * 100
end
def watch_bar_height_percentage
((1 - percentage) * zone_height_percentage + zone_height_percentage) * 100
end
def warning_bar_height_percentage
((1 - percentage) * zone_height_percentage + zone_height_percentage + zone_height_percentage) * 100
end
end
end

@ -27,10 +27,10 @@ module Analyze
def bars
@bars ||= yearly_scores.map.each_with_index do |yearly_score, index|
year = yearly_score.year
AnalyzeBarPresenter.new(measure:, academic_year: year,
score: yearly_score.score,
x_position: bar_x(index),
color: bar_color(year))
Analyze::BarPresenter.new(measure:, academic_year: year,
score: yearly_score.score,
x_position: bar_x(index),
color: bar_color(year))
end
end

@ -0,0 +1,28 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module IncomeColumn
class Disadvantaged < GroupedBarColumnPresenter
include Analyze::Graph::Column::IncomeColumn::ScoreForIncome
def label
"Economically Disadvantaged"
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def income
Income.find_by_designation "Economically Disadvantaged - Y"
end
end
end
end
end
end

@ -0,0 +1,28 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module IncomeColumn
class NotDisadvantaged < GroupedBarColumnPresenter
include Analyze::Graph::Column::IncomeColumn::ScoreForIncome
def label
"Not Disadvantaged"
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def income
Income.find_by_designation "Economically Disadvantaged - N"
end
end
end
end
end
end

@ -0,0 +1,43 @@
module Analyze
module Graph
module Column
module IncomeColumn
module ScoreForIncome
def score(year_index)
academic_year = academic_years[year_index]
averages = SurveyItemResponse.averages_for_income(measure.student_survey_items, school, academic_year,
income)
average = bubble_up_averages(averages:).round(2)
scorify(average:, meets_student_threshold: sufficient_student_responses?(academic_year:))
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
def scorify(average:, meets_student_threshold:)
return Score::NIL_SCORE unless meets_student_threshold
Score.new(average:,
meets_teacher_threshold: false,
meets_student_threshold: true,
meets_admin_data_threshold: false)
end
def sufficient_student_responses?(academic_year:)
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
income:, survey_item: measure.student_survey_items).group(:income).select(:response_id).distinct(:response_id).count
yearly_counts.any? do |count|
count[1] >= 10
end
end
end
end
end
end
end

@ -0,0 +1,28 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module IncomeColumn
class Unknown < GroupedBarColumnPresenter
include Analyze::Graph::Column::IncomeColumn::ScoreForIncome
def label
"Unknown"
end
def show_irrelevancy_message?
false
end
def show_insufficient_data_message?
false
end
def income
Income.find_by_designation "Unknown"
end
end
end
end
end
end

@ -0,0 +1,40 @@
module Analyze
module Graph
class StudentsByIncome
attr_reader :incomes
def initialize(incomes:)
@incomes = incomes
end
def to_s
"Students by income"
end
def slug
"students-by-income"
end
def columns
[].tap do |array|
incomes.each do |income|
array << column_for_income_code(code: income.slug)
end
array << Analyze::Graph::Column::AllStudent
end
end
private
def column_for_income_code(code:)
CFR[code.to_s]
end
CFR = {
"economically-disadvantaged-y" => Analyze::Graph::Column::IncomeColumn::Disadvantaged,
"economically-disadvantaged-n" => Analyze::Graph::Column::IncomeColumn::NotDisadvantaged,
"unknown" => Analyze::Graph::Column::IncomeColumn::Unknown
}.freeze
end
end
end

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

@ -0,0 +1,159 @@
module Analyze
class Presenter
attr_reader :params, :school, :academic_year
def initialize(params:, school:, academic_year:)
@params = params
@school = school
@academic_year = academic_year
end
def category
@category ||= Category.find_by_category_id(params[:category]) || Category.order(:category_id).first
end
def categories
@categories = Category.all.order(:category_id)
end
def subcategory
@subcategory ||= Subcategory.find_by_subcategory_id(params[:subcategory]) || subcategories.first
end
def subcategories
@subcategories = category.subcategories.order(:subcategory_id)
end
def measures
@measures = subcategory.measures.order(:measure_id).includes(%i[admin_data_items subcategory])
end
def academic_years
@academic_years = AcademicYear.order(:range).all
end
def selected_academic_years
@selected_academic_years ||= begin
year_params = params[:academic_years]
return [] unless year_params
year_params.split(",").map { |year| AcademicYear.find_by_range(year) }.compact
end
end
def races
@races ||= Race.all.order(designation: :ASC)
end
def selected_races
@selected_races ||= begin
race_params = params[:races]
return races unless race_params
race_params.split(",").map { |race| Race.find_by_slug race }.compact
end
end
def graphs
@graphs ||= [Analyze::Graph::AllData.new, Analyze::Graph::StudentsAndTeachers.new, Analyze::Graph::StudentsByRace.new(races: selected_races),
Analyze::Graph::StudentsByGrade.new(grades: selected_grades), Analyze::Graph::StudentsByGender.new(genders: selected_genders), Analyze::Graph::StudentsByIncome.new(incomes: selected_incomes)]
end
def graph
@graph ||= graphs.reduce(graphs.first) do |acc, graph|
graph.slug == params[:graph] ? graph : acc
end
end
def selected_grades
@selected_grades ||= begin
grade_params = params[:grades]
return grades unless grade_params
grade_params.split(",").map(&:to_i)
end
end
def selected_genders
@selected_genders ||= begin
gender_params = params[:genders]
return genders unless gender_params
gender_params.split(",").map { |gender| Gender.find_by_designation(gender) }.compact
end
end
def genders
@genders ||= Gender.all
end
def groups
@groups = [Analyze::Group::Gender.new, Analyze::Group::Grade.new, Analyze::Group::Income.new,
Analyze::Group::Race.new]
end
def group
@group ||= groups.reduce(groups.first) do |acc, group|
group.slug == params[:group] ? group : acc
end
end
def slice
@slice ||= slices.reduce(slices.first) do |acc, slice|
slice.slug == params[:slice] ? slice : acc
end
end
def slices
source.slices
end
def source
@source ||= sources.reduce(sources.first) do |acc, source|
source.slug == params[:source] ? source : acc
end
end
def sources
all_data_slices = [Analyze::Slice::AllData.new]
all_data_source = Analyze::Source::AllData.new(slices: all_data_slices)
students_and_teachers = Analyze::Slice::StudentsAndTeachers.new
students_by_group = Analyze::Slice::StudentsByGroup.new(races:, grades:)
survey_data_slices = [students_and_teachers, students_by_group]
survey_data_source = Analyze::Source::SurveyData.new(slices: survey_data_slices)
@sources = [all_data_source, survey_data_source]
end
def grades
@grades ||= SurveyItemResponse.where(school:, 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 race_score_timestamp
score = RaceScore.where(school: @school,
academic_year: @academic_year).order(updated_at: :DESC).first || Today.new
score.updated_at
end
def incomes
@incomes ||= Income.all
end
def selected_incomes
@selected_incomes ||= begin
income_params = params[:incomes]
return incomes unless income_params
income_params.split(",").map { |income| Income.find_by_slug(income) }.compact
end
end
end
end

@ -1,8 +0,0 @@
module Analyze
class Ui
attr_reader :params
def initialize(params:)
@params = params
end
end
end

@ -1,83 +0,0 @@
# frozen_string_literal: true
class AnalyzeBarPresenter
include AnalyzeHelper
attr_reader :score, :x_position, :academic_year, :measure_id, :measure, :color
MINIMUM_BAR_HEIGHT = 2
def initialize(measure:, academic_year:, score:, x_position:, color:)
@score = score
@x_position = x_position
@academic_year = academic_year
@measure = measure
@measure_id = measure.measure_id
@color = color
end
def y_offset
benchmark_height = analyze_zone_height * 2
case zone.type
when :ideal, :approval
benchmark_height - bar_height_percentage
else
benchmark_height
end
end
def bar_color
"fill-#{zone.type}"
end
def bar_height_percentage
bar_height = send("#{zone.type}_bar_height_percentage") || 0
enforce_minimum_height(bar_height:)
end
def percentage
low_benchmark = zone.low_benchmark
(score.average - low_benchmark) / (zone.high_benchmark - low_benchmark)
end
def zone
zones = Zones.new(
watch_low_benchmark: measure.watch_low_benchmark,
growth_low_benchmark: measure.growth_low_benchmark,
approval_low_benchmark: measure.approval_low_benchmark,
ideal_low_benchmark: measure.ideal_low_benchmark
)
zones.zone_for_score(score.average)
end
def average
average = score.average || 0
average.round(6)
end
private
def enforce_minimum_height(bar_height:)
bar_height < MINIMUM_BAR_HEIGHT ? MINIMUM_BAR_HEIGHT : bar_height
end
def ideal_bar_height_percentage
(percentage * zone_height_percentage + zone_height_percentage) * 100
end
def approval_bar_height_percentage
(percentage * zone_height_percentage) * 100
end
def growth_bar_height_percentage
((1 - percentage) * zone_height_percentage) * 100
end
def watch_bar_height_percentage
((1 - percentage) * zone_height_percentage + zone_height_percentage) * 100
end
def warning_bar_height_percentage
((1 - percentage) * zone_height_percentage + zone_height_percentage + zone_height_percentage) * 100
end
end

@ -5,6 +5,7 @@ class DemographicLoader
CSV.parse(File.read(filepath), headers: true) do |row|
process_race(row:)
process_gender(row:)
process_income(row:)
end
end
@ -28,6 +29,13 @@ class DemographicLoader
gender = ::Gender.find_or_create_by!(qualtrics_code:, designation:)
gender.save
end
def self.process_income(row:)
designation = row['Income']
return unless designation
Income.find_or_create_by!(designation:)
end
end
class KnownRace

@ -99,7 +99,9 @@ class SurveyItemValues
end
def raw_income
@raw_income ||= value_from(pattern: /Income|Low\s*Income/i)
@raw_income ||= value_from(pattern: /Low\s*Income|Raw\s*Income/i)
return @raw_income if @raw_income.present?
return 'Unknown' unless disaggregation_data.present?
disaggregation = disaggregation_data[[lasid, district.name, academic_year.range]]
@ -109,6 +111,9 @@ class SurveyItemValues
end
def income
@income ||= value_from(pattern: /^Income$/i)
return @income if @income.present?
@income ||= case raw_income
in /Free\s*Lunch|Reduced\s*Lunch|Low\s*Income/i
'Economically Disadvantaged - Y'

@ -7,12 +7,13 @@ class SurveyResponsesDataLoader
headers_array = CSV.parse(headers).first
genders = Gender.gender_hash
schools = School.school_hash
incomes = Income.by_designation
all_survey_items = survey_items(headers:)
file.lazy.each_slice(500) do |lines|
survey_item_responses = CSV.parse(lines.join, headers:).map do |row|
process_row(row: SurveyItemValues.new(row:, headers: headers_array, genders:, survey_items: all_survey_items, schools:),
rules:)
rules:, incomes:)
end
SurveyItemResponse.import survey_item_responses.compact.flatten, batch_size: 500
end
@ -24,6 +25,7 @@ class SurveyResponsesDataLoader
headers_array = CSV.parse(headers).first
genders = Gender.gender_hash
schools = School.school_hash
incomes = Income.by_designation
all_survey_items = survey_items(headers:)
survey_item_responses = []
@ -34,7 +36,7 @@ class SurveyResponsesDataLoader
CSV.parse(line, headers:).map do |row|
survey_item_responses << process_row(row: SurveyItemValues.new(row:, headers: headers_array, genders:, survey_items: all_survey_items, schools:),
rules:)
rules:, incomes:)
end
row_count += 1
@ -50,7 +52,7 @@ class SurveyResponsesDataLoader
private
def self.process_row(row:, rules:)
def self.process_row(row:, rules:, incomes:)
return unless row.dese_id?
return unless row.school.present?
@ -58,10 +60,10 @@ class SurveyResponsesDataLoader
return if rule.new(row:).skip_row?
end
process_survey_items(row:)
process_survey_items(row:, incomes:)
end
def self.process_survey_items(row:)
def self.process_survey_items(row:, incomes:)
row.survey_items.map do |survey_item|
likert_score = row.likert_score(survey_item_id: survey_item.survey_item_id) || next
@ -70,19 +72,20 @@ class SurveyResponsesDataLoader
next
end
response = row.survey_item_response(survey_item:)
create_or_update_response(survey_item_response: response, likert_score:, row:, survey_item:)
create_or_update_response(survey_item_response: response, likert_score:, row:, survey_item:, incomes:)
end.compact
end
def self.create_or_update_response(survey_item_response:, likert_score:, row:, survey_item:)
def self.create_or_update_response(survey_item_response:, likert_score:, row:, survey_item:, incomes:)
gender = row.gender
grade = row.grade
income = incomes[row.income]
if survey_item_response.present?
survey_item_response.update!(likert_score:, grade:, gender:, recorded_date: row.recorded_date)
survey_item_response.update!(likert_score:, grade:, gender:, recorded_date: row.recorded_date, income:)
[]
else
SurveyItemResponse.new(response_id: row.response_id, academic_year: row.academic_year, school: row.school, survey_item:,
likert_score:, grade:, gender:, recorded_date: row.recorded_date)
likert_score:, grade:, gender:, recorded_date: row.recorded_date, income:)
end
end

@ -0,0 +1,17 @@
<div class="d-flex align-items-center mx-5">
<input
id="<%= id %>"
class="m-3 <%= name %>-checkbox form-check-input"
type="checkbox"
name="<%= name %>-checkbox"
value="<%= base_url %>"
data-action="click->analyze#refresh"
<%= selected_items.include?(item) ? "checked" : "" %>
<%= @presenter.graph.slug == 'students-and-teachers' || @presenter.source.slug == 'all-data' ? "disabled" : "" %>
<%= @presenter.group.slug == name ? "" : "hidden" %>>
<label for="<%= id %>"
<%= @presenter.group.slug == name ? "" : "hidden" %>>
<%= label_text %>
</label>
</div>

@ -1,7 +1,7 @@
<h3 class="sub-header-4 mt-5">Data Filters</h3>
<div class="bg-gray p-3" data-controller="analyze">
<% @sources.each do |source| %>
<% @presenter.sources.each do |source| %>
<input type="radio"
id="<%= source.slug %>"
@ -9,7 +9,7 @@
name="source"
value="<%= base_url %>"
data-action="click->analyze#refresh"
<%= source.slug == @source.slug ? "checked" : "" %>>
<%= source.slug == @presenter.source.slug ? "checked" : "" %>>
<label for="<%= source.slug %>"><%= source.to_s %></label>
<% source.slices.each do | slice | %>
@ -20,7 +20,7 @@
name="slice"
value="<%= base_url %>"
data-action="click->analyze#refresh"
<%= slice.slug == @slice.slug ? "checked" : "" %>
<%= slice.slug == @presenter.slice.slug ? "checked" : "" %>
<%= slice.slug == "all-data" ? "hidden" : "" %>>
<label for="<%= slice.slug %>"
@ -34,8 +34,8 @@
</div>
<script>
window.source = "<%= @source.slug %>";
window.slice = "<%= @slice.slug %>";
window.group = "<%= @group.slug %>";
window.graph = "<%= @graph.slug %>";
window.source = "<%= @presenter.source.slug %>";
window.slice = "<%= @presenter.slice.slug %>";
window.group = "<%= @presenter.group.slug %>";
window.graph = "<%= @presenter.graph.slug %>";
</script>

@ -2,12 +2,12 @@
<p>Select a category & subcategory to analyze measure-level results</p>
<select id="select-category" class="mx-3 form-select" data-id="category-dropdown" data-action="analyze#refresh">
<% categories.each do |category| %>
<option value="<%= analyze_category_link(district: district, school: school, academic_year: academic_year, category: category) %>" <%= category.id == @category.id ? "selected": "" %>><%= "#{category.category_id}: #{category.name}" %></option>
<option value="<%= analyze_category_link(district: district, school: school, academic_year: academic_year, category: category) %>" <%= category.id == @presenter.category.id ? "selected": "" %>><%= "#{category.category_id}: #{category.name}" %></option>
<% end %>
</select>
<select id="select-subcategory" class="mx-3 form-select mt-3" data-id="subcategory-dropdown" data-action="analyze#refresh">
<% subcategories.each do |subcategory| %>
<option value="<%= analyze_subcategory_link(district: district, school: school, academic_year: academic_year, category: category, subcategory: subcategory) %>" <%= subcategory.subcategory_id == @subcategory.subcategory_id ? "selected": "" %>>
<option value="<%= analyze_subcategory_link(district: district, school: school, academic_year: academic_year, category: category, subcategory: subcategory) %>" <%= subcategory.subcategory_id == @presenter.subcategory.subcategory_id ? "selected": "" %>>
<%= "#{subcategory.subcategory_id}: #{subcategory.name}" %>
</option>
<% end %>

@ -1,67 +1,23 @@
<select id="select-group" name="group" class="mx-4 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>
<% @presenter.groups.each do |group| %>
<option id="<%= group.slug %>" name="group-option" value="<%= base_url %>" <%= group.slug == @presenter.group.slug ? "Selected": "" %>><%= group.name %> </option>
<% end %>
</select>
<p class="sub-header-5 mx-4 mt-3 font-size-14"> Select a group </p>
<% @races.each do |race| %>
<div class="d-flex align-items-center mx-5">
<input
id="<%= race.slug %>"
class="m-3 race-checkbox form-check-input"
type="checkbox"
name="race-checkbox"
value="<%= base_url %>"
data-action="click->analyze#refresh"
<%= @selected_races.map(&:slug).include?(race.slug) ? "checked" : "" %>
<%= @graph.slug == 'students-and-teachers' || @source.slug == 'all-data' ? "disabled" : "" %>
<%= @group.slug == 'race' ? "" : "hidden" %>>
<label for="<%= race.qualtrics_code %>"
<%= @group.slug == 'race' ? "" : "hidden" %>>
<%= race.designation %>
</label>
</div>
<% @presenter.races.each do |race| %>
<%= render(partial: "checkboxes", locals: {id: "race-#{race.slug}", item: race, selected_items: @presenter.selected_races, name: "race", label_text: race.designation}) %>
<% end %>
<% @grades.each do |grade| %>
<div class="d-flex align-items-center mx-5">
<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' || @source.slug == 'all-data' ? "disabled" : "" %>
<%= @group.slug == 'grade' ? "" : "hidden" %>>
<label for="grade-<%= grade %>"
<%= @group.slug == 'grade' ? "" : "hidden" %>>
<%= grade %>
</label>
</div>
<% @presenter.grades.each do |grade| %>
<%= render(partial: "checkboxes", locals: {id: "grade-#{grade}", item: grade, selected_items: @presenter.selected_grades, name: "grade", label_text: grade}) %>
<% end %>
<% @genders.each do |gender| %>
<div class="d-flex align-items-center mx-5">
<input
id="gender-<%= gender.designation %>"
class="m-3 gender-checkbox form-check-input"
type="checkbox"
name="gender-checkbox"
value="<%= base_url %>"
data-action="click->analyze#refresh"
<%= @selected_genders.include?(gender) ? "checked" : "" %>
<%= @graph.slug == 'students-and-teachers' || @source.slug == 'all-data' ? "disabled" : "" %>
<%= @group.slug == 'gender' ? "" : "hidden" %>>
<% @presenter.genders.each do |gender| %>
<%= render(partial: "checkboxes", locals: {id: "gender-#{gender.designation}", item: gender, selected_items: @presenter.selected_genders, name: "gender", label_text: gender.designation}) %>
<% end %>
<label for="gender-<%= gender %>"
<%= @group.slug == 'gender' ? "" : "hidden" %>>
<%= gender.designation %>
</label>
</div>
<% @presenter.incomes.each do |income| %>
<%= render(partial: "checkboxes", locals: {id: "income-#{income.slug}", item: income, selected_items: @presenter.selected_incomes, name: "income", label_text: income.designation}) %>
<% end %>

@ -1,9 +1,9 @@
<svg width="100%" height="<%= svg_height %>">
<%= render partial: "graph_background", locals: {background: @background} %>
<% number_of_columns = @graph.columns.length %>
<% @graph.columns.each_with_index do |column, index| %>
<% p = column.new(measure: measure, school: @school, academic_years: @selected_academic_years, position: index , number_of_columns:) %>
<% number_of_columns = @presenter.graph.columns.length %>
<% @presenter.graph.columns.each_with_index do |column, index| %>
<% p = column.new(measure: measure, school: @school, academic_years: @presenter.selected_academic_years, position: index , number_of_columns:) %>
<%= render partial: "grouped_bar_column", locals: {column: p} %>
<% end %>

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 493 B

@ -10,7 +10,7 @@
data-action="click->analyze#refresh"
<% empty_dataset = empty_dataset?(measures: measures, school: school, academic_year: year) %>
<% empty_survey_dataset = empty_survey_dataset?(measures: measures, school: school, academic_year: year) %>
<% if @graph.slug == 'all-data' %>
<% if graph.slug == 'all-data' %>
<%= empty_dataset ? "disabled" : "" %>
<% else %>
<%= empty_survey_dataset ? "disabled" : "" %>
@ -18,13 +18,13 @@
>
<label class="px-3" for="<%= year.range %>"><%= year.range %></label><br>
<div class="bg-color-blue px-3" style="width:20px;height:20px;background-color:<%= colors[index] %>;"></div>
<% if @graph.slug == 'all-data' && empty_dataset %>
<% if graph.slug == 'all-data' && empty_dataset %>
<i class="fa-solid fa-circle-exclamation px-3"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-content="No admin data OR teacher and student survey response rates below <%= ResponseRateCalculator::TEACHER_RATE_THRESHOLD %>%">
</i>
<% end %>
<% if @graph.slug != 'all-data' && empty_survey_dataset %>
<% if graph.slug != 'all-data' && empty_survey_dataset %>
<i class="fa-solid fa-circle-exclamation px-3"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-content="Teacher and student survey response rates below <%= ResponseRateCalculator::TEACHER_RATE_THRESHOLD %>%">

@ -3,19 +3,19 @@
<% end %>
<div class="graph-content">
<div class="breadcrumbs sub-header-4">
<%= @category.category_id %>:<%= @category.name %> > <%= @subcategory.subcategory_id %>:<%= @subcategory.name %>
<%= @presenter.category.category_id %>:<%= @presenter.category.name %> > <%= @presenter.subcategory.subcategory_id %>:<%= @presenter.subcategory.name %>
</div>
<hr>
</div>
<div class="d-flex flex-row pt-5 row">
<div class="d-flex flex-column flex-grow-6 bg-color-white col-3 px-5" data-controller="analyze">
<%= render partial: "focus_area", locals: {categories: @categories, district: @district, school: @school, academic_year: @academic_year, category: @category, subcategories: @subcategories} %>
<%= render partial: "school_years", locals: {available_academic_years: @available_academic_years, selected_academic_years: @selected_academic_years, district: @district, school: @school, academic_year: @academic_year, category: @category, subcategory: @subcategory, measures: @measures} %>
<%= render partial: "data_filters", locals: {district: @district, school: @school, academic_year: @academic_year, category: @category, subcategory: @subcategory} %>
<%= render partial: "focus_area", locals: {categories: @presenter.categories, district: @district, school: @school, academic_year: @academic_year, category: @presenter.category, subcategories: @presenter.subcategories} %>
<%= render partial: "school_years", locals: {available_academic_years: @presenter.academic_years, selected_academic_years: @presenter.selected_academic_years, district: @district, school: @school, academic_year: @academic_year, category: @presenter.category, subcategory: @presenter.subcategory, measures: @presenter.measures, graph: @presenter.graph} %>
<%= render partial: "data_filters", locals: {district: @district, school: @school, academic_year: @academic_year, category: @presenter.category, subcategory: @presenter.subcategory} %>
</div>
<% cache [@subcategory, @school, @selected_academic_years, @graph, @selected_races, @race_score_timestamp, @selected_grades, @grades, @selected_genders, @genders] do %>
<% cache [@presenter.subcategory, @school, @presenter.selected_academic_years, @presenter.graph, @presenter.selected_races, @presenter.race_score_timestamp, @presenter.selected_grades, @presenter.grades, @presenter.selected_genders, @presenter.genders] do %>
<div class="bg-color-white flex-grow-1 col-9">
<% @measures.each do |measure| %>
<% @presenter.measures.each do |measure| %>
<section class="mb-6">
<p class="construct-id">Measure <%= measure.measure_id %></p>
<h2> <%= measure.name %> </h2>

@ -1,11 +1,11 @@
Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender
1,American Indian or Alaskan Native,2,Male
2,Asian or Pacific Islander,1,Female
3,Black or African American,4,Non-Binary
4,Hispanic or Latinx,99,Unknown
5,White or Caucasian,,
6,Prefer not to disclose,,
7,Prefer to self-describe,,
8,Middle Eastern,,
99,Race/Ethnicity Not Listed,,
100,Multiracial,,
Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender,Income
1,American Indian or Alaskan Native,2,Male,Economically Disadvantaged - N
2,Asian or Pacific Islander,1,Female,Economically Disadvantaged - Y
3,Black or African American,4,Non-Binary,Unknown
4,Hispanic or Latinx,99,Unknown,
5,White or Caucasian,,,
6,Prefer not to disclose,,,
7,Prefer to self-describe,,,
8,Middle Eastern,,,
99,Race/Ethnicity Not Listed,,,
100,Multiracial,,,

1 Race Qualtrics Code Race/Ethnicity Gender Qualtrics Code Sex/Gender Income
2 1 American Indian or Alaskan Native 2 Male Economically Disadvantaged - N
3 2 Asian or Pacific Islander 1 Female Economically Disadvantaged - Y
4 3 Black or African American 4 Non-Binary Unknown
5 4 Hispanic or Latinx 99 Unknown
6 5 White or Caucasian
7 6 Prefer not to disclose
8 7 Prefer to self-describe
9 8 Middle Eastern
10 99 Race/Ethnicity Not Listed
11 100 Multiracial

@ -0,0 +1,9 @@
class CreateIncomes < ActiveRecord::Migration[7.0]
def change
create_table :incomes do |t|
t.string :designation
t.timestamps
end
end
end

@ -0,0 +1,5 @@
class AddIncomeToSurveyItemResponses < ActiveRecord::Migration[7.0]
def change
add_reference :survey_item_responses, :income, foreign_key: true
end
end

@ -0,0 +1,6 @@
class AddSlugToIncome < ActiveRecord::Migration[7.0]
def change
add_column :incomes, :slug, :string
add_index :incomes, :slug, unique: true
end
end

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_06_22_224103) do
ActiveRecord::Schema[7.0].define(version: 2023_06_30_215110) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -80,6 +80,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_06_22_224103) do
t.string "designation"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.index ["slug"], name: "index_incomes_on_slug", unique: true
end
create_table "legacy_attempts", id: :serial, force: :cascade do |t|

@ -183,10 +183,6 @@ namespace :one_off do
end
puts "=====================> Completed loading #{Student.count - student_count} students. #{Student.count} total students"
puts 'Resetting response rates'
ResponseRateLoader.reset(academic_years: [AcademicYear.find_by_range('2022-23')], schools:)
puts "=====================> Completed loading #{ResponseRate.count} response rates"
puts 'Resetting race scores'
RaceScoreLoader.reset(fast_processing: false, academic_years: [AcademicYear.find_by_range('2022-23')], schools:)
puts "=====================> Completed loading #{RaceScore.count} race scores"
@ -228,30 +224,30 @@ namespace :one_off do
sum+=c.values.first
nof_si+=1
end
end
end
avg = sum.to_f/ nof_si
counts.each do |key, value|
if key[0] == sc.id && key[1] == ay.id
count = value.values.first
percentage_diff = ((count-avg) / avg) * 100
counts[key] = { count: count, percentage_diff: percentage_diff }
counts[key] = { count: count, percentage_diff: percentage_diff }
end
end
end end
counts.each do |key, value|
output_rows << [School.where(id:key[0]).pluck(:name) , AcademicYear.where(id:key[1]).pluck(:range) , SurveyItem.where(id:key[2]).pluck(:survey_item_id), SurveyItem.where(id:key[2]).pluck(:prompt), value[:count], value[:percentage_diff]]
end
file = File.new('teacher_survey_questions.csv', 'w')
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
output_rows.each do |row|
csv << row
end
end
file.close
puts "CSV report of teacher survey item responses with removed stray responses.csv"
end
@ -288,31 +284,31 @@ namespace :one_off do
sum+=c.values.first
nof_si+=1
end
end
end
end
avg = sum.to_f/ nof_si
counts.each do |key, value|
if key[0] == sc.id && key[1] == ay.id
count = value.values.first
percentage_diff = ((count-avg) / avg) * 100
counts[key] = { count: count, percentage_diff: percentage_diff }
counts[key] = { count: count, percentage_diff: percentage_diff }
end
end
end end end
counts.each do |key, value|
output_rows << [School.where(id:key[0]).pluck(:name) , AcademicYear.where(id:key[1]).pluck(:range) , SurveyItem.where(id:key[2]).pluck(:survey_item_id), SurveyItem.where(id:key[2]).pluck(:prompt), value[:count], value[:percentage_diff]]
end
file = File.new('short_survey_questions.csv', 'w')
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
output_rows.each do |row|
csv << row
end
end
file.close
puts "CSV report of short survey item responses with removed stray responses.csv"
end
@ -349,31 +345,31 @@ namespace :one_off do
sum+=c.values.first
nof_si+=1
end
end
end
end
avg = sum.to_f/ nof_si
counts.each do |key, value|
if key[0] == sc.id && key[1] == ay.id
count = value.values.first
percentage_diff = ((count-avg) / avg) * 100
counts[key] = { count: count, percentage_diff: percentage_diff }
counts[key] = { count: count, percentage_diff: percentage_diff }
end
end
end end end
counts.each do |key, value|
output_rows << [School.where(id:key[0]).pluck(:name) , AcademicYear.where(id:key[1]).pluck(:range) , SurveyItem.where(id:key[2]).pluck(:survey_item_id), SurveyItem.where(id:key[2]).pluck(:prompt), value[:count], value[:percentage_diff]]
end
file = File.new('early_education_surveys_questions.csv', 'w')
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
output_rows.each do |row|
csv << row
end
end
file.close
puts "CSV report of early_education_surveys items with removed stray responses.csv"
end
@ -381,19 +377,19 @@ namespace :one_off do
desc "Generate CSV report of survey item responses"
task stray_responses: :environment do
headers = ['School ID', 'Academic Year', 'Survey Item', 'Count','SurveyItemResponse ids']
output_rows = []
sir_ids=[]
School.all.each do |sc|
AcademicYear.all.each do |ay|
SurveyItem.all.each do |si|
count = SurveyItemResponse.where(school: sc, academic_year: ay, survey_item: si).count
sir_ids= SurveyItemResponse.where(school: sc, academic_year: ay, survey_item: si).pluck(:response_id)
sir_ids= SurveyItemResponse.where(school: sc, academic_year: ay, survey_item: si).pluck(:response_id)
if count > 0 && count < 10
@ -403,7 +399,7 @@ namespace :one_off do
end
end
file = File.new('stray_responses.csv', 'w')
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
@ -412,7 +408,7 @@ namespace :one_off do
end
end
file.close
puts "CSV report of survey item responses created in stray_responses.csv"

@ -21,7 +21,7 @@
"debounce": "^1.2.1",
"esbuild": "^0.17.12",
"sass": "^1.43.4",
"semver": "7.5.2"
"semver": "^7.5.2"
},
"scripts": {
"build": "esbuild app/javascript/*.* --bundle --outdir=app/assets/builds",

@ -1,4 +1,8 @@
FactoryBot.define do
factory :income do
designation { "MyString" }
end
factory :gender do
qualtrics_code { 1 }
designation { 'MyString' }

@ -1,11 +1,11 @@
Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender
1,American Indian or Alaskan Native,2,Male
2,Asian or Pacific Islander,1,Female
3,Black or African American,4,Non-Binary
4,Hispanic or Latinx,99,Unknown
5,White or Caucasian,,
6,Prefer not to disclose,,
7,Prefer to self-describe,,
8,Middle Eastern,,
99,Race/Ethnicity Not Listed,,
100,Multiracial,,
Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender,Income
1,American Indian or Alaskan Native,2,Male,Economically Disadvantaged N
2,Asian or Pacific Islander,1,Female,Economically Disadvantaged Y
3,Black or African American,4,Non-Binary,Unknown
4,Hispanic or Latinx,99,Unknown,
5,White or Caucasian,,,
6,Prefer not to disclose,,,
7,Prefer to self-describe,,,
8,Middle Eastern,,,
99,Race/Ethnicity Not Listed,,,
100,Multiracial,,,

1 Race Qualtrics Code Race/Ethnicity Gender Qualtrics Code Sex/Gender Income
2 1 American Indian or Alaskan Native 2 Male Economically Disadvantaged – N
3 2 Asian or Pacific Islander 1 Female Economically Disadvantaged – Y
4 3 Black or African American 4 Non-Binary Unknown
5 4 Hispanic or Latinx 99 Unknown
6 5 White or Caucasian
7 6 Prefer not to disclose
8 7 Prefer to self-describe
9 8 Middle Eastern
10 99 Race/Ethnicity Not Listed
11 100 Multiracial

@ -1,9 +1,9 @@
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-q1-1,s-phys-q2,s-phys-q3,s-phys-q4,s-vale-q1,s-vale-q2,s-vale-q3,s-vale-q4,s-acst-q1,s-acst-q2,s-acst-q3,s-acst-q4,s-acst-q5,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,gender
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,1500025,,,,dddd,4,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,0,some non-integer response,6,,,,5,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,EN,,,,,1,888,11th,1
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,1500505,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,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,2
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,1500505,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,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_5,567890,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1500505,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,4
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,1500505,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,NA
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,1500505,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,,,,4,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"1,2,3,4,5,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-q1-1,s-phys-q2,s-phys-q3,s-phys-q4,s-vale-q1,s-vale-q2,s-vale-q3,s-vale-q4,s-acst-q1,s-acst-q2,s-acst-q3,s-acst-q4,s-acst-q5,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,gender,Raw Income,Income
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,1500025,,,,dddd,4,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,0,some non-integer response,6,,,,5,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,EN,,,,,1,888,11th,1,Free Lunch,Economically Disadvantaged Y
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,,Not Eligible,Economically Disadvantaged N
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,1500505,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,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,2,Reduced Lunch,Economically Disadvantaged Y
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,1500505,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,3,,Unknown
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,1500505,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,4,Free Lunch,Economically Disadvantaged Y
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,1500505,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,NA,Not Eligible,Economically Disadvantaged N
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,1500505,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,,,,4,,Reduced Lunch,Economically Disadvantaged Y
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"1,2,3,4,5,8",,,,,

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-q1-1 s-phys-q2 s-phys-q3 s-phys-q4 s-vale-q1 s-vale-q2 s-vale-q3 s-vale-q4 s-acst-q1 s-acst-q2 s-acst-q3 s-acst-q4 s-acst-q5 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 gender Raw Income Income
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 1500025 dddd 4 3 3 0 some non-integer response 6 5 1 EN 1 888 11th 1 Free Lunch Economically Disadvantaged – Y
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 Not Eligible Economically Disadvantaged – N
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 1500505 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 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 2 Reduced Lunch Economically Disadvantaged – Y
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 1500505 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 3 Unknown
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 1500505 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 4 Free Lunch Economically Disadvantaged – Y
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 1500505 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 NA Not Eligible Economically Disadvantaged – N
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 1500505 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 4 Reduced Lunch Economically Disadvantaged – Y
9 1,2,3,4,5,8

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

@ -0,0 +1,468 @@
require 'rails_helper'
describe Analyze::Presenter do
let(:category) { create(:category, category_id: '1', name: 'first category') }
let(:category_2) { create(:category, category_id: '2', name: 'second category') }
let(:wrong_category) { create(:category, category_id: '999', name: 'wrong category') }
let(:subcategory) { create(:subcategory, subcategory_id: '1A', name: 'first subcategory', category:) }
let(:subcategory_2) { create(:subcategory, subcategory_id: '2A', name: 'second subcategory', category: category_2) }
let(:wrong_subcategory) do
create(:subcategory, subcategory_id: '99A', name: 'wrong subcategory', category: wrong_category)
end
let(:measure) { create(:measure, measure_id: '1A-i', name: 'first measure', subcategory:) }
let(:measure_2) { create(:measure, measure_id: '2A-i', name: 'second measure', subcategory: subcategory_2) }
let(:wrong_measure) do
create(:wrong_measure, measure_id: '99A', name: 'wrong measure', subcategory: wrong_subcategory)
end
let(:scale) { create(:student_scale, measure:) }
let(:survey_item) { create(:student_survey_item, scale:) }
let(:school) { create(:school) }
let(:academic_year) { create(:academic_year) }
let(:ay_2021_22) { create(:academic_year, range: '2021-22') }
let(:ay_2022_23) { create(:academic_year, range: '2022-23') }
let(:wrong_ay) { create(:academic_year, range: '9999-99') }
let(:black) { create(:race, designation: 'black', qualtrics_code: 1) }
let(:white) { create(:race, designation: 'white', qualtrics_code: 2) }
let(:wrong_race) { create(:race, designation: 'wrong race', qualtrics_code: 9999) }
let(:female) { create(:gender, designation: 'female', qualtrics_code: 1) }
let(:male) { create(:gender, designation: 'male', qualtrics_code: 2) }
let(:wrong_gender) { create(:gender, designation: 'wrong_gender', qualtrics_code: 2) }
context '.category' do
before :each do
category
category_2
wrong_category
end
context 'when a category is provided in the params hash' do
it 'returns the category with the given id' do
params = { category: '1' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.category).to eq category
params = { category: '2' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.category).to eq category_2
end
end
context 'when no category is provided in the params hash' do
it 'returns the first category' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.category).to eq category
end
end
context 'when a category that doesnt exist in the database is passed' do
it 'returns the first category' do
params = { category: '4' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.category).to eq category
end
end
end
context '.categories' do
it 'returns all categories' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.categories).to eq Category.all.order(:category_id)
end
end
context '.subcategory' do
before :each do
category
category_2
wrong_category
subcategory
subcategory_2
wrong_subcategory
end
context 'when a subcategory is provided in the params hash' do
it 'returns the subcategory with the given id' do
params = { subcategory: '1A' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.subcategory).to eq subcategory
params = { subcategory: '2A' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.subcategory).to eq subcategory_2
end
end
context 'when no subcategory is provided in the params hash' do
it 'returns the first subcategory' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.subcategory).to eq subcategory
end
end
context 'when a subcategory that doesnt exist in the database is passed' do
it 'returns the first subcategory' do
params = { subcategory: '4A' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.subcategory).to eq subcategory
end
end
end
context '.subcategories' do
before :each do
category
wrong_category
subcategory
wrong_subcategory
end
it 'returns all subcategories for a given category' do
params = { category: '1' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.subcategories).to eq category.subcategories.all.order(:subcategory_id)
end
end
context '.measures' do
before :each do
category
subcategory
measure
end
it 'returns all measures for a given subcategory' do
params = { category: '1' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.measures).to eq category.subcategories.flat_map(&:measures)
end
end
context '.academic_years' do
before :each do
ay_2021_22
ay_2022_23
end
it 'returns all academic years' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.academic_years).to eq AcademicYear.all.order(:range)
end
end
context '.selected_academic_years' do
before :each do
ay_2021_22
ay_2022_23
wrong_ay
end
context 'when no academic years are provided in the params hash' do
it 'returns an empty array if no params are provided' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_academic_years).to eq []
end
end
context 'when a single academic year is provided in the params hash' do
it 'returns the academic year with the given id' do
params = { academic_years: '2021-22' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_academic_years).to eq [AcademicYear.find_by_range('2021-22')]
params = { academic_years: '2022-23' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_academic_years).to eq [AcademicYear.find_by_range('2022-23')]
end
end
context 'when multiple academic years are provided in the params hash' do
it 'returns the academic year with the given ids' do
params = { academic_years: '2021-22,2022-23' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_academic_years).to eq [AcademicYear.find_by_range('2021-22'),
AcademicYear.find_by_range('2022-23')]
end
end
end
context '.races' do
before :each do
black
white
wrong_race
end
it 'returns all races' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.races).to eq Race.all.order(designation: :ASC)
end
end
context '.selected_races' do
before :each do
black
white
wrong_race
end
context 'when no races are provided in the params hash' do
it 'returns an array with all races if no params are provided' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_races).to eq presenter.races
end
end
context 'when one race is provided in the params hash' do
it 'returns a single race with the given slug' do
params = { races: 'white' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_races).to eq [Race.find_by_slug('white')]
params = { races: 'black' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_races).to eq [Race.find_by_slug('black')]
end
end
context 'when multiple races are provided in the params hash' do
it 'returns multiple races with the given slugs' do
params = { races: 'white,black' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_races).to eq [Race.find_by_slug('white'), Race.find_by_slug('black')]
end
end
end
context '.graph' do
context 'when no params are provided' do
it 'returns the default(first) graph object' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.graph.to_s).to eq Analyze::Graph::AllData.new.to_s
end
end
context 'when a graph is provided in the params hash' do
it 'returns the graph object with the given slug' do
params = { graph: 'all_data' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.graph.to_s).to eq Analyze::Graph::AllData.new.to_s
params = { graph: 'students-and-teachers' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.graph.to_s).to eq Analyze::Graph::StudentsAndTeachers.new.to_s
params = { graph: 'students-by-race' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.graph.to_s).to eq Analyze::Graph::StudentsByRace.new(races: nil).to_s
params = { graph: 'students-by-grade' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.graph.to_s).to eq Analyze::Graph::StudentsByGrade.new(grades: nil).to_s
params = { graph: 'students-by-gender' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.graph.to_s).to eq Analyze::Graph::StudentsByGender.new(genders: nil).to_s
end
end
context 'when a parameter that does not match a graph is provided' do
it 'returns the default(first) graph object' do
params = { graph: 'invalid parameter' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.graph.to_s).to eq Analyze::Graph::AllData.new.to_s
end
end
end
context '.grades' do
before :each do
school
academic_year
create_list(:survey_item_response, 20, school:, academic_year:, grade: 1, survey_item:)
create_list(:survey_item_response, 20, school:, academic_year:, grade: 2, survey_item:)
create_list(:survey_item_response, 20, school:, academic_year:, grade: 3, survey_item:)
create_list(:survey_item_response, 20, school:, academic_year:, grade: 4, survey_item:)
end
context 'when no grades are provided in the params hash' do
it 'returns the set of grades for which there are more than ten responses' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.grades).to eq [1, 2, 3, 4]
end
end
end
context '.selected_grades' do
before :each do
school
academic_year
create_list(:survey_item_response, 20, school:, academic_year:, grade: 1, survey_item:)
create_list(:survey_item_response, 20, school:, academic_year:, grade: 2, survey_item:)
create_list(:survey_item_response, 20, school:, academic_year:, grade: 3, survey_item:)
create_list(:survey_item_response, 20, school:, academic_year:, grade: 4, survey_item:)
end
context 'when no grades are provided in the params hash' do
it 'returns only the set of grades selected even if other grades have sufficient responses' do
params = { grades: '1,2,3' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_grades).to eq [1, 2, 3]
end
end
end
context '.selected_genders' do
before :each do
male
female
wrong_gender
end
context 'when no parameters are provided' do
it 'returns all genders' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_genders).to eq Gender.all
end
end
context 'when a single gender is provided in the params hash' do
it 'returns the gender with the given designation' do
params = { genders: 'female' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_genders).to eq [Gender.find_by_designation('female')]
params = { genders: 'male' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_genders).to eq [Gender.find_by_designation('male')]
end
end
context 'when multiple genders are provided in the params hash' do
it 'returns multilple genders with the given designations' do
params = { genders: 'female,male' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.selected_genders).to eq [Gender.find_by_designation('female'),
Gender.find_by_designation('male')]
end
end
end
context '.genders' do
before :each do
female
male
end
it 'returns all genders' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.genders).to eq Gender.all
end
end
context '.group' do
context 'when no parameters are provided' do
it 'returns the first item in the list of groups' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.group.slug).to eq presenter.groups.first.slug
end
end
context 'when a group is provided in the params hash' do
it 'returns the group with the given slug' do
params = { group: 'gender' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.group.slug).to eq 'gender'
params = { group: 'grade' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.group.slug).to eq 'grade'
params = { group: 'race' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.group.slug).to eq 'race'
# Not yet implemented
# params = { group: 'income' }
# presenter = Analyze::Presenter.new(params:, school:, academic_year:)
# expect(presenter.group.slug).to eq 'income'
end
end
context 'when a parameter that does not match a group is provided' do
it 'returns the first item in the list of groups' do
params = { group: 'invalid group' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.group.slug).to eq presenter.groups.first.slug
end
end
end
context '.slice' do
context 'when no parameters are provided' do
it 'returns the first item in the list of slices' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.slice.slug).to eq 'all-data'
end
end
context 'when a slice is provided in the params hash' do
it 'returns the slice with the given slug' do
params = { source: 'survey-data-only', slice: 'students-and-teachers' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.slice.slug).to eq 'students-and-teachers'
end
end
context 'when a slice is provided but the source is left blank ' do
it 'returns the slice from the default source (all-data)' do
params = { slice: 'students-and-teachers' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.slice.slug).to eq 'all-data'
end
end
context 'when a parameter that does not match a slice is provided' do
it 'it returns the first slice from the chosen source' do
params = { source: 'survey-data-only', slice: 'invalid-slice' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.slice.slug).to eq 'students-and-teachers'
end
end
end
context '.source' do
context 'when no parameters are provided' do
it 'returns the first item in the list of sources' do
params = {}
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.slice.slug).to eq 'all-data'
end
end
context 'when a source is provided in the params hash' do
it 'returns the source with the given slug' do
params = { source: 'all-data' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.source.slug).to eq 'all-data'
params = { source: 'survey-data-only' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.source.slug).to eq 'survey-data-only'
end
end
context 'when a parameter that does not match a source is provided' do
it 'returns the first item in the list of sources' do
params = { source: 'invalid-source' }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.slice.slug).to eq 'all-data'
end
end
end
end

@ -227,12 +227,12 @@ describe GroupedBarColumnPresenter do
# it_behaves_like 'y_offset'
context 'and the score is right at the approval low benchmark' do
it "where bar would normally have a height of 0, we inflate the height to be at least the minimum bar height of #{AnalyzeBarPresenter::MINIMUM_BAR_HEIGHT}" do
expect(student_presenter.bars[year_index].bar_height_percentage).to be_within(0.01).of(AnalyzeBarPresenter::MINIMUM_BAR_HEIGHT)
it "where bar would normally have a height of 0, we inflate the height to be at least the minimum bar height of #{Analyze::BarPresenter::MINIMUM_BAR_HEIGHT}" do
expect(student_presenter.bars[year_index].bar_height_percentage).to be_within(0.01).of(Analyze::BarPresenter::MINIMUM_BAR_HEIGHT)
end
it "where the bar would normally start at the approval low benchmark, it shifts up to accomodate it being grown to the minimum bar height of #{AnalyzeBarPresenter::MINIMUM_BAR_HEIGHT}" do
expect(student_presenter.bars[year_index].y_offset).to be_within(0.01).of(analyze_zone_height * 2 - AnalyzeBarPresenter::MINIMUM_BAR_HEIGHT)
it "where the bar would normally start at the approval low benchmark, it shifts up to accomodate it being grown to the minimum bar height of #{Analyze::BarPresenter::MINIMUM_BAR_HEIGHT}" do
expect(student_presenter.bars[year_index].y_offset).to be_within(0.01).of(analyze_zone_height * 2 - Analyze::BarPresenter::MINIMUM_BAR_HEIGHT)
end
end
end
@ -257,8 +257,8 @@ describe GroupedBarColumnPresenter do
academic_year:, likert_score: 4)
end
it "it rounds to the the minimum bar height of #{AnalyzeBarPresenter::MINIMUM_BAR_HEIGHT} " do
expect(student_presenter.bars[year_index].bar_height_percentage).to be_within(0.01).of(AnalyzeBarPresenter::MINIMUM_BAR_HEIGHT)
it "it rounds to the the minimum bar height of #{Analyze::BarPresenter::MINIMUM_BAR_HEIGHT} " do
expect(student_presenter.bars[year_index].bar_height_percentage).to be_within(0.01).of(Analyze::BarPresenter::MINIMUM_BAR_HEIGHT)
end
end
end

@ -13,6 +13,10 @@ describe DemographicLoader do
}
end
let(:incomes) do
['Economically Disadvantaged N', 'Economically Disadvantaged Y', 'Unknown']
end
before :each do
DemographicLoader.load_data(filepath:)
end
@ -46,5 +50,12 @@ describe DemographicLoader do
expect(Gender.find_by_designation(key).qualtrics_code).to eq value
end
end
it 'loads all the income designations' do
expect(Income.all.count).to eq 3
incomes.each do |income|
expect(Income.find_by_designation(income).designation).to eq income
end
end
end
end

@ -1,40 +1,40 @@
require "rails_helper"
require 'rails_helper'
RSpec.describe SurveyItemValues, type: :model do
let(:headers) do
["StartDate", "EndDate", "Status", "IPAddress", "Progress", "Duration (in seconds)", "Finished", "RecordedDate",
"ResponseId", "RecipientLastName", "RecipientFirstName", "RecipientEmail", "ExternalReference", "LocationLatitude", "LocationLongitude", "DistributionChannel", "UserLanguage", "District", "School- Lee", "School- Maynard", "LASID", "Grade", "s-emsa-q1", "s-emsa-q2", "s-emsa-q3", "s-tint-q1", "s-tint-q2", "s-tint-q3", "s-tint-q4", "s-tint-q5", "s-acpr-q1", "s-acpr-q2", "s-acpr-q3", "s-acpr-q4", "s-cure-q1", "s-cure-q2", "s-cure-q3", "s-cure-q4", "s-sten-q1", "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", "s-grmi-q2", "s-grmi-q3", "s-grmi-q4", "s-appa-q1", "s-appa-q2", "s-appa-q3", "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", "s-vale-q2", "s-vale-q3", "s-vale-q4", "s-acst-q1", "s-acst-q2", "s-acst-q3", "s-sust-q1", "s-sust-q2", "s-grit-q1", "s-grit-q2", "s-grit-q3", "s-grit-q4", "s-expa-q1", "s-poaf-q1", "s-poaf-q2", "s-poaf-q3", "s-poaf-q4", "s-tint-q1-1", "s-tint-q2-1", "s-tint-q3-1", "s-tint-q4-1", "s-tint-q5-1", "s-acpr-q1-1", "s-acpr-q2-1", "s-acpr-q3-1", "s-acpr-q4-1", "s-peff-q1-1", "s-peff-q2-1", "s-peff-q3-1", "s-peff-q4-1", "s-peff-q5-1", "s-peff-q6-1", "Gender", "Race"]
['StartDate', 'EndDate', 'Status', 'IPAddress', 'Progress', 'Duration (in seconds)', 'Finished', 'RecordedDate',
'ResponseId', 'RecipientLastName', 'RecipientFirstName', 'RecipientEmail', 'ExternalReference', 'LocationLatitude', 'LocationLongitude', 'DistributionChannel', 'UserLanguage', 'District', 'School- Lee', 'School- Maynard', 'LASID', 'Grade', 's-emsa-q1', 's-emsa-q2', 's-emsa-q3', 's-tint-q1', 's-tint-q2', 's-tint-q3', 's-tint-q4', 's-tint-q5', 's-acpr-q1', 's-acpr-q2', 's-acpr-q3', 's-acpr-q4', 's-cure-q1', 's-cure-q2', 's-cure-q3', 's-cure-q4', 's-sten-q1', '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', 's-grmi-q2', 's-grmi-q3', 's-grmi-q4', 's-appa-q1', 's-appa-q2', 's-appa-q3', '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', 's-vale-q2', 's-vale-q3', 's-vale-q4', 's-acst-q1', 's-acst-q2', 's-acst-q3', 's-sust-q1', 's-sust-q2', 's-grit-q1', 's-grit-q2', 's-grit-q3', 's-grit-q4', 's-expa-q1', 's-poaf-q1', 's-poaf-q2', 's-poaf-q3', 's-poaf-q4', 's-tint-q1-1', 's-tint-q2-1', 's-tint-q3-1', 's-tint-q4-1', 's-tint-q5-1', 's-acpr-q1-1', 's-acpr-q2-1', 's-acpr-q3-1', 's-acpr-q4-1', 's-peff-q1-1', 's-peff-q2-1', 's-peff-q3-1', 's-peff-q4-1', 's-peff-q5-1', 's-peff-q6-1', 'Gender', 'Race']
end
let(:genders) do
create(:gender, qualtrics_code: 1)
Gender.gender_hash
end
let(:survey_items) { [] }
let(:district) { create(:district, name: "Attleboro") }
let(:district) { create(:district, name: 'Attleboro') }
let(:attleboro) do
create(:school, name: "Attleboro", dese_id: 1234, district:)
create(:school, name: 'Attleboro', dese_id: 1234, district:)
end
let(:attleboro_respondents) do
create(:respondent, school: attleboro, academic_year: ay_2022_23, nine: 40, ten: 40, eleven: 40, twelve: 40)
end
let(:schools) { School.school_hash }
let(:recorded_date) { "2023-04-01" }
let(:recorded_date) { '2023-04-01' }
let(:ay_2022_23) do
create(:academic_year, range: "2022-23")
create(:academic_year, range: '2022-23')
end
let(:common_headers) do
["Recorded Date", "DeseID", "ResponseID", "Duration (in seconds)", "Gender", "Grade"]
['Recorded Date', 'DeseID', 'ResponseID', 'Duration (in seconds)', 'Gender', 'Grade']
end
let(:standard_survey_items) do
survey_item_ids = %w[s-peff-q1 s-peff-q2 s-peff-q3 s-peff-q4 s-peff-q5 s-peff-q6 s-phys-q1 s-phys-q2 s-phys-q3 s-phys-q4
s-emsa-q1 s-emsa-q2 s-emsa-q3 s-sbel-q1 s-sbel-q2 s-sbel-q3 s-sbel-q4 s-sbel-q5 s-tint-q1 s-tint-q2
s-tint-q3 s-tint-q4 s-tint-q5 s-vale-q1 s-vale-q2 s-vale-q3 s-vale-q4 s-acpr-q1 s-acpr-q2 s-acpr-q3
s-acpr-q4 s-sust-q1 s-sust-q2 s-cure-q1 s-cure-q2 s-cure-q3 s-cure-q4 s-sten-q1 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-grit-q1 s-grit-q2
s-grit-q3 s-grit-q4 s-grmi-q1 s-grmi-q2 s-grmi-q3 s-grmi-q4 s-expa-q1 s-appa-q1 s-appa-q2 s-appa-q3
s-acst-q1 s-acst-q2 s-acst-q3 s-poaf-q1 s-poaf-q2 s-poaf-q3 s-poaf-q4]
s-emsa-q1 s-emsa-q2 s-emsa-q3 s-sbel-q1 s-sbel-q2 s-sbel-q3 s-sbel-q4 s-sbel-q5 s-tint-q1 s-tint-q2
s-tint-q3 s-tint-q4 s-tint-q5 s-vale-q1 s-vale-q2 s-vale-q3 s-vale-q4 s-acpr-q1 s-acpr-q2 s-acpr-q3
s-acpr-q4 s-sust-q1 s-sust-q2 s-cure-q1 s-cure-q2 s-cure-q3 s-cure-q4 s-sten-q1 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-grit-q1 s-grit-q2
s-grit-q3 s-grit-q4 s-grmi-q1 s-grmi-q2 s-grmi-q3 s-grmi-q4 s-expa-q1 s-appa-q1 s-appa-q2 s-appa-q3
s-acst-q1 s-acst-q2 s-acst-q3 s-poaf-q1 s-poaf-q2 s-poaf-q3 s-poaf-q4]
survey_item_ids.map do |survey_item_id|
create(:survey_item, survey_item_id:)
end
@ -42,10 +42,10 @@ RSpec.describe SurveyItemValues, type: :model do
end
let(:short_form_survey_items) do
survey_item_ids = [create(:survey_item, survey_item_id: "s-phys-q1", on_short_form: true),
create(:survey_item, survey_item_id: "s-phys-q2", on_short_form: true),
create(:survey_item, survey_item_id: "s-phys-q3",
on_short_form: true)].map(&:survey_item_id)
survey_item_ids = [create(:survey_item, survey_item_id: 's-phys-q1', on_short_form: true),
create(:survey_item, survey_item_id: 's-phys-q2', on_short_form: true),
create(:survey_item, survey_item_id: 's-phys-q3',
on_short_form: true)].map(&:survey_item_id)
survey_item_ids.map do |survey_item_id|
create(:survey_item, survey_item_id:)
end
@ -53,9 +53,9 @@ RSpec.describe SurveyItemValues, type: :model do
end
let(:early_education_survey_items) do
survey_item_ids = [create(:survey_item, survey_item_id: "s-emsa-es1"),
create(:survey_item, survey_item_id: "s-emsa-es2"),
create(:survey_item, survey_item_id: "s-emsa-es3")].map(&:survey_item_id)
survey_item_ids = [create(:survey_item, survey_item_id: 's-emsa-es1'),
create(:survey_item, survey_item_id: 's-emsa-es2'),
create(:survey_item, survey_item_id: 's-emsa-es3')].map(&:survey_item_id)
survey_item_ids.map do |survey_item_id|
create(:survey_item, survey_item_id:)
end
@ -64,12 +64,12 @@ RSpec.describe SurveyItemValues, type: :model do
let(:teacher_survey_items) do
survey_item_ids = %w[t-prep-q1 t-prep-q2 t-prep-q3 t-ieff-q1 t-ieff-q2 t-ieff-q3 t-ieff-q4 t-pcom-q1 t-pcom-q2 t-pcom-q3
t-pcom-q4 t-pcom-q5 t-inle-q1 t-inle-q2 t-inle-q3 t-prtr-q1 t-prtr-q2 t-prtr-q3 t-coll-q1 t-coll-q2
t-coll-q3 t-qupd-q1 t-qupd-q2 t-qupd-q3 t-qupd-q4 t-pvic-q1 t-pvic-q2 t-pvic-q3 t-psup-q1 t-psup-q2
t-psup-q3 t-psup-q4 t-acch-q1 t-acch-q2 t-acch-q3 t-reso-q1 t-reso-q2 t-reso-q3 t-reso-q4 t-reso-q5
t-sust-q1 t-sust-q2 t-sust-q3 t-sust-q4 t-curv-q1 t-curv-q2 t-curv-q3 t-curv-q4 t-cure-q1 t-cure-q2
t-cure-q3 t-cure-q4 t-peng-q1 t-peng-q2 t-peng-q3 t-peng-q4 t-ceng-q1 t-ceng-q2 t-ceng-q3 t-ceng-q4
t-sach-q1 t-sach-q2 t-sach-q3 t-psol-q1 t-psol-q2 t-psol-q3 t-expa-q2 t-expa-q3 t-phya-q2 t-phya-q3]
t-pcom-q4 t-pcom-q5 t-inle-q1 t-inle-q2 t-inle-q3 t-prtr-q1 t-prtr-q2 t-prtr-q3 t-coll-q1 t-coll-q2
t-coll-q3 t-qupd-q1 t-qupd-q2 t-qupd-q3 t-qupd-q4 t-pvic-q1 t-pvic-q2 t-pvic-q3 t-psup-q1 t-psup-q2
t-psup-q3 t-psup-q4 t-acch-q1 t-acch-q2 t-acch-q3 t-reso-q1 t-reso-q2 t-reso-q3 t-reso-q4 t-reso-q5
t-sust-q1 t-sust-q2 t-sust-q3 t-sust-q4 t-curv-q1 t-curv-q2 t-curv-q3 t-curv-q4 t-cure-q1 t-cure-q2
t-cure-q3 t-cure-q4 t-peng-q1 t-peng-q2 t-peng-q3 t-peng-q4 t-ceng-q1 t-ceng-q2 t-ceng-q3 t-ceng-q4
t-sach-q1 t-sach-q2 t-sach-q3 t-psol-q1 t-psol-q2 t-psol-q3 t-expa-q2 t-expa-q3 t-phya-q2 t-phya-q3]
survey_item_ids.map do |survey_item_id|
create(:survey_item, survey_item_id:)
@ -77,49 +77,49 @@ RSpec.describe SurveyItemValues, type: :model do
(survey_item_ids << common_headers).flatten
end
context ".recorded_date" do
it "returns the recorded date" do
row = {"RecordedDate" => "2017-01-01"}
context '.recorded_date' do
it 'returns the recorded date' do
row = { 'RecordedDate' => '2017-01-01' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
expect(values.recorded_date).to eq Date.parse("2017-01-01")
expect(values.recorded_date).to eq Date.parse('2017-01-01')
headers = ["Recorded Date"]
row = {"Recorded Date" => "2017-01-02"}
headers = ['Recorded Date']
row = { 'Recorded Date' => '2017-01-02' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
expect(values.recorded_date).to eq Date.parse("2017-01-02")
expect(values.recorded_date).to eq Date.parse('2017-01-02')
end
end
context ".school" do
it "returns the school that maps to the dese id provided" do
context '.school' do
it 'returns the school that maps to the dese id provided' do
attleboro
row = {"Dese ID" => "1234"}
row = { 'Dese ID' => '1234' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
expect(values.school).to eq attleboro
row = {"DeseID" => "1234"}
row = { 'DeseID' => '1234' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
expect(values.school).to eq attleboro
end
end
context ".grade" do
it "returns the grade that maps to the grade provided" do
row = {"Grade" => "1"}
context '.grade' do
it 'returns the grade that maps to the grade provided' do
row = { 'Grade' => '1' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
expect(values.grade).to eq 1
end
end
context ".gender" do
it "returns the grade that maps to the grade provided" do
row = {"Gender" => "1"}
context '.gender' do
it 'returns the grade that maps to the grade provided' do
row = { 'Gender' => '1' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
expect(values.gender.qualtrics_code).to eq 1
end
end
context ".respondent_type" do
it "reads header to find the survey type" do
context '.respondent_type' do
it 'reads header to find the survey type' do
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
expect(values.respondent_type).to eq :student
@ -130,32 +130,32 @@ RSpec.describe SurveyItemValues, type: :model do
end
end
context ".survey_type" do
context "when survey type is standard form" do
it "returns the survey type" do
context '.survey_type' do
context 'when survey type is standard form' do
it 'returns the survey type' do
headers = standard_survey_items
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
expect(values.survey_type).to eq :standard
end
end
context "when survey type is teacher form" do
it "returns the survey type" do
context 'when survey type is teacher form' do
it 'returns the survey type' do
headers = teacher_survey_items
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
expect(values.survey_type).to eq :teacher
end
end
context "when survey type is short form" do
it "returns the survey type" do
context 'when survey type is short form' do
it 'returns the survey type' do
headers = short_form_survey_items
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
expect(values.survey_type).to eq :short_form
end
end
context "when survey type is early education" do
it "returns the survey type" do
context 'when survey type is early education' do
it 'returns the survey type' do
headers = early_education_survey_items
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
expect(values.survey_type).to eq :early_education
@ -163,236 +163,236 @@ RSpec.describe SurveyItemValues, type: :model do
end
end
context ".income" do
context "when no disaggregation data is provided" do
it "returns an empty string " do
context '.income' do
context 'when no disaggregation data is provided' do
it 'returns an empty string ' do
disaggregation_data = {}
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:, disaggregation_data:)
expect(values.income).to eq "Unknown"
expect(values.income).to eq 'Unknown'
end
end
context "when disaggregation data is provided" do
context 'when disaggregation data is provided' do
before :each do
attleboro
ay_2022_23
end
it "translates Free Lunch to Economically Disadvantaged - Y" do
headers = ["District", "Academic Year", "LASID", "LowIncome"]
row = {"District" => "Attleboro", "AcademicYear" => "2022-23", "LASID" => "1", "LowIncome" => "Free Lunch"}
disaggregation_data = {%w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:)}
it 'translates Free Lunch to Economically Disadvantaged - Y' do
headers = ['District', 'Academic Year', 'LASID', 'LowIncome']
row = { 'District' => 'Attleboro', 'AcademicYear' => '2022-23', 'LASID' => '1', 'LowIncome' => 'Free Lunch' }
disaggregation_data = { %w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:) }
headers = ["LASID", "Dese Id", "RecordedDate"]
row = {"LASID" => "1", "DESE ID" => "1234", "RecordedDate" => "2023-1-1"}
headers = ['LASID', 'Dese Id', 'RecordedDate']
row = { 'LASID' => '1', 'DESE ID' => '1234', 'RecordedDate' => '2023-1-1' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
disaggregation_data:)
expect(values.income).to eq "Economically Disadvantaged - Y"
disaggregation_data:)
expect(values.income).to eq 'Economically Disadvantaged - Y'
end
it "translates Reduced Lunch to Economically Disadvantaged - Y" do
headers = ["District", "Academic Year", "LASID", "LowIncome"]
row = {"District" => "Attleboro", "AcademicYear" => "2022-23", "LASID" => "1", "LowIncome" => "Reduced Lunch"}
disaggregation_data = {%w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:)}
it 'translates Reduced Lunch to Economically Disadvantaged - Y' do
headers = ['District', 'Academic Year', 'LASID', 'LowIncome']
row = { 'District' => 'Attleboro', 'AcademicYear' => '2022-23', 'LASID' => '1', 'LowIncome' => 'Reduced Lunch' }
disaggregation_data = { %w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:) }
headers = ["LASID", "Dese Id", "RecordedDate"]
row = {"LASID" => "1", "DESE ID" => "1234", "RecordedDate" => "2023-1-1"}
headers = ['LASID', 'Dese Id', 'RecordedDate']
row = { 'LASID' => '1', 'DESE ID' => '1234', 'RecordedDate' => '2023-1-1' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
disaggregation_data:)
expect(values.income).to eq "Economically Disadvantaged - Y"
disaggregation_data:)
expect(values.income).to eq 'Economically Disadvantaged - Y'
end
it "translates LowIncome to Economically Disadvantaged - Y" do
headers = ["District", "Academic Year", "LASID", "LowIncome"]
row = {"District" => "Attleboro", "AcademicYear" => "2022-23", "LASID" => "1", "LowIncome" => "LowIncome"}
disaggregation_data = {%w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:)}
it 'translates LowIncome to Economically Disadvantaged - Y' do
headers = ['District', 'Academic Year', 'LASID', 'LowIncome']
row = { 'District' => 'Attleboro', 'AcademicYear' => '2022-23', 'LASID' => '1', 'LowIncome' => 'LowIncome' }
disaggregation_data = { %w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:) }
headers = ["LASID", "Dese Id", "RecordedDate"]
row = {"LASID" => "1", "DESE ID" => "1234", "RecordedDate" => "2023-1-1"}
headers = ['LASID', 'Dese Id', 'RecordedDate']
row = { 'LASID' => '1', 'DESE ID' => '1234', 'RecordedDate' => '2023-1-1' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
disaggregation_data:)
expect(values.income).to eq "Economically Disadvantaged - Y"
disaggregation_data:)
expect(values.income).to eq 'Economically Disadvantaged - Y'
end
it "translates Not Eligible to Economically Disadvantaged - N" do
headers = ["District", "Academic Year", "LASID", "LowIncome"]
row = {"District" => "Attleboro", "AcademicYear" => "2022-23", "LASID" => "1", "LowIncome" => "Not Eligible"}
disaggregation_data = {%w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:)}
it 'translates Not Eligible to Economically Disadvantaged - N' do
headers = ['District', 'Academic Year', 'LASID', 'LowIncome']
row = { 'District' => 'Attleboro', 'AcademicYear' => '2022-23', 'LASID' => '1', 'LowIncome' => 'Not Eligible' }
disaggregation_data = { %w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:) }
headers = ["LASID", "Dese Id", "RecordedDate"]
row = {"LASID" => "1", "DESE ID" => "1234", "RecordedDate" => "2023-1-1"}
headers = ['LASID', 'Dese Id', 'RecordedDate']
row = { 'LASID' => '1', 'DESE ID' => '1234', 'RecordedDate' => '2023-1-1' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
disaggregation_data:)
expect(values.income).to eq "Economically Disadvantaged - N"
disaggregation_data:)
expect(values.income).to eq 'Economically Disadvantaged - N'
end
it "translates blanks to Unknown" do
headers = ["District", "Academic Year", "LASID", "LowIncome"]
row = {"District" => "Attleboro", "AcademicYear" => "2022-23", "LASID" => "1", "LowIncome" => ""}
disaggregation_data = {%w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:)}
it 'translates blanks to Unknown' do
headers = ['District', 'Academic Year', 'LASID', 'LowIncome']
row = { 'District' => 'Attleboro', 'AcademicYear' => '2022-23', 'LASID' => '1', 'LowIncome' => '' }
disaggregation_data = { %w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:) }
headers = ["LASID", "Dese Id", "RecordedDate"]
row = {"LASID" => "1", "DESE ID" => "1234", "RecordedDate" => "2023-1-1"}
headers = ['LASID', 'Dese Id', 'RecordedDate']
row = { 'LASID' => '1', 'DESE ID' => '1234', 'RecordedDate' => '2023-1-1' }
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
disaggregation_data:)
expect(values.income).to eq "Unknown"
disaggregation_data:)
expect(values.income).to eq 'Unknown'
end
end
end
context ".valid_duration" do
context "when duration is valid" do
it "returns true" do
context '.valid_duration' do
context 'when duration is valid' do
it 'returns true' do
headers = standard_survey_items
values = SurveyItemValues.new(row: {"Duration (in seconds)" => "240", "Gender" => "Male"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '240', 'Gender' => 'Male' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_duration?).to eq true
headers = teacher_survey_items
values = SurveyItemValues.new(row: {"Duration (in seconds)" => "300"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '300' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_duration?).to eq true
headers = short_form_survey_items
values = SurveyItemValues.new(row: {"Duration (in seconds)" => "100"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '100' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_duration?).to eq true
# When duration is blank or N/A or NA, we don't have enough information to kick out the row as invalid so we keep it in
headers = short_form_survey_items
values = SurveyItemValues.new(row: {"Duration (in seconds)" => ""}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_duration?).to eq true
headers = short_form_survey_items
values = SurveyItemValues.new(row: {"Duration (in seconds)" => "N/A"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Duration (in seconds)' => 'N/A' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_duration?).to eq true
headers = short_form_survey_items
values = SurveyItemValues.new(row: {"Duration (in seconds)" => "NA"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Duration (in seconds)' => 'NA' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_duration?).to eq true
end
end
context "when duration is invalid" do
it "returns false" do
context 'when duration is invalid' do
it 'returns false' do
headers = standard_survey_items
values = SurveyItemValues.new(row: {"Duration (in seconds)" => "239"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '239' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_duration?).to eq false
headers = teacher_survey_items
values = SurveyItemValues.new(row: {"Duration (in seconds)" => "299"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '299' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_duration?).to eq false
headers = short_form_survey_items
values = SurveyItemValues.new(row: {"Duration (in seconds)" => "99"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '99' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_duration?).to eq false
end
end
end
context ".valid_progress" do
context "when progress is valid" do
it "returns true" do
context '.valid_progress' do
context 'when progress is valid' do
it 'returns true' do
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
values = SurveyItemValues.new(row: {"Progress" => "25"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Progress' => '25' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_progress?).to eq true
# When progress is blank or N/A or NA, we don't have enough information to kick out the row as invalid so we keep it in
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
values = SurveyItemValues.new(row: {"Progress" => ""}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Progress' => '' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_progress?).to eq true
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
values = SurveyItemValues.new(row: {"Progress" => "N/A"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Progress' => 'N/A' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_progress?).to eq true
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
values = SurveyItemValues.new(row: {"Progress" => "NA"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Progress' => 'NA' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_progress?).to eq true
end
end
context "when progress is invalid" do
it "returns false" do
context 'when progress is invalid' do
it 'returns false' do
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
values = SurveyItemValues.new(row: {"Progress" => "24"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'Progress' => '24' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_progress?).to eq false
end
end
end
context ".valid_grade?" do
context "when grade is valid" do
context '.valid_grade?' do
context 'when grade is valid' do
before :each do
attleboro
attleboro_respondents
end
it "returns true for students" do
it 'returns true for students' do
headers = %w[s-sbel-q5 s-phys-q2 grade RecordedDate]
values = SurveyItemValues.new(row: {"grade" => "9", "RecordedDate" => recorded_date, "Dese ID" => "1234"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'grade' => '9', 'RecordedDate' => recorded_date, 'Dese ID' => '1234' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_grade?).to eq true
end
it "returns true for teachers" do
it 'returns true for teachers' do
headers = %w[t-sbel-q5 t-phys-q2 grade RecordedDate]
values = SurveyItemValues.new(row: {"RecordedDate" => recorded_date, "Dese ID" => "1234"}, headers:, genders:, survey_items:,
schools:)
values = SurveyItemValues.new(row: { 'RecordedDate' => recorded_date, 'Dese ID' => '1234' }, headers:, genders:, survey_items:,
schools:)
expect(values.valid_grade?).to eq true
end
end
context "when grade is invalid" do
context 'when grade is invalid' do
before :each do
attleboro
attleboro_respondents
end
it "returns false" do
it 'returns false' do
headers = %w[s-sbel-q5 s-phys-q2 grade RecordedDate]
values = SurveyItemValues.new(row: {"grade" => "2", "RecordedDate" => recorded_date, "Dese ID" => "1234"}, headers:, genders:, survey_items:,
schools: School.school_hash)
values = SurveyItemValues.new(row: { 'grade' => '2', 'RecordedDate' => recorded_date, 'Dese ID' => '1234' }, headers:, genders:, survey_items:,
schools: School.school_hash)
expect(values.valid_grade?).to eq false
end
end
end
context ".valid_sd?" do
context "when the standard deviation is valid" do
it "returns true for student questions" do
context '.valid_sd?' do
context 'when the standard deviation is valid' do
it 'returns true for student questions' do
headers = %w[s-sbel-q5 s-phys-q1 s-phys-q2 RecordedDate]
values = SurveyItemValues.new(row: {"RecordedDate" => recorded_date, "Dese ID" => "1234", "s-sbel-q5" => "1", "s-phys-q1" => "", "s-phys-q2" => "5"}, headers:, genders:, survey_items:,
schools: School.school_hash)
values = SurveyItemValues.new(row: { 'RecordedDate' => recorded_date, 'Dese ID' => '1234', 's-sbel-q5' => '1', 's-phys-q1' => '', 's-phys-q2' => '5' }, headers:, genders:, survey_items:,
schools: School.school_hash)
expect(values.valid_sd?).to eq true
end
it "returns true for teacher questions" do
it 'returns true for teacher questions' do
headers = %w[t-sbel-q5 t-phys-q2]
values = SurveyItemValues.new(row: {"RecordedDate" => recorded_date, "Dese ID" => "1234", "t-sbel-q5" => "1", "t-phys-q2" => "5"}, headers:, genders:, survey_items:,
schools: School.school_hash)
values = SurveyItemValues.new(row: { 'RecordedDate' => recorded_date, 'Dese ID' => '1234', 't-sbel-q5' => '1', 't-phys-q2' => '5' }, headers:, genders:, survey_items:,
schools: School.school_hash)
expect(values.valid_sd?).to eq true
end
end
context "when the standard deviation is invalid" do
it "returns false for student questions" do
context 'when the standard deviation is invalid' do
it 'returns false for student questions' do
headers = %w[s-sbel-q5 s-phys-q1 s-phys-q2 RecordedDate]
values = SurveyItemValues.new(row: {"RecordedDate" => recorded_date, "Dese ID" => "1234", "s-sbel-q5" => "1", "s-phys-q2" => "", "s-phys-q2" => "1"}, headers:, genders:, survey_items:,
schools: School.school_hash)
values = SurveyItemValues.new(row: { 'RecordedDate' => recorded_date, 'Dese ID' => '1234', 's-sbel-q5' => '1', 's-phys-q2' => '1' }, headers:, genders:, survey_items:,
schools: School.school_hash)
expect(values.valid_sd?).to eq false
end
it "returns false for teacher questions" do
it 'returns false for teacher questions' do
headers = %w[t-sbel-q5 t-phys-q1 t-phys-q2 RecordedDate]
values = SurveyItemValues.new(row: {"RecordedDate" => recorded_date, "Dese ID" => "1234", "t-sbel-q5" => "1", "t-phys-q2" => "", "t-phys-q2" => "1"}, headers:, genders:, survey_items:,
schools: School.school_hash)
values = SurveyItemValues.new(row: { 'RecordedDate' => recorded_date, 'Dese ID' => '1234', 't-sbel-q5' => '1', 't-phys-q2' => '1' }, headers:, genders:, survey_items:,
schools: School.school_hash)
expect(values.valid_sd?).to eq false
end
end

@ -1,53 +1,59 @@
require "rails_helper"
require 'rails_helper'
describe SurveyResponsesDataLoader do
let(:path_to_teacher_responses) { Rails.root.join("spec", "fixtures", "test_2020-21_teacher_survey_responses.csv") }
let(:path_to_student_responses) { Rails.root.join("spec", "fixtures", "test_2020-21_student_survey_responses.csv") }
let(:path_to_teacher_responses) { Rails.root.join('spec', 'fixtures', 'test_2020-21_teacher_survey_responses.csv') }
let(:path_to_student_responses) { Rails.root.join('spec', 'fixtures', 'test_2020-21_student_survey_responses.csv') }
let(:path_to_butler_student_responses) do
Rails.root.join("spec", "fixtures", "test_2022-23_butler_student_survey_responses.csv")
Rails.root.join('spec', 'fixtures', 'test_2022-23_butler_student_survey_responses.csv')
end
let(:ay_2020_21) { create(:academic_year, range: "2020-21") }
let(:ay_2022_23) { create(:academic_year, range: "2022-23") }
let(:ay_2020_21) { create(:academic_year, range: '2020-21') }
let(:ay_2022_23) { create(:academic_year, range: '2022-23') }
let(:school) { create(:school, name: "Lee Elementary School", slug: "lee-elementary-school", dese_id: 1_500_025) }
let(:lowell) { create(:district, name: "Lowell", slug: "lowell") }
let(:second_school) { create(:school, name: "Lee Middle High School", slug: "lee-middle-high-school", dese_id: 1_500_505, district: lowell) }
let(:school) { create(:school, name: 'Lee Elementary School', slug: 'lee-elementary-school', dese_id: 1_500_025) }
let(:lowell) { create(:district, name: 'Lowell', slug: 'lowell') }
let(:second_school) do
create(:school, name: 'Lee Middle High School', slug: 'lee-middle-high-school', dese_id: 1_500_505,
district: lowell)
end
let(:butler_school) do
create(:school, name: "Butler Elementary School", slug: "butler-elementary-school", dese_id: 1_600_310,
district: lowell)
create(:school, name: 'Butler Elementary School', slug: 'butler-elementary-school', dese_id: 1_600_310,
district: lowell)
end
let(:t_pcom_q3) { create(:survey_item, survey_item_id: "t-pcom-q3") }
let(:t_pcom_q2) { create(:survey_item, survey_item_id: "t-pcom-q2") }
let(:t_coll_q1) { create(:survey_item, survey_item_id: "t-coll-q1") }
let(:t_coll_q2) { create(:survey_item, survey_item_id: "t-coll-q2") }
let(:t_coll_q3) { create(:survey_item, survey_item_id: "t-coll-q3") }
let(:t_sach_q1) { create(:survey_item, survey_item_id: "t-sach-q1") }
let(:t_sach_q2) { create(:survey_item, survey_item_id: "t-sach-q2") }
let(:t_sach_q3) { create(:survey_item, survey_item_id: "t-sach-q3") }
let(:s_phys_q1) { create(:survey_item, survey_item_id: "s-phys-q1") }
let(:s_phys_q2) { create(:survey_item, survey_item_id: "s-phys-q2") }
let(:s_phys_q3) { create(:survey_item, survey_item_id: "s-phys-q3") }
let(:s_phys_q4) { create(:survey_item, survey_item_id: "s-phys-q4") }
let(:s_vale_q1) { create(:survey_item, survey_item_id: "s-phys-q1") }
let(:s_vale_q2) { create(:survey_item, survey_item_id: "s-phys-q2") }
let(:s_vale_q3) { create(:survey_item, survey_item_id: "s-phys-q3") }
let(:s_vale_q4) { create(:survey_item, survey_item_id: "s-phys-q4") }
let(:s_acst_q1) { create(:survey_item, survey_item_id: "s-acst-q1") }
let(:s_acst_q2) { create(:survey_item, survey_item_id: "s-acst-q2") }
let(:s_acst_q3) { create(:survey_item, survey_item_id: "s-acst-q3") }
let(:s_acst_q4) { create(:survey_item, survey_item_id: "s-acst-q4") }
let(:s_emsa_q1) { create(:survey_item, survey_item_id: "s-emsa-q1") }
let(:s_emsa_q2) { create(:survey_item, survey_item_id: "s-emsa-q2") }
let(:s_emsa_q3) { create(:survey_item, survey_item_id: "s-emsa-q3") }
let(:t_pcom_q3) { create(:survey_item, survey_item_id: 't-pcom-q3') }
let(:t_pcom_q2) { create(:survey_item, survey_item_id: 't-pcom-q2') }
let(:t_coll_q1) { create(:survey_item, survey_item_id: 't-coll-q1') }
let(:t_coll_q2) { create(:survey_item, survey_item_id: 't-coll-q2') }
let(:t_coll_q3) { create(:survey_item, survey_item_id: 't-coll-q3') }
let(:t_sach_q1) { create(:survey_item, survey_item_id: 't-sach-q1') }
let(:t_sach_q2) { create(:survey_item, survey_item_id: 't-sach-q2') }
let(:t_sach_q3) { create(:survey_item, survey_item_id: 't-sach-q3') }
let(:s_phys_q1) { create(:survey_item, survey_item_id: 's-phys-q1') }
let(:s_phys_q2) { create(:survey_item, survey_item_id: 's-phys-q2') }
let(:s_phys_q3) { create(:survey_item, survey_item_id: 's-phys-q3') }
let(:s_phys_q4) { create(:survey_item, survey_item_id: 's-phys-q4') }
let(:s_vale_q1) { create(:survey_item, survey_item_id: 's-phys-q1') }
let(:s_vale_q2) { create(:survey_item, survey_item_id: 's-phys-q2') }
let(:s_vale_q3) { create(:survey_item, survey_item_id: 's-phys-q3') }
let(:s_vale_q4) { create(:survey_item, survey_item_id: 's-phys-q4') }
let(:s_acst_q1) { create(:survey_item, survey_item_id: 's-acst-q1') }
let(:s_acst_q2) { create(:survey_item, survey_item_id: 's-acst-q2') }
let(:s_acst_q3) { create(:survey_item, survey_item_id: 's-acst-q3') }
let(:s_acst_q4) { create(:survey_item, survey_item_id: 's-acst-q4') }
let(:s_emsa_q1) { create(:survey_item, survey_item_id: 's-emsa-q1') }
let(:s_emsa_q2) { create(:survey_item, survey_item_id: 's-emsa-q2') }
let(:s_emsa_q3) { create(:survey_item, survey_item_id: 's-emsa-q3') }
let(:female) { create(:gender, qualtrics_code: 1) }
let(:male) { create(:gender, qualtrics_code: 2) }
let(:another_gender) { create(:gender, qualtrics_code: 3) }
let(:non_binary) { create(:gender, qualtrics_code: 4) }
let(:unknown_gender) { create(:gender, qualtrics_code: 99) }
let(:low_income) { create(:income, designation: 'Economically Disadvantaged Y') }
let(:high_income) { create(:income, designation: 'Economically Disadvantaged N') }
let(:unknown_income) { create(:income, designation: 'Unknown') }
let(:setup) do
ay_2020_21
@ -83,18 +89,21 @@ describe SurveyResponsesDataLoader do
another_gender
non_binary
unknown_gender
low_income
high_income
unknown_income
end
before :each do
setup
end
describe "loading teacher survey responses" do
describe 'loading teacher survey responses' do
before do
SurveyResponsesDataLoader.load_data filepath: path_to_teacher_responses
end
it "ensures teacher responses load correctly" do
it 'ensures teacher responses load correctly' do
assigns_academic_year_to_survey_item_responses
assigns_school_to_the_survey_item_responses
assigns_recorded_date_to_teacher_responses
@ -105,12 +114,12 @@ describe SurveyResponsesDataLoader do
end
end
describe "student survey responses" do
describe 'student survey responses' do
before do
SurveyResponsesDataLoader.load_data filepath: path_to_student_responses
end
it "ensures student responses load correctly" do
it 'ensures student responses load correctly' do
assigns_academic_year_to_student_survey_item_responses
assigns_school_to_student_survey_item_responses
assigns_recorded_date_to_student_responses
@ -119,85 +128,86 @@ describe SurveyResponsesDataLoader do
captures_likert_scores_for_student_survey_item_responses
assigns_grade_level_to_responses
assigns_gender_to_responses
assigns_income_to_responses
is_idempotent_for_students
end
context "when updating student survey responses from another csv file" do
context 'when updating student survey responses from another csv file' do
before :each do
SurveyResponsesDataLoader.load_data filepath: Rails.root.join("spec", "fixtures",
"secondary_test_2020-21_student_survey_responses.csv")
SurveyResponsesDataLoader.load_data filepath: Rails.root.join('spec', 'fixtures',
'secondary_test_2020-21_student_survey_responses.csv')
end
it "updates the likert score to the score on the new csv file" do
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
expect(SurveyItemResponse.where(response_id: "student_survey_response_5",
survey_item: s_acst_q3).first.likert_score).to eq 4
it 'updates the likert score to the score on the new csv file' do
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
expect(SurveyItemResponse.where(response_id: 'student_survey_response_5',
survey_item: s_acst_q3).first.likert_score).to eq 4
end
end
end
# figure out why this is failing
describe "when using Lowell rules to skip rows in the csv file" do
describe 'when using Lowell rules to skip rows in the csv file' do
before :each do
SurveyResponsesDataLoader.load_data filepath: path_to_student_responses,
rules: [Rule::SkipNonLowellSchools]
rules: [Rule::SkipNonLowellSchools]
end
it "rejects any non-lowell school" do
expect(SurveyItemResponse.where(response_id: "student_survey_response_1").count).to eq 0
it 'rejects any non-lowell school' do
expect(SurveyItemResponse.where(response_id: 'student_survey_response_1').count).to eq 0
expect(SurveyItemResponse.count).to eq 69
end
it "loads the correct number of responses for lowell schools" do
expect(SurveyItemResponse.where(response_id: "student_survey_response_2").count).to eq 0
expect(SurveyItemResponse.where(response_id: "student_survey_response_3").count).to eq 12
expect(SurveyItemResponse.where(response_id: "student_survey_response_4").count).to eq 15
expect(SurveyItemResponse.where(response_id: "student_survey_response_5").count).to eq 14
it 'loads the correct number of responses for lowell schools' do
expect(SurveyItemResponse.where(response_id: 'student_survey_response_2').count).to eq 0
expect(SurveyItemResponse.where(response_id: 'student_survey_response_3').count).to eq 12
expect(SurveyItemResponse.where(response_id: 'student_survey_response_4').count).to eq 15
expect(SurveyItemResponse.where(response_id: 'student_survey_response_5').count).to eq 14
end
context "when loading 22-23 butler survey responses" do
context 'when loading 22-23 butler survey responses' do
before :each do
SurveyResponsesDataLoader.load_data filepath: path_to_butler_student_responses,
rules: [Rule::SkipNonLowellSchools]
rules: [Rule::SkipNonLowellSchools]
end
it "loads all the responses for Butler" do
it 'loads all the responses for Butler' do
expect(SurveyItemResponse.where(school: butler_school).count).to eq 56
end
it "blank entries for grade get loaded as nils, not zero values" do
expect(SurveyItemResponse.where(response_id: "butler_student_survey_response_1").first.grade).to eq 7
expect(SurveyItemResponse.where(response_id: "butler_student_survey_response_2").first.grade).to eq 7
expect(SurveyItemResponse.where(response_id: "butler_student_survey_response_3").first.grade).to eq 7
expect(SurveyItemResponse.where(response_id: "butler_student_survey_response_4").first.grade).to eq 5
expect(SurveyItemResponse.where(response_id: "butler_student_survey_response_5").first.grade).to eq 7
expect(SurveyItemResponse.where(response_id: "butler_student_survey_response_6").first.grade).to eq 6
expect(SurveyItemResponse.where(response_id: "butler_student_survey_response_7").first.grade).to eq nil
expect(SurveyItemResponse.where(response_id: "butler_student_survey_response_8").first.grade).to eq 0
it 'blank entries for grade get loaded as nils, not zero values' do
expect(SurveyItemResponse.where(response_id: 'butler_student_survey_response_1').first.grade).to eq 7
expect(SurveyItemResponse.where(response_id: 'butler_student_survey_response_2').first.grade).to eq 7
expect(SurveyItemResponse.where(response_id: 'butler_student_survey_response_3').first.grade).to eq 7
expect(SurveyItemResponse.where(response_id: 'butler_student_survey_response_4').first.grade).to eq 5
expect(SurveyItemResponse.where(response_id: 'butler_student_survey_response_5').first.grade).to eq 7
expect(SurveyItemResponse.where(response_id: 'butler_student_survey_response_6').first.grade).to eq 6
expect(SurveyItemResponse.where(response_id: 'butler_student_survey_response_7').first.grade).to eq nil
expect(SurveyItemResponse.where(response_id: 'butler_student_survey_response_8').first.grade).to eq 0
end
end
end
end
def assigns_academic_year_to_survey_item_responses
expect(SurveyItemResponse.find_by_response_id("teacher_survey_response_1").academic_year).to eq ay_2020_21
expect(SurveyItemResponse.find_by_response_id('teacher_survey_response_1').academic_year).to eq ay_2020_21
end
def assigns_school_to_the_survey_item_responses
expect(SurveyItemResponse.find_by_response_id("teacher_survey_response_1").school).to eq school
expect(SurveyItemResponse.find_by_response_id('teacher_survey_response_1').school).to eq school
end
def loads_survey_item_responses_for_a_given_survey_response
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_1").count).to eq 5
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_2").count).to eq 0
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_3").count).to eq 8
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_4").count).to eq 8
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_5").count).to eq 8
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_1').count).to eq 5
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_2').count).to eq 0
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_3').count).to eq 8
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_4').count).to eq 8
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_5').count).to eq 8
end
def loads_all_survey_item_responses_for_a_given_survey_item
@ -206,20 +216,20 @@ def loads_all_survey_item_responses_for_a_given_survey_item
end
def captures_likert_scores_for_survey_item_responses
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_1").where(survey_item: t_pcom_q2)).to be_empty
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_1").where(survey_item: t_pcom_q3).first.likert_score).to eq 3
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_1').where(survey_item: t_pcom_q2)).to be_empty
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_1').where(survey_item: t_pcom_q3).first.likert_score).to eq 3
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_2").where(survey_item: t_pcom_q2)).to be_empty
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_2").where(survey_item: t_pcom_q3)).to be_empty
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_2').where(survey_item: t_pcom_q2)).to be_empty
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_2').where(survey_item: t_pcom_q3)).to be_empty
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_3").where(survey_item: t_pcom_q2).first.likert_score).to eq 5
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_3").where(survey_item: t_pcom_q3).first.likert_score).to eq 5
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_3').where(survey_item: t_pcom_q2).first.likert_score).to eq 5
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_3').where(survey_item: t_pcom_q3).first.likert_score).to eq 5
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_4").where(survey_item: t_pcom_q2).first.likert_score).to eq 4
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_4").where(survey_item: t_pcom_q3).first.likert_score).to eq 4
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_4').where(survey_item: t_pcom_q2).first.likert_score).to eq 4
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_4').where(survey_item: t_pcom_q3).first.likert_score).to eq 4
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_5").where(survey_item: t_pcom_q2).first.likert_score).to eq 2
expect(SurveyItemResponse.where(response_id: "teacher_survey_response_5").where(survey_item: t_pcom_q3).first.likert_score).to eq 4
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_5').where(survey_item: t_pcom_q2).first.likert_score).to eq 2
expect(SurveyItemResponse.where(response_id: 'teacher_survey_response_5').where(survey_item: t_pcom_q3).first.likert_score).to eq 4
end
def is_idempotent
@ -231,19 +241,19 @@ def is_idempotent
end
def assigns_academic_year_to_student_survey_item_responses
expect(SurveyItemResponse.find_by_response_id("student_survey_response_3").academic_year).to eq ay_2020_21
expect(SurveyItemResponse.find_by_response_id('student_survey_response_3').academic_year).to eq ay_2020_21
end
def assigns_school_to_student_survey_item_responses
expect(SurveyItemResponse.find_by_response_id("student_survey_response_3").school).to eq second_school
expect(SurveyItemResponse.find_by_response_id('student_survey_response_3').school).to eq second_school
end
def loads_student_survey_item_response_values
expect(SurveyItemResponse.where(response_id: "student_survey_response_1").count).to eq 3
expect(SurveyItemResponse.where(response_id: "student_survey_response_2").count).to eq 0
expect(SurveyItemResponse.where(response_id: "student_survey_response_3").count).to eq 12
expect(SurveyItemResponse.where(response_id: "student_survey_response_4").count).to eq 15
expect(SurveyItemResponse.where(response_id: "student_survey_response_5").count).to eq 14
expect(SurveyItemResponse.where(response_id: 'student_survey_response_1').count).to eq 3
expect(SurveyItemResponse.where(response_id: 'student_survey_response_2').count).to eq 0
expect(SurveyItemResponse.where(response_id: 'student_survey_response_3').count).to eq 12
expect(SurveyItemResponse.where(response_id: 'student_survey_response_4').count).to eq 15
expect(SurveyItemResponse.where(response_id: 'student_survey_response_5').count).to eq 14
end
def student_survey_item_response_count_matches_expected
@ -252,20 +262,20 @@ def student_survey_item_response_count_matches_expected
end
def captures_likert_scores_for_student_survey_item_responses
expect(SurveyItemResponse.where(response_id: "student_survey_response_1").where(survey_item: s_phys_q1).first.likert_score).to eq 3
expect(SurveyItemResponse.where(response_id: "student_survey_response_1").where(survey_item: s_phys_q2)).to be_empty
expect(SurveyItemResponse.where(response_id: 'student_survey_response_1').where(survey_item: s_phys_q1).first.likert_score).to eq 3
expect(SurveyItemResponse.where(response_id: 'student_survey_response_1').where(survey_item: s_phys_q2)).to be_empty
expect(SurveyItemResponse.where(response_id: "student_survey_response_2").where(survey_item: s_phys_q1)).to be_empty
expect(SurveyItemResponse.where(response_id: "student_survey_response_2").where(survey_item: s_phys_q2)).to be_empty
expect(SurveyItemResponse.where(response_id: 'student_survey_response_2').where(survey_item: s_phys_q1)).to be_empty
expect(SurveyItemResponse.where(response_id: 'student_survey_response_2').where(survey_item: s_phys_q2)).to be_empty
expect(SurveyItemResponse.where(response_id: "student_survey_response_3").where(survey_item: s_phys_q1).first.likert_score).to eq 1
expect(SurveyItemResponse.where(response_id: "student_survey_response_3").where(survey_item: s_phys_q2).first.likert_score).to eq 3
expect(SurveyItemResponse.where(response_id: 'student_survey_response_3').where(survey_item: s_phys_q1).first.likert_score).to eq 1
expect(SurveyItemResponse.where(response_id: 'student_survey_response_3').where(survey_item: s_phys_q2).first.likert_score).to eq 3
expect(SurveyItemResponse.where(response_id: "student_survey_response_4").where(survey_item: s_phys_q1).first.likert_score).to eq 1
expect(SurveyItemResponse.where(response_id: "student_survey_response_4").where(survey_item: s_phys_q2).first.likert_score).to eq 1
expect(SurveyItemResponse.where(response_id: 'student_survey_response_4').where(survey_item: s_phys_q1).first.likert_score).to eq 1
expect(SurveyItemResponse.where(response_id: 'student_survey_response_4').where(survey_item: s_phys_q2).first.likert_score).to eq 1
expect(SurveyItemResponse.where(response_id: "student_survey_response_5").where(survey_item: s_phys_q1).first.likert_score).to eq 1
expect(SurveyItemResponse.where(response_id: "student_survey_response_5").where(survey_item: s_phys_q2).first.likert_score).to eq 2
expect(SurveyItemResponse.where(response_id: 'student_survey_response_5').where(survey_item: s_phys_q1).first.likert_score).to eq 1
expect(SurveyItemResponse.where(response_id: 'student_survey_response_5').where(survey_item: s_phys_q2).first.likert_score).to eq 2
end
def is_idempotent_for_students
@ -277,26 +287,26 @@ def is_idempotent_for_students
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 = { '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
response.grade == value
end).to eq true
end
end
def assigns_gender_to_responses
results = {"student_survey_response_1" => female,
"student_survey_response_3" => male,
"student_survey_response_4" => non_binary,
"student_survey_response_5" => non_binary,
"student_survey_response_6" => unknown_gender,
"student_survey_response_7" => unknown_gender}
results = { 'student_survey_response_1' => female,
'student_survey_response_3' => male,
'student_survey_response_4' => non_binary,
'student_survey_response_5' => non_binary,
'student_survey_response_6' => unknown_gender,
'student_survey_response_7' => unknown_gender }
results.each do |key, value|
expect(SurveyItemResponse.where(response_id: key).first.gender).to eq value
@ -304,23 +314,36 @@ def assigns_gender_to_responses
end
def assigns_recorded_date_to_student_responses
results = {"student_survey_response_1" => "2020-09-30T18:48:50",
"student_survey_response_3" => "2021-03-31T09:59:02",
"student_survey_response_4" => "2021-03-31T10:00:17",
"student_survey_response_5" => "2021-03-31T10:01:36",
"student_survey_response_6" => "2021-03-31T10:01:37",
"student_survey_response_7" => "2021-03-31T10:01:38"}
results = { 'student_survey_response_1' => '2020-09-30T18:48:50',
'student_survey_response_3' => '2021-03-31T09:59:02',
'student_survey_response_4' => '2021-03-31T10:00:17',
'student_survey_response_5' => '2021-03-31T10:01:36',
'student_survey_response_6' => '2021-03-31T10:01:37',
'student_survey_response_7' => '2021-03-31T10:01:38' }
results.each do |key, value|
expect(SurveyItemResponse.find_by_response_id(key).recorded_date).to eq Date.parse(value)
end
end
def assigns_recorded_date_to_teacher_responses
results = {"teacher_survey_response_1" => "2020-10-16 11:09:03",
"teacher_survey_response_3" => "2020-12-06 8:36:52",
"teacher_survey_response_4" => "2020-12-06 8:51:25",
"teacher_survey_response_5" => "2020-12-06 8:55:58"}
results = { 'teacher_survey_response_1' => '2020-10-16 11:09:03',
'teacher_survey_response_3' => '2020-12-06 8:36:52',
'teacher_survey_response_4' => '2020-12-06 8:51:25',
'teacher_survey_response_5' => '2020-12-06 8:55:58' }
results.each do |key, value|
expect(SurveyItemResponse.find_by_response_id(key).recorded_date).to eq Date.parse(value)
end
end
def assigns_income_to_responses
results = { 'student_survey_response_1' => low_income,
'student_survey_response_3' => low_income,
'student_survey_response_4' => unknown_income,
'student_survey_response_5' => low_income,
'student_survey_response_6' => high_income,
'student_survey_response_7' => low_income }
results.each do |key, value|
expect(SurveyItemResponse.where(response_id: key).first.income).to eq value
end
end

@ -1,25 +1,20 @@
require 'rails_helper'
require "rails_helper"
include AnalyzeHelper
include Analyze::Graph
describe 'analyze/index' do
describe "analyze/index" do
subject { Nokogiri::HTML(rendered) }
let(:category) { create(:category) }
let(:subcategory) { create(:subcategory, category:) }
let(:school) { create(:school) }
let(:academic_year) { create(:academic_year) }
let(:races) do
DemographicLoader.load_data(filepath: 'spec/fixtures/sample_demographics.csv')
DemographicLoader.load_data(filepath: "spec/fixtures/sample_demographics.csv")
Race.all
end
let(:graph) { StudentsAndTeachers.new }
let(:graphs) do
[StudentsAndTeachers.new, StudentsByRace.new(races:)]
end
let(:background) { BackgroundPresenter.new(num_of_columns: graph.columns.count) }
let(:selected_races) { races }
let(:support_for_teaching) do
measure = create(:measure, name: 'Support For Teaching Development & Growth', measure_id: '1A-I', subcategory:)
measure = create(:measure, name: "Support For Teaching Development & Growth", measure_id: "1A-I", subcategory:)
scale = create(:scale, measure:)
create(:student_survey_item,
scale:,
@ -31,7 +26,7 @@ describe 'analyze/index' do
end
let(:effective_leadership) do
measure = create(:measure, name: 'Effective Leadership', measure_id: '1A-II', subcategory:)
measure = create(:measure, name: "Effective Leadership", measure_id: "1A-II", subcategory:)
scale = create(:scale, measure:)
create(:teacher_survey_item,
scale:,
@ -43,7 +38,7 @@ describe 'analyze/index' do
end
let(:professional_qualifications) do
measure = create(:measure, name: 'Professional Qualifications', measure_id: '1A-III', subcategory:)
measure = create(:measure, name: "Professional Qualifications", measure_id: "1A-III", subcategory:)
scale = create(:scale, measure:)
create(:admin_data_item,
scale:,
@ -54,73 +49,30 @@ describe 'analyze/index' do
measure
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(:genders) do
DemographicLoader.load_data(filepath: 'spec/fixtures/sample_demographics.csv')
DemographicLoader.load_data(filepath: "spec/fixtures/sample_demographics.csv")
Gender.all
end
let(:selected_genders) do
genders
end
let(:selected_grades) do
grades
end
let(:respondent) { create(:respondent, school:, academic_year:) }
before :each do
assign :races, races
assign :selected_races, selected_races
assign :graph, graph
assign :graphs, graphs
assign :background, background
races
category
subcategory
support_for_teaching
effective_leadership
professional_qualifications
respondent
assign :academic_year, academic_year
assign :available_academic_years, [academic_year]
assign :selected_academic_years, [academic_year]
assign :district, create(:district)
assign :school, school
assign :category, category
assign :categories, [category]
assign :subcategory, subcategory
assign :subcategories, category.subcategories
assign :measures, [support_for_teaching, effective_leadership, professional_qualifications]
assign :sources, sources
assign :source, sources.first
assign :groups, groups
assign :group, group
assign :slice, slice
assign :grades, grades
assign :selected_grades, selected_grades
assign :genders, genders
assign :selected_genders, selected_genders
create(:respondent, school:, academic_year:)
assign :presenter,
Analyze::Presenter.new(school:, academic_year:,
params: { category: category.category_id, subcategory: subcategory.subcategory_id, races: "american-indian-or-alaskan-native,asian-or-pacific-islander,black-or-african-american,hispanic-or-latinx,middle-eastern,multiracial,race-ethnicity-not-listed,white-or-caucasian", source: "survey-data-only", slice: "students-and-teachers", group: "race", graph: "students-by-race" })
assign :background, BackgroundPresenter.new(num_of_columns: 4)
end
context 'when all the presenters have a nil score' do
context "when all the presenters have a nil score" do
before do
render
end
@ -139,63 +91,72 @@ describe 'analyze/index' do
# ]
# end
it 'displays a set of grouped bars for each presenter' do
displayed_variance_columns = subject.css('.grouped-bar-column')
expect(displayed_variance_columns.count).to eq 9
it "displays a set of grouped bars for each presenter" do
displayed_variance_columns = subject.css(".grouped-bar-column")
expect(displayed_variance_columns.count).to eq 27
displayed_variance_rows = subject.css('[data-for-measure-id]')
expect(displayed_variance_rows.first.attribute('data-for-measure-id').value).to eq '1A-I'
displayed_variance_rows = subject.css("[data-for-measure-id]")
expect(displayed_variance_rows.first.attribute("data-for-measure-id").value).to eq "1A-I"
displayed_academic_years = subject.css('[data-for-academic-year]')
displayed_academic_years = subject.css("[data-for-academic-year]")
expect(displayed_academic_years.count).to eq 0
displayed_variance_labels = subject.css('[data-grouped-bar-label]')
expect(displayed_variance_labels.count).to eq 18
expect(displayed_variance_labels.first.inner_text).to include 'All'
expect(displayed_variance_labels[1].inner_text).to include 'Students'
expect(displayed_variance_labels.last.inner_text).to include 'Data'
displayed_variance_labels = subject.css("[data-grouped-bar-label]")
expect(displayed_variance_labels.count).to eq 39
expect(displayed_variance_labels.first.inner_text).to include "American"
expect(displayed_variance_labels.text).to include "Indian"
expect(displayed_variance_labels.text).to include "Asian"
expect(displayed_variance_labels.text).to include "Black"
expect(displayed_variance_labels.text).to include "White"
expect(displayed_variance_labels.text).to include "Hispanic"
expect(displayed_variance_labels.text).to include "Middle"
expect(displayed_variance_labels.text).to include "Eastern"
expect(displayed_variance_labels.text).to include "Multiracial"
expect(displayed_variance_labels.text).to include "Not"
expect(displayed_variance_labels.text).to include "Listed"
end
it 'displays all measures for the first subcategory' do
expect(rendered).to have_text '1A-I'
expect(rendered).to have_text '1A-II'
expect(rendered).to have_text '1A-III'
it "displays all measures for the first subcategory" do
expect(rendered).to have_text "1A-I"
expect(rendered).to have_text "1A-II"
expect(rendered).to have_text "1A-III"
end
it 'displays user interface controls' do
expect(subject).to have_text 'Focus Area'
expect(subject).to have_css '#select-category'
expect(subject).to have_css '#select-subcategory'
it "displays user interface controls" do
expect(subject).to have_text "Focus Area"
expect(subject).to have_css "#select-category"
expect(subject).to have_css "#select-subcategory"
expect(subject).to have_css "##{academic_year.range}"
end
it 'displays disabled checkboxes for years that dont have data' do
it "displays disabled checkboxes for years that dont have data" do
year_checkbox = subject.css("##{academic_year.range}").first
expect(year_checkbox.name).to eq 'input'
expect(academic_year.range).to eq '2050-51'
expect(year_checkbox).to have_attribute 'disabled'
expect(year_checkbox.name).to eq "input"
expect(academic_year.range).to eq "2050-51"
expect(year_checkbox).to have_attribute "disabled"
end
it 'displays a radio box selector for each type of data filter' do
expect(subject).to have_css '#students-and-teachers'
expect(subject).to have_css '#students-by-group'
it "displays a radio box selector for each type of data filter" do
expect(subject).to have_css "#students-and-teachers"
expect(subject).to have_css "#students-by-group"
end
it 'displays a checkbox for each race designation' do
race_slugs = %w[american-indian-or-alaskan-native asian-or-pacific-islander black-or-african-american
hispanic-or-latinx middle-eastern multiracial race-ethnicity-not-listed white-or-caucasian]
it "displays a checkbox for each race designation" do
race_slugs = %w[race-american-indian-or-alaskan-native race-asian-or-pacific-islander race-black-or-african-american
race-hispanic-or-latinx race-middle-eastern race-multiracial race-race-ethnicity-not-listed race-white-or-caucasian]
race_slugs.each do |slug|
expect(subject).to have_css("//input[@type='checkbox'][@id='#{slug}']")
end
end
end
context 'when presenters have a displayable score' do
context "when presenters have a displayable score" do
before do
render
end
context 'when displaying a student and teacher graph' do
context "when displaying a student and teacher graph" do
end
end
end

@ -3254,7 +3254,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.2:
semver@^7.3.2, semver@^7.5.2:
version "7.5.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==

Loading…
Cancel
Save