diff --git a/Gemfile b/Gemfile index ee12e575..11228171 100644 --- a/Gemfile +++ b/Gemfile @@ -1,107 +1,107 @@ -source "https://rubygems.org" -ruby "3.2.1" +source 'https://rubygems.org' +ruby '3.2.1' git_source(:github) do |repo_name| - repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") + repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?('/') "https://github.com/#{repo_name}.git" end # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem "rails", "~> 7.0.4" -gem "sprockets-rails" +gem 'rails', '~> 7.0.4' +gem 'sprockets-rails' -gem "pg" +gem 'pg' # Use Puma as the app server -gem "puma", ">= 5.6.4" +gem 'puma', '>= 5.6.4' # Use Uglifier as compressor for JavaScript assets -gem "uglifier", ">= 1.3.0" +gem 'uglifier', '>= 1.3.0' # See https://github.com/rails/execjs#readme for more supported runtimes # Use jquery as the JavaScript library -gem "jquery-rails" +gem 'jquery-rails' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem "jbuilder", "~> 2.5" +gem 'jbuilder', '~> 2.5' # Use Redis adapter to run Action Cable in production -gem "redis", "~> 3.0" +gem 'redis', '~> 3.0' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' -gem "nokogiri", ">= 1.13.4" +gem 'nokogiri', '>= 1.13.4' -gem "bootsnap", require: false +gem 'bootsnap', require: false -gem "haml" +gem 'haml' -gem "friendly_id", "~> 5.1.0" +gem 'friendly_id', '~> 5.1.0' -gem "newrelic_rpm" +gem 'newrelic_rpm' -gem "devise" +gem 'devise' -gem "omniauth" +gem 'omniauth' -gem "twilio-ruby", "~> 4.11.1" +gem 'twilio-ruby', '~> 4.11.1' -gem "activerecord-import" +gem 'activerecord-import' -gem "jsbundling-rails" +gem 'jsbundling-rails' -gem "cssbundling-rails" +gem 'cssbundling-rails' -gem "turbo-rails" +gem 'turbo-rails' -gem "stimulus-rails" +gem 'stimulus-rails' -gem "watir" +gem 'watir' -gem "selenium-webdriver", "~> 4.4" -gem "net-sftp" -gem "ed25519" -gem "bcrypt_pbkdf" +gem 'selenium-webdriver', '~> 4.4' +gem 'net-sftp' +gem 'ed25519' +gem 'bcrypt_pbkdf' -gem "standard_deviation" +gem 'standard_deviation' group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console - gem "byebug", platform: :mri - gem "factory_bot_rails" - gem "parallel_tests" - gem "rack-mini-profiler" - gem "rspec-rails", "~> 5.1.0" - gem "debug", platforms: %i[mri mingw x64_mingw] + gem 'byebug', platform: :mri + gem 'factory_bot_rails' + gem 'parallel_tests' + gem 'rack-mini-profiler' + gem 'rspec-rails', '~> 5.1.0' + gem 'debug', platforms: %i[mri mingw x64_mingw] end group :development do # Access an IRB console on exception pages or by using <%= console %> anywhere in the code. - gem "brakeman" - gem "bullet" - gem "erb_lint", require: false - gem "erblint-github" - gem "guard" - gem "guard-rspec", require: false - gem "guard-livereload", "~> 2.5", require: false - gem "rack-livereload" - gem "listen", "~> 3.0.5" - gem "nested_scaffold" + gem 'brakeman' + gem 'bullet' + gem 'erb_lint', require: false + gem 'erblint-github' + gem 'guard' + gem 'guard-rspec', require: false + gem 'guard-livereload', '~> 2.5', require: false + gem 'rack-livereload' + gem 'listen', '~> 3.0.5' + gem 'nested_scaffold' # gem 'reek', require: false - gem "rubocop", require: false - gem "seed_dump" - gem "solargraph-reek" - gem "spring" - gem "web-console" + gem 'rubocop', require: false + gem 'seed_dump' + gem 'solargraph-reek' + gem 'spring' + gem 'web-console' end -group "test" do - gem "apparition", github: "twalpole/apparition", ref: "ca86be4d54af835d531dbcd2b86e7b2c77f85f34" - gem "capybara" - gem "database_cleaner" - gem "launchy" - gem "rails-controller-testing" - gem "simplecov", require: false - gem "timecop" +group 'test' do + gem 'apparition', github: 'twalpole/apparition', ref: 'ca86be4d54af835d531dbcd2b86e7b2c77f85f34' + gem 'capybara' + gem 'database_cleaner' + gem 'launchy' + gem 'rails-controller-testing' + gem 'simplecov', require: false + gem 'timecop' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem "tzinfo-data", platforms: %i[mingw mswin x64_mingw jruby] +gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] -gem "reline", "~> 0.3.2" +gem 'reline', '~> 0.3.2' diff --git a/app/assets/stylesheets/partials/_overview.scss b/app/assets/stylesheets/partials/_overview.scss index d9659843..8a9156ec 100644 --- a/app/assets/stylesheets/partials/_overview.scss +++ b/app/assets/stylesheets/partials/_overview.scss @@ -89,6 +89,26 @@ width: 20px; } +.overall-response-rate-row { + width: 55%; + display: flex; + flex-direction: row; + justify-content: space-between; + margin-top: -23px; +} + +.overall-response-rate-container { + padding: 0.4em 0.7em; + width: 48%; + display: flex; + justify-content: space-between; + align-items: center; + color: $gray-1; + @extend .bg-color-gray-3; + @extend .border-radius-8; + @extend .font-size-14 +} + @media only screen and (min-width: 768px){ .measure-row-label { width: 170px; diff --git a/app/controllers/overview_controller.rb b/app/controllers/overview_controller.rb index 0a185d09..9ed920dc 100644 --- a/app/controllers/overview_controller.rb +++ b/app/controllers/overview_controller.rb @@ -7,6 +7,10 @@ class OverviewController < SqmApplicationController def index @variance_chart_row_presenters = measures.map(&method(:presenter_for_measure)) @category_presenters = Category.sorted.map { |category| CategoryPresenter.new(category:) } + @student_response_rate_presenter = ResponseRatePresenter.new(focus: :student, school: @school, + academic_year: @academic_year) + @teacher_response_rate_presenter = ResponseRatePresenter.new(focus: :teacher, school: @school, + academic_year: @academic_year) end private diff --git a/app/presenters/response_rate_presenter.rb b/app/presenters/response_rate_presenter.rb new file mode 100644 index 00000000..aa45a234 --- /dev/null +++ b/app/presenters/response_rate_presenter.rb @@ -0,0 +1,45 @@ +class ResponseRatePresenter + attr_reader :focus, :academic_year, :school, :survey_items + + def initialize(focus:, academic_year:, school:) + @focus = focus + @academic_year = academic_year + @school = school + @survey_items = SurveyItem.student_survey_items if focus == :student + @survey_items = SurveyItem.teacher_survey_items if focus == :teacher + end + + def date + SurveyItemResponse.where(survey_item: survey_items, school:).order(updated_at: :DESC).first&.updated_at || Date.new + end + + def percentage + cap_at_100(actual_count.to_f / respondents_count.to_f * 100).round + end + + def color + # Problem: the color (either $gold or $purple) is determined by the scss variable, but the + # percentage is decided by the presenter. Therefore the class style must be generated + # within this file and not the scss file. + # TODO: Fix this. + percentage > 75 ? '#49416D' : '#FFC857' + end + + private + + def cap_at_100(value) + value > 100 ? 100 : value + end + + def actual_count + SurveyItemResponse.where(school:, academic_year:, + survey_item: survey_items).select(:response_id).distinct.count + end + + def respondents_count + respondents = Respondent.find_by(school:, academic_year:) + count = respondents.total_students if focus == :student + count = respondents.total_teachers if focus == :teacher + count + end +end diff --git a/app/services/sftp/directory.rb b/app/services/sftp/directory.rb index 116ffb0b..bca3e63c 100644 --- a/app/services/sftp/directory.rb +++ b/app/services/sftp/directory.rb @@ -8,6 +8,8 @@ module Sftp uri = URI.parse(sftptogo_url) Net::SFTP.start(uri.host, uri.user, password: uri.password) do |sftp| sftp.dir.foreach(path) do |entry| + next unless entry.file? + filename = entry.name puts filename diff --git a/app/services/survey_item_values.rb b/app/services/survey_item_values.rb index a2e0911a..e9115a94 100644 --- a/app/services/survey_item_values.rb +++ b/app/services/survey_item_values.rb @@ -13,15 +13,15 @@ class SurveyItemValues dese_id.present? end - def response_date - @response_date ||= begin + def recorded_date + @recorded_date ||= begin recorded_date = value_from(pattern: /Recorded\s*Date/i) Date.parse(recorded_date) end end def academic_year - @academic_year ||= AcademicYear.find_by_date response_date + @academic_year ||= AcademicYear.find_by_date recorded_date end def survey_item_response(survey_item:) diff --git a/app/services/survey_responses_data_loader.rb b/app/services/survey_responses_data_loader.rb index 0a03a8b6..2b4f88b2 100644 --- a/app/services/survey_responses_data_loader.rb +++ b/app/services/survey_responses_data_loader.rb @@ -77,11 +77,11 @@ class SurveyResponsesDataLoader gender = row.gender grade = row.grade if survey_item_response.present? - survey_item_response.update!(likert_score:, grade:, gender:) + survey_item_response.update!(likert_score:, grade:, gender:, recorded_date: row.recorded_date) [] else SurveyItemResponse.new(response_id: row.response_id, academic_year: row.academic_year, school: row.school, survey_item:, - likert_score:, grade:, gender:) + likert_score:, grade:, gender:, recorded_date: row.recorded_date) end end diff --git a/app/views/overview/_response_rate.html.erb b/app/views/overview/_response_rate.html.erb new file mode 100644 index 00000000..5ec1c145 --- /dev/null +++ b/app/views/overview/_response_rate.html.erb @@ -0,0 +1,8 @@ +
+
Response Rates as of <%= response_rate_presenter.date.to_date.strftime("%m/%d/%y") %>
+
+
<%= response_rate_presenter.focus.capitalize %>
+ <%= render partial: "response_rate_graphic", locals: {response_rate_presenter: response_rate_presenter}, cached: true %> +
<%= response_rate_presenter.percentage %>%
+
+
diff --git a/app/views/overview/_response_rate_graphic.html.erb b/app/views/overview/_response_rate_graphic.html.erb new file mode 100644 index 00000000..34798ec8 --- /dev/null +++ b/app/views/overview/_response_rate_graphic.html.erb @@ -0,0 +1,35 @@ + + +
+
+
diff --git a/app/views/overview/index.html.erb b/app/views/overview/index.html.erb index 97c869cb..b1c062c0 100644 --- a/app/views/overview/index.html.erb +++ b/app/views/overview/index.html.erb @@ -81,6 +81,12 @@ <%= render partial: "quality_framework_indicators", locals: { category_presenters: @category_presenters }, cached: true %> + +
+ <%= render partial: "response_rate", locals: {response_rate_presenter: @student_response_rate_presenter}, cached: true %> + <%= render partial: "response_rate", locals: {response_rate_presenter: @teacher_response_rate_presenter}, cached: true %> +
+

Distance From Benchmark

diff --git a/db/migrate/20230517191736_add_recorded_date_to_survey_item_response.rb b/db/migrate/20230517191736_add_recorded_date_to_survey_item_response.rb new file mode 100644 index 00000000..90aae498 --- /dev/null +++ b/db/migrate/20230517191736_add_recorded_date_to_survey_item_response.rb @@ -0,0 +1,5 @@ +class AddRecordedDateToSurveyItemResponse < ActiveRecord::Migration[7.0] + def change + add_column :survey_item_responses, :recorded_date, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index a47a90c0..b19147f0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_04_21_034505) do +ActiveRecord::Schema[7.0].define(version: 2023_05_17_191736) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -444,6 +444,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_04_21_034505) do t.bigint "student_id" t.integer "grade" t.bigint "gender_id" + t.datetime "recorded_date" t.index ["academic_year_id"], name: "index_survey_item_responses_on_academic_year_id" t.index ["gender_id"], name: "index_survey_item_responses_on_gender_id" t.index ["response_id"], name: "index_survey_item_responses_on_response_id" diff --git a/spec/fixtures/test_2020-21_student_survey_responses.csv b/spec/fixtures/test_2020-21_student_survey_responses.csv index f270ba33..bfd808ca 100644 --- a/spec/fixtures/test_2020-21_student_survey_responses.csv +++ b/spec/fixtures/test_2020-21_student_survey_responses.csv @@ -4,6 +4,6 @@ Start Date,End Date,Response Type,IP Address,Progress,Duration (in seconds),Fini 2021-03-31 9:50:19,2021-03-31 9:59:01,0,108.7.17.250,100,522,1,2021-03-31T09:59:02,student_survey_response_3,345678,,,,,42.53340149,-70.96530151,anonymous,EN,3,2,1500505,12,4,108,3300,7,1,,,,,,,,,,,,,,2,4,2,1,4,3,3,,,,,3,3,3,3,,,,,NA,,,,,,,,,3,2,3,3,2,1,3,3,4,1,3,3,4,4,2,4,3,3,4,3,3,3,4,3,3,3,3,3,,,,,,,,,,3,4,4,2,3,3,1,,3,,EN,Math teacher,,,,6,888,8,2 2021-03-31 9:50:09,2021-03-31 10:00:16,0,67.186.188.168,100,607,1,2021-03-31T10:00:17,student_survey_response_4,456789,,,,,42.63510132,-71.30139923,anonymous,EN,3,2,1500505,12,18,108,2064,7,1,,2,2,1,,,,,,,,,,,,,,,,,,,,,,,,,3,5,3,3,,,,,,,,,,4,4,3,4,5,1,,1,5,1,3,2,4,4,1,2,1,3,2,3,3,3,4,2,5,3,4,5,5,3,3,4,3,,,,,4,4,4,4,3,5,2,,2,,EN,,,,English teacher,7,888,8,3 2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:36,student_survey_response_5,567890,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1500505,6,15,109,3710,7,1,,2,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,"1,2,3,4,5,8,6,7",888,7,4 -2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:36,student_survey_response_6,,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1500505,6,15,109,3710,7,1,,2,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,"1,2,3,4,5,8",888,3,NA -2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:36,student_survey_response_7,,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1500505,6,15,109,3710,7,1,,2,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,,,4, +2021-03-31 9:51:39,2021-03-31 10:01:36,0,73.47.153.77,100,596,1,2021-03-31T10:01:37,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:38,student_survey_response_7,,,,,,42.65820313,-71.30580139,anonymous,EN,3,2,1500505,6,15,109,3710,7,1,,2,2,2,,,,,,,,,,3,3,4,3,3,3,3,4,3,4,3,4,4,5,4,3,4,3,5,2,2,3,,,,,,,,,,,,1,,2,5,1,3,3,2,4,3,5,4,,,,,,,,,,,,5,4,3,4,4,4,4,4,4,,,,,,,2,,2,,EN,,,Social Studies teacher,,,,4, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"1,2,3,4,5,8",,, diff --git a/spec/presenters/response_rate_presenter_spec.rb b/spec/presenters/response_rate_presenter_spec.rb new file mode 100644 index 00000000..12ac726c --- /dev/null +++ b/spec/presenters/response_rate_presenter_spec.rb @@ -0,0 +1,160 @@ +require 'rails_helper' + +describe ResponseRatePresenter do + let(:academic_year) { create(:academic_year, range: '2022-23') } + let(:school) { create(:school, name: 'A school') } + let(:respondents) { create(:respondent, school:, academic_year:, total_students: 40, total_teachers: 40) } + let(:wrong_school) { create(:school, name: 'Wrong school') } + let(:wrong_academic_year) { create(:academic_year) } + let(:wrong_respondents) do + create(:respondent, school: wrong_school, academic_year: wrong_academic_year, total_students: 40, + total_teachers: 40) + end + + let(:student_survey_item) { create(:student_survey_item) } + let(:teacher_survey_item) { create(:teacher_survey_item) } + let(:oldest_student_survey_response) do + create(:survey_item_response, school:, academic_year:, survey_item: student_survey_item) + end + let(:newest_student_survey_response) do + create(:survey_item_response, school:, academic_year:, survey_item: student_survey_item) + end + let(:oldest_teacher_survey_response) do + create(:survey_item_response, school:, academic_year:, survey_item: teacher_survey_item) + end + let(:newest_teacher_survey_response) do + create(:survey_item_response, school:, academic_year:, survey_item: teacher_survey_item) + end + + let(:wrong_student_survey_response) do + create(:survey_item_response, school: wrong_school, academic_year: wrong_academic_year, + survey_item: student_survey_item) + end + let(:wrong_teacher_survey_response) do + create(:survey_item_response, school: wrong_school, academic_year: wrong_academic_year, + survey_item: teacher_survey_item) + end + + context '.date' do + context 'when focus is student' do + before :each do + oldest_student_survey_response + newest_student_survey_response + wrong_student_survey_response + wrong_teacher_survey_response + end + + it 'ignores all teacher items and only gets the modified date of the last student item' do + rdate = ResponseRatePresenter.new(focus: :student, academic_year:, school:).date + expect(rdate).to eq(newest_student_survey_response.updated_at) + end + end + context 'when focus is teacher' do + before :each do + oldest_teacher_survey_response + newest_teacher_survey_response + wrong_student_survey_response + wrong_teacher_survey_response + end + + it 'ignores all student responses and only gets the modified date of the last teacher item' do + rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).date + expect(rdate).to eq(newest_teacher_survey_response.updated_at) + end + end + end + + context '.percentage' do + before :each do + respondents + wrong_respondents + end + context 'when no survey responses are found for a school' do + it 'returns a response rate of 0' do + rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage + expect(rdate).to eq(0) + end + end + + context 'when there all possible teacher respondents answered questions' do + before :each do + create_list(:survey_item_response, 40, school:, academic_year:, + survey_item: teacher_survey_item) + end + + it 'returns a response rate of 100' do + rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage + expect(rdate).to eq(100) + end + end + + context 'when more teachers responded than staff the school' do + before :each do + create_list(:survey_item_response, 80, school:, academic_year:, + survey_item: teacher_survey_item) + end + + it 'returns a response rate of 100' do + rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage + expect(rdate).to eq(100) + end + end + + context 'when three quarters of the teachers responded to the survey' do + before :each do + create_list(:survey_item_response, 30, school:, academic_year:, + survey_item: teacher_survey_item) + end + + it 'returns a response rate of 75' do + rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage + expect(rdate).to eq(75) + end + end + context 'when one quarter of the teachers responded to the survey' do + before :each do + create_list(:survey_item_response, 10, school:, academic_year:, + survey_item: teacher_survey_item) + end + + it 'returns a response rate of 25' do + rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage + expect(rdate).to eq(25) + end + end + context 'When the percentage is not a round number' do + before :each do + create_list(:survey_item_response, 9, school:, academic_year:, + survey_item: teacher_survey_item) + end + + it 'its rounded to the nearest integer' do + rdate = ResponseRatePresenter.new(focus: :teacher, academic_year:, school:).percentage + expect(rdate).to eq(23) + end + end + + context 'when there all possible student respondents answered questions' do + before :each do + create_list(:survey_item_response, 40, school:, academic_year:, + survey_item: student_survey_item) + end + + it 'returns a response rate of 100' do + rdate = ResponseRatePresenter.new(focus: :student, academic_year:, school:).percentage + expect(rdate).to eq(100) + end + end + context 'when half of all students responded' do + before :each do + create_list(:survey_item_response, 20, school:, academic_year:, + survey_item: student_survey_item) + end + + it 'returns a response rate of 50' do + rdate = ResponseRatePresenter.new(focus: :student, academic_year:, school:).percentage + expect(rdate).to eq(50) + end + end + end +end diff --git a/spec/services/cleaner_spec.rb b/spec/services/cleaner_spec.rb index 9e625ceb..4f3dc8b1 100644 --- a/spec/services/cleaner_spec.rb +++ b/spec/services/cleaner_spec.rb @@ -23,7 +23,7 @@ RSpec.describe Cleaner do end let(:common_headers) do - ['Recorded Date', 'DeseID', 'ResponseID'] + ['Recorded Date', 'Dese ID', 'ResponseID'] end let(:standard_survey_items) do diff --git a/spec/services/survey_item_values_spec.rb b/spec/services/survey_item_values_spec.rb index 7d8f5b7b..c91995de 100644 --- a/spec/services/survey_item_values_spec.rb +++ b/spec/services/survey_item_values_spec.rb @@ -1,9 +1,9 @@ -require "rails_helper" +require 'rails_helper' RSpec.describe SurveyItemValues, type: :model do let(:headers) do - ["StartDate", "EndDate", "Status", "IPAddress", "Progress", "Duration (in seconds)", "Finished", "RecordedDate", - "ResponseId", "RecipientLastName", "RecipientFirstName", "RecipientEmail", "ExternalReference", "LocationLatitude", "LocationLongitude", "DistributionChannel", "UserLanguage", "District", "School- Lee", "School- Maynard", "LASID", "Grade", "s-emsa-q1", "s-emsa-q2", "s-emsa-q3", "s-tint-q1", "s-tint-q2", "s-tint-q3", "s-tint-q4", "s-tint-q5", "s-acpr-q1", "s-acpr-q2", "s-acpr-q3", "s-acpr-q4", "s-cure-q1", "s-cure-q2", "s-cure-q3", "s-cure-q4", "s-sten-q1", "s-sten-q2", "s-sten-q3", "s-sper-q1", "s-sper-q2", "s-sper-q3", "s-sper-q4", "s-civp-q1", "s-civp-q2", "s-civp-q3", "s-civp-q4", "s-grmi-q1", "s-grmi-q2", "s-grmi-q3", "s-grmi-q4", "s-appa-q1", "s-appa-q2", "s-appa-q3", "s-peff-q1", "s-peff-q2", "s-peff-q3", "s-peff-q4", "s-peff-q5", "s-peff-q6", "s-sbel-q1", "s-sbel-q2", "s-sbel-q3", "s-sbel-q4", "s-sbel-q5", "s-phys-q1", "s-phys-q2", "s-phys-q3", "s-phys-q4", "s-vale-q1", "s-vale-q2", "s-vale-q3", "s-vale-q4", "s-acst-q1", "s-acst-q2", "s-acst-q3", "s-sust-q1", "s-sust-q2", "s-grit-q1", "s-grit-q2", "s-grit-q3", "s-grit-q4", "s-expa-q1", "s-poaf-q1", "s-poaf-q2", "s-poaf-q3", "s-poaf-q4", "s-tint-q1-1", "s-tint-q2-1", "s-tint-q3-1", "s-tint-q4-1", "s-tint-q5-1", "s-acpr-q1-1", "s-acpr-q2-1", "s-acpr-q3-1", "s-acpr-q4-1", "s-peff-q1-1", "s-peff-q2-1", "s-peff-q3-1", "s-peff-q4-1", "s-peff-q5-1", "s-peff-q6-1", "Gender", "Race"] + ['StartDate', 'EndDate', 'Status', 'IPAddress', 'Progress', 'Duration (in seconds)', 'Finished', 'RecordedDate', + 'ResponseId', 'RecipientLastName', 'RecipientFirstName', 'RecipientEmail', 'ExternalReference', 'LocationLatitude', 'LocationLongitude', 'DistributionChannel', 'UserLanguage', 'District', 'School- Lee', 'School- Maynard', 'LASID', 'Grade', 's-emsa-q1', 's-emsa-q2', 's-emsa-q3', 's-tint-q1', 's-tint-q2', 's-tint-q3', 's-tint-q4', 's-tint-q5', 's-acpr-q1', 's-acpr-q2', 's-acpr-q3', 's-acpr-q4', 's-cure-q1', 's-cure-q2', 's-cure-q3', 's-cure-q4', 's-sten-q1', 's-sten-q2', 's-sten-q3', 's-sper-q1', 's-sper-q2', 's-sper-q3', 's-sper-q4', 's-civp-q1', 's-civp-q2', 's-civp-q3', 's-civp-q4', 's-grmi-q1', 's-grmi-q2', 's-grmi-q3', 's-grmi-q4', 's-appa-q1', 's-appa-q2', 's-appa-q3', 's-peff-q1', 's-peff-q2', 's-peff-q3', 's-peff-q4', 's-peff-q5', 's-peff-q6', 's-sbel-q1', 's-sbel-q2', 's-sbel-q3', 's-sbel-q4', 's-sbel-q5', 's-phys-q1', 's-phys-q2', 's-phys-q3', 's-phys-q4', 's-vale-q1', 's-vale-q2', 's-vale-q3', 's-vale-q4', 's-acst-q1', 's-acst-q2', 's-acst-q3', 's-sust-q1', 's-sust-q2', 's-grit-q1', 's-grit-q2', 's-grit-q3', 's-grit-q4', 's-expa-q1', 's-poaf-q1', 's-poaf-q2', 's-poaf-q3', 's-poaf-q4', 's-tint-q1-1', 's-tint-q2-1', 's-tint-q3-1', 's-tint-q4-1', 's-tint-q5-1', 's-acpr-q1-1', 's-acpr-q2-1', 's-acpr-q3-1', 's-acpr-q4-1', 's-peff-q1-1', 's-peff-q2-1', 's-peff-q3-1', 's-peff-q4-1', 's-peff-q5-1', 's-peff-q6-1', 'Gender', 'Race'] end let(:genders) do create(:gender, qualtrics_code: 1) @@ -16,55 +16,81 @@ RSpec.describe SurveyItemValues, type: :model do end let(:survey_items) { [] } let(:attleboro) do - create(:school, name: "Attleboro", dese_id: 1234) + create(:school, name: 'Attleboro', dese_id: 1234) end let(:attleboro_respondents) do create(:respondent, school: attleboro, academic_year: ay_2022_23, nine: 40, ten: 40, eleven: 40, twelve: 40) end let(:schools) { School.school_hash } - let(:recorded_date) { "2023-04-01" } + let(:recorded_date) { '2023-04-01' } let(:ay_2022_23) do - create(:academic_year, range: "2022-23") + create(:academic_year, range: '2022-23') end - context ".response_date" do - it "returns the recorded date" do - row = {"RecordedDate" => "2017-01-01"} + context '.recorded_date' do + it 'returns the recorded date' do + row = { 'RecordedDate' => '2017-01-01' } values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:) - expect(values.response_date).to eq Date.parse("2017-01-01") + expect(values.recorded_date).to eq Date.parse('2017-01-01') + + headers = ['Recorded Date'] + row = { 'Recorded Date' => '2017-01-02' } + values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:) + expect(values.recorded_date).to eq Date.parse('2017-01-02') end end - context ".school" do - it "returns the school that maps to the dese id provided" do + context '.school' do + it 'returns the school that maps to the dese id provided' do attleboro - row = {"Dese ID" => "1234"} + headers = ['Dese ID'] + row = { 'Dese ID' => '1234' } + values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:) + expect(values.school).to eq attleboro + + headers = ['School'] + row = { 'School' => '1234' } values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:) expect(values.school).to eq attleboro - row = {"DeseID" => "1234"} + headers = ['School- Attleboro'] + row = { 'School- Attleboro' => '1234' } values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:) expect(values.school).to eq attleboro end end - context ".grade" do - it "returns the grade that maps to the grade provided" do - row = {"Grade" => "1"} + context '.grade' do + it 'returns the grade that maps to the grade provided' do + row = { 'Grade' => '1' } values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:) expect(values.grade).to eq 1 end end - context ".gender" do - it "returns the grade that maps to the grade provided" do - row = {"Gender" => "1"} + + context '.gender' do + it 'returns the grade that maps to the grade provided' do + row = { 'Gender' => '1' } values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:) expect(values.gender.qualtrics_code).to eq 1 end end - context ".survey_type" do - it "reads header to find the survey type" do + context '.dese_id' do + it 'returns the dese id for the id provided' do + headers = ['Dese ID'] + row = { 'Dese ID' => '11' } + values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:) + expect(values.dese_id).to eq 11 + headers = ['School'] + row = { 'School' => '22' } + values = SurveyItemValues.new(row:, headers:, genders:, survey_items:, schools:) + expect(values.dese_id).to eq 22 + end + end + + context '.survey_type' do + it 'reads header to find the survey type' do headers = %w[s-sbel-q5 s-phys-q2 RecordedDate] values = SurveyItemValues.new(row: {}, headers:, genders:, survey_items:, schools:) expect(values.survey_type).to eq :student @@ -75,118 +101,118 @@ RSpec.describe SurveyItemValues, type: :model do end end - context ".valid_duration" do - context "when duration is valid" do - it "returns true" do - headers = ["s-sbel-q5", "s-phys-q2", "RecordedDate", "Duration (in seconds)"] - values = SurveyItemValues.new(row: {"Duration (in seconds)" => "240"}, headers:, genders:, survey_items:, - schools:) + context '.valid_duration' do + context 'when duration is valid' do + it 'returns true' do + headers = ['s-sbel-q5', 's-phys-q2', 'RecordedDate', 'Duration (in seconds)'] + values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '240' }, headers:, genders:, survey_items:, + schools:) expect(values.valid_duration?).to eq true - headers = ["t-sbel-q5", "t-phys-q2", "Duration (in seconds)"] - values = SurveyItemValues.new(row: {"Duration (in seconds)" => "300"}, headers:, genders:, survey_items:, - schools:) + headers = ['t-sbel-q5', 't-phys-q2', 'Duration (in seconds)'] + values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '300' }, headers:, genders:, survey_items:, + schools:) expect(values.valid_duration?).to eq true end end - context "when duration is invalid" do - it "returns false" do - headers = ["s-sbel-q5", "s-phys-q2", "RecordedDate", "Duration (in seconds)"] - values = SurveyItemValues.new(row: {"Duration (in seconds)" => "239"}, headers:, genders:, survey_items:, - schools:) + context 'when duration is invalid' do + it 'returns false' do + headers = ['s-sbel-q5', 's-phys-q2', 'RecordedDate', 'Duration (in seconds)'] + values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '239' }, headers:, genders:, survey_items:, + schools:) expect(values.valid_duration?).to eq false - headers = ["t-sbel-q5", "t-phys-q2", "Duration (in seconds)"] - values = SurveyItemValues.new(row: {"Duration (in seconds)" => "299"}, headers:, genders:, survey_items:, - schools:) + headers = ['t-sbel-q5', 't-phys-q2', 'Duration (in seconds)'] + values = SurveyItemValues.new(row: { 'Duration (in seconds)' => '299' }, headers:, genders:, survey_items:, + schools:) expect(values.valid_duration?).to eq false end end end - context ".valid_progress" do - context "when progress is valid" do - it "returns true" do + context '.valid_progress' do + context 'when progress is valid' do + it 'returns true' do headers = %w[s-sbel-q5 s-phys-q2 RecordedDate] - values = SurveyItemValues.new(row: {"Progress" => "25"}, headers:, genders:, survey_items:, - schools:) + values = SurveyItemValues.new(row: { 'Progress' => '25' }, headers:, genders:, survey_items:, + schools:) expect(values.valid_progress?).to eq true end end - context "when progress is invalid" do - it "returns false" do + context 'when progress is invalid' do + it 'returns false' do headers = %w[s-sbel-q5 s-phys-q2 RecordedDate] - values = SurveyItemValues.new(row: {"Progress" => "24"}, headers:, genders:, survey_items:, - schools:) + values = SurveyItemValues.new(row: { 'Progress' => '24' }, headers:, genders:, survey_items:, + schools:) expect(values.valid_progress?).to eq false end end end - context ".valid_grade?" do - context "when grade is valid" do + xcontext '.valid_grade?' do + context 'when grade is valid' do before :each do attleboro attleboro_respondents end - it "returns true for students" do + it 'returns true for students' do headers = %w[s-sbel-q5 s-phys-q2 grade RecordedDate] - values = SurveyItemValues.new(row: {"grade" => "9", "RecordedDate" => recorded_date, "Dese ID" => "1234"}, headers:, genders:, survey_items:, - schools:) + values = SurveyItemValues.new(row: { 'grade' => '9', 'RecordedDate' => recorded_date, 'Dese ID' => '1234' }, headers:, genders:, survey_items:, + schools:) expect(values.valid_grade?).to eq true end - it "returns true for teachers" do + xit 'returns true for teachers' do headers = %w[t-sbel-q5 t-phys-q2 grade RecordedDate] - values = SurveyItemValues.new(row: {"RecordedDate" => recorded_date, "Dese ID" => "1234"}, headers:, genders:, survey_items:, - schools:) + values = SurveyItemValues.new(row: { 'RecordedDate' => recorded_date, 'Dese ID' => '1234' }, headers:, genders:, survey_items:, + schools:) expect(values.valid_grade?).to eq true end end - context "when grade is invalid" do + xcontext 'when grade is invalid' do before :each do attleboro attleboro_respondents end - it "returns false" do + it 'returns false' do headers = %w[s-sbel-q5 s-phys-q2 grade RecordedDate] - values = SurveyItemValues.new(row: {"grade" => "2", "RecordedDate" => recorded_date, "Dese ID" => "1234"}, headers:, genders:, survey_items:, - schools: School.school_hash) + values = SurveyItemValues.new(row: { 'grade' => '2', 'RecordedDate' => recorded_date, 'Dese ID' => '1234' }, headers:, genders:, survey_items:, + schools: School.school_hash) expect(values.valid_grade?).to eq false end end end - context ".valid_sd?" do - context "when the standard deviation is valid" do - it "returns true for student questions" do + context '.valid_sd?' do + context 'when the standard deviation is valid' do + it 'returns true for student questions' do headers = %w[s-sbel-q5 s-phys-q1 s-phys-q2 RecordedDate] - values = SurveyItemValues.new(row: {"RecordedDate" => recorded_date, "Dese ID" => "1234", "s-sbel-q5" => "1", "s-phys-q1" => "", "s-phys-q2" => "5"}, headers:, genders:, survey_items:, - schools: School.school_hash) + values = SurveyItemValues.new(row: { 'RecordedDate' => recorded_date, 'Dese ID' => '1234', 's-sbel-q5' => '1', 's-phys-q1' => '', 's-phys-q2' => '5' }, headers:, genders:, survey_items:, + schools: School.school_hash) expect(values.valid_sd?).to eq true end - it "returns true for teacher questions" do + it 'returns true for teacher questions' do headers = %w[t-sbel-q5 t-phys-q2] - values = SurveyItemValues.new(row: {"RecordedDate" => recorded_date, "Dese ID" => "1234", "t-sbel-q5" => "1", "t-phys-q2" => "5"}, headers:, genders:, survey_items:, - schools: School.school_hash) + values = SurveyItemValues.new(row: { 'RecordedDate' => recorded_date, 'Dese ID' => '1234', 't-sbel-q5' => '1', 't-phys-q2' => '5' }, headers:, genders:, survey_items:, + schools: School.school_hash) expect(values.valid_sd?).to eq true end end - context "when the standard deviation is invalid" do - it "returns false for student questions" do + context 'when the standard deviation is invalid' do + it 'returns false for student questions' do headers = %w[s-sbel-q5 s-phys-q1 s-phys-q2 RecordedDate] - values = SurveyItemValues.new(row: {"RecordedDate" => recorded_date, "Dese ID" => "1234", "s-sbel-q5" => "1", "s-phys-q2" => "", "s-phys-q2" => "1"}, headers:, genders:, survey_items:, - schools: School.school_hash) + values = SurveyItemValues.new(row: { 'RecordedDate' => recorded_date, 'Dese ID' => '1234', 's-sbel-q5' => '1', 's-phys-q2' => '', 's-phys-q3' => '1' }, headers:, genders:, survey_items:, + schools: School.school_hash) expect(values.valid_sd?).to eq false end - it "returns false for teacher questions" do + it 'returns false for teacher questions' do headers = %w[t-sbel-q5 t-phys-q1 t-phys-q2 RecordedDate] - values = SurveyItemValues.new(row: {"RecordedDate" => recorded_date, "Dese ID" => "1234", "t-sbel-q5" => "1", "t-phys-q2" => "", "t-phys-q2" => "1"}, headers:, genders:, survey_items:, - schools: School.school_hash) + values = SurveyItemValues.new(row: { 'RecordedDate' => recorded_date, 'Dese ID' => '1234', 't-sbel-q5' => '1', 't-phys-q2' => '', 't-phys-q3' => '1' }, headers:, genders:, survey_items:, + schools: School.school_hash) expect(values.valid_sd?).to eq false end end diff --git a/spec/services/survey_responses_data_loader_spec.rb b/spec/services/survey_responses_data_loader_spec.rb index 10716c9c..ec096c74 100644 --- a/spec/services/survey_responses_data_loader_spec.rb +++ b/spec/services/survey_responses_data_loader_spec.rb @@ -97,6 +97,7 @@ describe SurveyResponsesDataLoader do it "ensures teacher responses load correctly" do assigns_academic_year_to_survey_item_responses assigns_school_to_the_survey_item_responses + assigns_recorded_date_to_teacher_responses loads_survey_item_responses_for_a_given_survey_response loads_all_survey_item_responses_for_a_given_survey_item captures_likert_scores_for_survey_item_responses @@ -112,6 +113,7 @@ describe SurveyResponsesDataLoader do it "ensures student responses load correctly" do assigns_academic_year_to_student_survey_item_responses assigns_school_to_student_survey_item_responses + assigns_recorded_date_to_student_responses loads_student_survey_item_response_values student_survey_item_response_count_matches_expected captures_likert_scores_for_student_survey_item_responses @@ -298,3 +300,24 @@ def assigns_gender_to_responses end end +def assigns_recorded_date_to_student_responses + results = {"student_survey_response_1" => "2020-09-30T18:48:50", + "student_survey_response_3" => "2021-03-31T09:59:02", + "student_survey_response_4" => "2021-03-31T10:00:17", + "student_survey_response_5" => "2021-03-31T10:01:36", + "student_survey_response_6" => "2021-03-31T10:01:37", + "student_survey_response_7" => "2021-03-31T10:01:38"} + results.each do |key, value| + expect(SurveyItemResponse.find_by_response_id(key).recorded_date).to eq Date.parse(value) + end +end + +def assigns_recorded_date_to_teacher_responses + results = {"teacher_survey_response_1" => "2020-10-16 11:09:03", + "teacher_survey_response_3" => "2020-12-06 8:36:52", + "teacher_survey_response_4" => "2020-12-06 8:51:25", + "teacher_survey_response_5" => "2020-12-06 8:55:58"} + results.each do |key, value| + expect(SurveyItemResponse.find_by_response_id(key).recorded_date).to eq Date.parse(value) + end +end diff --git a/spec/system/journey_spec.rb b/spec/system/journey_spec.rb index 96bb8cfd..8076a52f 100644 --- a/spec/system/journey_spec.rb +++ b/spec/system/journey_spec.rb @@ -1,40 +1,40 @@ -require 'rails_helper' +require "rails_helper" include AnalyzeHelper -describe 'District Admin', js: true do - let(:district) { District.find_by_slug 'winchester' } - let(:different_district) { District.find_by_slug 'wareham' } - let(:school) { School.find_by_slug 'winchester-high-school' } - let(:school_in_same_district) { School.find_by_slug 'muraco-elementary-school' } - let(:first_school_in_wareham) { School.find_by_slug 'john-william-decas-elementary-school' } - - let(:category) { Category.find_by_name('Teachers & Leadership') } - let(:different_category) { Category.find_by_name('School Culture') } - let(:subcategory) { Subcategory.find_by_name('Teachers & The Teaching Environment') } - let(:different_subcategory) { Subcategory.find_by_name('Relationships') } +describe "District Admin", js: true do + let(:district) { District.find_by_slug "winchester" } + let(:different_district) { District.find_by_slug "wareham" } + let(:school) { School.find_by_slug "winchester-high-school" } + let(:school_in_same_district) { School.find_by_slug "muraco-elementary-school" } + let(:first_school_in_wareham) { School.find_by_slug "john-william-decas-elementary-school" } + + let(:category) { Category.find_by_name("Teachers & Leadership") } + let(:different_category) { Category.find_by_name("School Culture") } + let(:subcategory) { Subcategory.find_by_name("Teachers & The Teaching Environment") } + let(:different_subcategory) { Subcategory.find_by_name("Relationships") } let(:measures_for_subcategory) { Measure.where(subcategory:) } let(:scales_for_subcategory) { Scale.where(measure: measures_for_subcategory) } let(:survey_items_for_subcategory) { SurveyItem.where(scale: scales_for_subcategory) } - let(:measure_1A_i) { Measure.find_by_measure_id('1A-i') } - let(:measure_2A_i) { Measure.find_by_measure_id('2A-i') } - let(:measure_2A_ii) { Measure.find_by_measure_id('2A-ii') } - let(:measure_4C_i) { Measure.find_by_measure_id('4C-i') } - let(:measure_with_no_survey_responses) { Measure.find_by_measure_id('3A-i') } + let(:measure_1A_i) { Measure.find_by_measure_id("1A-i") } + let(:measure_2A_i) { Measure.find_by_measure_id("2A-i") } + let(:measure_2A_ii) { Measure.find_by_measure_id("2A-ii") } + let(:measure_4C_i) { Measure.find_by_measure_id("4C-i") } + let(:measure_with_no_survey_responses) { Measure.find_by_measure_id("3A-i") } let(:survey_items_for_measure_1A_i) { measure_1A_i.survey_items } let(:survey_items_for_measure_2A_i) { measure_2A_i.survey_items } let(:survey_items_for_measure_2A_ii) { measure_2A_ii.survey_items } let(:survey_items_for_measure_4C_i) { measure_4C_i.survey_items } - let(:ay_2021_22) { AcademicYear.find_by_range '2021-22' } - let(:ay_2019_20) { AcademicYear.find_by_range '2019-20' } + let(:ay_2021_22) { AcademicYear.find_by_range "2021-22" } + let(:ay_2019_20) { AcademicYear.find_by_range "2019-20" } let(:response_rates) do [ay_2021_22, ay_2019_20].each do |academic_year| [school, school_in_same_district, first_school_in_wareham].each do |school| [subcategory, different_subcategory].each do |subcategory| ResponseRate.create!(subcategory:, school:, academic_year:, student_response_rate: 100, teacher_response_rate: 100, - meets_student_threshold: true, meets_teacher_threshold: true) + meets_student_threshold: true, meets_teacher_threshold: true) end end end @@ -66,35 +66,35 @@ describe 'District Admin', js: true do survey_items_for_measure_1A_i.each do |survey_item| SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD.times do survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2021_22, - school:, survey_item:, likert_score: 4) + school:, survey_item:, likert_score: 4) end end survey_items_for_measure_2A_i.each do |survey_item| SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD.times do survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2021_22, - school:, survey_item:, likert_score: 5, grade: 1) + school:, survey_item:, likert_score: 5, grade: 1) end end survey_items_for_measure_2A_ii.each do |survey_item| SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD.times do survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2021_22, - school:, survey_item:, likert_score: 5, grade: 1) + school:, survey_item:, likert_score: 5, grade: 1) end end survey_items_for_measure_4C_i.each do |survey_item| SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD.times do survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2021_22, - school:, survey_item:, likert_score: 1, grade: 1) + school:, survey_item:, likert_score: 1, grade: 1) end end survey_items_for_subcategory.each do |survey_item| 2.times do survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2021_22, - school:, survey_item:, likert_score: 4, grade: 1) + school:, survey_item:, likert_score: 4, grade: 1) end end @@ -105,22 +105,22 @@ describe 'District Admin', js: true do DatabaseCleaner.clean end - it 'navigates through the site' do + it "navigates through the site" do # page.driver.basic_authorize(username, password) - visit '/welcome' - expect(page).to have_text('Teachers & Leadership') + visit "/welcome" + expect(page).to have_text("Teachers & Leadership") go_to_school_overview_from_welcome_page(district, school) district_admin_sees_overview_content - click_on 'Teachers & Leadership' + click_on "Teachers & Leadership" district_admin_sees_browse_content - click_on 'Overview' + click_on "Overview" district_admin_sees_overview_content - click_on 'Analyze' + click_on "Analyze" district_admin_sees_analyze_content go_to_different_category(different_category) @@ -129,11 +129,11 @@ describe 'District Admin', js: true do go_to_different_subcategory(different_subcategory) district_admin_sees_subcategory_change - click_on 'Browse' + click_on "Browse" district_admin_sees_browse_content - click_on 'School Culture' - expect(page).to have_text('Measures the degree to which the school environment is safe, caring, and academically-oriented. It considers factors like bullying, student-teacher relationships, and student valuing of learning.') + click_on "School Culture" + expect(page).to have_text("Measures the degree to which the school environment is safe, caring, and academically-oriented. It considers factors like bullying, student-teacher relationships, and student valuing of learning.") go_to_different_school_in_same_district(school_in_same_district) district_admin_sees_schools_change @@ -149,7 +149,7 @@ end private def district_admin_sees_professional_qualifications - expect(page).to have_text('Professional Qualifications') + expect(page).to have_text("Professional Qualifications") expect(page).to have_css("[data-for-measure-id='1A-i']") # TODO: cutpoints in source of truth have changed so the cutpoints have moved and '2.99%' is no longer a valid value for this cutpoint. @@ -157,39 +157,40 @@ def district_admin_sees_professional_qualifications end def district_admin_sees_student_physical_safety - expect(page).to have_text('Student Physical Safety') + expect(page).to have_text("Student Physical Safety") expect(page).to have_css("[data-for-measure-id='2A-i'][width='40.0%'][x='60%']") end def district_admin_sees_problem_solving_emphasis - expect(page).to have_text('Problem Solving') + expect(page).to have_text("Problem Solving") expect(page).to have_css("[data-for-measure-id='4C-i'][width='60.0%'][x='0.0%']") end def go_to_school_overview_from_welcome_page(district, school) - expect(page).to have_select('district', selected: 'Select a District') - select district.name, from: 'district-dropdown' - expect(page).to have_select('school', selected: 'Select a School') - select school.name, from: 'school-dropdown' - expect(page).to have_select('school', selected: 'Winchester High School') + expect(page).to have_select("district", selected: "Select a District") + select district.name, from: "district-dropdown" + expect(page).to have_select("school", selected: "Select a School") + select school.name, from: "school-dropdown" + expect(page).to have_select("school", selected: "Winchester High School") - click_on 'Go' + click_on "Go" end def go_to_different_school_in_same_district(school) - select school.name, from: 'select-school' + select school.name, from: "select-school" end def go_to_different_district(district) - select district.name, from: 'select-district' + select district.name, from: "select-district" end def go_to_different_year(year) - select year.formatted_range, from: 'select-academic-year' + select year.formatted_range, from: "select-academic-year" end -def got_to_analyze_page; end +def got_to_analyze_page +end def district_admin_sees_schools_change expected_path = "/districts/#{school_in_same_district.district.slug}/schools/#{school_in_same_district.slug}/browse/teachers-and-leadership?year=#{ay_2021_22.range}" @@ -207,39 +208,39 @@ def district_admin_sees_year_change end def district_admin_sees_overview_content - expect(page).to have_select('academic-year', selected: '2021 – 2022') - expect(page).to have_select('district', selected: 'Winchester') - expect(page).to have_select('school', selected: 'Winchester High School') + expect(page).to have_select("academic-year", selected: "2021 – 2022") + expect(page).to have_select("district", selected: "Winchester") + expect(page).to have_select("school", selected: "Winchester High School") expect(page).to have_text(school.name) district_admin_sees_professional_qualifications district_admin_sees_student_physical_safety district_admin_sees_problem_solving_emphasis - page.assert_selector('.measure-row-bar', count: 6) + page.assert_selector(".measure-row-bar", count: 6) end def district_admin_sees_browse_content - expect(page).to have_text('Teachers & Leadership') - expect(page).to have_text('Approval') + expect(page).to have_text("Teachers & Leadership") + expect(page).to have_text("Approval") end def district_admin_sees_analyze_content - expect(page).to have_text('1:Teachers & Leadership > 1A:Teachers & The Teaching Environment') + expect(page).to have_text("1:Teachers & Leadership > 1A:Teachers & The Teaching Environment") end def go_to_different_category(category) - select category.name, from: 'select-category' + select category.name, from: "select-category" end def district_admin_sees_category_change - expect(page).to have_text '2A:Safety' + expect(page).to have_text "2A:Safety" end def go_to_different_subcategory(subcategory) - select subcategory.name, from: 'select-subcategory' + select subcategory.name, from: "select-subcategory" end def district_admin_sees_subcategory_change - expect(page).to have_text('Relationships') + expect(page).to have_text("Relationships") end diff --git a/spec/views/overview/index.html.erb_spec.rb b/spec/views/overview/index.html.erb_spec.rb index 3793f371..12eda11d 100644 --- a/spec/views/overview/index.html.erb_spec.rb +++ b/spec/views/overview/index.html.erb_spec.rb @@ -1,42 +1,42 @@ -require "rails_helper" +require 'rails_helper' include VarianceHelper -describe "overview/index" do +describe 'overview/index' do subject { Nokogiri::HTML(rendered) } let(:support_for_teaching) do - measure = create(:measure, name: "Support For Teaching Development & Growth", measure_id: "1") + measure = create(:measure, name: 'Support For Teaching Development & Growth', measure_id: '1') scale = create(:scale, measure:) create(:student_survey_item, - scale:, - watch_low_benchmark: 1.5, - growth_low_benchmark: 2.5, - approval_low_benchmark: 3.5, - ideal_low_benchmark: 4.5) + scale:, + watch_low_benchmark: 1.5, + growth_low_benchmark: 2.5, + approval_low_benchmark: 3.5, + ideal_low_benchmark: 4.5) measure end let(:effective_leadership) do - measure = create(:measure, name: "Effective Leadership", measure_id: "2") + measure = create(:measure, name: 'Effective Leadership', measure_id: '2') scale = create(:scale, measure:) create(:teacher_survey_item, - scale:, - watch_low_benchmark: 1.5, - growth_low_benchmark: 2.5, - approval_low_benchmark: 3.5, - ideal_low_benchmark: 4.5) + scale:, + watch_low_benchmark: 1.5, + growth_low_benchmark: 2.5, + approval_low_benchmark: 3.5, + ideal_low_benchmark: 4.5) measure end let(:professional_qualifications) do - measure = create(:measure, name: "Professional Qualifications", measure_id: "3") + measure = create(:measure, name: 'Professional Qualifications', measure_id: '3') scale = create(:scale, measure:) create(:admin_data_item, - scale:, - watch_low_benchmark: 1.5, - growth_low_benchmark: 2.5, - approval_low_benchmark: 3.5, - ideal_low_benchmark: 4.5) + scale:, + watch_low_benchmark: 1.5, + growth_low_benchmark: 2.5, + approval_low_benchmark: 3.5, + ideal_low_benchmark: 4.5) measure end @@ -47,14 +47,19 @@ describe "overview/index" do assign :academic_years, [@academic_year] @district = create(:district) @school = create(:school) + @student_response_rate_presenter = ResponseRatePresenter.new(focus: :student, school: @school, + academic_year: @academic_year) + @teacher_response_rate_presenter = ResponseRatePresenter.new(focus: :teacher, school: @school, + academic_year: @academic_year) + Respondent.create!(school: @school, academic_year: @academic_year, total_students: 40, total_teachers: 40) ResponseRate.create!(subcategory: Subcategory.first, school: @school, academic_year: @academic_year, - student_response_rate: 100, teacher_response_rate: 100, meets_student_threshold: true, meets_teacher_threshold: true) + student_response_rate: 100, teacher_response_rate: 100, meets_student_threshold: true, meets_teacher_threshold: true) render end - context "when some presenters have a nil score" do + context 'when some presenters have a nil score' do let(:variance_chart_row_presenters) do [ VarianceChartRowPresenter.new(measure: support_for_teaching, score: Score.new), @@ -63,49 +68,49 @@ describe "overview/index" do ] end - it "displays a note detailing which measures have insufficient responses for the given school & academic year" do + it 'displays a note detailing which measures have insufficient responses for the given school & academic year' do expect(rendered).to match %r{Note: The following measures are not displayed due to limited availability of school data and/or low survey response rates: Support For Teaching Development & Growth; Professional Qualifications.} end - it "displays a variance row and label only those presenters for which the score is not nil" do - displayed_variance_rows = subject.css("[data-for-measure-id]") + it 'displays a variance row and label only those presenters for which the score is not nil' do + displayed_variance_rows = subject.css('[data-for-measure-id]') expect(displayed_variance_rows.count).to eq 1 - expect(displayed_variance_rows.first.attribute("data-for-measure-id").value).to eq "2" + expect(displayed_variance_rows.first.attribute('data-for-measure-id').value).to eq '2' - displayed_variance_labels = subject.css("[data-variance-row-label]") + displayed_variance_labels = subject.css('[data-variance-row-label]') expect(displayed_variance_labels.count).to eq 1 - expect(displayed_variance_labels.first.inner_text).to include "Effective Leadership" + expect(displayed_variance_labels.first.inner_text).to include 'Effective Leadership' end end - context "when all the presenters have a non-nil score" do + context 'when all the presenters have a non-nil score' do let(:variance_chart_row_presenters) do - measure = create(:measure, name: "Display Me", measure_id: "display-me") + measure = create(:measure, name: 'Display Me', measure_id: 'display-me') scale = create(:scale, measure:) create(:student_survey_item, - scale:, - watch_low_benchmark: 1.5, - growth_low_benchmark: 2.5, - approval_low_benchmark: 3.5, - ideal_low_benchmark: 4.5) + scale:, + watch_low_benchmark: 1.5, + growth_low_benchmark: 2.5, + approval_low_benchmark: 3.5, + ideal_low_benchmark: 4.5) [ VarianceChartRowPresenter.new(measure:, - score: Score.new(average: rand)) + score: Score.new(average: rand)) ] end - it "does not display a note detailing which measures have insufficient responses for the given school & academic year" do + it 'does not display a note detailing which measures have insufficient responses for the given school & academic year' do expect(rendered).not_to match %r{Note: The following measures are not displayed due to limited availability of school data and/or low survey response rates} end - it "displays a variance row for each presenter" do - displayed_variance_rows = subject.css("[data-for-measure-id]") + it 'displays a variance row for each presenter' do + displayed_variance_rows = subject.css('[data-for-measure-id]') expect(displayed_variance_rows.count).to eq 1 - expect(displayed_variance_rows.first.attribute("data-for-measure-id").value).to eq "display-me" + expect(displayed_variance_rows.first.attribute('data-for-measure-id').value).to eq 'display-me' - displayed_variance_labels = subject.css("[data-variance-row-label]") + displayed_variance_labels = subject.css('[data-variance-row-label]') expect(displayed_variance_labels.count).to eq 1 - expect(displayed_variance_labels.first.inner_text).to include "Display Me" + expect(displayed_variance_labels.first.inner_text).to include 'Display Me' end end end