Browse Source

Cldc 1227 supported housing index (#648)

* Added test file for supported housing schemes

* Added factory bot for supported housing schemes

* swapped managing agent to org for scheme

* created migration for schemes

* created model for scheme

* added migration to add foreign key to the schemes table

* missing spec and log spec for supported housing

* fixed failing specs

* added schemes migration

* next step feature

* added route

* added controller

* added index

* added all schemes

* correct test for scheme

* added view

* route alias for schemes

* spec for index schemes

* failing scheme controller spec

* added simple view, scheme seed and authentication

* spec for index schemes list

* rubocop - thanks

* better seed

* added Heading to org

* added feature flag to hide supported services on prod

* added feature flag testing nav items

* testing coordinator user can see the link to supported housing

* moved toggle to a different place

* moved toggle to PrimaryNavigationComponent

* testing not being signed in on support pages

* testing showing search bar

* added search bar

* testing subset of schemes for coordinator user

* rubocop

* failing test for title in page

* code to expose title

* pagination with tests without searching

* partial for schemes

* scoping out all but support and coord users

* searching schemes code and test

* searching via code and org tests

* searching by org name tests

* searching by org name code

* search_by tests

* search_by code

* search_by woops must search by service

* searching schemes feature

* tests for data coordinator user

* redirect for data coordinator user

* testing org schemes for coordiantor user

* schemes in org controller for coordiantor user

* refactored specs moved into orgs what belongs there

* view for org schemes

* rubocop

* accebility field

* accebility field on org page

* correct return when on org schemes

* passing search test on the orgs page

* highlight nav tab

* navs helper done

* rubocop

* fixed failing tests for support user

* correct view

* how did I manage to delete this file?

* checking you cant access schems unathorized

* moved test

* renamed service name

* correct title for sup user schemes org

* testing not being able to view any other orgs supported housing for coordinator user

* Trigger WF

* last fix

* aded has many to org for schemes

* rubocop

Co-authored-by: Ted <ted.booton@madetech.com>
pull/654/head
J G 3 years ago committed by GitHub
parent
commit
402780c53f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      app/components/primary_navigation_component.rb
  2. 2
      app/components/search_component.rb
  3. 8
      app/controllers/organisations_controller.rb
  4. 26
      app/controllers/schemes_controller.rb
  5. 19
      app/helpers/navigation_items_helper.rb
  6. 1
      app/models/organisation.rb
  7. 7
      app/models/scheme.rb
  8. 22
      app/views/organisations/schemes.html.erb
  9. 39
      app/views/schemes/_scheme_list.html.erb
  10. 16
      app/views/schemes/index.html.erb
  11. 3
      config/routes.rb
  12. 11
      db/migrate/20220608144156_create_schemes.rb
  13. 16
      db/schema.rb
  14. 39
      db/seeds.rb
  15. 14
      spec/components/primary_navigation_component_spec.rb
  16. 8
      spec/factories/scheme.rb
  17. 78
      spec/features/schemes_spec.rb
  18. 82
      spec/helpers/navigation_items_helper_spec.rb
  19. 5
      spec/models/organisation_spec.rb
  20. 49
      spec/models/scheme_spec.rb
  21. 131
      spec/requests/organisations_controller_spec.rb
  22. 163
      spec/requests/schemes_controller_spec.rb

1
app/components/primary_navigation_component.rb

@ -3,6 +3,7 @@ class PrimaryNavigationComponent < ViewComponent::Base
def initialize(items:) def initialize(items:)
@items = items @items = items
Rails.env.production? ? @items = @items.reject { |nav_item| nav_item.text.include?("Supported housing") } : @items
super super
end end

2
app/components/search_component.rb

@ -13,6 +13,8 @@ class SearchComponent < ViewComponent::Base
request.path request.path
elsif request.path.include?("organisations") && request.path.include?("logs") elsif request.path.include?("organisations") && request.path.include?("logs")
request.path request.path
elsif request.path.include?("organisations") && request.path.include?("supported-housing")
request.path
elsif request.path.include?("users") elsif request.path.include?("users")
user_path(current_user) user_path(current_user)
elsif request.path.include?("organisations") elsif request.path.include?("organisations")

8
app/controllers/organisations_controller.rb

@ -16,6 +16,14 @@ class OrganisationsController < ApplicationController
@total_count = all_organisations.size @total_count = all_organisations.size
end end
def schemes
all_schemes = Scheme.where(organisation: @organisation)
@pagy, @schemes = pagy(filtered_collection(all_schemes, search_term))
@searched = search_term.presence
@total_count = all_schemes.size
end
def show def show
redirect_to details_organisation_path(@organisation) redirect_to details_organisation_path(@organisation)
end end

26
app/controllers/schemes_controller.rb

@ -0,0 +1,26 @@
class SchemesController < ApplicationController
include Pagy::Backend
include Modules::SearchFilter
before_action :authenticate_user!
before_action :authenticate_scope!
def index
redirect_to supported_housing_organisation_path(current_user.organisation) unless current_user.support?
all_schemes = Scheme.all
@pagy, @schemes = pagy(filtered_collection(all_schemes, search_term))
@searched = search_term.presence
@total_count = all_schemes.size
end
private
def search_term
params["search"]
end
def authenticate_scope!
head :unauthorized and return unless current_user.data_coordinator? || current_user.support?
end
end

19
app/helpers/navigation_items_helper.rb

@ -7,6 +7,14 @@ module NavigationItemsHelper
NavigationItem.new("Organisations", organisations_path, organisations_current?(path)), NavigationItem.new("Organisations", organisations_path, organisations_current?(path)),
NavigationItem.new("Users", "/users", users_current?(path)), NavigationItem.new("Users", "/users", users_current?(path)),
NavigationItem.new("Logs", case_logs_path, logs_current?(path)), NavigationItem.new("Logs", case_logs_path, logs_current?(path)),
NavigationItem.new("Supported housing", "/supported-housing", supported_housing_current?(path)),
]
elsif current_user.data_coordinator?
[
NavigationItem.new("Logs", case_logs_path, logs_current?(path)),
NavigationItem.new("Supported housing", "/supported-housing", subnav_supported_housing_path?(path)),
NavigationItem.new("Users", users_organisation_path(current_user.organisation), subnav_users_path?(path)),
NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", subnav_details_path?(path)),
] ]
else else
[ [
@ -20,6 +28,7 @@ module NavigationItemsHelper
def secondary_items(path, current_organisation_id) def secondary_items(path, current_organisation_id)
[ [
NavigationItem.new("Logs", "/organisations/#{current_organisation_id}/logs", subnav_logs_path?(path)), NavigationItem.new("Logs", "/organisations/#{current_organisation_id}/logs", subnav_logs_path?(path)),
NavigationItem.new("Supported housing", "/organisations/#{current_organisation_id}/supported-housing", subnav_supported_housing_path?(path)),
NavigationItem.new("Users", "/organisations/#{current_organisation_id}/users", subnav_users_path?(path)), NavigationItem.new("Users", "/organisations/#{current_organisation_id}/users", subnav_users_path?(path)),
NavigationItem.new("About this organisation", "/organisations/#{current_organisation_id}", subnav_details_path?(path)), NavigationItem.new("About this organisation", "/organisations/#{current_organisation_id}", subnav_details_path?(path)),
] ]
@ -35,8 +44,16 @@ private
path == "/users" path == "/users"
end end
def supported_housing_current?(path)
path == "/supported-housing"
end
def organisations_current?(path) def organisations_current?(path)
path == "/organisations" || subnav_users_path?(path) || subnav_logs_path?(path) || subnav_details_path?(path) path == "/organisations" || subnav_users_path?(path) || subnav_logs_path?(path) || subnav_details_path?(path) || subnav_supported_housing_path?(path)
end
def subnav_supported_housing_path?(path)
path.include?("/organisations") && path.include?("/supported-housing")
end end
def subnav_users_path?(path) def subnav_users_path?(path)

1
app/models/organisation.rb

@ -4,6 +4,7 @@ class Organisation < ApplicationRecord
has_many :managed_case_logs, class_name: "CaseLog", foreign_key: "managing_organisation_id" has_many :managed_case_logs, class_name: "CaseLog", foreign_key: "managing_organisation_id"
has_many :data_protection_confirmations has_many :data_protection_confirmations
has_many :organisation_rent_periods has_many :organisation_rent_periods
has_many :schemes
scope :search_by_name, ->(name) { where("name ILIKE ?", "%#{name}%") } scope :search_by_name, ->(name) { where("name ILIKE ?", "%#{name}%") }
scope :search_by, ->(param) { search_by_name(param) } scope :search_by, ->(param) { search_by_name(param) }

7
app/models/scheme.rb

@ -0,0 +1,7 @@
class Scheme < ApplicationRecord
belongs_to :organisation
scope :search_by_code, ->(code) { where("code ILIKE ?", "%#{code}%") }
scope :search_by_service_name, ->(name) { where("service_name ILIKE ?", "%#{name}%") }
scope :search_by, ->(param) { search_by_code(param).or(search_by_service_name(param)) }
end

22
app/views/organisations/schemes.html.erb

@ -0,0 +1,22 @@
<% item_label = format_label(@pagy.count, "scheme") %>
<% title = format_title(@searched, "Supported housing services", current_user, item_label, @pagy.count, @organisation.name) %>
<% content_for :title, title %>
<%= render partial: "organisations/headings", locals: current_user.support? ? { main: @organisation.name, sub: nil } : { main: "Supported housing services", sub: current_user.organisation.name } %>
<% if current_user.support? %>
<%= render SubNavigationComponent.new(
items: secondary_items(request.path, @organisation.id),
) %>
<% end %>
<h2 class="govuk-visually-hidden">Supported housing services</h2>
<%= render SearchComponent.new(current_user:, search_label: "Search by service name or code", value: @searched) %>
<hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m">
<%= render partial: "schemes/scheme_list", locals: { schemes: @schemes, title:, pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %>
<%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "schemes" } %>

39
app/views/schemes/_scheme_list.html.erb

@ -0,0 +1,39 @@
<section class="app-table-group" tabindex="0" aria-labelledby="<%= title.dasherize %>">
<%= govuk_table do |table| %>
<%= table.caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %>
<span class="govuk-!-margin-right-4">
<% if searched.present? %>
<strong><%= pagy.count %></strong> <%= item_label %> found matching ‘<%= searched %>’ of <strong><%= total_count %></strong> total schemes. <%= govuk_link_to("Clear search", request.path) %>
<% else %>
<strong><%= pagy.count %></strong> total schemes.
<% end %>
</span>
<% end %>
<%= table.head do |head| %>
<%= head.row do |row| %>
<% row.cell(header: true, text: "Code", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Service", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Managing agent", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Created", html_attributes: {
scope: "col",
}) %>
<% end %>
<% end %>
<% @schemes.each do |scheme| %>
<%= table.body do |body| %>
<%= body.row do |row| %>
<% row.cell(text: scheme.code) %>
<% row.cell(text: scheme.service_name) %>
<% row.cell(text: scheme.organisation.name) %>
<% row.cell(text: scheme.created_at.to_formatted_s(:govuk_date)) %>
<% end %>
<% end %>
<% end %>
<% end %>
</section>

16
app/views/schemes/index.html.erb

@ -0,0 +1,16 @@
<% item_label = format_label(@pagy.count, "scheme") %>
<% title = format_title(@searched, "Supported housing services", current_user, item_label, @pagy.count, nil) %>
<% content_for :title, title %>
<%= render partial: "organisations/headings", locals: current_user.support? ? { main: "Supported housing services", sub: nil } : { main: "Supported housing services", sub: current_user.organisation.name } %>
<h2 class="govuk-visually-hidden">Supported housing services</h2>
<%= render SearchComponent.new(current_user:, search_label: "Search by service name or code", value: @searched) %>
<hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m">
<%= render partial: "schemes/scheme_list", locals: { schemes: @schemes, title:, pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %>
<%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "schemes" } %>

3
config/routes.rb

@ -35,6 +35,8 @@ Rails.application.routes.draw do
get "edit/password", to: "users#edit_password" get "edit/password", to: "users#edit_password"
end end
resources :schemes, path: "/supported-housing", only: [:index]
resources :users do resources :users do
member do member do
get "deactivate", to: "users#deactivate" get "deactivate", to: "users#deactivate"
@ -48,6 +50,7 @@ Rails.application.routes.draw do
get "users", to: "organisations#users" get "users", to: "organisations#users"
get "users/invite", to: "users/account#new" get "users/invite", to: "users/account#new"
get "logs", to: "organisations#logs" get "logs", to: "organisations#logs"
get "supported-housing", to: "organisations#schemes"
end end
end end

11
db/migrate/20220608144156_create_schemes.rb

@ -0,0 +1,11 @@
class CreateSchemes < ActiveRecord::Migration[7.0]
def change
create_table :schemes do |t|
t.string :code
t.string :service_name
t.references :organisation, null: false, foreign_key: true
t.timestamps
end
end
end

16
db/schema.rb

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2022_06_06_082639) do ActiveRecord::Schema[7.0].define(version: 2022_06_08_144156) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -192,9 +192,9 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_06_082639) do
t.integer "joint" t.integer "joint"
t.bigint "created_by_id" t.bigint "created_by_id"
t.integer "illness_type_0" t.integer "illness_type_0"
t.integer "retirement_value_check"
t.integer "tshortfall_known" t.integer "tshortfall_known"
t.integer "shelteredaccom" t.integer "shelteredaccom"
t.integer "retirement_value_check"
t.integer "pregnancy_value_check" t.integer "pregnancy_value_check"
t.index ["created_by_id"], name: "index_case_logs_on_created_by_id" t.index ["created_by_id"], name: "index_case_logs_on_created_by_id"
t.index ["managing_organisation_id"], name: "index_case_logs_on_managing_organisation_id" t.index ["managing_organisation_id"], name: "index_case_logs_on_managing_organisation_id"
@ -232,7 +232,7 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_06_082639) do
create_table "logs_exports", force: :cascade do |t| create_table "logs_exports", force: :cascade do |t|
t.datetime "created_at", default: -> { "CURRENT_TIMESTAMP" } t.datetime "created_at", default: -> { "CURRENT_TIMESTAMP" }
t.datetime "started_at", precision: nil, null: false t.datetime "started_at", null: false
t.integer "base_number", default: 1, null: false t.integer "base_number", default: 1, null: false
t.integer "increment_number", default: 1, null: false t.integer "increment_number", default: 1, null: false
t.boolean "empty_export", default: false, null: false t.boolean "empty_export", default: false, null: false
@ -277,6 +277,15 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_06_082639) do
t.index ["old_visible_id"], name: "index_organisations_on_old_visible_id", unique: true t.index ["old_visible_id"], name: "index_organisations_on_old_visible_id", unique: true
end end
create_table "schemes", force: :cascade do |t|
t.string "code"
t.string "service_name"
t.bigint "organisation_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["organisation_id"], name: "index_schemes_on_organisation_id"
end
create_table "users", force: :cascade do |t| create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false t.string "encrypted_password", default: "", null: false
@ -330,4 +339,5 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_06_082639) do
t.index ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id" t.index ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id"
end end
add_foreign_key "schemes", "organisations"
end end

39
db/seeds.rb

@ -54,6 +54,45 @@ unless Rails.env.test?
pp "Seeded 3 dummy users" pp "Seeded 3 dummy users"
end end
if Rails.env.development?
dummy_org = Organisation.find_or_create_by!(
name: "FooBar LTD",
address_line1: "Higher Kingston",
address_line2: "Yeovil",
postcode: "BA21 4AT",
holds_own_stock: false,
other_stock_owners: "None",
managing_agents: "None",
provider_type: "LA",
)
pp "Seeded dummy FooBar LTD organisation"
end
if Rails.env.development? && Scheme.count.zero?
Scheme.create!(
code: "S878",
service_name: "Beulahside Care",
organisation: org,
created_at: Time.zone.now,
)
Scheme.create!(
code: "S312",
service_name: "Abdullahview Point",
organisation: org,
created_at: Time.zone.now,
)
Scheme.create!(
code: "7XYZ",
service_name: "Caspermouth Center",
organisation: dummy_org,
created_at: Time.zone.now,
)
end
pp "Seeded 3 dummy schemes"
if LaRentRange.count.zero? if LaRentRange.count.zero?
Dir.glob("config/rent_range_data/*.csv").each do |path| Dir.glob("config/rent_range_data/*.csv").each do |path|
start_year = File.basename(path, ".csv") start_year = File.basename(path, ".csv")

14
spec/components/primary_navigation_component_spec.rb

@ -6,6 +6,7 @@ RSpec.describe PrimaryNavigationComponent, type: :component do
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Logs ", "/logs", false), NavigationItemsHelper::NavigationItem.new("Logs ", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
] ]
end end
@ -24,6 +25,7 @@ RSpec.describe PrimaryNavigationComponent, type: :component do
expect(navigation_panel).to be_highlighted_item(items[0], "/something-else") expect(navigation_panel).to be_highlighted_item(items[0], "/something-else")
expect(navigation_panel).not_to be_highlighted_item(items[1], "/something-else") expect(navigation_panel).not_to be_highlighted_item(items[1], "/something-else")
expect(navigation_panel).not_to be_highlighted_item(items[2], "/something-else") expect(navigation_panel).not_to be_highlighted_item(items[2], "/something-else")
expect(navigation_panel).not_to be_highlighted_item(items[3], "/something-else")
end end
end end
@ -34,6 +36,18 @@ RSpec.describe PrimaryNavigationComponent, type: :component do
expect(result.text).to include("Organisations") expect(result.text).to include("Organisations")
expect(result.text).to include("Users") expect(result.text).to include("Users")
expect(result.text).to include("Logs") expect(result.text).to include("Logs")
expect(result.text).to include("Supported housing")
end
end
context "when production environment" do
before do
allow(Rails.env).to receive(:production?).and_return(true)
end
it "doesn't render supported housing" do
result = render_inline(described_class.new(items:))
expect(result.text).not_to include("Supported housing")
end end
end end
end end

8
spec/factories/scheme.rb

@ -0,0 +1,8 @@
FactoryBot.define do
factory :scheme do
code { Faker::Name.initials(number: 4) }
service_name { Faker::Name.name_with_middle }
organisation
created_at { Time.zone.now }
end
end

78
spec/features/schemes_spec.rb

@ -0,0 +1,78 @@
require "rails_helper"
RSpec.describe "Supported housing scheme Features" do
context "when viewing list of schemes" do
context "when I am signed as a support user in there are schemes in the database" do
let(:user) { FactoryBot.create(:user, :support, last_sign_in_at: Time.zone.now) }
let!(:schemes) { FactoryBot.create_list(:scheme, 5) }
let!(:scheme_to_search) { FactoryBot.create(:scheme) }
let(:notify_client) { instance_double(Notifications::Client) }
let(:confirmation_token) { "MCDH5y6Km-U7CFPgAMVS" }
let(:devise_notify_mailer) { DeviseNotifyMailer.new }
let(:otp) { "999111" }
before do
allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer)
allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client)
allow(Devise).to receive(:friendly_token).and_return(confirmation_token)
allow(notify_client).to receive(:send_email).and_return(true)
allow(SecureRandom).to receive(:random_number).and_return(otp)
visit("/logs")
fill_in("user[email]", with: user.email)
fill_in("user[password]", with: user.password)
click_button("Sign in")
fill_in("code", with: otp)
click_button("Submit")
end
it "displays the link to the supported housing" do
expect(page).to have_link("Supported housing", href: "/supported-housing")
end
context "when I click Supported housing" do
before do
click_link "Supported housing", href: "/supported-housing"
end
it "shows list of schemes" do
schemes.each do |scheme|
expect(page).to have_content(scheme.code)
end
end
context "when I search for a specific scheme" do
it "there is a search bar with a message and search button for schemes" do
expect(page).to have_field("search")
expect(page).to have_content("Search by service name or code")
expect(page).to have_button("Search")
end
context "when I fill in search information and press the search button" do
before do
fill_in("search", with: scheme_to_search.code)
click_button("Search")
end
it "displays scheme matching the scheme code" do
expect(page).to have_content(scheme_to_search.code)
end
context "when I want to clear results" do
it "there is link to clear the search results" do
expect(page).to have_link("Clear search")
end
it "displays all schemes after I clear the search results" do
click_link("Clear search")
expect(page).to have_content(scheme_to_search.code)
schemes.each do |scheme|
expect(page).to have_content(scheme.code)
end
end
end
end
end
end
end
end
end

82
spec/helpers/navigation_items_helper_spec.rb

@ -8,10 +8,26 @@ RSpec.describe NavigationItemsHelper do
describe "#primary items" do describe "#primary items" do
context "when the user is a data coordinator" do context "when the user is a data coordinator" do
context "when the user is on the logs page" do
let(:expected_navigation_items) do
[
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", true),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
NavigationItemsHelper::NavigationItem.new("Users", users_path, false),
NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false),
]
end
it "returns navigation items with the users item set as current" do
expect(primary_items("/logs", current_user)).to eq(expected_navigation_items)
end
end
context "when the user is on the users page" do context "when the user is on the users page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
NavigationItemsHelper::NavigationItem.new("Users", users_path, true), NavigationItemsHelper::NavigationItem.new("Users", users_path, true),
NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false),
] ]
@ -26,6 +42,7 @@ RSpec.describe NavigationItemsHelper do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
NavigationItemsHelper::NavigationItem.new("Users", users_path, false), NavigationItemsHelper::NavigationItem.new("Users", users_path, false),
NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, true), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, true),
] ]
@ -40,6 +57,7 @@ RSpec.describe NavigationItemsHelper do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false),
NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false),
] ]
@ -54,12 +72,28 @@ RSpec.describe NavigationItemsHelper do
context "when the user is a support user" do context "when the user is a support user" do
let(:current_user) { FactoryBot.create(:user, :support) } let(:current_user) { FactoryBot.create(:user, :support) }
context "when the user is on the logs page" do
let(:expected_navigation_items) do
[
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", true),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
]
end
it "returns navigation items with the users item set as current" do
expect(primary_items("/logs", current_user)).to eq(expected_navigation_items)
end
end
context "when the user is on the users page" do context "when the user is on the users page" do
let(:expected_navigation_items) do let(:expected_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", true), NavigationItemsHelper::NavigationItem.new("Users", "/users", true),
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
] ]
end end
@ -74,6 +108,7 @@ RSpec.describe NavigationItemsHelper do
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
] ]
end end
@ -82,6 +117,21 @@ RSpec.describe NavigationItemsHelper do
end end
end end
context "when the user is on the supported housing page" do
let(:expected_navigation_items) do
[
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", true),
]
end
it "returns navigation items with the users item set as current" do
expect(primary_items("/supported-housing", current_user)).to eq(expected_navigation_items)
end
end
context "when the user is on the specific organisation's page" do context "when the user is on the specific organisation's page" do
context "when the user is on organisation logs page" do context "when the user is on organisation logs page" do
let(:required_sub_path) { "logs" } let(:required_sub_path) { "logs" }
@ -90,12 +140,14 @@ RSpec.describe NavigationItemsHelper do
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
] ]
end end
let(:expected_secondary_navigation_items) do let(:expected_secondary_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", true), NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", true),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/organisations/#{current_user.organisation.id}/supported-housing", false),
NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false),
NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false),
] ]
@ -114,12 +166,14 @@ RSpec.describe NavigationItemsHelper do
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
] ]
end end
let(:expected_secondary_navigation_items) do let(:expected_secondary_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", false), NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/organisations/#{current_user.organisation.id}/supported-housing", false),
NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", true), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", true),
NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false), NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false),
] ]
@ -131,6 +185,32 @@ RSpec.describe NavigationItemsHelper do
end end
end end
context "when the user is on organisation schemes page" do
let(:required_sub_path) { "supported-housing" }
let(:expected_navigation_items) do
[
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
]
end
let(:expected_secondary_navigation_items) do
[
NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/organisations/#{current_user.organisation.id}/supported-housing", true),
NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false),
NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false),
]
end
it "returns navigation items with the schemes item set as current" do
expect(primary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user)).to eq(expected_navigation_items)
expect(secondary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user.organisation.id)).to eq(expected_secondary_navigation_items)
end
end
context "when the user is on organisation details page" do context "when the user is on organisation details page" do
let(:required_sub_path) { "details" } let(:required_sub_path) { "details" }
let(:expected_navigation_items) do let(:expected_navigation_items) do
@ -138,12 +218,14 @@ RSpec.describe NavigationItemsHelper do
NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true),
NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false),
NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false),
] ]
end end
let(:expected_secondary_navigation_items) do let(:expected_secondary_navigation_items) do
[ [
NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", false), NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", false),
NavigationItemsHelper::NavigationItem.new("Supported housing", "/organisations/#{current_user.organisation.id}/supported-housing", false),
NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false),
NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", true), NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", true),
] ]

5
spec/models/organisation_spec.rb

@ -4,6 +4,7 @@ RSpec.describe Organisation, type: :model do
describe "#new" do describe "#new" do
let(:user) { FactoryBot.create(:user) } let(:user) { FactoryBot.create(:user) }
let!(:organisation) { user.organisation } let!(:organisation) { user.organisation }
let!(:scheme) { FactoryBot.create(:scheme, organisation:) }
it "has expected fields" do it "has expected fields" do
expect(organisation.attribute_names).to include("name", "phone", "provider_type") expect(organisation.attribute_names).to include("name", "phone", "provider_type")
@ -13,6 +14,10 @@ RSpec.describe Organisation, type: :model do
expect(organisation.users.first).to eq(user) expect(organisation.users.first).to eq(user)
end end
it "has schemes" do
expect(organisation.schemes.first).to eq(scheme)
end
it "validates provider_type presence" do it "validates provider_type presence" do
expect { FactoryBot.create(:organisation, provider_type: nil) } expect { FactoryBot.create(:organisation, provider_type: nil) }
.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Provider type can’t be blank") .to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Provider type can’t be blank")

49
spec/models/scheme_spec.rb

@ -0,0 +1,49 @@
require "rails_helper"
RSpec.describe Scheme, type: :model do
describe "#new" do
let(:scheme) { FactoryBot.create(:scheme) }
it "belongs to an organisation" do
expect(scheme.organisation).to be_a(Organisation)
end
describe "scopes" do
let!(:scheme_1) { FactoryBot.create(:scheme) }
let!(:scheme_2) { FactoryBot.create(:scheme) }
context "when searching by code" do
it "returns case insensitive matching records" do
expect(described_class.search_by_code(scheme_1.code.upcase).count).to eq(1)
expect(described_class.search_by_code(scheme_1.code.downcase).count).to eq(1)
expect(described_class.search_by_code(scheme_1.code.downcase).first.code).to eq(scheme_1.code)
expect(described_class.search_by_code(scheme_2.code.upcase).count).to eq(1)
expect(described_class.search_by_code(scheme_2.code.downcase).count).to eq(1)
expect(described_class.search_by_code(scheme_2.code.downcase).first.code).to eq(scheme_2.code)
end
end
context "when searching by service name" do
it "returns case insensitive matching records" do
expect(described_class.search_by_service_name(scheme_1.service_name.upcase).count).to eq(1)
expect(described_class.search_by_service_name(scheme_1.service_name.downcase).count).to eq(1)
expect(described_class.search_by_service_name(scheme_1.service_name.downcase).first.service_name).to eq(scheme_1.service_name)
expect(described_class.search_by_service_name(scheme_2.service_name.upcase).count).to eq(1)
expect(described_class.search_by_service_name(scheme_2.service_name.downcase).count).to eq(1)
expect(described_class.search_by_service_name(scheme_2.service_name.downcase).first.service_name).to eq(scheme_2.service_name)
end
end
context "when searching by all searchable field" do
it "returns case insensitive matching records" do
expect(described_class.search_by(scheme_1.code.upcase).count).to eq(1)
expect(described_class.search_by(scheme_1.code.downcase).count).to eq(1)
expect(described_class.search_by(scheme_1.code.downcase).first.code).to eq(scheme_1.code)
expect(described_class.search_by_service_name(scheme_2.service_name.upcase).count).to eq(1)
expect(described_class.search_by_service_name(scheme_2.service_name.downcase).count).to eq(1)
expect(described_class.search_by_service_name(scheme_2.service_name.downcase).first.service_name).to eq(scheme_2.service_name)
end
end
end
end
end

131
spec/requests/organisations_controller_spec.rb

@ -30,10 +30,141 @@ RSpec.describe OrganisationsController, type: :request do
get "/organisations", headers: headers, params: {} get "/organisations", headers: headers, params: {}
expect(response).to redirect_to("/account/sign-in") expect(response).to redirect_to("/account/sign-in")
end end
it "does not let you see supported housing list" do
get "/organisations/#{organisation.id}/supported-housing", headers: headers, params: {}
expect(response).to redirect_to("/account/sign-in")
end
end end
end end
context "when user is signed in" do context "when user is signed in" do
describe "#schemes" do
context "when support user" do
let(:user) { FactoryBot.create(:user, :support) }
let!(:schemes) { FactoryBot.create_list(:scheme, 5) }
let!(:same_org_scheme) { FactoryBot.create(:scheme, organisation: user.organisation) }
before do
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
get "/organisations/#{organisation.id}/supported-housing", headers:, params: {}
end
it "has page heading" do
expect(page).to have_content("Supported housing services")
end
it "shows a search bar" do
expect(page).to have_field("search", type: "search")
end
it "has hidden accebility field with description" do
expected_field = "<h2 class=\"govuk-visually-hidden\">Supported housing services</h2>"
expect(CGI.unescape_html(response.body)).to include(expected_field)
end
it "shows only schemes belonging to the same organisation" do
expect(page).to have_content(same_org_scheme.code)
schemes.each do |scheme|
expect(page).not_to have_content(scheme.code)
end
end
context "when searching" do
let!(:searched_scheme) { FactoryBot.create(:scheme, code: "CODE321", organisation: user.organisation) }
let(:search_param) { "CODE321" }
before do
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
get "/organisations/#{organisation.id}/supported-housing?search=#{search_param}"
end
it "returns matching results" do
expect(page).to have_content(searched_scheme.code)
schemes.each do |scheme|
expect(page).not_to have_content(scheme.code)
end
end
it "updates the table caption" do
expect(page).to have_content("1 scheme found matching ‘#{search_param}")
end
it "has search in the title" do
expect(page).to have_title("#{user.organisation.name} (1 scheme matching ‘#{search_param}’) - Submit social housing lettings and sales data (CORE) - GOV.UK")
end
end
end
context "when data coordinator user" do
let(:user) { FactoryBot.create(:user, :data_coordinator) }
let!(:schemes) { FactoryBot.create_list(:scheme, 5) }
let!(:same_org_scheme) { FactoryBot.create(:scheme, organisation: user.organisation) }
before do
sign_in user
get "/organisations/#{organisation.id}/supported-housing", headers:, params: {}
end
it "has page heading" do
expect(page).to have_content("Supported housing services")
end
it "shows a search bar" do
expect(page).to have_field("search", type: "search")
end
it "has hidden accebility field with description" do
expected_field = "<h2 class=\"govuk-visually-hidden\">Supported housing services</h2>"
expect(CGI.unescape_html(response.body)).to include(expected_field)
end
it "shows only schemes belonging to the same organisation" do
expect(page).to have_content(same_org_scheme.code)
schemes.each do |scheme|
expect(page).not_to have_content(scheme.code)
end
end
context "with schemes that are not in scope for the user, i.e. that they do not belong to" do
let!(:unauthorised_organisation) { FactoryBot.create(:organisation) }
before do
get "/organisations/#{unauthorised_organisation.id}/supported-housing", headers:, params: {}
end
it "returns not found 404 from org details route" do
expect(response).to have_http_status(:not_found)
end
end
context "when searching" do
let!(:searched_scheme) { FactoryBot.create(:scheme, code: "CODE321", organisation: user.organisation) }
let(:search_param) { "CODE321" }
before do
get "/organisations/#{organisation.id}/supported-housing?search=#{search_param}"
end
it "returns matching results" do
expect(page).to have_content(searched_scheme.code)
schemes.each do |scheme|
expect(page).not_to have_content(scheme.code)
end
end
it "updates the table caption" do
expect(page).to have_content("1 scheme found matching ‘#{search_param}")
end
it "has search in the title" do
expect(page).to have_title("Supported housing services (1 scheme matching ‘#{search_param}’) - Submit social housing lettings and sales data (CORE) - GOV.UK")
end
end
end
end
describe "#show" do describe "#show" do
context "with an organisation that the user belongs to" do context "with an organisation that the user belongs to" do
before do before do

163
spec/requests/schemes_controller_spec.rb

@ -0,0 +1,163 @@
require "rails_helper"
RSpec.describe SchemesController, type: :request do
let(:organisation) { user.organisation }
let(:headers) { { "Accept" => "text/html" } }
let(:page) { Capybara::Node::Simple.new(response.body) }
let(:user) { FactoryBot.create(:user, :support) }
let!(:schemes) { FactoryBot.create_list(:scheme, 5) }
describe "#index" do
context "when not signed in" do
it "redirects to the sign in page" do
get "/supported-housing"
expect(response).to redirect_to("/account/sign-in")
end
end
context "when signed in as a data provider user" do
let(:user) { FactoryBot.create(:user) }
before do
sign_in user
get "/supported-housing"
end
it "returns 401 unauthorized" do
request
expect(response).to have_http_status(:unauthorized)
end
end
context "when signed in as a data coordinator user" do
let(:user) { FactoryBot.create(:user, :data_coordinator) }
before do
sign_in user
get "/supported-housing"
end
it "redirects to the organisation schemes path" do
follow_redirect!
expect(path).to match("/organisations/#{user.organisation.id}/supported-housing")
end
end
context "when signed in as a support user" do
before do
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
get "/supported-housing"
end
it "has page heading" do
expect(page).to have_content("Supported housing services")
end
it "shows all schemes" do
schemes.each do |scheme|
expect(page).to have_content(scheme.code)
end
end
it "shows a search bar" do
expect(page).to have_field("search", type: "search")
end
it "has correct title" do
expect(page).to have_title("Supported housing services - Submit social housing lettings and sales data (CORE) - GOV.UK")
end
it "shows the total organisations count" do
expect(CGI.unescape_html(response.body)).to match("<strong>#{schemes.count}</strong> total schemes.")
end
it "has hidden accebility field with description" do
expected_field = "<h2 class=\"govuk-visually-hidden\">Supported housing services</h2>"
expect(CGI.unescape_html(response.body)).to include(expected_field)
end
context "when paginating over 20 results" do
let(:total_schemes_count) { Scheme.count }
before do
FactoryBot.create_list(:scheme, 20)
end
context "when on the first page" do
before do
get "/supported-housing"
end
it "shows the total schemes count" do
expect(CGI.unescape_html(response.body)).to match("<strong>#{total_schemes_count}</strong> total schemes.")
end
it "shows which schemes are being shown on the current page" do
expect(CGI.unescape_html(response.body)).to match("Showing <b>1</b> to <b>20</b> of <b>#{total_schemes_count}</b> schemes")
end
it "has correct page 1 of 2 title" do
expect(page).to have_title("Supported housing services (page 1 of 2) - Submit social housing lettings and sales data (CORE) - GOV.UK")
end
it "has pagination links" do
expect(page).to have_content("Previous")
expect(page).not_to have_link("Previous")
expect(page).to have_content("Next")
expect(page).to have_link("Next")
end
end
context "when on the second page" do
before do
get "/supported-housing?page=2"
end
it "shows the total schemes count" do
expect(CGI.unescape_html(response.body)).to match("<strong>#{total_schemes_count}</strong> total schemes.")
end
it "has pagination links" do
expect(page).to have_content("Previous")
expect(page).to have_link("Previous")
expect(page).to have_content("Next")
expect(page).not_to have_link("Next")
end
it "shows which schemes are being shown on the current page" do
expect(CGI.unescape_html(response.body)).to match("Showing <b>21</b> to <b>25</b> of <b>#{total_schemes_count}</b> schemes")
end
it "has correct page 1 of 2 title" do
expect(page).to have_title("Supported housing services (page 2 of 2) - Submit social housing lettings and sales data (CORE) - GOV.UK")
end
end
end
context "when searching" do
let!(:searched_scheme) { FactoryBot.create(:scheme, code: "CODE321") }
let(:search_param) { "CODE321" }
before do
get "/supported-housing?search=#{search_param}"
end
it "returns matching results" do
expect(page).to have_content(searched_scheme.code)
schemes.each do |scheme|
expect(page).not_to have_content(scheme.code)
end
end
it "updates the table caption" do
expect(page).to have_content("1 scheme found matching ‘#{search_param}")
end
it "has search in the title" do
expect(page).to have_title("Supported housing services (1 scheme matching ‘#{search_param}’) - Submit social housing lettings and sales data (CORE) - GOV.UK")
end
end
end
end
end
Loading…
Cancel
Save