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
|
Enabled: false
|
||||||
|
|
||||||
Style/StringLiterals:
|
Style/StringLiterals:
|
||||||
EnforcedStyle: single_quotes
|
EnforcedStyle: double_quotes
|
||||||
|
|
|
||||||
|
|
@ -1,172 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AnalyzeController < SqmApplicationController
|
class AnalyzeController < SqmApplicationController
|
||||||
before_action :assign_categories, :assign_subcategories, :assign_measures, :assign_academic_years,
|
def index
|
||||||
:races, :selected_races, :graph, :graphs, :background, :race_score_timestamp,
|
@presenter = Analyze::Presenter.new(params:, school: @school, academic_year: @academic_year)
|
||||||
:source, :sources, :group, :groups, :selected_grades, :grades, :slice, :selected_genders, :genders, only: [:index]
|
@background ||= BackgroundPresenter.new(num_of_columns: @presenter.graph.columns.count)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ module AnalyzeHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def base_url
|
def base_url
|
||||||
analyze_subcategory_link(district: @district, school: @school, academic_year: @academic_year, category: @category,
|
analyze_subcategory_link(district: @district, school: @school, academic_year: @academic_year, category: @presenter.category,
|
||||||
subcategory: @subcategory)
|
subcategory: @presenter.subcategory)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -22,16 +22,17 @@ export default class extends Controller {
|
||||||
"&graph=" +
|
"&graph=" +
|
||||||
this.selected_graph(target) +
|
this.selected_graph(target) +
|
||||||
"&races=" +
|
"&races=" +
|
||||||
this.selected_races().join(",") +
|
this.selected_items("race").join(",") +
|
||||||
"&genders=" +
|
"&genders=" +
|
||||||
this.selected_genders().join(",") +
|
this.selected_items("gender").join(",") +
|
||||||
|
"&incomes=" +
|
||||||
|
this.selected_items("income").join(",") +
|
||||||
"&grades=" +
|
"&grades=" +
|
||||||
this.selected_grades().join(",");
|
this.selected_items("grade").join(",");
|
||||||
|
|
||||||
this.go_to(url);
|
this.go_to(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
go_to(location) {
|
go_to(location) {
|
||||||
window.location = location;
|
window.location = location;
|
||||||
}
|
}
|
||||||
|
|
@ -121,58 +122,34 @@ export default class extends Controller {
|
||||||
return item.id;
|
return item.id;
|
||||||
})[0];
|
})[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 (target.name === 'slice' || target.name === 'group') {
|
||||||
if (selected_slice === 'students-and-teachers') {
|
if (selected_slice === 'students-and-teachers') {
|
||||||
return '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;
|
return window.graph;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selected_races() {
|
selected_items(type) {
|
||||||
let race_checkboxes = [...document.getElementsByName("race-checkbox")]
|
let checkboxes = [...document.getElementsByName(`${type}-checkbox`)]
|
||||||
let races = race_checkboxes
|
let items = checkboxes
|
||||||
.filter((item) => {
|
.filter((item) => {
|
||||||
return item.checked;
|
return item.checked;
|
||||||
})
|
})
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return item.id;
|
return item.id.replace(`${type}-`, '');
|
||||||
});
|
});
|
||||||
|
|
||||||
return races;
|
return items;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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 :survey_item, counter_cache: true
|
||||||
belongs_to :student, foreign_key: :student_id, optional: true
|
belongs_to :student, foreign_key: :student_id, optional: true
|
||||||
belongs_to :gender
|
belongs_to :gender
|
||||||
|
belongs_to :income
|
||||||
|
|
||||||
has_one :measure, through: :survey_item
|
has_one :measure, through: :survey_item
|
||||||
|
|
||||||
|
|
@ -25,4 +26,9 @@ class SurveyItemResponse < ActiveRecord::Base
|
||||||
SurveyItemResponse.where(survey_item: survey_items, school:,
|
SurveyItemResponse.where(survey_item: survey_items, school:,
|
||||||
academic_year:, gender:).group(:survey_item).average(:likert_score)
|
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
|
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,10 +27,10 @@ module Analyze
|
||||||
def bars
|
def bars
|
||||||
@bars ||= yearly_scores.map.each_with_index do |yearly_score, index|
|
@bars ||= yearly_scores.map.each_with_index do |yearly_score, index|
|
||||||
year = yearly_score.year
|
year = yearly_score.year
|
||||||
AnalyzeBarPresenter.new(measure:, academic_year: year,
|
Analyze::BarPresenter.new(measure:, academic_year: year,
|
||||||
score: yearly_score.score,
|
score: yearly_score.score,
|
||||||
x_position: bar_x(index),
|
x_position: bar_x(index),
|
||||||
color: bar_color(year))
|
color: bar_color(year))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Analyze
|
||||||
|
module Graph
|
||||||
|
module Column
|
||||||
|
module IncomeColumn
|
||||||
|
class Disadvantaged < GroupedBarColumnPresenter
|
||||||
|
include Analyze::Graph::Column::IncomeColumn::ScoreForIncome
|
||||||
|
def label
|
||||||
|
"Economically Disadvantaged"
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_irrelevancy_message?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_insufficient_data_message?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def income
|
||||||
|
Income.find_by_designation "Economically Disadvantaged - Y"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Analyze
|
||||||
|
module Graph
|
||||||
|
module Column
|
||||||
|
module IncomeColumn
|
||||||
|
class NotDisadvantaged < GroupedBarColumnPresenter
|
||||||
|
include Analyze::Graph::Column::IncomeColumn::ScoreForIncome
|
||||||
|
def label
|
||||||
|
"Not Disadvantaged"
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_irrelevancy_message?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_insufficient_data_message?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def income
|
||||||
|
Income.find_by_designation "Economically Disadvantaged - N"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
module Analyze
|
||||||
|
module Graph
|
||||||
|
module Column
|
||||||
|
module IncomeColumn
|
||||||
|
module ScoreForIncome
|
||||||
|
def score(year_index)
|
||||||
|
academic_year = academic_years[year_index]
|
||||||
|
averages = SurveyItemResponse.averages_for_income(measure.student_survey_items, school, academic_year,
|
||||||
|
income)
|
||||||
|
average = bubble_up_averages(averages:).round(2)
|
||||||
|
|
||||||
|
scorify(average:, meets_student_threshold: sufficient_student_responses?(academic_year:))
|
||||||
|
end
|
||||||
|
|
||||||
|
def bubble_up_averages(averages:)
|
||||||
|
measure.student_scales.map do |scale|
|
||||||
|
scale.survey_items.map do |survey_item|
|
||||||
|
averages[survey_item]
|
||||||
|
end.remove_blanks.average
|
||||||
|
end.remove_blanks.average
|
||||||
|
end
|
||||||
|
|
||||||
|
def scorify(average:, meets_student_threshold:)
|
||||||
|
return Score::NIL_SCORE unless meets_student_threshold
|
||||||
|
|
||||||
|
Score.new(average:,
|
||||||
|
meets_teacher_threshold: false,
|
||||||
|
meets_student_threshold: true,
|
||||||
|
meets_admin_data_threshold: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def sufficient_student_responses?(academic_year:)
|
||||||
|
yearly_counts = SurveyItemResponse.where(school:, academic_year:,
|
||||||
|
income:, survey_item: measure.student_survey_items).group(:income).select(:response_id).distinct(:response_id).count
|
||||||
|
yearly_counts.any? do |count|
|
||||||
|
count[1] >= 10
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
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|
|
CSV.parse(File.read(filepath), headers: true) do |row|
|
||||||
process_race(row:)
|
process_race(row:)
|
||||||
process_gender(row:)
|
process_gender(row:)
|
||||||
|
process_income(row:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -28,6 +29,13 @@ class DemographicLoader
|
||||||
gender = ::Gender.find_or_create_by!(qualtrics_code:, designation:)
|
gender = ::Gender.find_or_create_by!(qualtrics_code:, designation:)
|
||||||
gender.save
|
gender.save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.process_income(row:)
|
||||||
|
designation = row['Income']
|
||||||
|
return unless designation
|
||||||
|
|
||||||
|
Income.find_or_create_by!(designation:)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class KnownRace
|
class KnownRace
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,9 @@ class SurveyItemValues
|
||||||
end
|
end
|
||||||
|
|
||||||
def raw_income
|
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?
|
return 'Unknown' unless disaggregation_data.present?
|
||||||
|
|
||||||
disaggregation = disaggregation_data[[lasid, district.name, academic_year.range]]
|
disaggregation = disaggregation_data[[lasid, district.name, academic_year.range]]
|
||||||
|
|
@ -109,6 +111,9 @@ class SurveyItemValues
|
||||||
end
|
end
|
||||||
|
|
||||||
def income
|
def income
|
||||||
|
@income ||= value_from(pattern: /^Income$/i)
|
||||||
|
return @income if @income.present?
|
||||||
|
|
||||||
@income ||= case raw_income
|
@income ||= case raw_income
|
||||||
in /Free\s*Lunch|Reduced\s*Lunch|Low\s*Income/i
|
in /Free\s*Lunch|Reduced\s*Lunch|Low\s*Income/i
|
||||||
'Economically Disadvantaged - Y'
|
'Economically Disadvantaged - Y'
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,13 @@ class SurveyResponsesDataLoader
|
||||||
headers_array = CSV.parse(headers).first
|
headers_array = CSV.parse(headers).first
|
||||||
genders = Gender.gender_hash
|
genders = Gender.gender_hash
|
||||||
schools = School.school_hash
|
schools = School.school_hash
|
||||||
|
incomes = Income.by_designation
|
||||||
all_survey_items = survey_items(headers:)
|
all_survey_items = survey_items(headers:)
|
||||||
|
|
||||||
file.lazy.each_slice(500) do |lines|
|
file.lazy.each_slice(500) do |lines|
|
||||||
survey_item_responses = CSV.parse(lines.join, headers:).map do |row|
|
survey_item_responses = CSV.parse(lines.join, headers:).map do |row|
|
||||||
process_row(row: SurveyItemValues.new(row:, headers: headers_array, genders:, survey_items: all_survey_items, schools:),
|
process_row(row: SurveyItemValues.new(row:, headers: headers_array, genders:, survey_items: all_survey_items, schools:),
|
||||||
rules:)
|
rules:, incomes:)
|
||||||
end
|
end
|
||||||
SurveyItemResponse.import survey_item_responses.compact.flatten, batch_size: 500
|
SurveyItemResponse.import survey_item_responses.compact.flatten, batch_size: 500
|
||||||
end
|
end
|
||||||
|
|
@ -24,6 +25,7 @@ class SurveyResponsesDataLoader
|
||||||
headers_array = CSV.parse(headers).first
|
headers_array = CSV.parse(headers).first
|
||||||
genders = Gender.gender_hash
|
genders = Gender.gender_hash
|
||||||
schools = School.school_hash
|
schools = School.school_hash
|
||||||
|
incomes = Income.by_designation
|
||||||
all_survey_items = survey_items(headers:)
|
all_survey_items = survey_items(headers:)
|
||||||
|
|
||||||
survey_item_responses = []
|
survey_item_responses = []
|
||||||
|
|
@ -34,7 +36,7 @@ class SurveyResponsesDataLoader
|
||||||
|
|
||||||
CSV.parse(line, headers:).map do |row|
|
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:),
|
survey_item_responses << process_row(row: SurveyItemValues.new(row:, headers: headers_array, genders:, survey_items: all_survey_items, schools:),
|
||||||
rules:)
|
rules:, incomes:)
|
||||||
end
|
end
|
||||||
|
|
||||||
row_count += 1
|
row_count += 1
|
||||||
|
|
@ -50,7 +52,7 @@ class SurveyResponsesDataLoader
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def self.process_row(row:, rules:)
|
def self.process_row(row:, rules:, incomes:)
|
||||||
return unless row.dese_id?
|
return unless row.dese_id?
|
||||||
return unless row.school.present?
|
return unless row.school.present?
|
||||||
|
|
||||||
|
|
@ -58,10 +60,10 @@ class SurveyResponsesDataLoader
|
||||||
return if rule.new(row:).skip_row?
|
return if rule.new(row:).skip_row?
|
||||||
end
|
end
|
||||||
|
|
||||||
process_survey_items(row:)
|
process_survey_items(row:, incomes:)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.process_survey_items(row:)
|
def self.process_survey_items(row:, incomes:)
|
||||||
row.survey_items.map do |survey_item|
|
row.survey_items.map do |survey_item|
|
||||||
likert_score = row.likert_score(survey_item_id: survey_item.survey_item_id) || next
|
likert_score = row.likert_score(survey_item_id: survey_item.survey_item_id) || next
|
||||||
|
|
||||||
|
|
@ -70,19 +72,20 @@ class SurveyResponsesDataLoader
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
response = row.survey_item_response(survey_item:)
|
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.compact
|
||||||
end
|
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
|
gender = row.gender
|
||||||
grade = row.grade
|
grade = row.grade
|
||||||
|
income = incomes[row.income]
|
||||||
if survey_item_response.present?
|
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
|
else
|
||||||
SurveyItemResponse.new(response_id: row.response_id, academic_year: row.academic_year, school: row.school, survey_item:,
|
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
|
||||||
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>
|
<h3 class="sub-header-4 mt-5">Data Filters</h3>
|
||||||
<div class="bg-gray p-3" data-controller="analyze">
|
<div class="bg-gray p-3" data-controller="analyze">
|
||||||
|
|
||||||
<% @sources.each do |source| %>
|
<% @presenter.sources.each do |source| %>
|
||||||
|
|
||||||
<input type="radio"
|
<input type="radio"
|
||||||
id="<%= source.slug %>"
|
id="<%= source.slug %>"
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
name="source"
|
name="source"
|
||||||
value="<%= base_url %>"
|
value="<%= base_url %>"
|
||||||
data-action="click->analyze#refresh"
|
data-action="click->analyze#refresh"
|
||||||
<%= source.slug == @source.slug ? "checked" : "" %>>
|
<%= source.slug == @presenter.source.slug ? "checked" : "" %>>
|
||||||
<label for="<%= source.slug %>"><%= source.to_s %></label>
|
<label for="<%= source.slug %>"><%= source.to_s %></label>
|
||||||
|
|
||||||
<% source.slices.each do | slice | %>
|
<% source.slices.each do | slice | %>
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
name="slice"
|
name="slice"
|
||||||
value="<%= base_url %>"
|
value="<%= base_url %>"
|
||||||
data-action="click->analyze#refresh"
|
data-action="click->analyze#refresh"
|
||||||
<%= slice.slug == @slice.slug ? "checked" : "" %>
|
<%= slice.slug == @presenter.slice.slug ? "checked" : "" %>
|
||||||
<%= slice.slug == "all-data" ? "hidden" : "" %>>
|
<%= slice.slug == "all-data" ? "hidden" : "" %>>
|
||||||
|
|
||||||
<label for="<%= slice.slug %>"
|
<label for="<%= slice.slug %>"
|
||||||
|
|
@ -34,8 +34,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.source = "<%= @source.slug %>";
|
window.source = "<%= @presenter.source.slug %>";
|
||||||
window.slice = "<%= @slice.slug %>";
|
window.slice = "<%= @presenter.slice.slug %>";
|
||||||
window.group = "<%= @group.slug %>";
|
window.group = "<%= @presenter.group.slug %>";
|
||||||
window.graph = "<%= @graph.slug %>";
|
window.graph = "<%= @presenter.graph.slug %>";
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
<p>Select a category & subcategory to analyze measure-level results</p>
|
<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">
|
<select id="select-category" class="mx-3 form-select" data-id="category-dropdown" data-action="analyze#refresh">
|
||||||
<% categories.each do |category| %>
|
<% 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 %>
|
<% end %>
|
||||||
</select>
|
</select>
|
||||||
<select id="select-subcategory" class="mx-3 form-select mt-3" data-id="subcategory-dropdown" data-action="analyze#refresh">
|
<select id="select-subcategory" class="mx-3 form-select mt-3" data-id="subcategory-dropdown" data-action="analyze#refresh">
|
||||||
<% subcategories.each do |subcategory| %>
|
<% 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}" %>
|
<%= "#{subcategory.subcategory_id}: #{subcategory.name}" %>
|
||||||
</option>
|
</option>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,23 @@
|
||||||
<select id="select-group" name="group" class="mx-4 form-select" data-id="group-dropdown" data-action="analyze#refresh">
|
<select id="select-group" name="group" class="mx-4 form-select" data-id="group-dropdown" data-action="analyze#refresh">
|
||||||
<% @groups.each do |group| %>
|
<% @presenter.groups.each do |group| %>
|
||||||
<option id="<%= group.slug %>" name="group-option" value="<%= base_url %>" <%= group.slug == @group.slug ? "Selected": "" %>><%= group.name %> </option>
|
<option id="<%= group.slug %>" name="group-option" value="<%= base_url %>" <%= group.slug == @presenter.group.slug ? "Selected": "" %>><%= group.name %> </option>
|
||||||
<% end %>
|
<% end %>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<p class="sub-header-5 mx-4 mt-3 font-size-14"> Select a group </p>
|
<p class="sub-header-5 mx-4 mt-3 font-size-14"> Select a group </p>
|
||||||
|
|
||||||
<% @races.each do |race| %>
|
<% @presenter.races.each do |race| %>
|
||||||
<div class="d-flex align-items-center mx-5">
|
<%= render(partial: "checkboxes", locals: {id: "race-#{race.slug}", item: race, selected_items: @presenter.selected_races, name: "race", label_text: race.designation}) %>
|
||||||
<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>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% @grades.each do |grade| %>
|
<% @presenter.grades.each do |grade| %>
|
||||||
<div class="d-flex align-items-center mx-5">
|
<%= render(partial: "checkboxes", locals: {id: "grade-#{grade}", item: grade, selected_items: @presenter.selected_grades, name: "grade", label_text: grade}) %>
|
||||||
<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>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% @genders.each do |gender| %>
|
<% @presenter.genders.each do |gender| %>
|
||||||
<div class="d-flex align-items-center mx-5">
|
<%= render(partial: "checkboxes", locals: {id: "gender-#{gender.designation}", item: gender, selected_items: @presenter.selected_genders, name: "gender", label_text: gender.designation}) %>
|
||||||
<input
|
<% end %>
|
||||||
id="gender-<%= gender.designation %>"
|
|
||||||
class="m-3 gender-checkbox form-check-input"
|
<% @presenter.incomes.each do |income| %>
|
||||||
type="checkbox"
|
<%= render(partial: "checkboxes", locals: {id: "income-#{income.slug}", item: income, selected_items: @presenter.selected_incomes, name: "income", label_text: income.designation}) %>
|
||||||
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>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<svg width="100%" height="<%= svg_height %>">
|
<svg width="100%" height="<%= svg_height %>">
|
||||||
<%= render partial: "graph_background", locals: {background: @background} %>
|
<%= render partial: "graph_background", locals: {background: @background} %>
|
||||||
|
|
||||||
<% number_of_columns = @graph.columns.length %>
|
<% number_of_columns = @presenter.graph.columns.length %>
|
||||||
<% @graph.columns.each_with_index do |column, index| %>
|
<% @presenter.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:) %>
|
<% 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} %>
|
<%= render partial: "grouped_bar_column", locals: {column: p} %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 493 B |
|
|
@ -10,7 +10,7 @@
|
||||||
data-action="click->analyze#refresh"
|
data-action="click->analyze#refresh"
|
||||||
<% empty_dataset = empty_dataset?(measures: measures, school: school, academic_year: year) %>
|
<% empty_dataset = empty_dataset?(measures: measures, school: school, academic_year: year) %>
|
||||||
<% empty_survey_dataset = empty_survey_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" : "" %>
|
<%= empty_dataset ? "disabled" : "" %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= empty_survey_dataset ? "disabled" : "" %>
|
<%= empty_survey_dataset ? "disabled" : "" %>
|
||||||
|
|
@ -18,13 +18,13 @@
|
||||||
>
|
>
|
||||||
<label class="px-3" for="<%= year.range %>"><%= year.range %></label><br>
|
<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>
|
<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"
|
<i class="fa-solid fa-circle-exclamation px-3"
|
||||||
data-bs-toggle="popover" data-bs-placement="right"
|
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 %>%">
|
data-bs-content="No admin data OR teacher and student survey response rates below <%= ResponseRateCalculator::TEACHER_RATE_THRESHOLD %>%">
|
||||||
</i>
|
</i>
|
||||||
<% end %>
|
<% 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"
|
<i class="fa-solid fa-circle-exclamation px-3"
|
||||||
data-bs-toggle="popover" data-bs-placement="right"
|
data-bs-toggle="popover" data-bs-placement="right"
|
||||||
data-bs-content="Teacher and student survey response rates below <%= ResponseRateCalculator::TEACHER_RATE_THRESHOLD %>%">
|
data-bs-content="Teacher and student survey response rates below <%= ResponseRateCalculator::TEACHER_RATE_THRESHOLD %>%">
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,19 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="graph-content">
|
<div class="graph-content">
|
||||||
<div class="breadcrumbs sub-header-4">
|
<div class="breadcrumbs sub-header-4">
|
||||||
<%= @category.category_id %>:<%= @category.name %> > <%= @subcategory.subcategory_id %>:<%= @subcategory.name %>
|
<%= @presenter.category.category_id %>:<%= @presenter.category.name %> > <%= @presenter.subcategory.subcategory_id %>:<%= @presenter.subcategory.name %>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex flex-row pt-5 row">
|
<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">
|
<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: "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: @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: "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: @category, subcategory: @subcategory} %>
|
<%= render partial: "data_filters", locals: {district: @district, school: @school, academic_year: @academic_year, category: @presenter.category, subcategory: @presenter.subcategory} %>
|
||||||
</div>
|
</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">
|
<div class="bg-color-white flex-grow-1 col-9">
|
||||||
<% @measures.each do |measure| %>
|
<% @presenter.measures.each do |measure| %>
|
||||||
<section class="mb-6">
|
<section class="mb-6">
|
||||||
<p class="construct-id">Measure <%= measure.measure_id %></p>
|
<p class="construct-id">Measure <%= measure.measure_id %></p>
|
||||||
<h2> <%= measure.name %> </h2>
|
<h2> <%= measure.name %> </h2>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender
|
Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender,Income
|
||||||
1,American Indian or Alaskan Native,2,Male
|
1,American Indian or Alaskan Native,2,Male,Economically Disadvantaged - N
|
||||||
2,Asian or Pacific Islander,1,Female
|
2,Asian or Pacific Islander,1,Female,Economically Disadvantaged - Y
|
||||||
3,Black or African American,4,Non-Binary
|
3,Black or African American,4,Non-Binary,Unknown
|
||||||
4,Hispanic or Latinx,99,Unknown
|
4,Hispanic or Latinx,99,Unknown,
|
||||||
5,White or Caucasian,,
|
5,White or Caucasian,,,
|
||||||
6,Prefer not to disclose,,
|
6,Prefer not to disclose,,,
|
||||||
7,Prefer to self-describe,,
|
7,Prefer to self-describe,,,
|
||||||
8,Middle Eastern,,
|
8,Middle Eastern,,,
|
||||||
99,Race/Ethnicity Not Listed,,
|
99,Race/Ethnicity Not Listed,,,
|
||||||
100,Multiracial,,
|
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.
|
# 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
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
|
||||||
|
|
@ -80,6 +80,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_06_22_224103) do
|
||||||
t.string "designation"
|
t.string "designation"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
|
t.string "slug"
|
||||||
|
t.index ["slug"], name: "index_incomes_on_slug", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "legacy_attempts", id: :serial, force: :cascade do |t|
|
create_table "legacy_attempts", id: :serial, force: :cascade do |t|
|
||||||
|
|
|
||||||
|
|
@ -183,10 +183,6 @@ namespace :one_off do
|
||||||
end
|
end
|
||||||
puts "=====================> Completed loading #{Student.count - student_count} students. #{Student.count} total students"
|
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'
|
puts 'Resetting race scores'
|
||||||
RaceScoreLoader.reset(fast_processing: false, academic_years: [AcademicYear.find_by_range('2022-23')], schools:)
|
RaceScoreLoader.reset(fast_processing: false, academic_years: [AcademicYear.find_by_range('2022-23')], schools:)
|
||||||
puts "=====================> Completed loading #{RaceScore.count} race scores"
|
puts "=====================> Completed loading #{RaceScore.count} race scores"
|
||||||
|
|
@ -228,30 +224,30 @@ namespace :one_off do
|
||||||
sum+=c.values.first
|
sum+=c.values.first
|
||||||
nof_si+=1
|
nof_si+=1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
avg = sum.to_f/ nof_si
|
avg = sum.to_f/ nof_si
|
||||||
counts.each do |key, value|
|
counts.each do |key, value|
|
||||||
if key[0] == sc.id && key[1] == ay.id
|
if key[0] == sc.id && key[1] == ay.id
|
||||||
count = value.values.first
|
count = value.values.first
|
||||||
percentage_diff = ((count-avg) / avg) * 100
|
percentage_diff = ((count-avg) / avg) * 100
|
||||||
counts[key] = { count: count, percentage_diff: percentage_diff }
|
counts[key] = { count: count, percentage_diff: percentage_diff }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end end
|
end end
|
||||||
|
|
||||||
counts.each do |key, value|
|
counts.each do |key, value|
|
||||||
output_rows << [School.where(id:key[0]).pluck(:name) , AcademicYear.where(id:key[1]).pluck(:range) , SurveyItem.where(id:key[2]).pluck(:survey_item_id), SurveyItem.where(id:key[2]).pluck(:prompt), value[:count], value[:percentage_diff]]
|
output_rows << [School.where(id:key[0]).pluck(:name) , AcademicYear.where(id:key[1]).pluck(:range) , SurveyItem.where(id:key[2]).pluck(:survey_item_id), SurveyItem.where(id:key[2]).pluck(:prompt), value[:count], value[:percentage_diff]]
|
||||||
end
|
end
|
||||||
|
|
||||||
file = File.new('teacher_survey_questions.csv', 'w')
|
file = File.new('teacher_survey_questions.csv', 'w')
|
||||||
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
|
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
|
||||||
output_rows.each do |row|
|
output_rows.each do |row|
|
||||||
csv << row
|
csv << row
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
file.close
|
file.close
|
||||||
puts "CSV report of teacher survey item responses with removed stray responses.csv"
|
puts "CSV report of teacher survey item responses with removed stray responses.csv"
|
||||||
end
|
end
|
||||||
|
|
@ -288,31 +284,31 @@ namespace :one_off do
|
||||||
sum+=c.values.first
|
sum+=c.values.first
|
||||||
nof_si+=1
|
nof_si+=1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
avg = sum.to_f/ nof_si
|
avg = sum.to_f/ nof_si
|
||||||
counts.each do |key, value|
|
counts.each do |key, value|
|
||||||
if key[0] == sc.id && key[1] == ay.id
|
if key[0] == sc.id && key[1] == ay.id
|
||||||
count = value.values.first
|
count = value.values.first
|
||||||
percentage_diff = ((count-avg) / avg) * 100
|
percentage_diff = ((count-avg) / avg) * 100
|
||||||
counts[key] = { count: count, percentage_diff: percentage_diff }
|
counts[key] = { count: count, percentage_diff: percentage_diff }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end end end
|
end end end
|
||||||
|
|
||||||
counts.each do |key, value|
|
counts.each do |key, value|
|
||||||
output_rows << [School.where(id:key[0]).pluck(:name) , AcademicYear.where(id:key[1]).pluck(:range) , SurveyItem.where(id:key[2]).pluck(:survey_item_id), SurveyItem.where(id:key[2]).pluck(:prompt), value[:count], value[:percentage_diff]]
|
output_rows << [School.where(id:key[0]).pluck(:name) , AcademicYear.where(id:key[1]).pluck(:range) , SurveyItem.where(id:key[2]).pluck(:survey_item_id), SurveyItem.where(id:key[2]).pluck(:prompt), value[:count], value[:percentage_diff]]
|
||||||
end
|
end
|
||||||
|
|
||||||
file = File.new('short_survey_questions.csv', 'w')
|
file = File.new('short_survey_questions.csv', 'w')
|
||||||
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
|
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
|
||||||
output_rows.each do |row|
|
output_rows.each do |row|
|
||||||
csv << row
|
csv << row
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
file.close
|
file.close
|
||||||
puts "CSV report of short survey item responses with removed stray responses.csv"
|
puts "CSV report of short survey item responses with removed stray responses.csv"
|
||||||
end
|
end
|
||||||
|
|
@ -349,31 +345,31 @@ namespace :one_off do
|
||||||
sum+=c.values.first
|
sum+=c.values.first
|
||||||
nof_si+=1
|
nof_si+=1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
avg = sum.to_f/ nof_si
|
avg = sum.to_f/ nof_si
|
||||||
counts.each do |key, value|
|
counts.each do |key, value|
|
||||||
if key[0] == sc.id && key[1] == ay.id
|
if key[0] == sc.id && key[1] == ay.id
|
||||||
count = value.values.first
|
count = value.values.first
|
||||||
percentage_diff = ((count-avg) / avg) * 100
|
percentage_diff = ((count-avg) / avg) * 100
|
||||||
counts[key] = { count: count, percentage_diff: percentage_diff }
|
counts[key] = { count: count, percentage_diff: percentage_diff }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end end end
|
end end end
|
||||||
|
|
||||||
counts.each do |key, value|
|
counts.each do |key, value|
|
||||||
output_rows << [School.where(id:key[0]).pluck(:name) , AcademicYear.where(id:key[1]).pluck(:range) , SurveyItem.where(id:key[2]).pluck(:survey_item_id), SurveyItem.where(id:key[2]).pluck(:prompt), value[:count], value[:percentage_diff]]
|
output_rows << [School.where(id:key[0]).pluck(:name) , AcademicYear.where(id:key[1]).pluck(:range) , SurveyItem.where(id:key[2]).pluck(:survey_item_id), SurveyItem.where(id:key[2]).pluck(:prompt), value[:count], value[:percentage_diff]]
|
||||||
end
|
end
|
||||||
|
|
||||||
file = File.new('early_education_surveys_questions.csv', 'w')
|
file = File.new('early_education_surveys_questions.csv', 'w')
|
||||||
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
|
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
|
||||||
output_rows.each do |row|
|
output_rows.each do |row|
|
||||||
csv << row
|
csv << row
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
file.close
|
file.close
|
||||||
puts "CSV report of early_education_surveys items with removed stray responses.csv"
|
puts "CSV report of early_education_surveys items with removed stray responses.csv"
|
||||||
end
|
end
|
||||||
|
|
@ -381,19 +377,19 @@ namespace :one_off do
|
||||||
|
|
||||||
desc "Generate CSV report of survey item responses"
|
desc "Generate CSV report of survey item responses"
|
||||||
task stray_responses: :environment do
|
task stray_responses: :environment do
|
||||||
|
|
||||||
headers = ['School ID', 'Academic Year', 'Survey Item', 'Count','SurveyItemResponse ids']
|
headers = ['School ID', 'Academic Year', 'Survey Item', 'Count','SurveyItemResponse ids']
|
||||||
|
|
||||||
|
|
||||||
output_rows = []
|
output_rows = []
|
||||||
sir_ids=[]
|
sir_ids=[]
|
||||||
|
|
||||||
|
|
||||||
School.all.each do |sc|
|
School.all.each do |sc|
|
||||||
AcademicYear.all.each do |ay|
|
AcademicYear.all.each do |ay|
|
||||||
SurveyItem.all.each do |si|
|
SurveyItem.all.each do |si|
|
||||||
count = SurveyItemResponse.where(school: sc, academic_year: ay, survey_item: si).count
|
count = SurveyItemResponse.where(school: sc, academic_year: ay, survey_item: si).count
|
||||||
sir_ids= SurveyItemResponse.where(school: sc, academic_year: ay, survey_item: si).pluck(:response_id)
|
sir_ids= SurveyItemResponse.where(school: sc, academic_year: ay, survey_item: si).pluck(:response_id)
|
||||||
|
|
||||||
if count > 0 && count < 10
|
if count > 0 && count < 10
|
||||||
|
|
||||||
|
|
@ -403,7 +399,7 @@ namespace :one_off do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
file = File.new('stray_responses.csv', 'w')
|
file = File.new('stray_responses.csv', 'w')
|
||||||
|
|
||||||
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
|
CSV.open(file, 'w', write_headers: true, headers: headers) do |csv|
|
||||||
|
|
@ -412,7 +408,7 @@ namespace :one_off do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
file.close
|
file.close
|
||||||
|
|
||||||
puts "CSV report of survey item responses created in stray_responses.csv"
|
puts "CSV report of survey item responses created in stray_responses.csv"
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
"debounce": "^1.2.1",
|
"debounce": "^1.2.1",
|
||||||
"esbuild": "^0.17.12",
|
"esbuild": "^0.17.12",
|
||||||
"sass": "^1.43.4",
|
"sass": "^1.43.4",
|
||||||
"semver": "7.5.2"
|
"semver": "^7.5.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "esbuild app/javascript/*.* --bundle --outdir=app/assets/builds",
|
"build": "esbuild app/javascript/*.* --bundle --outdir=app/assets/builds",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
|
factory :income do
|
||||||
|
designation { "MyString" }
|
||||||
|
end
|
||||||
|
|
||||||
factory :gender do
|
factory :gender do
|
||||||
qualtrics_code { 1 }
|
qualtrics_code { 1 }
|
||||||
designation { 'MyString' }
|
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
|
Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender,Income
|
||||||
1,American Indian or Alaskan Native,2,Male
|
1,American Indian or Alaskan Native,2,Male,Economically Disadvantaged – N
|
||||||
2,Asian or Pacific Islander,1,Female
|
2,Asian or Pacific Islander,1,Female,Economically Disadvantaged – Y
|
||||||
3,Black or African American,4,Non-Binary
|
3,Black or African American,4,Non-Binary,Unknown
|
||||||
4,Hispanic or Latinx,99,Unknown
|
4,Hispanic or Latinx,99,Unknown,
|
||||||
5,White or Caucasian,,
|
5,White or Caucasian,,,
|
||||||
6,Prefer not to disclose,,
|
6,Prefer not to disclose,,,
|
||||||
7,Prefer to self-describe,,
|
7,Prefer to self-describe,,,
|
||||||
8,Middle Eastern,,
|
8,Middle Eastern,,,
|
||||||
99,Race/Ethnicity Not Listed,,
|
99,Race/Ethnicity Not Listed,,,
|
||||||
100,Multiracial,,
|
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
|
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
|
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,
|
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
|
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
|
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
|
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
|
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,
|
2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:36,student_survey_response_7,,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1500505,6,15,109,3710,7,1,,2,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,,,4,,Reduced Lunch,Economically Disadvantaged – Y
|
||||||
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"1,2,3,4,5,8",,,
|
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"1,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'
|
# it_behaves_like 'y_offset'
|
||||||
|
|
||||||
context 'and the score is right at the approval low benchmark' do
|
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
|
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(AnalyzeBarPresenter::MINIMUM_BAR_HEIGHT)
|
expect(student_presenter.bars[year_index].bar_height_percentage).to be_within(0.01).of(Analyze::BarPresenter::MINIMUM_BAR_HEIGHT)
|
||||||
end
|
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
|
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 - AnalyzeBarPresenter::MINIMUM_BAR_HEIGHT)
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -257,8 +257,8 @@ describe GroupedBarColumnPresenter do
|
||||||
academic_year:, likert_score: 4)
|
academic_year:, likert_score: 4)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "it rounds to the the minimum bar height of #{AnalyzeBarPresenter::MINIMUM_BAR_HEIGHT} " do
|
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(AnalyzeBarPresenter::MINIMUM_BAR_HEIGHT)
|
expect(student_presenter.bars[year_index].bar_height_percentage).to be_within(0.01).of(Analyze::BarPresenter::MINIMUM_BAR_HEIGHT)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,10 @@ describe DemographicLoader do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:incomes) do
|
||||||
|
['Economically Disadvantaged – N', 'Economically Disadvantaged – Y', 'Unknown']
|
||||||
|
end
|
||||||
|
|
||||||
before :each do
|
before :each do
|
||||||
DemographicLoader.load_data(filepath:)
|
DemographicLoader.load_data(filepath:)
|
||||||
end
|
end
|
||||||
|
|
@ -46,5 +50,12 @@ describe DemographicLoader do
|
||||||
expect(Gender.find_by_designation(key).qualtrics_code).to eq value
|
expect(Gender.find_by_designation(key).qualtrics_code).to eq value
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,40 @@
|
||||||
require "rails_helper"
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe SurveyItemValues, type: :model do
|
RSpec.describe SurveyItemValues, type: :model do
|
||||||
let(:headers) do
|
let(:headers) do
|
||||||
["StartDate", "EndDate", "Status", "IPAddress", "Progress", "Duration (in seconds)", "Finished", "RecordedDate",
|
['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"]
|
'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
|
end
|
||||||
let(:genders) do
|
let(:genders) do
|
||||||
create(:gender, qualtrics_code: 1)
|
create(:gender, qualtrics_code: 1)
|
||||||
Gender.gender_hash
|
Gender.gender_hash
|
||||||
end
|
end
|
||||||
let(:survey_items) { [] }
|
let(:survey_items) { [] }
|
||||||
let(:district) { create(:district, name: "Attleboro") }
|
let(:district) { create(:district, name: 'Attleboro') }
|
||||||
let(:attleboro) do
|
let(:attleboro) do
|
||||||
create(:school, name: "Attleboro", dese_id: 1234, district:)
|
create(:school, name: 'Attleboro', dese_id: 1234, district:)
|
||||||
end
|
end
|
||||||
let(:attleboro_respondents) do
|
let(:attleboro_respondents) do
|
||||||
create(:respondent, school: attleboro, academic_year: ay_2022_23, nine: 40, ten: 40, eleven: 40, twelve: 40)
|
create(:respondent, school: attleboro, academic_year: ay_2022_23, nine: 40, ten: 40, eleven: 40, twelve: 40)
|
||||||
end
|
end
|
||||||
let(:schools) { School.school_hash }
|
let(:schools) { School.school_hash }
|
||||||
let(:recorded_date) { "2023-04-01" }
|
let(:recorded_date) { '2023-04-01' }
|
||||||
let(:ay_2022_23) do
|
let(:ay_2022_23) do
|
||||||
create(:academic_year, range: "2022-23")
|
create(:academic_year, range: '2022-23')
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:common_headers) do
|
let(:common_headers) do
|
||||||
["Recorded Date", "DeseID", "ResponseID", "Duration (in seconds)", "Gender", "Grade"]
|
['Recorded Date', 'DeseID', 'ResponseID', 'Duration (in seconds)', 'Gender', 'Grade']
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:standard_survey_items) do
|
let(:standard_survey_items) do
|
||||||
survey_item_ids = %w[s-peff-q1 s-peff-q2 s-peff-q3 s-peff-q4 s-peff-q5 s-peff-q6 s-phys-q1 s-phys-q2 s-phys-q3 s-phys-q4
|
survey_item_ids = %w[s-peff-q1 s-peff-q2 s-peff-q3 s-peff-q4 s-peff-q5 s-peff-q6 s-phys-q1 s-phys-q2 s-phys-q3 s-phys-q4
|
||||||
s-emsa-q1 s-emsa-q2 s-emsa-q3 s-sbel-q1 s-sbel-q2 s-sbel-q3 s-sbel-q4 s-sbel-q5 s-tint-q1 s-tint-q2
|
s-emsa-q1 s-emsa-q2 s-emsa-q3 s-sbel-q1 s-sbel-q2 s-sbel-q3 s-sbel-q4 s-sbel-q5 s-tint-q1 s-tint-q2
|
||||||
s-tint-q3 s-tint-q4 s-tint-q5 s-vale-q1 s-vale-q2 s-vale-q3 s-vale-q4 s-acpr-q1 s-acpr-q2 s-acpr-q3
|
s-tint-q3 s-tint-q4 s-tint-q5 s-vale-q1 s-vale-q2 s-vale-q3 s-vale-q4 s-acpr-q1 s-acpr-q2 s-acpr-q3
|
||||||
s-acpr-q4 s-sust-q1 s-sust-q2 s-cure-q1 s-cure-q2 s-cure-q3 s-cure-q4 s-sten-q1 s-sten-q2 s-sten-q3
|
s-acpr-q4 s-sust-q1 s-sust-q2 s-cure-q1 s-cure-q2 s-cure-q3 s-cure-q4 s-sten-q1 s-sten-q2 s-sten-q3
|
||||||
s-sper-q1 s-sper-q2 s-sper-q3 s-sper-q4 s-civp-q1 s-civp-q2 s-civp-q3 s-civp-q4 s-grit-q1 s-grit-q2
|
s-sper-q1 s-sper-q2 s-sper-q3 s-sper-q4 s-civp-q1 s-civp-q2 s-civp-q3 s-civp-q4 s-grit-q1 s-grit-q2
|
||||||
s-grit-q3 s-grit-q4 s-grmi-q1 s-grmi-q2 s-grmi-q3 s-grmi-q4 s-expa-q1 s-appa-q1 s-appa-q2 s-appa-q3
|
s-grit-q3 s-grit-q4 s-grmi-q1 s-grmi-q2 s-grmi-q3 s-grmi-q4 s-expa-q1 s-appa-q1 s-appa-q2 s-appa-q3
|
||||||
s-acst-q1 s-acst-q2 s-acst-q3 s-poaf-q1 s-poaf-q2 s-poaf-q3 s-poaf-q4]
|
s-acst-q1 s-acst-q2 s-acst-q3 s-poaf-q1 s-poaf-q2 s-poaf-q3 s-poaf-q4]
|
||||||
survey_item_ids.map do |survey_item_id|
|
survey_item_ids.map do |survey_item_id|
|
||||||
create(:survey_item, survey_item_id:)
|
create(:survey_item, survey_item_id:)
|
||||||
end
|
end
|
||||||
|
|
@ -42,10 +42,10 @@ RSpec.describe SurveyItemValues, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:short_form_survey_items) do
|
let(:short_form_survey_items) do
|
||||||
survey_item_ids = [create(:survey_item, survey_item_id: "s-phys-q1", on_short_form: true),
|
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-q2', on_short_form: true),
|
||||||
create(:survey_item, survey_item_id: "s-phys-q3",
|
create(:survey_item, survey_item_id: 's-phys-q3',
|
||||||
on_short_form: true)].map(&:survey_item_id)
|
on_short_form: true)].map(&:survey_item_id)
|
||||||
survey_item_ids.map do |survey_item_id|
|
survey_item_ids.map do |survey_item_id|
|
||||||
create(:survey_item, survey_item_id:)
|
create(:survey_item, survey_item_id:)
|
||||||
end
|
end
|
||||||
|
|
@ -53,9 +53,9 @@ RSpec.describe SurveyItemValues, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:early_education_survey_items) do
|
let(:early_education_survey_items) do
|
||||||
survey_item_ids = [create(:survey_item, survey_item_id: "s-emsa-es1"),
|
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-es2'),
|
||||||
create(:survey_item, survey_item_id: "s-emsa-es3")].map(&:survey_item_id)
|
create(:survey_item, survey_item_id: 's-emsa-es3')].map(&:survey_item_id)
|
||||||
survey_item_ids.map do |survey_item_id|
|
survey_item_ids.map do |survey_item_id|
|
||||||
create(:survey_item, survey_item_id:)
|
create(:survey_item, survey_item_id:)
|
||||||
end
|
end
|
||||||
|
|
@ -64,12 +64,12 @@ RSpec.describe SurveyItemValues, type: :model do
|
||||||
|
|
||||||
let(:teacher_survey_items) do
|
let(:teacher_survey_items) do
|
||||||
survey_item_ids = %w[t-prep-q1 t-prep-q2 t-prep-q3 t-ieff-q1 t-ieff-q2 t-ieff-q3 t-ieff-q4 t-pcom-q1 t-pcom-q2 t-pcom-q3
|
survey_item_ids = %w[t-prep-q1 t-prep-q2 t-prep-q3 t-ieff-q1 t-ieff-q2 t-ieff-q3 t-ieff-q4 t-pcom-q1 t-pcom-q2 t-pcom-q3
|
||||||
t-pcom-q4 t-pcom-q5 t-inle-q1 t-inle-q2 t-inle-q3 t-prtr-q1 t-prtr-q2 t-prtr-q3 t-coll-q1 t-coll-q2
|
t-pcom-q4 t-pcom-q5 t-inle-q1 t-inle-q2 t-inle-q3 t-prtr-q1 t-prtr-q2 t-prtr-q3 t-coll-q1 t-coll-q2
|
||||||
t-coll-q3 t-qupd-q1 t-qupd-q2 t-qupd-q3 t-qupd-q4 t-pvic-q1 t-pvic-q2 t-pvic-q3 t-psup-q1 t-psup-q2
|
t-coll-q3 t-qupd-q1 t-qupd-q2 t-qupd-q3 t-qupd-q4 t-pvic-q1 t-pvic-q2 t-pvic-q3 t-psup-q1 t-psup-q2
|
||||||
t-psup-q3 t-psup-q4 t-acch-q1 t-acch-q2 t-acch-q3 t-reso-q1 t-reso-q2 t-reso-q3 t-reso-q4 t-reso-q5
|
t-psup-q3 t-psup-q4 t-acch-q1 t-acch-q2 t-acch-q3 t-reso-q1 t-reso-q2 t-reso-q3 t-reso-q4 t-reso-q5
|
||||||
t-sust-q1 t-sust-q2 t-sust-q3 t-sust-q4 t-curv-q1 t-curv-q2 t-curv-q3 t-curv-q4 t-cure-q1 t-cure-q2
|
t-sust-q1 t-sust-q2 t-sust-q3 t-sust-q4 t-curv-q1 t-curv-q2 t-curv-q3 t-curv-q4 t-cure-q1 t-cure-q2
|
||||||
t-cure-q3 t-cure-q4 t-peng-q1 t-peng-q2 t-peng-q3 t-peng-q4 t-ceng-q1 t-ceng-q2 t-ceng-q3 t-ceng-q4
|
t-cure-q3 t-cure-q4 t-peng-q1 t-peng-q2 t-peng-q3 t-peng-q4 t-ceng-q1 t-ceng-q2 t-ceng-q3 t-ceng-q4
|
||||||
t-sach-q1 t-sach-q2 t-sach-q3 t-psol-q1 t-psol-q2 t-psol-q3 t-expa-q2 t-expa-q3 t-phya-q2 t-phya-q3]
|
t-sach-q1 t-sach-q2 t-sach-q3 t-psol-q1 t-psol-q2 t-psol-q3 t-expa-q2 t-expa-q3 t-phya-q2 t-phya-q3]
|
||||||
|
|
||||||
survey_item_ids.map do |survey_item_id|
|
survey_item_ids.map do |survey_item_id|
|
||||||
create(:survey_item, survey_item_id:)
|
create(:survey_item, survey_item_id:)
|
||||||
|
|
@ -77,49 +77,49 @@ RSpec.describe SurveyItemValues, type: :model do
|
||||||
(survey_item_ids << common_headers).flatten
|
(survey_item_ids << common_headers).flatten
|
||||||
end
|
end
|
||||||
|
|
||||||
context ".recorded_date" do
|
context '.recorded_date' do
|
||||||
it "returns the recorded date" do
|
it 'returns the recorded date' do
|
||||||
row = {"RecordedDate" => "2017-01-01"}
|
row = { 'RecordedDate' => '2017-01-01' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
|
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"]
|
headers = ['Recorded Date']
|
||||||
row = {"Recorded Date" => "2017-01-02"}
|
row = { 'Recorded Date' => '2017-01-02' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
context ".school" do
|
context '.school' do
|
||||||
it "returns the school that maps to the dese id provided" do
|
it 'returns the school that maps to the dese id provided' do
|
||||||
attleboro
|
attleboro
|
||||||
row = {"Dese ID" => "1234"}
|
row = { 'Dese ID' => '1234' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
|
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
|
||||||
expect(values.school).to eq attleboro
|
expect(values.school).to eq attleboro
|
||||||
|
|
||||||
row = {"DeseID" => "1234"}
|
row = { 'DeseID' => '1234' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
|
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
|
||||||
expect(values.school).to eq attleboro
|
expect(values.school).to eq attleboro
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context ".grade" do
|
context '.grade' do
|
||||||
it "returns the grade that maps to the grade provided" do
|
it 'returns the grade that maps to the grade provided' do
|
||||||
row = {"Grade" => "1"}
|
row = { 'Grade' => '1' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
|
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
|
||||||
expect(values.grade).to eq 1
|
expect(values.grade).to eq 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context ".gender" do
|
context '.gender' do
|
||||||
it "returns the grade that maps to the grade provided" do
|
it 'returns the grade that maps to the grade provided' do
|
||||||
row = {"Gender" => "1"}
|
row = { 'Gender' => '1' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
|
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:)
|
||||||
expect(values.gender.qualtrics_code).to eq 1
|
expect(values.gender.qualtrics_code).to eq 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context ".respondent_type" do
|
context '.respondent_type' do
|
||||||
it "reads header to find the survey type" do
|
it 'reads header to find the survey type' do
|
||||||
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
|
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
|
||||||
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
|
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
|
||||||
expect(values.respondent_type).to eq :student
|
expect(values.respondent_type).to eq :student
|
||||||
|
|
@ -130,32 +130,32 @@ RSpec.describe SurveyItemValues, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context ".survey_type" do
|
context '.survey_type' do
|
||||||
context "when survey type is standard form" do
|
context 'when survey type is standard form' do
|
||||||
it "returns the survey type" do
|
it 'returns the survey type' do
|
||||||
headers = standard_survey_items
|
headers = standard_survey_items
|
||||||
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
|
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
|
||||||
expect(values.survey_type).to eq :standard
|
expect(values.survey_type).to eq :standard
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context "when survey type is teacher form" do
|
context 'when survey type is teacher form' do
|
||||||
it "returns the survey type" do
|
it 'returns the survey type' do
|
||||||
headers = teacher_survey_items
|
headers = teacher_survey_items
|
||||||
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
|
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
|
||||||
expect(values.survey_type).to eq :teacher
|
expect(values.survey_type).to eq :teacher
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when survey type is short form" do
|
context 'when survey type is short form' do
|
||||||
it "returns the survey type" do
|
it 'returns the survey type' do
|
||||||
headers = short_form_survey_items
|
headers = short_form_survey_items
|
||||||
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
|
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
|
||||||
expect(values.survey_type).to eq :short_form
|
expect(values.survey_type).to eq :short_form
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when survey type is early education" do
|
context 'when survey type is early education' do
|
||||||
it "returns the survey type" do
|
it 'returns the survey type' do
|
||||||
headers = early_education_survey_items
|
headers = early_education_survey_items
|
||||||
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
|
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:)
|
||||||
expect(values.survey_type).to eq :early_education
|
expect(values.survey_type).to eq :early_education
|
||||||
|
|
@ -163,236 +163,236 @@ RSpec.describe SurveyItemValues, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context ".income" do
|
context '.income' do
|
||||||
context "when no disaggregation data is provided" do
|
context 'when no disaggregation data is provided' do
|
||||||
it "returns an empty string " do
|
it 'returns an empty string ' do
|
||||||
disaggregation_data = {}
|
disaggregation_data = {}
|
||||||
values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:, 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
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when disaggregation data is provided" do
|
context 'when disaggregation data is provided' do
|
||||||
before :each do
|
before :each do
|
||||||
attleboro
|
attleboro
|
||||||
ay_2022_23
|
ay_2022_23
|
||||||
end
|
end
|
||||||
|
|
||||||
it "translates Free Lunch to Economically Disadvantaged - Y" do
|
it 'translates Free Lunch to Economically Disadvantaged - Y' do
|
||||||
headers = ["District", "Academic Year", "LASID", "LowIncome"]
|
headers = ['District', 'Academic Year', 'LASID', 'LowIncome']
|
||||||
row = {"District" => "Attleboro", "AcademicYear" => "2022-23", "LASID" => "1", "LowIncome" => "Free Lunch"}
|
row = { 'District' => 'Attleboro', 'AcademicYear' => '2022-23', 'LASID' => '1', 'LowIncome' => 'Free Lunch' }
|
||||||
disaggregation_data = {%w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:)}
|
disaggregation_data = { %w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:) }
|
||||||
|
|
||||||
headers = ["LASID", "Dese Id", "RecordedDate"]
|
headers = ['LASID', 'Dese Id', 'RecordedDate']
|
||||||
row = {"LASID" => "1", "DESE ID" => "1234", "RecordedDate" => "2023-1-1"}
|
row = { 'LASID' => '1', 'DESE ID' => '1234', 'RecordedDate' => '2023-1-1' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
|
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
|
||||||
disaggregation_data:)
|
disaggregation_data:)
|
||||||
expect(values.income).to eq "Economically Disadvantaged - Y"
|
expect(values.income).to eq 'Economically Disadvantaged - Y'
|
||||||
end
|
end
|
||||||
|
|
||||||
it "translates Reduced Lunch to Economically Disadvantaged - Y" do
|
it 'translates Reduced Lunch to Economically Disadvantaged - Y' do
|
||||||
headers = ["District", "Academic Year", "LASID", "LowIncome"]
|
headers = ['District', 'Academic Year', 'LASID', 'LowIncome']
|
||||||
row = {"District" => "Attleboro", "AcademicYear" => "2022-23", "LASID" => "1", "LowIncome" => "Reduced Lunch"}
|
row = { 'District' => 'Attleboro', 'AcademicYear' => '2022-23', 'LASID' => '1', 'LowIncome' => 'Reduced Lunch' }
|
||||||
disaggregation_data = {%w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:)}
|
disaggregation_data = { %w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:) }
|
||||||
|
|
||||||
headers = ["LASID", "Dese Id", "RecordedDate"]
|
headers = ['LASID', 'Dese Id', 'RecordedDate']
|
||||||
row = {"LASID" => "1", "DESE ID" => "1234", "RecordedDate" => "2023-1-1"}
|
row = { 'LASID' => '1', 'DESE ID' => '1234', 'RecordedDate' => '2023-1-1' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
|
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
|
||||||
disaggregation_data:)
|
disaggregation_data:)
|
||||||
expect(values.income).to eq "Economically Disadvantaged - Y"
|
expect(values.income).to eq 'Economically Disadvantaged - Y'
|
||||||
end
|
end
|
||||||
|
|
||||||
it "translates LowIncome to Economically Disadvantaged - Y" do
|
it 'translates LowIncome to Economically Disadvantaged - Y' do
|
||||||
headers = ["District", "Academic Year", "LASID", "LowIncome"]
|
headers = ['District', 'Academic Year', 'LASID', 'LowIncome']
|
||||||
row = {"District" => "Attleboro", "AcademicYear" => "2022-23", "LASID" => "1", "LowIncome" => "LowIncome"}
|
row = { 'District' => 'Attleboro', 'AcademicYear' => '2022-23', 'LASID' => '1', 'LowIncome' => 'LowIncome' }
|
||||||
disaggregation_data = {%w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:)}
|
disaggregation_data = { %w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:) }
|
||||||
|
|
||||||
headers = ["LASID", "Dese Id", "RecordedDate"]
|
headers = ['LASID', 'Dese Id', 'RecordedDate']
|
||||||
row = {"LASID" => "1", "DESE ID" => "1234", "RecordedDate" => "2023-1-1"}
|
row = { 'LASID' => '1', 'DESE ID' => '1234', 'RecordedDate' => '2023-1-1' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
|
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
|
||||||
disaggregation_data:)
|
disaggregation_data:)
|
||||||
expect(values.income).to eq "Economically Disadvantaged - Y"
|
expect(values.income).to eq 'Economically Disadvantaged - Y'
|
||||||
end
|
end
|
||||||
|
|
||||||
it "translates Not Eligible to Economically Disadvantaged - N" do
|
it 'translates Not Eligible to Economically Disadvantaged - N' do
|
||||||
headers = ["District", "Academic Year", "LASID", "LowIncome"]
|
headers = ['District', 'Academic Year', 'LASID', 'LowIncome']
|
||||||
row = {"District" => "Attleboro", "AcademicYear" => "2022-23", "LASID" => "1", "LowIncome" => "Not Eligible"}
|
row = { 'District' => 'Attleboro', 'AcademicYear' => '2022-23', 'LASID' => '1', 'LowIncome' => 'Not Eligible' }
|
||||||
disaggregation_data = {%w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:)}
|
disaggregation_data = { %w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:) }
|
||||||
|
|
||||||
headers = ["LASID", "Dese Id", "RecordedDate"]
|
headers = ['LASID', 'Dese Id', 'RecordedDate']
|
||||||
row = {"LASID" => "1", "DESE ID" => "1234", "RecordedDate" => "2023-1-1"}
|
row = { 'LASID' => '1', 'DESE ID' => '1234', 'RecordedDate' => '2023-1-1' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
|
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
|
||||||
disaggregation_data:)
|
disaggregation_data:)
|
||||||
expect(values.income).to eq "Economically Disadvantaged - N"
|
expect(values.income).to eq 'Economically Disadvantaged - N'
|
||||||
end
|
end
|
||||||
|
|
||||||
it "translates blanks to Unknown" do
|
it 'translates blanks to Unknown' do
|
||||||
headers = ["District", "Academic Year", "LASID", "LowIncome"]
|
headers = ['District', 'Academic Year', 'LASID', 'LowIncome']
|
||||||
row = {"District" => "Attleboro", "AcademicYear" => "2022-23", "LASID" => "1", "LowIncome" => ""}
|
row = { 'District' => 'Attleboro', 'AcademicYear' => '2022-23', 'LASID' => '1', 'LowIncome' => '' }
|
||||||
disaggregation_data = {%w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:)}
|
disaggregation_data = { %w[1 Attleboro 2022-23] => DisaggregationRow.new(row:, headers:) }
|
||||||
|
|
||||||
headers = ["LASID", "Dese Id", "RecordedDate"]
|
headers = ['LASID', 'Dese Id', 'RecordedDate']
|
||||||
row = {"LASID" => "1", "DESE ID" => "1234", "RecordedDate" => "2023-1-1"}
|
row = { 'LASID' => '1', 'DESE ID' => '1234', 'RecordedDate' => '2023-1-1' }
|
||||||
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
|
values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:,
|
||||||
disaggregation_data:)
|
disaggregation_data:)
|
||||||
expect(values.income).to eq "Unknown"
|
expect(values.income).to eq 'Unknown'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context ".valid_duration" do
|
context '.valid_duration' do
|
||||||
context "when duration is valid" do
|
context 'when duration is valid' do
|
||||||
it "returns true" do
|
it 'returns true' do
|
||||||
headers = standard_survey_items
|
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:)
|
schools:)
|
||||||
expect(values.valid_duration?).to eq true
|
expect(values.valid_duration?).to eq true
|
||||||
|
|
||||||
headers = teacher_survey_items
|
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:)
|
schools:)
|
||||||
expect(values.valid_duration?).to eq true
|
expect(values.valid_duration?).to eq true
|
||||||
|
|
||||||
headers = short_form_survey_items
|
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:)
|
schools:)
|
||||||
expect(values.valid_duration?).to eq true
|
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
|
# 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
|
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:)
|
schools:)
|
||||||
expect(values.valid_duration?).to eq true
|
expect(values.valid_duration?).to eq true
|
||||||
|
|
||||||
headers = short_form_survey_items
|
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:)
|
schools:)
|
||||||
expect(values.valid_duration?).to eq true
|
expect(values.valid_duration?).to eq true
|
||||||
|
|
||||||
headers = short_form_survey_items
|
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:)
|
schools:)
|
||||||
expect(values.valid_duration?).to eq true
|
expect(values.valid_duration?).to eq true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when duration is invalid" do
|
context 'when duration is invalid' do
|
||||||
it "returns false" do
|
it 'returns false' do
|
||||||
headers = standard_survey_items
|
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:)
|
schools:)
|
||||||
expect(values.valid_duration?).to eq false
|
expect(values.valid_duration?).to eq false
|
||||||
|
|
||||||
headers = teacher_survey_items
|
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:)
|
schools:)
|
||||||
expect(values.valid_duration?).to eq false
|
expect(values.valid_duration?).to eq false
|
||||||
headers = short_form_survey_items
|
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:)
|
schools:)
|
||||||
expect(values.valid_duration?).to eq false
|
expect(values.valid_duration?).to eq false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context ".valid_progress" do
|
context '.valid_progress' do
|
||||||
context "when progress is valid" do
|
context 'when progress is valid' do
|
||||||
it "returns true" do
|
it 'returns true' do
|
||||||
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
|
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:)
|
schools:)
|
||||||
expect(values.valid_progress?).to eq true
|
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
|
# 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]
|
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:)
|
schools:)
|
||||||
expect(values.valid_progress?).to eq true
|
expect(values.valid_progress?).to eq true
|
||||||
|
|
||||||
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
|
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:)
|
schools:)
|
||||||
expect(values.valid_progress?).to eq true
|
expect(values.valid_progress?).to eq true
|
||||||
|
|
||||||
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
|
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:)
|
schools:)
|
||||||
expect(values.valid_progress?).to eq true
|
expect(values.valid_progress?).to eq true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when progress is invalid" do
|
context 'when progress is invalid' do
|
||||||
it "returns false" do
|
it 'returns false' do
|
||||||
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]
|
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:)
|
schools:)
|
||||||
expect(values.valid_progress?).to eq false
|
expect(values.valid_progress?).to eq false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context ".valid_grade?" do
|
context '.valid_grade?' do
|
||||||
context "when grade is valid" do
|
context 'when grade is valid' do
|
||||||
before :each do
|
before :each do
|
||||||
attleboro
|
attleboro
|
||||||
attleboro_respondents
|
attleboro_respondents
|
||||||
end
|
end
|
||||||
it "returns true for students" do
|
it 'returns true for students' do
|
||||||
headers = %w[s-sbel-q5 s-phys-q2 grade RecordedDate]
|
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:)
|
schools:)
|
||||||
|
|
||||||
expect(values.valid_grade?).to eq true
|
expect(values.valid_grade?).to eq true
|
||||||
end
|
end
|
||||||
it "returns true for teachers" do
|
it 'returns true for teachers' do
|
||||||
headers = %w[t-sbel-q5 t-phys-q2 grade RecordedDate]
|
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:)
|
schools:)
|
||||||
expect(values.valid_grade?).to eq true
|
expect(values.valid_grade?).to eq true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when grade is invalid" do
|
context 'when grade is invalid' do
|
||||||
before :each do
|
before :each do
|
||||||
attleboro
|
attleboro
|
||||||
attleboro_respondents
|
attleboro_respondents
|
||||||
end
|
end
|
||||||
it "returns false" do
|
it 'returns false' do
|
||||||
headers = %w[s-sbel-q5 s-phys-q2 grade RecordedDate]
|
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)
|
schools: School.school_hash)
|
||||||
expect(values.valid_grade?).to eq false
|
expect(values.valid_grade?).to eq false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context ".valid_sd?" do
|
context '.valid_sd?' do
|
||||||
context "when the standard deviation is valid" do
|
context 'when the standard deviation is valid' do
|
||||||
it "returns true for student questions" do
|
it 'returns true for student questions' do
|
||||||
headers = %w[s-sbel-q5 s-phys-q1 s-phys-q2 RecordedDate]
|
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)
|
schools: School.school_hash)
|
||||||
expect(values.valid_sd?).to eq true
|
expect(values.valid_sd?).to eq true
|
||||||
end
|
end
|
||||||
it "returns true for teacher questions" do
|
it 'returns true for teacher questions' do
|
||||||
headers = %w[t-sbel-q5 t-phys-q2]
|
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)
|
schools: School.school_hash)
|
||||||
expect(values.valid_sd?).to eq true
|
expect(values.valid_sd?).to eq true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the standard deviation is invalid" do
|
context 'when the standard deviation is invalid' do
|
||||||
it "returns false for student questions" do
|
it 'returns false for student questions' do
|
||||||
headers = %w[s-sbel-q5 s-phys-q1 s-phys-q2 RecordedDate]
|
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)
|
schools: School.school_hash)
|
||||||
expect(values.valid_sd?).to eq false
|
expect(values.valid_sd?).to eq false
|
||||||
end
|
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]
|
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)
|
schools: School.school_hash)
|
||||||
expect(values.valid_sd?).to eq false
|
expect(values.valid_sd?).to eq false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,59 @@
|
||||||
require "rails_helper"
|
require 'rails_helper'
|
||||||
|
|
||||||
describe SurveyResponsesDataLoader do
|
describe SurveyResponsesDataLoader do
|
||||||
let(:path_to_teacher_responses) { Rails.root.join("spec", "fixtures", "test_2020-21_teacher_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_student_responses) { Rails.root.join('spec', 'fixtures', 'test_2020-21_student_survey_responses.csv') }
|
||||||
let(:path_to_butler_student_responses) do
|
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
|
end
|
||||||
|
|
||||||
let(:ay_2020_21) { create(:academic_year, range: "2020-21") }
|
let(:ay_2020_21) { create(:academic_year, range: '2020-21') }
|
||||||
let(:ay_2022_23) { create(:academic_year, range: "2022-23") }
|
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(: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(: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(: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
|
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)
|
district: lowell)
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:t_pcom_q3) { create(:survey_item, survey_item_id: "t-pcom-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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_emsa_q3) { create(:survey_item, survey_item_id: 's-emsa-q3') }
|
||||||
|
|
||||||
let(:female) { create(:gender, qualtrics_code: 1) }
|
let(:female) { create(:gender, qualtrics_code: 1) }
|
||||||
let(:male) { create(:gender, qualtrics_code: 2) }
|
let(:male) { create(:gender, qualtrics_code: 2) }
|
||||||
let(:another_gender) { create(:gender, qualtrics_code: 3) }
|
let(:another_gender) { create(:gender, qualtrics_code: 3) }
|
||||||
let(:non_binary) { create(:gender, qualtrics_code: 4) }
|
let(:non_binary) { create(:gender, qualtrics_code: 4) }
|
||||||
let(:unknown_gender) { create(:gender, qualtrics_code: 99) }
|
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
|
let(:setup) do
|
||||||
ay_2020_21
|
ay_2020_21
|
||||||
|
|
@ -83,18 +89,21 @@ describe SurveyResponsesDataLoader do
|
||||||
another_gender
|
another_gender
|
||||||
non_binary
|
non_binary
|
||||||
unknown_gender
|
unknown_gender
|
||||||
|
low_income
|
||||||
|
high_income
|
||||||
|
unknown_income
|
||||||
end
|
end
|
||||||
|
|
||||||
before :each do
|
before :each do
|
||||||
setup
|
setup
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "loading teacher survey responses" do
|
describe 'loading teacher survey responses' do
|
||||||
before do
|
before do
|
||||||
SurveyResponsesDataLoader.load_data filepath: path_to_teacher_responses
|
SurveyResponsesDataLoader.load_data filepath: path_to_teacher_responses
|
||||||
end
|
end
|
||||||
|
|
||||||
it "ensures teacher responses load correctly" do
|
it 'ensures teacher responses load correctly' do
|
||||||
assigns_academic_year_to_survey_item_responses
|
assigns_academic_year_to_survey_item_responses
|
||||||
assigns_school_to_the_survey_item_responses
|
assigns_school_to_the_survey_item_responses
|
||||||
assigns_recorded_date_to_teacher_responses
|
assigns_recorded_date_to_teacher_responses
|
||||||
|
|
@ -105,12 +114,12 @@ describe SurveyResponsesDataLoader do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "student survey responses" do
|
describe 'student survey responses' do
|
||||||
before do
|
before do
|
||||||
SurveyResponsesDataLoader.load_data filepath: path_to_student_responses
|
SurveyResponsesDataLoader.load_data filepath: path_to_student_responses
|
||||||
end
|
end
|
||||||
|
|
||||||
it "ensures student responses load correctly" do
|
it 'ensures student responses load correctly' do
|
||||||
assigns_academic_year_to_student_survey_item_responses
|
assigns_academic_year_to_student_survey_item_responses
|
||||||
assigns_school_to_student_survey_item_responses
|
assigns_school_to_student_survey_item_responses
|
||||||
assigns_recorded_date_to_student_responses
|
assigns_recorded_date_to_student_responses
|
||||||
|
|
@ -119,85 +128,86 @@ describe SurveyResponsesDataLoader do
|
||||||
captures_likert_scores_for_student_survey_item_responses
|
captures_likert_scores_for_student_survey_item_responses
|
||||||
assigns_grade_level_to_responses
|
assigns_grade_level_to_responses
|
||||||
assigns_gender_to_responses
|
assigns_gender_to_responses
|
||||||
|
assigns_income_to_responses
|
||||||
is_idempotent_for_students
|
is_idempotent_for_students
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when updating student survey responses from another csv file" do
|
context 'when updating student survey responses from another csv file' do
|
||||||
before :each do
|
before :each do
|
||||||
SurveyResponsesDataLoader.load_data filepath: Rails.root.join("spec", "fixtures",
|
SurveyResponsesDataLoader.load_data filepath: Rails.root.join('spec', 'fixtures',
|
||||||
"secondary_test_2020-21_student_survey_responses.csv")
|
'secondary_test_2020-21_student_survey_responses.csv')
|
||||||
end
|
end
|
||||||
it "updates the likert score to the score on the new csv file" do
|
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"
|
s_emsa_q1 = SurveyItem.find_by_survey_item_id 's-emsa-q1'
|
||||||
expect(SurveyItemResponse.where(response_id: "student_survey_response_3",
|
expect(SurveyItemResponse.where(response_id: 'student_survey_response_3',
|
||||||
survey_item: s_emsa_q1).first.likert_score).to eq 1
|
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
|
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
|
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
|
survey_item: s_acst_q3).first.likert_score).to eq 4
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# figure out why this is failing
|
# 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
|
before :each do
|
||||||
SurveyResponsesDataLoader.load_data filepath: path_to_student_responses,
|
SurveyResponsesDataLoader.load_data filepath: path_to_student_responses,
|
||||||
rules: [Rule::SkipNonLowellSchools]
|
rules: [Rule::SkipNonLowellSchools]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "rejects any non-lowell school" do
|
it 'rejects any non-lowell school' do
|
||||||
expect(SurveyItemResponse.where(response_id: "student_survey_response_1").count).to eq 0
|
expect(SurveyItemResponse.where(response_id: 'student_survey_response_1').count).to eq 0
|
||||||
expect(SurveyItemResponse.count).to eq 69
|
expect(SurveyItemResponse.count).to eq 69
|
||||||
end
|
end
|
||||||
|
|
||||||
it "loads the correct number of responses for lowell schools" do
|
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_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_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_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_5').count).to eq 14
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when loading 22-23 butler survey responses" do
|
context 'when loading 22-23 butler survey responses' do
|
||||||
before :each do
|
before :each do
|
||||||
SurveyResponsesDataLoader.load_data filepath: path_to_butler_student_responses,
|
SurveyResponsesDataLoader.load_data filepath: path_to_butler_student_responses,
|
||||||
rules: [Rule::SkipNonLowellSchools]
|
rules: [Rule::SkipNonLowellSchools]
|
||||||
end
|
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
|
expect(SurveyItemResponse.where(school: butler_school).count).to eq 56
|
||||||
end
|
end
|
||||||
|
|
||||||
it "blank entries for grade get loaded as nils, not zero values" do
|
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_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_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_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_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_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_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_7').first.grade).to eq nil
|
||||||
expect(SurveyItemResponse.where(response_id: "butler_student_survey_response_8").first.grade).to eq 0
|
expect(SurveyItemResponse.where(response_id: 'butler_student_survey_response_8').first.grade).to eq 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigns_academic_year_to_survey_item_responses
|
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
|
end
|
||||||
|
|
||||||
def assigns_school_to_the_survey_item_responses
|
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
|
end
|
||||||
|
|
||||||
def loads_survey_item_responses_for_a_given_survey_response
|
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_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_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_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_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_5').count).to eq 8
|
||||||
end
|
end
|
||||||
|
|
||||||
def loads_all_survey_item_responses_for_a_given_survey_item
|
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
|
end
|
||||||
|
|
||||||
def captures_likert_scores_for_survey_item_responses
|
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_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_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_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_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_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_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_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_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_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_q3).first.likert_score).to eq 4
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_idempotent
|
def is_idempotent
|
||||||
|
|
@ -231,19 +241,19 @@ def is_idempotent
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigns_academic_year_to_student_survey_item_responses
|
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
|
end
|
||||||
|
|
||||||
def assigns_school_to_student_survey_item_responses
|
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
|
end
|
||||||
|
|
||||||
def loads_student_survey_item_response_values
|
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_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_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_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_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_5').count).to eq 14
|
||||||
end
|
end
|
||||||
|
|
||||||
def student_survey_item_response_count_matches_expected
|
def student_survey_item_response_count_matches_expected
|
||||||
|
|
@ -252,20 +262,20 @@ def student_survey_item_response_count_matches_expected
|
||||||
end
|
end
|
||||||
|
|
||||||
def captures_likert_scores_for_student_survey_item_responses
|
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_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_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_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_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_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_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_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_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_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_q2).first.likert_score).to eq 2
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_idempotent_for_students
|
def is_idempotent_for_students
|
||||||
|
|
@ -277,26 +287,26 @@ def is_idempotent_for_students
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigns_grade_level_to_responses
|
def assigns_grade_level_to_responses
|
||||||
results = {"student_survey_response_1" => 11,
|
results = { 'student_survey_response_1' => 11,
|
||||||
"student_survey_response_3" => 8,
|
'student_survey_response_3' => 8,
|
||||||
"student_survey_response_4" => 8,
|
'student_survey_response_4' => 8,
|
||||||
"student_survey_response_5" => 7,
|
'student_survey_response_5' => 7,
|
||||||
"student_survey_response_6" => 3,
|
'student_survey_response_6' => 3,
|
||||||
"student_survey_response_7" => 4}
|
'student_survey_response_7' => 4 }
|
||||||
results.each do |key, value|
|
results.each do |key, value|
|
||||||
expect(SurveyItemResponse.where(response_id: key).all? do |response|
|
expect(SurveyItemResponse.where(response_id: key).all? do |response|
|
||||||
response.grade == value
|
response.grade == value
|
||||||
end).to eq true
|
end).to eq true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigns_gender_to_responses
|
def assigns_gender_to_responses
|
||||||
results = {"student_survey_response_1" => female,
|
results = { 'student_survey_response_1' => female,
|
||||||
"student_survey_response_3" => male,
|
'student_survey_response_3' => male,
|
||||||
"student_survey_response_4" => non_binary,
|
'student_survey_response_4' => non_binary,
|
||||||
"student_survey_response_5" => non_binary,
|
'student_survey_response_5' => non_binary,
|
||||||
"student_survey_response_6" => unknown_gender,
|
'student_survey_response_6' => unknown_gender,
|
||||||
"student_survey_response_7" => unknown_gender}
|
'student_survey_response_7' => unknown_gender }
|
||||||
|
|
||||||
results.each do |key, value|
|
results.each do |key, value|
|
||||||
expect(SurveyItemResponse.where(response_id: key).first.gender).to eq value
|
expect(SurveyItemResponse.where(response_id: key).first.gender).to eq value
|
||||||
|
|
@ -304,23 +314,36 @@ def assigns_gender_to_responses
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigns_recorded_date_to_student_responses
|
def assigns_recorded_date_to_student_responses
|
||||||
results = {"student_survey_response_1" => "2020-09-30T18:48:50",
|
results = { 'student_survey_response_1' => '2020-09-30T18:48:50',
|
||||||
"student_survey_response_3" => "2021-03-31T09:59:02",
|
'student_survey_response_3' => '2021-03-31T09:59:02',
|
||||||
"student_survey_response_4" => "2021-03-31T10:00:17",
|
'student_survey_response_4' => '2021-03-31T10:00:17',
|
||||||
"student_survey_response_5" => "2021-03-31T10:01:36",
|
'student_survey_response_5' => '2021-03-31T10:01:36',
|
||||||
"student_survey_response_6" => "2021-03-31T10:01:37",
|
'student_survey_response_6' => '2021-03-31T10:01:37',
|
||||||
"student_survey_response_7" => "2021-03-31T10:01:38"}
|
'student_survey_response_7' => '2021-03-31T10:01:38' }
|
||||||
results.each do |key, value|
|
results.each do |key, value|
|
||||||
expect(SurveyItemResponse.find_by_response_id(key).recorded_date).to eq Date.parse(value)
|
expect(SurveyItemResponse.find_by_response_id(key).recorded_date).to eq Date.parse(value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigns_recorded_date_to_teacher_responses
|
def assigns_recorded_date_to_teacher_responses
|
||||||
results = {"teacher_survey_response_1" => "2020-10-16 11:09:03",
|
results = { 'teacher_survey_response_1' => '2020-10-16 11:09:03',
|
||||||
"teacher_survey_response_3" => "2020-12-06 8:36:52",
|
'teacher_survey_response_3' => '2020-12-06 8:36:52',
|
||||||
"teacher_survey_response_4" => "2020-12-06 8:51:25",
|
'teacher_survey_response_4' => '2020-12-06 8:51:25',
|
||||||
"teacher_survey_response_5" => "2020-12-06 8:55:58"}
|
'teacher_survey_response_5' => '2020-12-06 8:55:58' }
|
||||||
results.each do |key, value|
|
results.each do |key, value|
|
||||||
expect(SurveyItemResponse.find_by_response_id(key).recorded_date).to eq Date.parse(value)
|
expect(SurveyItemResponse.find_by_response_id(key).recorded_date).to eq Date.parse(value)
|
||||||
end
|
end
|
||||||
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 AnalyzeHelper
|
||||||
include Analyze::Graph
|
include Analyze::Graph
|
||||||
describe 'analyze/index' do
|
describe "analyze/index" do
|
||||||
subject { Nokogiri::HTML(rendered) }
|
subject { Nokogiri::HTML(rendered) }
|
||||||
let(:category) { create(:category) }
|
let(:category) { create(:category) }
|
||||||
let(:subcategory) { create(:subcategory, category:) }
|
let(:subcategory) { create(:subcategory, category:) }
|
||||||
let(:school) { create(:school) }
|
let(:school) { create(:school) }
|
||||||
let(:academic_year) { create(:academic_year) }
|
let(:academic_year) { create(:academic_year) }
|
||||||
let(:races) do
|
let(:races) do
|
||||||
DemographicLoader.load_data(filepath: 'spec/fixtures/sample_demographics.csv')
|
DemographicLoader.load_data(filepath: "spec/fixtures/sample_demographics.csv")
|
||||||
Race.all
|
Race.all
|
||||||
end
|
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(:background) { BackgroundPresenter.new(num_of_columns: graph.columns.count) }
|
||||||
let(:selected_races) { races }
|
|
||||||
|
|
||||||
let(:support_for_teaching) do
|
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:)
|
scale = create(:scale, measure:)
|
||||||
create(:student_survey_item,
|
create(:student_survey_item,
|
||||||
scale:,
|
scale:,
|
||||||
|
|
@ -31,7 +26,7 @@ describe 'analyze/index' do
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:effective_leadership) do
|
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:)
|
scale = create(:scale, measure:)
|
||||||
create(:teacher_survey_item,
|
create(:teacher_survey_item,
|
||||||
scale:,
|
scale:,
|
||||||
|
|
@ -43,7 +38,7 @@ describe 'analyze/index' do
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:professional_qualifications) do
|
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:)
|
scale = create(:scale, measure:)
|
||||||
create(:admin_data_item,
|
create(:admin_data_item,
|
||||||
scale:,
|
scale:,
|
||||||
|
|
@ -54,73 +49,30 @@ describe 'analyze/index' do
|
||||||
measure
|
measure
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:sources) do
|
|
||||||
[Analyze::Source::SurveyData.new(slices:)]
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:slices) do
|
|
||||||
students_and_teachers = Analyze::Slice::StudentsAndTeachers.new
|
|
||||||
students_by_group = Analyze::Slice::StudentsByGroup.new(races:, grades:)
|
|
||||||
[students_and_teachers, students_by_group]
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:slice) do
|
|
||||||
slices.first
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:groups) do
|
|
||||||
[Analyze::Group::Race.new, Analyze::Group::Grade.new]
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:group) do
|
|
||||||
groups.first
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:grades) do
|
|
||||||
(1..12).to_a
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:genders) do
|
let(:genders) do
|
||||||
DemographicLoader.load_data(filepath: 'spec/fixtures/sample_demographics.csv')
|
DemographicLoader.load_data(filepath: "spec/fixtures/sample_demographics.csv")
|
||||||
Gender.all
|
Gender.all
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:selected_genders) do
|
let(:respondent) { create(:respondent, school:, academic_year:) }
|
||||||
genders
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:selected_grades) do
|
|
||||||
grades
|
|
||||||
end
|
|
||||||
|
|
||||||
before :each do
|
before :each do
|
||||||
assign :races, races
|
races
|
||||||
assign :selected_races, selected_races
|
category
|
||||||
assign :graph, graph
|
subcategory
|
||||||
assign :graphs, graphs
|
support_for_teaching
|
||||||
assign :background, background
|
effective_leadership
|
||||||
|
professional_qualifications
|
||||||
|
respondent
|
||||||
assign :academic_year, academic_year
|
assign :academic_year, academic_year
|
||||||
assign :available_academic_years, [academic_year]
|
|
||||||
assign :selected_academic_years, [academic_year]
|
|
||||||
assign :district, create(:district)
|
assign :district, create(:district)
|
||||||
assign :school, school
|
assign :school, school
|
||||||
assign :category, category
|
assign :presenter,
|
||||||
assign :categories, [category]
|
Analyze::Presenter.new(school:, academic_year:,
|
||||||
assign :subcategory, subcategory
|
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 :subcategories, category.subcategories
|
assign :background, BackgroundPresenter.new(num_of_columns: 4)
|
||||||
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:)
|
|
||||||
end
|
end
|
||||||
context 'when all the presenters have a nil score' do
|
context "when all the presenters have a nil score" do
|
||||||
before do
|
before do
|
||||||
render
|
render
|
||||||
end
|
end
|
||||||
|
|
@ -139,63 +91,72 @@ describe 'analyze/index' do
|
||||||
# ]
|
# ]
|
||||||
# end
|
# end
|
||||||
|
|
||||||
it 'displays a set of grouped bars for each presenter' do
|
it "displays a set of grouped bars for each presenter" do
|
||||||
displayed_variance_columns = subject.css('.grouped-bar-column')
|
displayed_variance_columns = subject.css(".grouped-bar-column")
|
||||||
expect(displayed_variance_columns.count).to eq 9
|
expect(displayed_variance_columns.count).to eq 27
|
||||||
|
|
||||||
displayed_variance_rows = subject.css('[data-for-measure-id]')
|
displayed_variance_rows = subject.css("[data-for-measure-id]")
|
||||||
expect(displayed_variance_rows.first.attribute('data-for-measure-id').value).to eq '1A-I'
|
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
|
expect(displayed_academic_years.count).to eq 0
|
||||||
|
|
||||||
displayed_variance_labels = subject.css('[data-grouped-bar-label]')
|
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.count).to eq 39
|
||||||
expect(displayed_variance_labels[1].inner_text).to include 'Students'
|
expect(displayed_variance_labels.first.inner_text).to include "American"
|
||||||
expect(displayed_variance_labels.last.inner_text).to include 'Data'
|
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
|
end
|
||||||
|
|
||||||
it 'displays all measures for the first subcategory' do
|
it "displays all measures for the first subcategory" do
|
||||||
expect(rendered).to have_text '1A-I'
|
expect(rendered).to have_text "1A-I"
|
||||||
expect(rendered).to have_text '1A-II'
|
expect(rendered).to have_text "1A-II"
|
||||||
expect(rendered).to have_text '1A-III'
|
expect(rendered).to have_text "1A-III"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'displays user interface controls' do
|
it "displays user interface controls" do
|
||||||
expect(subject).to have_text 'Focus Area'
|
expect(subject).to have_text "Focus Area"
|
||||||
expect(subject).to have_css '#select-category'
|
expect(subject).to have_css "#select-category"
|
||||||
expect(subject).to have_css '#select-subcategory'
|
expect(subject).to have_css "#select-subcategory"
|
||||||
expect(subject).to have_css "##{academic_year.range}"
|
expect(subject).to have_css "##{academic_year.range}"
|
||||||
end
|
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
|
year_checkbox = subject.css("##{academic_year.range}").first
|
||||||
expect(year_checkbox.name).to eq 'input'
|
expect(year_checkbox.name).to eq "input"
|
||||||
expect(academic_year.range).to eq '2050-51'
|
expect(academic_year.range).to eq "2050-51"
|
||||||
expect(year_checkbox).to have_attribute 'disabled'
|
expect(year_checkbox).to have_attribute "disabled"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'displays a radio box selector for each type of data filter' do
|
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-and-teachers"
|
||||||
expect(subject).to have_css '#students-by-group'
|
expect(subject).to have_css "#students-by-group"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'displays a checkbox for each race designation' do
|
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
|
race_slugs = %w[race-american-indian-or-alaskan-native race-asian-or-pacific-islander race-black-or-african-american
|
||||||
hispanic-or-latinx middle-eastern multiracial race-ethnicity-not-listed white-or-caucasian]
|
race-hispanic-or-latinx race-middle-eastern race-multiracial race-race-ethnicity-not-listed race-white-or-caucasian]
|
||||||
race_slugs.each do |slug|
|
race_slugs.each do |slug|
|
||||||
expect(subject).to have_css("//input[@type='checkbox'][@id='#{slug}']")
|
expect(subject).to have_css("//input[@type='checkbox'][@id='#{slug}']")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when presenters have a displayable score' do
|
context "when presenters have a displayable score" do
|
||||||
before do
|
before do
|
||||||
render
|
render
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when displaying a student and teacher graph' do
|
context "when displaying a student and teacher graph" do
|
||||||
end
|
end
|
||||||
end
|
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"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||||
|
|
||||||
semver@^7.3.2:
|
semver@^7.3.2, semver@^7.5.2:
|
||||||
version "7.5.3"
|
version "7.5.3"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
|
||||||
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
|
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue