Browse Source
* 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
22 changed files with 736 additions and 4 deletions
@ -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 |
@ -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 |
@ -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" } %> |
@ -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> |
@ -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" } %> |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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…
Reference in new issue