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