mirror of
https://github.com/edcommonwealth/sqm-dashboards.git
synced 2026-03-07 21:48:16 -08:00
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
This commit is contained in:
parent
7e1be4860c
commit
4f035f6a63
45 changed files with 1494 additions and 856 deletions
|
|
@ -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
|
||||
selected_items(type) {
|
||||
let checkboxes = [...document.getElementsByName(`${type}-checkbox`)]
|
||||
let items = checkboxes
|
||||
.filter((item) => {
|
||||
return item.checked;
|
||||
})
|
||||
.map((item) => {
|
||||
return item.id;
|
||||
return item.id.replace(`${type}-`, '');
|
||||
});
|
||||
|
||||
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
|
||||
.filter((item) => {
|
||||
return item.checked;
|
||||
})
|
||||
.map((item) => {
|
||||
return item.id.replace('gender-', '');
|
||||
});
|
||||
|
||||
return genders;
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
7
app/models/income.rb
Normal file
7
app/models/income.rb
Normal file
|
|
@ -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
|
||||
|
|
|
|||
85
app/presenters/analyze/bar_presenter.rb
Normal file
85
app/presenters/analyze/bar_presenter.rb
Normal file
|
|
@ -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,7 +27,7 @@ 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,
|
||||
Analyze::BarPresenter.new(measure:, academic_year: year,
|
||||
score: yearly_score.score,
|
||||
x_position: bar_x(index),
|
||||
color: bar_color(year))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
28
app/presenters/analyze/graph/column/income_column/unknown.rb
Normal file
28
app/presenters/analyze/graph/column/income_column/unknown.rb
Normal file
|
|
@ -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
|
||||
40
app/presenters/analyze/graph/students_by_income.rb
Normal file
40
app/presenters/analyze/graph/students_by_income.rb
Normal file
|
|
@ -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
|
||||
13
app/presenters/analyze/group/income.rb
Normal file
13
app/presenters/analyze/group/income.rb
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
module Analyze
|
||||
module Group
|
||||
class Income
|
||||
def name
|
||||
'Income'
|
||||
end
|
||||
|
||||
def slug
|
||||
'income'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
159
app/presenters/analyze/presenter.rb
Normal file
159
app/presenters/analyze/presenter.rb
Normal file
|
|
@ -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
|
||||
|
||||
|
|
|
|||
17
app/views/analyze/_checkboxes.html.erb
Normal file
17
app/views/analyze/_checkboxes.html.erb
Normal file
|
|
@ -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" %>>
|
||||
|
||||
<label for="gender-<%= gender %>"
|
||||
<%= @group.slug == 'gender' ? "" : "hidden" %>>
|
||||
<%= gender.designation %>
|
||||
</label>
|
||||
</div>
|
||||
<% @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 %>
|
||||
|
||||
<% @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,,,
|
||||
|
|
|
|||
|
9
db/migrate/20230620221633_create_incomes.rb
Normal file
9
db/migrate/20230620221633_create_incomes.rb
Normal file
|
|
@ -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
|
||||
6
db/migrate/20230630215110_add_slug_to_income.rb
Normal file
6
db/migrate/20230630215110_add_slug_to_income.rb
Normal file
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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' }
|
||||
|
|
|
|||
22
spec/fixtures/sample_demographics.csv
vendored
22
spec/fixtures/sample_demographics.csv
vendored
|
|
@ -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,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",,,,,
|
||||
|
|
|
|||
|
5
spec/models/income_spec.rb
Normal file
5
spec/models/income_spec.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Income, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
||||
468
spec/presenters/analyze/presenter_spec.rb
Normal file
468
spec/presenters/analyze/presenter_spec.rb
Normal file
|
|
@ -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,30 +1,30 @@
|
|||
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
|
||||
|
|
@ -42,9 +42,9 @@ 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",
|
||||
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:)
|
||||
|
|
@ -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
|
||||
|
|
@ -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,235 +163,235 @@ 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"}
|
||||
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"
|
||||
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"}
|
||||
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"
|
||||
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"}
|
||||
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"
|
||||
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"}
|
||||
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"
|
||||
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" => ""}
|
||||
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"
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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:,
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
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(: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(: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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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]
|
||||
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]
|
||||
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,12 +287,12 @@ 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
|
||||
|
|
@ -291,12 +301,12 @@ def assigns_grade_level_to_responses
|
|||
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…
Add table
Add a link
Reference in a new issue