diff --git a/.bundler-audit.yml b/.bundler-audit.yml index fa8df175..c3edd997 100644 --- a/.bundler-audit.yml +++ b/.bundler-audit.yml @@ -1,3 +1,5 @@ --- ignore: - CVE-2023-26141 + - CVE-2024-21636 + - GHSA-xc9x-jj77-9p9j diff --git a/.gitignore b/.gitignore index 06cce314..f3143d54 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,6 @@ bin/fetch_config.rb /app/assets/builds/* !/app/assets/builds/.keep + +./nginx/key.pem +./nginx/cert.pem diff --git a/Gemfile b/Gemfile index 3fc8d31a..b115f248 100644 --- a/Gemfile +++ b/Gemfile @@ -10,7 +10,7 @@ gem "foreman" gem "jbuilder" gem "okcomputer" gem "pg", "~> 1.5" -gem "puma", "~> 6.4" +gem "puma", ">= 6.4.2", "< 7" gem "rails", "~> 7.1" gem "tzinfo-data", platforms: %i[mingw mswin x64_mingw jruby] diff --git a/Gemfile.lock b/Gemfile.lock index a7017861..db860902 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -319,7 +319,7 @@ GEM psych (5.1.1.1) stringio public_suffix (5.0.1) - puma (6.4.0) + puma (6.4.2) nio4r (~> 2.0) raabro (1.4.0) racc (1.7.3) @@ -536,7 +536,7 @@ DEPENDENCIES phonelib propshaft (~> 0.8.0) pry-byebug - puma (~> 6.4) + puma (>= 6.4.2, < 7) rails (~> 7.1) rolify rspec-rails diff --git a/app/controllers/system_admin/dashboard_controller.rb b/app/controllers/system_admin/dashboard_controller.rb index 97aefbb1..d334eb59 100644 --- a/app/controllers/system_admin/dashboard_controller.rb +++ b/app/controllers/system_admin/dashboard_controller.rb @@ -1,7 +1,7 @@ module SystemAdmin class DashboardController < AdminController def show - @kpis = Kpis.new(**kpi_params) + @kpis = Kpis.new(**kpi_params.merge(window_params)) rescue ArgumentError => e flash[:alert] = e.message redirect_to(dashboard_path) @@ -16,5 +16,9 @@ def kpi_params .to_hash .symbolize_keys end + + def window_params + { window: params[:window] } + end end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e5e2f9cd..7fba106c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -34,4 +34,13 @@ def application_statuses_options(selected: nil, all_statuses: false) options_for_select(statuses, selected:) end + + def dashboard_link(window_param, label) + current_window = params[:window] || "all" + if current_window == window_param + content_tag(:strong, label) + else + link_to(label, dashboard_path(window: window_param)) + end + end end diff --git a/app/helpers/inflection_helper.rb b/app/helpers/inflection_helper.rb new file mode 100644 index 00000000..68dd378d --- /dev/null +++ b/app/helpers/inflection_helper.rb @@ -0,0 +1,15 @@ +# Initially created to help display the correct form of day or days in the dashboard. +module InflectionHelper + def pluralize_word(count, word) + "#{count} #{word.pluralize(count)}" + end + + def calculate_day_stats(durations) + min_days = pluralize_word(durations.min.abs, "day") if durations.min + max_days = pluralize_word(durations.max.abs, "day") if durations.max + average_duration = durations.size.positive? ? (durations.sum / durations.size.to_f).round.abs : 0 + average_days = pluralize_word(average_duration, "day") + + { min: min_days, max: max_days, average: average_days } + end +end diff --git a/app/models/kpis.rb b/app/models/kpis.rb index 87307493..1977859f 100644 --- a/app/models/kpis.rb +++ b/app/models/kpis.rb @@ -1,73 +1,74 @@ class Kpis - def initialize(unit: "hours", range_start: "24", range_end: "0") + def initialize(unit: "hours", range_start: "24", range_end: "0", window: "all") @date_range_params = parse_date_range(unit:, range_start:, range_end:) @date_range = to_date_range(**@date_range_params) + @window = window end - attr_reader :date_range, :date_range_params + attr_reader :date_range, :date_range_params, :window def total_applications - Application.count + filtered_applications_by_date.count end def total_rejections - ApplicationProgress.where.not(rejection_completed_at: nil).count + filter_by_date_range(ApplicationProgress.where.not(rejection_completed_at: nil)).count end def average_age - AverageAgeQuery.new.call + AverageAgeQuery.new(filtered_applications_by_date).call end def total_paid - ApplicationProgress.where.not(banking_approval_completed_at: nil).count + filter_by_date_range(ApplicationProgress.where.not(banking_approval_completed_at: nil)).count end def route_breakdown - RouteBreakdownQuery.new.call + RouteBreakdownQuery.new(filtered_applications_by_date).call end def subject_breakdown - SubjectBreakdownQuery.new.call + SubjectBreakdownQuery.new(filtered_applications_by_date).call end def visa_breakdown - VisaBreakdownQuery.new.call.first(3) + VisaBreakdownQuery.new(filtered_applications_by_date).call.first(3) end def nationality_breakdown - NationalityBreakdownQuery.new.call.first(5) + NationalityBreakdownQuery.new(filtered_applications_by_date).call.first(5) end def gender_breakdown - GenderBreakdownQuery.new.call + GenderBreakdownQuery.new(filtered_applications_by_date).call end def rejection_reason_breakdown - RejectionReasonBreakdownQuery.new.call + RejectionReasonBreakdownQuery.new(filtered_applications_by_date).call end def time_to_initial_checks - TimeToInitialChecksQuery.new.call + TimeToInitialChecksQuery.new(filtered_progress_by_date).call end def time_to_home_office_checks - TimeToHomeOfficeChecksQuery.new.call + TimeToHomeOfficeChecksQuery.new(filtered_progress_by_date).call end def time_to_school_checks - TimeToSchoolChecksQuery.new.call + TimeToSchoolChecksQuery.new(filtered_progress_by_date).call end def time_to_banking_approval - TimeToBankingApprovalQuery.new.call + TimeToBankingApprovalQuery.new(filtered_progress_by_date).call end def time_to_payment_confirmation - TimeToPaymentConfirmationQuery.new.call + TimeToPaymentConfirmationQuery.new(filtered_progress_by_date).call end def status_breakdown - StatusBreakdownQuery.call + StatusBreakdownQuery.call(filtered_progress_by_date) end def forms_funnel @@ -119,4 +120,27 @@ def to_date_range(unit:, range_start:, range_end:) def forms_funnel_query @forms_funnel_query ||= FormsFunnelQuery.call(date_range:) end + + def date_ranges + { + "sept_oct" => Date.new(2023, 9, 1).beginning_of_day..Date.new(2023, 10, 31).end_of_day, + "jan_feb" => Date.new(2024, 1, 1).beginning_of_day..Date.new(2024, 3, 1).end_of_day, + } + end + + def filter_by_date_range(scope) + if date_ranges.key?(window) + scope.where(created_at: date_ranges[window]) + else + scope + end + end + + def filtered_applications_by_date + filter_by_date_range(Application.all) + end + + def filtered_progress_by_date + filter_by_date_range(ApplicationProgress.all) + end end diff --git a/app/queries/average_age_query.rb b/app/queries/average_age_query.rb index 383d827d..92d322fe 100644 --- a/app/queries/average_age_query.rb +++ b/app/queries/average_age_query.rb @@ -1,6 +1,6 @@ class AverageAgeQuery - def initialize(relation = Applicant.all) - @relation = relation.joins(:application).merge(Application.all) + def initialize(applications = Application.all) + @relation = Applicant.joins(:application).merge(applications) end def call diff --git a/app/queries/gender_breakdown_query.rb b/app/queries/gender_breakdown_query.rb index 98340ba9..7c658fb7 100644 --- a/app/queries/gender_breakdown_query.rb +++ b/app/queries/gender_breakdown_query.rb @@ -1,6 +1,6 @@ class GenderBreakdownQuery - def initialize(relation = Applicant.all) - @relation = relation.joins(:application).merge(Application.all) + def initialize(applications = Application.all) + @relation = Applicant.joins(:application).merge(applications) end def call diff --git a/app/queries/nationality_breakdown_query.rb b/app/queries/nationality_breakdown_query.rb index 6b075920..3ddfa34c 100644 --- a/app/queries/nationality_breakdown_query.rb +++ b/app/queries/nationality_breakdown_query.rb @@ -1,6 +1,6 @@ class NationalityBreakdownQuery - def initialize(relation = Applicant.all) - @relation = relation.joins(:application).merge(Application.all) + def initialize(applications = Application.all) + @relation = Applicant.joins(:application).merge(applications) end def call diff --git a/app/queries/rejection_reason_breakdown_query.rb b/app/queries/rejection_reason_breakdown_query.rb index ee8a6a07..fe7b5c67 100644 --- a/app/queries/rejection_reason_breakdown_query.rb +++ b/app/queries/rejection_reason_breakdown_query.rb @@ -1,6 +1,6 @@ class RejectionReasonBreakdownQuery - def initialize(relation = ApplicationProgress.all) - @relation = relation.joins(:application).merge(Application.all).where.not(rejection_reason: nil) + def initialize(applications = Application.all) + @relation = ApplicationProgress.joins(:application).merge(applications).where.not(rejection_reason: nil) end def call diff --git a/app/queries/status_breakdown_query.rb b/app/queries/status_breakdown_query.rb index 2b08f888..1a4f7f71 100644 --- a/app/queries/status_breakdown_query.rb +++ b/app/queries/status_breakdown_query.rb @@ -1,6 +1,10 @@ class StatusBreakdownQuery - def self.call - new.execute + def self.call(scope = ApplicationProgress.all) + new(scope).execute + end + + def initialize(scope) + @scope = scope end def execute @@ -10,7 +14,7 @@ def execute private def status_breakdown - ApplicationProgress.group(:status).count + @scope.group(:status).count end def ordered_with_defaults(breakdown) diff --git a/app/queries/time_to_banking_approval_query.rb b/app/queries/time_to_banking_approval_query.rb index 11b35e7a..807524d6 100644 --- a/app/queries/time_to_banking_approval_query.rb +++ b/app/queries/time_to_banking_approval_query.rb @@ -1,17 +1,12 @@ class TimeToBankingApprovalQuery + include InflectionHelper def initialize(relation = ApplicationProgress.all) @relation = relation end def call applications_list = @relation.where.not(school_checks_completed_at: nil).where.not(banking_approval_completed_at: nil) - durations = applications_list.map { |app| (app.banking_approval_completed_at.to_date - app.school_checks_completed_at.to_date).to_i } - - min_days = "#{durations.min.abs} days" if durations.min - max_days = "#{durations.max.abs} days" if durations.max - average_days = durations.size.positive? ? "#{(durations.sum / durations.size.to_f).round.abs} days" : "0 days" - - { min: min_days, max: max_days, average: average_days } + calculate_day_stats(durations) end end diff --git a/app/queries/time_to_home_office_checks_query.rb b/app/queries/time_to_home_office_checks_query.rb index 81288934..8d5eb016 100644 --- a/app/queries/time_to_home_office_checks_query.rb +++ b/app/queries/time_to_home_office_checks_query.rb @@ -1,17 +1,13 @@ class TimeToHomeOfficeChecksQuery + include InflectionHelper + def initialize(relation = ApplicationProgress.all) @relation = relation end def call applications_list = @relation.where.not(initial_checks_completed_at: nil).where.not(home_office_checks_completed_at: nil) - durations = applications_list.map { |app| (app.home_office_checks_completed_at.to_date - app.initial_checks_completed_at.to_date).to_i } - - min_days = "#{durations.min.abs} days" if durations.min - max_days = "#{durations.max.abs} days" if durations.max - average_days = durations.size.positive? ? "#{(durations.sum / durations.size.to_f).round.abs} days" : "0 days" - - { min: min_days, max: max_days, average: average_days } + calculate_day_stats(durations) end end diff --git a/app/queries/time_to_initial_checks_query.rb b/app/queries/time_to_initial_checks_query.rb index 902e551a..3a5e8fb0 100644 --- a/app/queries/time_to_initial_checks_query.rb +++ b/app/queries/time_to_initial_checks_query.rb @@ -1,17 +1,13 @@ class TimeToInitialChecksQuery + include InflectionHelper + def initialize(relation = ApplicationProgress.all) @relation = relation end def call applications_list = @relation.where.not(created_at: nil).where.not(initial_checks_completed_at: nil) - durations = applications_list.map { |app| (app.initial_checks_completed_at.to_date - app.created_at.to_date).to_i } - - min_days = "#{durations.min.abs} days" if durations.min - max_days = "#{durations.max.abs} days" if durations.max - average_days = durations.size.positive? ? "#{(durations.sum / durations.size.to_f).round.abs} days" : "0 days" - - { min: min_days, max: max_days, average: average_days } + calculate_day_stats(durations) end end diff --git a/app/queries/time_to_payment_confirmation_query.rb b/app/queries/time_to_payment_confirmation_query.rb index 927a4bb3..21a7fbae 100644 --- a/app/queries/time_to_payment_confirmation_query.rb +++ b/app/queries/time_to_payment_confirmation_query.rb @@ -1,17 +1,12 @@ class TimeToPaymentConfirmationQuery + include InflectionHelper def initialize(relation = ApplicationProgress.all) @relation = relation end def call applications_list = @relation.where.not(payment_confirmation_completed_at: nil).where.not(banking_approval_completed_at: nil) - durations = applications_list.map { |app| (app.payment_confirmation_completed_at.to_date - app.banking_approval_completed_at.to_date).to_i } - - min_days = "#{durations.min.abs} days" if durations.min - max_days = "#{durations.max.abs} days" if durations.max - average_days = durations.size.positive? ? "#{(durations.sum / durations.size.to_f).round.abs} days" : "0 days" - - { min: min_days, max: max_days, average: average_days } + calculate_day_stats(durations) end end diff --git a/app/queries/time_to_school_checks_query.rb b/app/queries/time_to_school_checks_query.rb index 02bc280b..c05e2cf1 100644 --- a/app/queries/time_to_school_checks_query.rb +++ b/app/queries/time_to_school_checks_query.rb @@ -1,17 +1,12 @@ class TimeToSchoolChecksQuery + include InflectionHelper def initialize(relation = ApplicationProgress.all) @relation = relation end def call applications_list = @relation.where.not(home_office_checks_completed_at: nil).where.not(school_checks_completed_at: nil) - durations = applications_list.map { |app| (app.school_checks_completed_at.to_date - app.home_office_checks_completed_at.to_date).to_i } - - min_days = "#{durations.min.abs} days" if durations.min - max_days = "#{durations.max.abs} days" if durations.max - average_days = durations.size.positive? ? "#{(durations.sum / durations.size.to_f).round.abs} days" : "0 days" - - { min: min_days, max: max_days, average: average_days } + calculate_day_stats(durations) end end diff --git a/app/views/system_admin/dashboard/show.html.erb b/app/views/system_admin/dashboard/show.html.erb index 20ab633e..ed7d258b 100644 --- a/app/views/system_admin/dashboard/show.html.erb +++ b/app/views/system_admin/dashboard/show.html.erb @@ -1,3 +1,11 @@ +
+ <%= dashboard_link('all', 'All') %> + | + <%= dashboard_link('sept_oct', 'Sept/Oct 2023') %> + | + <%= dashboard_link('jan_feb', 'Jan/Feb 2024') %> +
+

Applications

diff --git a/config/environments/development.rb b/config/environments/development.rb index c2563f66..7341ed86 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -61,4 +61,6 @@ # Uncomment if you wish to allow Action Cable access from any origin. # config.action_cable.disable_request_forgery_protection = true + + config.hosts << "itrp.local" end diff --git a/config/environments/test.rb b/config/environments/test.rb index 58fa5bad..a13e8607 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -54,4 +54,6 @@ # config/initializers/dartsass.rb config.dartsass.build_options << " --quiet-deps" + + config.hosts << "www.example.com" end diff --git a/spec/helpers/inflection_helper_spec.rb b/spec/helpers/inflection_helper_spec.rb new file mode 100644 index 00000000..6b540f31 --- /dev/null +++ b/spec/helpers/inflection_helper_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe InflectionHelper do + it "returns singular when count is 1" do + expect(pluralize_word(1, "day")).to eq "1 day" + end + + it "returns plural when count is not 1" do + expect(pluralize_word(0, "day")).to eq "0 days" + expect(pluralize_word(2, "day")).to eq "2 days" + expect(pluralize_word(10, "day")).to eq "10 days" + end +end diff --git a/spec/models/kpis_spec.rb b/spec/models/kpis_spec.rb index 58abc3ed..5364bb08 100644 --- a/spec/models/kpis_spec.rb +++ b/spec/models/kpis_spec.rb @@ -44,21 +44,713 @@ end describe "#total_applications" do - before { create_list(:application, 5) } + before do + create_list(:application, 3, created_at: Date.new(2023, 9, 15)) + create_list(:application, 2, created_at: Date.new(2024, 1, 15)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns total number of applications" do + expect(kpis.total_applications).to eq(5) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns total number of applications created within 'sept_oct' window" do + expect(kpis.total_applications).to eq(3) + end + end - it { expect(kpis.total_applications).to eq(5) } + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns total number of applications created within 'jan_feb' window" do + expect(kpis.total_applications).to eq(2) + end + end end describe "#total_rejections" do - before { create_list(:application_progress, 5, :rejection_completed, application:) } + before do + create_list(:application_progress, 3, :rejection_completed, application: create(:application), created_at: Date.new(2023, 9, 15)) + create_list(:application_progress, 2, :rejection_completed, application: create(:application), created_at: Date.new(2024, 1, 15)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns total number of rejections" do + expect(kpis.total_rejections).to eq(5) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns total number of rejections created within 'sept_oct' window" do + expect(kpis.total_rejections).to eq(3) + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns total number of rejections created within 'jan_feb' window" do + expect(kpis.total_rejections).to eq(2) + end + end + end + + describe "#average_age" do + before do + create(:application, applicant: create(:applicant, date_of_birth: 35.years.ago), created_at: Date.new(2023, 9, 15)) + create(:application, applicant: create(:applicant, date_of_birth: 45.years.ago), created_at: Date.new(2023, 9, 20)) + create(:application, applicant: create(:applicant, date_of_birth: 52.years.ago), created_at: Date.new(2024, 1, 15)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns the average age of all applications" do + expect(kpis.average_age).to eq(44) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns the average age of applications created in 'sept_oct' window" do + expect(kpis.average_age).to eq(40) # Average of first two applicants (35 and 45) + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } - it { expect(kpis.total_rejections).to eq(5) } + it "returns the average age of applications created within 'jan_feb' window" do + expect(kpis.average_age).to eq(52) # Only one applicant in this date range (52) + end + end end describe "#total_paid" do - before { create_list(:application_progress, 5, :banking_approval_completed, application:) } + before do + create(:application_progress, :banking_approval_completed, application: create(:application), created_at: Date.new(2023, 9, 15)) + create(:application_progress, :banking_approval_completed, application: create(:application), created_at: Date.new(2024, 1, 15)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns total number of paid applications" do + expect(kpis.total_paid).to eq(2) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns total number of paid applications" do + total = kpis.total_paid + expect(total).to eq(1) + sept_oct_payment = ApplicationProgress.where("extract(month from created_at) IN (?) AND banking_approval_completed_at IS NOT NULL", [9, 10]).last + expect(sept_oct_payment).to be_present + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns total number of paid applications" do + total = kpis.total_paid + expect(total).to eq(1) + jan_feb_payment = ApplicationProgress.where("extract(month from created_at) IN (?) AND banking_approval_completed_at IS NOT NULL", [1, 2]).last + expect(jan_feb_payment).to be_present + end + end + end + + describe "#route_breakdown" do + before do + create_list(:teacher_application, 3, created_at: Date.new(2023, 9, 15)) + create_list(:salaried_trainee_application, 2, created_at: Date.new(2024, 1, 15)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns a breakdown of all application routes" do + expect(kpis.route_breakdown).to eq({ "teacher" => 3, "salaried_trainee" => 2 }) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns a breakdown of application routes created within 'sept_oct' window" do + expect(kpis.route_breakdown).to eq({ "teacher" => 3 }) + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns a breakdown of application routes created within 'jan_feb' window" do + expect(kpis.route_breakdown).to eq({ "salaried_trainee" => 2 }) + end + end + end + + describe "#subject_breakdown" do + before do + create_list(:application, 3, subject: :physics, created_at: Date.new(2023, 9, 15)) + create_list(:application, 2, subject: :languages, created_at: Date.new(2024, 1, 15)) + create(:application, subject: :general_science, created_at: Date.new(2024, 1, 16)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns a breakdown of all application subjects" do + expect(kpis.subject_breakdown).to eq({ "physics" => 3, "languages" => 2, "general_science" => 1 }) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns a breakdown of application subjects created within 'sept_oct' window" do + expect(kpis.subject_breakdown).to eq({ "physics" => 3 }) + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns a breakdown of application subjects created within 'jan_feb' window" do + expect(kpis.subject_breakdown).to eq({ "languages" => 2, "general_science" => 1 }) + end + end + end + + describe "#visa_breakdown" do + before do + create_list(:application, 3, visa_type: "visa_1", created_at: Date.new(2023, 9, 15)) + create_list(:application, 2, visa_type: "visa_2", created_at: Date.new(2023, 9, 15)) + create(:application, visa_type: "visa_3", created_at: Date.new(2024, 1, 15)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns a breakdown of all application visas" do + expect(kpis.visa_breakdown).to contain_exactly(["visa_1", 3], ["visa_2", 2], ["visa_3", 1]) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns a breakdown of application visas created within 'sept_oct' window" do + expect(kpis.visa_breakdown).to contain_exactly(["visa_1", 3], ["visa_2", 2]) + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns a breakdown of application visas created within 'jan_feb' window" do + expect(kpis.visa_breakdown).to contain_exactly(["visa_3", 1]) + end + end + end + + describe "#nationality_breakdown" do + before do + create_list(:application, 3, applicant: create(:applicant, nationality: "Nationality 1"), created_at: Date.new(2023, 9, 15)) + create(:application, applicant: create(:applicant, nationality: "Nationality 2"), created_at: Date.new(2023, 9, 15)) + create_list(:application, 2, applicant: create(:applicant, nationality: "Nationality 3"), created_at: Date.new(2024, 1, 15)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns a breakdown of all application nationalities" do + expect(kpis.nationality_breakdown).to contain_exactly(["Nationality 1", 3], ["Nationality 2", 1], ["Nationality 3", 2]) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns a breakdown of application nationalities within 'sept_oct' window" do + expect(kpis.nationality_breakdown).to contain_exactly(["Nationality 1", 3], ["Nationality 2", 1]) + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns a breakdown of application nationalities within 'jan_feb' window" do + expect(kpis.nationality_breakdown).to contain_exactly(["Nationality 3", 2]) + end + end + end + + describe "#gender_breakdown" do + before do + create_list(:application, 3, applicant: create(:applicant, sex: "male"), created_at: Date.new(2023, 9, 15)) + create(:application, applicant: create(:applicant, sex: "female"), created_at: Date.new(2023, 9, 15)) + create(:application, applicant: create(:applicant, sex: "female"), created_at: Date.new(2024, 1, 15)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns a breakdown of all application genders" do + expect(kpis.gender_breakdown).to contain_exactly(["male", 3], ["female", 2]) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns a breakdown of application genders within 'sept_oct' window" do + expect(kpis.gender_breakdown).to contain_exactly(["male", 3], ["female", 1]) + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns a breakdown of application genders within 'jan_feb' window" do + expect(kpis.gender_breakdown).to contain_exactly(["female", 1]) + end + end + end + + describe "#rejection_reason_breakdown" do + before do + applicant = create(:applicant) + create_list(:application_progress, 2, application: create(:application, applicant: applicant, created_at: Date.new(2023, 9, 15)), rejection_reason: "suspected_fraud") + create(:application_progress, application: create(:application, applicant: applicant, created_at: Date.new(2023, 9, 15)), rejection_reason: "ineligible_school") + create(:application_progress, application: create(:application, applicant: applicant, created_at: Date.new(2024, 1, 15)), rejection_reason: "ineligible_school") + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns a breakdown of all application rejection reasons" do + expect(kpis.rejection_reason_breakdown).to contain_exactly(["suspected_fraud", 2], ["ineligible_school", 2]) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns a breakdown of application rejection reasons within 'sept_oct' window" do + expect(kpis.rejection_reason_breakdown).to contain_exactly(["suspected_fraud", 2], ["ineligible_school", 1]) + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns a breakdown of application rejection reasons within 'jan_feb' window" do + expect(kpis.rejection_reason_breakdown).to contain_exactly(["ineligible_school", 1]) + end + end + end + + describe "#time_to_initial_checks" do + before do + create(:application_progress, :initial_checks_completed, + application: create(:application, created_at: Date.new(2023, 9, 10)), + created_at: Date.new(2023, 9, 10), + initial_checks_completed_at: Date.new(2023, 9, 15)) + + create(:application_progress, :initial_checks_completed, + application: create(:application, created_at: Date.new(2023, 9, 10)), + created_at: Date.new(2023, 9, 10), + initial_checks_completed_at: Date.new(2023, 9, 15)) + + create(:application_progress, :initial_checks_completed, + application: create(:application, created_at: Date.new(2024, 1, 10)), + created_at: Date.new(2024, 1, 10), + initial_checks_completed_at: Date.new(2024, 1, 15)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns min, max and average time to initial checks for all applications" do + result = kpis.time_to_initial_checks + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "5 days" + expect(result[:average]).to eq "5 days" + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns min, max and average time to initial checks for applications in 'sept_oct' window" do + result = kpis.time_to_initial_checks + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "5 days" + expect(result[:average]).to eq "5 days" + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns min, max and average time to initial checks for applications in 'jan_feb' window" do + result = kpis.time_to_initial_checks + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "5 days" + expect(result[:average]).to eq "5 days" + end + end + end + + describe "#time_to_home_office_checks" do + before do + create(:application_progress, :home_office_checks_completed, + application: create(:application, created_at: Date.new(2023, 9, 10)), + created_at: Date.new(2023, 9, 10), + initial_checks_completed_at: Date.new(2023, 9, 15), + home_office_checks_completed_at: Date.new(2023, 9, 21)) + + create(:application_progress, :home_office_checks_completed, + application: create(:application, created_at: Date.new(2023, 9, 10)), + created_at: Date.new(2023, 9, 10), + initial_checks_completed_at: Date.new(2023, 9, 15), + home_office_checks_completed_at: Date.new(2023, 9, 25)) + + create(:application_progress, :home_office_checks_completed, + application: create(:application, created_at: Date.new(2024, 1, 10)), + created_at: Date.new(2024, 1, 10), + initial_checks_completed_at: Date.new(2024, 1, 15), + home_office_checks_completed_at: Date.new(2024, 1, 20)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns min, max and average time to home office checks for all applications" do + result = kpis.time_to_home_office_checks + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "10 days" + expect(result[:average]).to eq "7 days" + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns min, max and average time to home office checks for applications in 'sept_oct' window" do + result = kpis.time_to_home_office_checks + + expect(result[:min]).to eq "6 days" + expect(result[:max]).to eq "10 days" + expect(result[:average]).to eq "8 days" + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns min, max and average time to home office checks for applications in 'jan_feb' window" do + result = kpis.time_to_home_office_checks + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "5 days" + expect(result[:average]).to eq "5 days" + end + end + end + + describe "#time_to_school_checks" do + before do + create(:application_progress, :school_checks_completed, + application: create(:application, created_at: Date.new(2023, 9, 10)), + created_at: Date.new(2023, 9, 10), + home_office_checks_completed_at: Date.new(2023, 9, 15), + school_checks_completed_at: Date.new(2023, 9, 20)) + + create(:application_progress, :school_checks_completed, + application: create(:application, created_at: Date.new(2023, 9, 10)), + created_at: Date.new(2023, 9, 10), + home_office_checks_completed_at: Date.new(2023, 9, 15), + school_checks_completed_at: Date.new(2023, 9, 25)) + + create(:application_progress, :school_checks_completed, + application: create(:application, created_at: Date.new(2024, 1, 10)), + created_at: Date.new(2024, 1, 10), + home_office_checks_completed_at: Date.new(2024, 1, 15), + school_checks_completed_at: Date.new(2024, 1, 25)) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns min, max and average time to school checks for all applications" do + result = kpis.time_to_school_checks + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "10 days" + expect(result[:average]).to eq "8 days" + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns min, max and average time to school checks for applications in 'sept_oct' window" do + result = kpis.time_to_school_checks + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "10 days" + expect(result[:average]).to eq "8 days" + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns min, max and average time to school checks for applications in 'jan_feb' window" do + result = kpis.time_to_school_checks + + expect(result[:min]).to eq "10 days" + expect(result[:max]).to eq "10 days" + expect(result[:average]).to eq "10 days" + end + end + end + + describe "#time_to_banking_approval" do + before do + sept_oct_school_check = Date.new(2023, 9, 27) + jan_feb_school_check = Date.new(2024, 1, 20) + + create(:application_progress, :banking_approval_completed, + application: create(:application, created_at: sept_oct_school_check), + created_at: sept_oct_school_check, + school_checks_completed_at: sept_oct_school_check, + banking_approval_completed_at: sept_oct_school_check + 5.days) + + create(:application_progress, :banking_approval_completed, + application: create(:application, created_at: sept_oct_school_check), + created_at: sept_oct_school_check, + school_checks_completed_at: sept_oct_school_check, + banking_approval_completed_at: sept_oct_school_check + 7.days) + + create(:application_progress, :banking_approval_completed, + application: create(:application, created_at: jan_feb_school_check), + created_at: jan_feb_school_check, + school_checks_completed_at: jan_feb_school_check, + banking_approval_completed_at: jan_feb_school_check + 10.days) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns min, max and average time to banking approval for all applications" do + result = kpis.time_to_banking_approval + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "10 days" + expect(result[:average]).to eq "7 days" + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns min, max and average time to banking approval for applications in 'sept_oct' window" do + result = kpis.time_to_banking_approval + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "7 days" + expect(result[:average]).to eq "6 days" + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns min, max and average time to banking approval for applications in 'jan_feb'" do + result = kpis.time_to_banking_approval + + expect(result[:min]).to eq "10 days" + expect(result[:max]).to eq "10 days" + expect(result[:average]).to eq "10 days" + end + end + end + + describe "#time_to_payment_confirmation" do + before do + sept_oct_banking_approval = Date.new(2023, 9, 27) + jan_feb_banking_approval = Date.new(2024, 1, 20) + + create(:application_progress, :payment_confirmation_completed, + application: create(:application, created_at: sept_oct_banking_approval), + created_at: sept_oct_banking_approval, + banking_approval_completed_at: sept_oct_banking_approval, + payment_confirmation_completed_at: sept_oct_banking_approval + 5.days) + + create(:application_progress, :payment_confirmation_completed, + application: create(:application, created_at: sept_oct_banking_approval), + created_at: sept_oct_banking_approval, + banking_approval_completed_at: sept_oct_banking_approval, + payment_confirmation_completed_at: sept_oct_banking_approval + 7.days) + + create(:application_progress, :payment_confirmation_completed, + application: create(:application, created_at: jan_feb_banking_approval), + created_at: jan_feb_banking_approval, + banking_approval_completed_at: jan_feb_banking_approval, + payment_confirmation_completed_at: jan_feb_banking_approval + 10.days) + end + + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + it "returns min, max and average time to payment confirmation for all applications" do + result = kpis.time_to_payment_confirmation + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "10 days" + expect(result[:average]).to eq "7 days" + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + it "returns min, max and average time to payment confirmation for applications in 'sept_oct' window" do + result = kpis.time_to_payment_confirmation + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "7 days" + expect(result[:average]).to eq "6 days" + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + it "returns min, max and average time to payment confirmation for applications in 'jan_feb' window" do + result = kpis.time_to_payment_confirmation + + expect(result[:min]).to eq "10 days" + expect(result[:max]).to eq "10 days" + expect(result[:average]).to eq "10 days" + end + end + end + + describe "#status_breakdown" do + context "when window is 'all'" do + subject(:kpis) { described_class.new(window: "all") } + + before do + create(:application_progress, :initial_checks_completed, + application: build(:application), + created_at: Date.new(2023, 9, 10)) + create(:application_progress, :home_office_checks_completed, + application: build(:application), + created_at: Date.new(2024, 1, 5)) + end + + let(:expected_breakdown) do + { + "initial_checks" => 0, + "home_office_checks" => 1, + "school_checks" => 1, + "bank_approval" => 0, + "payment_confirmation" => 0, + "paid" => 0, + "rejected" => 0, + } + end + + it "returns the ordered application status breakdown" do + result = kpis.status_breakdown - it { expect(kpis.total_paid).to eq(5) } + expect(result).to include(expected_breakdown) + end + end + + context "when window is 'sept_oct'" do + subject(:kpis) { described_class.new(window: "sept_oct") } + + before do + create(:application_progress, :initial_checks_completed, + application: build(:application), + created_at: Date.new(2023, 9, 10)) + create(:application_progress, :home_office_checks_completed, + application: build(:application), + created_at: Date.new(2024, 1, 5)) + end + + let(:expected_breakdown) do + { + "initial_checks" => 0, + "home_office_checks" => 1, + "school_checks" => 0, + "bank_approval" => 0, + "payment_confirmation" => 0, + "paid" => 0, + "rejected" => 0, + } + end + + it "returns the ordered application status breakdown for applications in 'sept_oct' window" do + result = kpis.status_breakdown + + expect(result).to include(expected_breakdown) + end + end + + context "when window is 'jan_feb'" do + subject(:kpis) { described_class.new(window: "jan_feb") } + + before do + create(:application_progress, :initial_checks_completed, + application: build(:application), + created_at: Date.new(2023, 9, 10)) + create(:application_progress, :home_office_checks_completed, + application: build(:application), + created_at: Date.new(2024, 1, 5)) + end + + let(:expected_breakdown) do + { + "initial_checks" => 0, + "home_office_checks" => 0, + "school_checks" => 1, + "bank_approval" => 0, + "payment_confirmation" => 0, + "paid" => 0, + "rejected" => 0, + } + end + + it "returns the ordered application status breakdown for applications in 'jan_feb' window" do + result = kpis.status_breakdown + + expect(result).to include(expected_breakdown) + end + end end describe "funnel_date_range_title" do diff --git a/spec/models/summary_spec.rb b/spec/models/summary_spec.rb index 21ed3d04..83558eab 100644 --- a/spec/models/summary_spec.rb +++ b/spec/models/summary_spec.rb @@ -51,7 +51,7 @@ value: { text: "Yes" }, actions: [{ href: "/step/contract-details", visually_hidden_text: "contract details" }] }, { key: { text: "Contract start date" }, - value: { text: "01-09-2023" }, + value: { text: "01-09-2024" }, actions: [{ href: "/step/start-date", visually_hidden_text: "start date" }] }, { key: { text: "Subject" }, value: { text: "Physics" }, @@ -60,7 +60,7 @@ value: { text: "British National (Overseas) visa" }, actions: [{ href: "/step/visa", visually_hidden_text: "visa" }] }, { key: { text: "Date of entry" }, - value: { text: "01-09-2023" }, + value: { text: "01-09-2024" }, actions: [{ href: "/step/entry-date", visually_hidden_text: "entry date" }] }, ] end diff --git a/spec/queries/time_to_banking_approval_query_spec.rb b/spec/queries/time_to_banking_approval_query_spec.rb index 6a4a6d82..00038e24 100644 --- a/spec/queries/time_to_banking_approval_query_spec.rb +++ b/spec/queries/time_to_banking_approval_query_spec.rb @@ -2,21 +2,44 @@ RSpec.describe TimeToBankingApprovalQuery, type: :model do describe "#call" do - before do - create(:application_progress, :banking_approval_completed, application: build(:application), - school_checks_completed_at: 10.days.ago, banking_approval_completed_at: 5.days.ago) - create(:application_progress, :banking_approval_completed, application: build(:application), - school_checks_completed_at: 20.days.ago, banking_approval_completed_at: 10.days.ago) - create(:application_progress, :banking_approval_completed, application: build(:application), - school_checks_completed_at: 30.days.ago, banking_approval_completed_at: 15.days.ago) + context "with various days taken for banking approval" do + before do + create(:application_progress, :banking_approval_completed, + application: build(:application), + school_checks_completed_at: 10.days.ago, banking_approval_completed_at: 5.days.ago) + create(:application_progress, :banking_approval_completed, + application: build(:application), + school_checks_completed_at: 20.days.ago, banking_approval_completed_at: 10.days.ago) + create(:application_progress, :banking_approval_completed, + application: build(:application), + school_checks_completed_at: 30.days.ago, banking_approval_completed_at: 15.days.ago) + end + + it "returns min, max and average time in days" do + result = described_class.new.call + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "15 days" + expect(result[:average]).to eq "10 days" + end end - it "returns min, max and average time in days" do - result = described_class.new.call + context "with banking approval completed within a day" do + before do + create(:application_progress, :banking_approval_completed, + application: build(:application), + school_checks_completed_at: 0.days.ago, banking_approval_completed_at: 0.days.ago) + + create(:application_progress, :banking_approval_completed, + application: build(:application), + school_checks_completed_at: 1.day.ago, banking_approval_completed_at: 0.days.ago) + end - expect(result[:min]).to eq "5 days" - expect(result[:max]).to eq "15 days" - expect(result[:average]).to eq "10 days" + it "returns correct pluralization for 0 days and 1 day" do + result = described_class.new.call + expect(result[:min]).to eq "0 days" + expect(result[:max]).to eq "1 day" + end end end end diff --git a/spec/queries/time_to_home_office_checks_query_spec.rb b/spec/queries/time_to_home_office_checks_query_spec.rb index 7d42499a..8051359a 100644 --- a/spec/queries/time_to_home_office_checks_query_spec.rb +++ b/spec/queries/time_to_home_office_checks_query_spec.rb @@ -2,21 +2,44 @@ RSpec.describe TimeToHomeOfficeChecksQuery, type: :model do describe "#call" do - before do - create(:application_progress, :home_office_checks_completed, application: build(:application), - initial_checks_completed_at: 10.days.ago, home_office_checks_completed_at: 5.days.ago) - create(:application_progress, :home_office_checks_completed, application: build(:application), - initial_checks_completed_at: 20.days.ago, home_office_checks_completed_at: 10.days.ago) - create(:application_progress, :home_office_checks_completed, application: build(:application), - initial_checks_completed_at: 30.days.ago, home_office_checks_completed_at: 15.days.ago) + context "with various days taken for home office checks" do + before do + create(:application_progress, :home_office_checks_completed, + application: build(:application), + initial_checks_completed_at: 10.days.ago, home_office_checks_completed_at: 5.days.ago) + create(:application_progress, :home_office_checks_completed, + application: build(:application), + initial_checks_completed_at: 20.days.ago, home_office_checks_completed_at: 10.days.ago) + create(:application_progress, :home_office_checks_completed, + application: build(:application), + initial_checks_completed_at: 30.days.ago, home_office_checks_completed_at: 15.days.ago) + end + + it "returns min, max and average time in days" do + result = described_class.new.call + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "15 days" + expect(result[:average]).to eq "10 days" + end end - it "returns min, max and average time in days" do - result = described_class.new.call + context "with home office checks completed within a day" do + before do + create(:application_progress, :home_office_checks_completed, + application: build(:application), + initial_checks_completed_at: 0.days.ago, home_office_checks_completed_at: 0.days.ago) + create(:application_progress, :home_office_checks_completed, + application: build(:application), + initial_checks_completed_at: 1.day.ago, home_office_checks_completed_at: 0.days.ago) + end - expect(result[:min]).to eq "5 days" - expect(result[:max]).to eq "15 days" - expect(result[:average]).to eq "10 days" + it "returns correct pluralization for 0 days and 1 day" do + result = described_class.new.call + expect(result[:min]).to eq "0 days" + expect(result[:average]).to eq "1 day" + expect(result[:max]).to eq "1 day" + end end end end diff --git a/spec/queries/time_to_initial_checks_query_spec.rb b/spec/queries/time_to_initial_checks_query_spec.rb index 8f69d2bb..9c55885b 100644 --- a/spec/queries/time_to_initial_checks_query_spec.rb +++ b/spec/queries/time_to_initial_checks_query_spec.rb @@ -2,21 +2,43 @@ RSpec.describe TimeToInitialChecksQuery, type: :model do describe "#call" do - before do - create(:application_progress, :initial_checks_completed, application: build(:application), - created_at: 10.days.ago, initial_checks_completed_at: 5.days.ago) - create(:application_progress, :initial_checks_completed, application: build(:application), - created_at: 20.days.ago, initial_checks_completed_at: 10.days.ago) - create(:application_progress, :initial_checks_completed, application: build(:application), - created_at: 30.days.ago, initial_checks_completed_at: 15.days.ago) + context "with various days taken for initial query checks" do + before do + create(:application_progress, :initial_checks_completed, + application: build(:application), + created_at: 10.days.ago, initial_checks_completed_at: 5.days.ago) + create(:application_progress, :initial_checks_completed, + application: build(:application), + created_at: 20.days.ago, initial_checks_completed_at: 10.days.ago) + create(:application_progress, :initial_checks_completed, + application: build(:application), + created_at: 30.days.ago, initial_checks_completed_at: 15.days.ago) + end + + it "returns min, max and average time in days" do + result = described_class.new.call + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "15 days" + expect(result[:average]).to eq "10 days" + end end - it "returns min, max and average time in days" do - result = described_class.new.call + context "with initial checks completed within a day" do + before do + create(:application_progress, :initial_checks_completed, + application: build(:application), + created_at: 0.days.ago, initial_checks_completed_at: 0.days.ago) + create(:application_progress, :initial_checks_completed, + application: build(:application), + created_at: 1.day.ago, initial_checks_completed_at: 0.days.ago) + end - expect(result[:min]).to eq "5 days" - expect(result[:max]).to eq "15 days" - expect(result[:average]).to eq "10 days" + it "returns correct pluralization for 0 days and 1 day" do + result = described_class.new.call + expect(result[:min]).to eq "0 days" + expect(result[:max]).to eq "1 day" + end end end end diff --git a/spec/queries/time_to_payment_confirmation_query_spec.rb b/spec/queries/time_to_payment_confirmation_query_spec.rb index de6efe4b..327b741a 100644 --- a/spec/queries/time_to_payment_confirmation_query_spec.rb +++ b/spec/queries/time_to_payment_confirmation_query_spec.rb @@ -2,21 +2,43 @@ RSpec.describe TimeToPaymentConfirmationQuery, type: :model do describe "#call" do - before do - create(:application_progress, :payment_confirmation_completed, application: build(:application), - banking_approval_completed_at: 10.days.ago, payment_confirmation_completed_at: 5.days.ago) - create(:application_progress, :payment_confirmation_completed, application: build(:application), - banking_approval_completed_at: 20.days.ago, payment_confirmation_completed_at: 10.days.ago) - create(:application_progress, :payment_confirmation_completed, application: build(:application), - banking_approval_completed_at: 30.days.ago, payment_confirmation_completed_at: 15.days.ago) + context "with various days taken for payment confirmation" do + before do + create(:application_progress, :payment_confirmation_completed, + application: build(:application), + banking_approval_completed_at: 10.days.ago, payment_confirmation_completed_at: 5.days.ago) + create(:application_progress, :payment_confirmation_completed, + application: build(:application), + banking_approval_completed_at: 20.days.ago, payment_confirmation_completed_at: 10.days.ago) + create(:application_progress, :payment_confirmation_completed, + application: build(:application), + banking_approval_completed_at: 30.days.ago, payment_confirmation_completed_at: 15.days.ago) + end + + it "returns min, max and average time in days" do + result = described_class.new.call + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "15 days" + expect(result[:average]).to eq "10 days" + end end - it "returns min, max and average time in days" do - result = described_class.new.call + context "with payment confirmation completed within a day" do + before do + create(:application_progress, :payment_confirmation_completed, + application: build(:application), + banking_approval_completed_at: 0.days.ago, payment_confirmation_completed_at: 0.days.ago) + create(:application_progress, :payment_confirmation_completed, + application: build(:application), + banking_approval_completed_at: 1.day.ago, payment_confirmation_completed_at: 0.days.ago) + end - expect(result[:min]).to eq "5 days" - expect(result[:max]).to eq "15 days" - expect(result[:average]).to eq "10 days" + it "returns correct pluralization for 0 days and 1 day" do + result = described_class.new.call + expect(result[:min]).to eq "0 days" + expect(result[:max]).to eq "1 day" + end end end end diff --git a/spec/queries/time_to_school_checks_query_spec.rb b/spec/queries/time_to_school_checks_query_spec.rb index 7822503a..e5a498aa 100644 --- a/spec/queries/time_to_school_checks_query_spec.rb +++ b/spec/queries/time_to_school_checks_query_spec.rb @@ -2,21 +2,43 @@ RSpec.describe TimeToSchoolChecksQuery, type: :model do describe "#call" do - before do - create(:application_progress, :school_checks_completed, application: build(:application), - home_office_checks_completed_at: 10.days.ago, school_checks_completed_at: 5.days.ago) - create(:application_progress, :school_checks_completed, application: build(:application), - home_office_checks_completed_at: 20.days.ago, school_checks_completed_at: 10.days.ago) - create(:application_progress, :school_checks_completed, application: build(:application), - home_office_checks_completed_at: 30.days.ago, school_checks_completed_at: 15.days.ago) + context "with various days taken for school checks" do + before do + create(:application_progress, :school_checks_completed, + application: build(:application), + home_office_checks_completed_at: 10.days.ago, school_checks_completed_at: 5.days.ago) + create(:application_progress, :school_checks_completed, + application: build(:application), + home_office_checks_completed_at: 20.days.ago, school_checks_completed_at: 10.days.ago) + create(:application_progress, :school_checks_completed, + application: build(:application), + home_office_checks_completed_at: 30.days.ago, school_checks_completed_at: 15.days.ago) + end + + it "returns min, max and average time in days" do + result = described_class.new.call + + expect(result[:min]).to eq "5 days" + expect(result[:max]).to eq "15 days" + expect(result[:average]).to eq "10 days" + end end - it "returns min, max and average time in days" do - result = described_class.new.call + context "with school checks completed within a day" do + before do + create(:application_progress, :school_checks_completed, + application: build(:application), + home_office_checks_completed_at: 0.days.ago, school_checks_completed_at: 0.days.ago) + create(:application_progress, :school_checks_completed, + application: build(:application), + home_office_checks_completed_at: 1.day.ago, school_checks_completed_at: 0.days.ago) + end - expect(result[:min]).to eq "5 days" - expect(result[:max]).to eq "15 days" - expect(result[:average]).to eq "10 days" + it "returns correct pluralization for 0 days and 1 day" do + result = described_class.new.call + expect(result[:min]).to eq "0 days" + expect(result[:max]).to eq "1 day" + end end end end diff --git a/spec/support/application_form_steps.rb b/spec/support/application_form_steps.rb index ebdea7d9..d687f956 100644 --- a/spec/support/application_form_steps.rb +++ b/spec/support/application_form_steps.rb @@ -52,9 +52,7 @@ def and_i_select_my_visa_type def and_i_enter_my_entry_date(route) assert_i_am_in_the_entry_date_question(route) - fill_in("Day", with: 12) - fill_in("Month", with: 6) - fill_in("Year", with: 2023) + fill_in_date click_button("Continue") end @@ -114,9 +112,7 @@ def choose_no def and_i_enter_my_contract_start_date assert_i_am_in_the_contract_start_date_question - fill_in("Day", with: 12) - fill_in("Month", with: 7) - fill_in("Year", with: 2023) + fill_in_date click_button("Continue") end @@ -139,3 +135,11 @@ def and_i_enter_an_invalid_date click_button("Continue") end end + +def fill_in_date + three_months_ago = Time.zone.today - 3.months + + fill_in("Day", with: three_months_ago.day) + fill_in("Month", with: three_months_ago.month) + fill_in("Year", with: three_months_ago.year) +end