Browse Source
* Prototype * Remove git from dockerfile * UPRN search too * Revert address client and use uprn client * Add address search to lettings too * Updates with lettings logs * Update copy * Move guidance to partial * Fix uprn return * Delete new db file, restore old * Lint * Remove old db file * Lint * Add new db file, remove old * JS lint * Update schema * Add manual entry option * Update derived variables * Comment out old version of find address in 2024 * Remove db column * Add new db columns * Update guidance partial * Add unless to migration * Add migration files to remove and readd * authenticate user * Remove file * Delete migration files * Add search url * Add search url * Fix onConfirm * Add manual entry button instead of change skip link * Revert "Add manual entry button instead of change skip link" This reverts commitpull/2948/head^222577c801a
. * Revert "Revert "Add manual entry button instead of change skip link"" This reverts commit9f0a2111a5
. * Replace uprn question * Update question copy * Allow changing the address search value * Rename address autocomplete to address search * Add buttons to switch between address questions * Fix controller logic * Enable adding question numbers to page headers * Update skip links * Add js disabled message to select * Alternative way to handle js disabled users * Revert "Alternative way to handle js disabled users" This reverts commit10da3d61e2
. * Fix typo * Fix address options for address search question * Reuse AddressDataPresenter where appropriate * Lint * Remove uprn selection question tests * Reuse UprnDataPresenter where appropriate * CSV export, exclude address_search * Add address search to sales and lettings factory bots * Exclude old address questions from routing, keep as exported values * lint * Update uprn value * Add address search input boolean and switch between questions * Reword copy, remove "Find" and "Search by" * Align address questions, add question number and question text * Remove old wip depends on * Update some tests * Update migration, move default value from db to model * Update test * Remove binding pry * Lint * Update test * Lint * Update test * Update routes with underscores * Remove debugging * Limit visible logs to user * Add manual address entry selected variable * Change address search min length to 3chars * Remove binding.pry * Update factory bots, manual_address_entry_selected to true for preexisting tests * Update model tests * Update sales model tests excl E-code tests * Update address search request test * Reuse uprn id instead of address_search * Set manual address entry selected as false when creating test logs * Update model test * Update request tests and remove old questions * Add back test * Update services * Update more tests Co-authored-by: kosiakkatrina <kosiakkatrina@users.noreply.github.com> * Update request tests * update model tests * Also update sales log * Update service csv uprn_selection values to 1 * Add tests for pages and questions * Update test * Update uprn_known * Lint * Add feature test * Update test * Update tests * Remove test * pre-consolidate migration files * Indentation * Controller method improvements * Update question numbers for 2025/26 * Update question numbers tests * consolidate and delete old migration files * undo changes to schema.rb * Update 2025 property information translation files * Update answer options to show singular previously selected result if present * Move buttons to bottom guidance partials * Small improvements, make address search and existing search more similar * Validate entered addresses as within England * Update test * Revert "Validate entered addresses as within England" This reverts commit2dbfbcc8a5
. * Add missing button to sales address page * Change error code * Clear invalid options * Edit no results message method * Keep no result logic just change text * Display uprn value with address value * Still show no results message when characters entered is less than 3 rather than nothing * Fix uprn result when query is ambiguous * Reduce min match for address search * Hide no result found message just before results are populated * Prevent changing logs to 2025 with invalid addresses * Correct attribute name * Handle nil * Remove custom error message * Remove unused variables from factory * Update tests, remove address and postcode from old find address * Fix bug clearing uprn from see all answers * Revert "Fix bug clearing uprn from see all answers" This reverts commita66c47a1ab
. * Undo changes to validation method * Fix unchanged uprn_selection when clearing or changing uprn * Undo a change * Update bulk upload 2025 * Fix typo * Remove redundant line --------- Co-authored-by: Kat <54268893+kosiakkatrina@users.noreply.github.com> Co-authored-by: kosiakkatrina <kosiakkatrina@users.noreply.github.com>
73 changed files with 997 additions and 1041 deletions
@ -0,0 +1,70 @@ |
|||||||
|
class AddressSearchController < ApplicationController |
||||||
|
before_action :authenticate_user! |
||||||
|
before_action :set_log, only: %i[manual_input search_input] |
||||||
|
|
||||||
|
def index |
||||||
|
query = params[:query] |
||||||
|
|
||||||
|
if query.match?(/\A\d+\z/) && query.length > 5 |
||||||
|
# Query is all numbers and greater than 5 digits, assume it's a UPRN |
||||||
|
service = UprnClient.new(query) |
||||||
|
service.call |
||||||
|
|
||||||
|
if service.error.present? |
||||||
|
render json: { error: service.error }, status: :not_found |
||||||
|
else |
||||||
|
presenter = UprnDataPresenter.new(service.result) |
||||||
|
render json: [{ text: presenter.address, value: presenter.uprn }] |
||||||
|
end |
||||||
|
elsif query.match?(/[a-zA-Z]/) |
||||||
|
# Query contains letters, assume it's an address |
||||||
|
service = AddressClient.new(query, { minmatch: 0.2 }) |
||||||
|
service.call |
||||||
|
|
||||||
|
if service.error.present? |
||||||
|
render json: { error: service.error }, status: :not_found |
||||||
|
else |
||||||
|
results = service.result.map do |result| |
||||||
|
presenter = AddressDataPresenter.new(result) |
||||||
|
{ text: presenter.address, value: presenter.uprn } |
||||||
|
end |
||||||
|
render json: results |
||||||
|
end |
||||||
|
else |
||||||
|
# Query is ambiguous, use both APIs and merge results |
||||||
|
address_service = AddressClient.new(query, { minmatch: 0.2 }) |
||||||
|
uprn_service = UprnClient.new(query) |
||||||
|
|
||||||
|
address_service.call |
||||||
|
uprn_service.call |
||||||
|
|
||||||
|
results = ([uprn_service.result] || []) + (address_service.result || []) |
||||||
|
|
||||||
|
if address_service.error.present? && uprn_service.error.present? |
||||||
|
render json: { error: "Address and UPRN are not recognised." }, status: :not_found |
||||||
|
else |
||||||
|
formatted_results = results.map do |result| |
||||||
|
presenter = AddressDataPresenter.new(result) |
||||||
|
{ text: presenter.address, value: presenter.uprn } |
||||||
|
end |
||||||
|
render json: formatted_results |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def manual_input |
||||||
|
@log.update!(manual_address_entry_selected: true) |
||||||
|
redirect_to polymorphic_url([@log, :address]) |
||||||
|
end |
||||||
|
|
||||||
|
def search_input |
||||||
|
@log.update!(manual_address_entry_selected: false) |
||||||
|
redirect_to polymorphic_url([@log, :address_search]) |
||||||
|
end |
||||||
|
|
||||||
|
private |
||||||
|
|
||||||
|
def set_log |
||||||
|
@log = current_user.send("#{params[:log_type]}s").find(params[:log_id]) |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,73 @@ |
|||||||
|
import { Controller } from '@hotwired/stimulus' |
||||||
|
import accessibleAutocomplete from 'accessible-autocomplete' |
||||||
|
import 'accessible-autocomplete/dist/accessible-autocomplete.min.css' |
||||||
|
|
||||||
|
const options = [] |
||||||
|
|
||||||
|
const fetchOptions = async (query, searchUrl) => { |
||||||
|
if (query.length < 2) { |
||||||
|
throw new Error('Query must be at least 2 characters long.') |
||||||
|
} |
||||||
|
try { |
||||||
|
const response = await fetch(`${searchUrl}?query=${encodeURIComponent(query.trim())}`) |
||||||
|
return await response.json() |
||||||
|
} catch (error) { |
||||||
|
return error |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const fetchAndPopulateSearchResults = async (query, populateResults, searchUrl, populateOptions, selectEl) => { |
||||||
|
if (/\S/.test(query)) { |
||||||
|
try { |
||||||
|
const results = await fetchOptions(query, searchUrl) |
||||||
|
if (results.length === 0) { |
||||||
|
populateOptions([], selectEl) |
||||||
|
populateResults([]) |
||||||
|
} else { |
||||||
|
populateOptions(results, selectEl) |
||||||
|
populateResults(Object.values(results).map((o) => `${o.text} (${o.value})`)) |
||||||
|
} |
||||||
|
} catch (error) { |
||||||
|
populateOptions([], selectEl) |
||||||
|
populateResults([]) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const populateOptions = (results, selectEl) => { |
||||||
|
selectEl.innerHTML = '' |
||||||
|
|
||||||
|
results.forEach((result) => { |
||||||
|
const option = document.createElement('option') |
||||||
|
option.value = result.value |
||||||
|
option.innerHTML = `${result.text} (${result.value})` |
||||||
|
selectEl.appendChild(option) |
||||||
|
options.push(option) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
export default class extends Controller { |
||||||
|
connect () { |
||||||
|
const searchUrl = JSON.parse(this.element.dataset.info).search_url |
||||||
|
const selectEl = this.element |
||||||
|
|
||||||
|
accessibleAutocomplete.enhanceSelectElement({ |
||||||
|
defaultValue: '', |
||||||
|
selectElement: selectEl, |
||||||
|
minLength: 2, |
||||||
|
source: (query, populateResults) => { |
||||||
|
fetchAndPopulateSearchResults(query, populateResults, searchUrl, populateOptions, selectEl) |
||||||
|
}, |
||||||
|
autoselect: true, |
||||||
|
showNoOptionsFound: true, |
||||||
|
placeholder: 'Start typing to search', |
||||||
|
templates: { suggestion: (value) => value }, |
||||||
|
onConfirm: (val) => { |
||||||
|
const selectedResult = Array.from(selectEl.options).find(option => option.text === val) |
||||||
|
if (selectedResult) { |
||||||
|
selectedResult.selected = true |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
class Form::Lettings::Pages::AddressSearch < ::Form::Page |
||||||
|
def initialize(id, hsh, subsection) |
||||||
|
super |
||||||
|
@id = "address_search" |
||||||
|
@copy_key = "sales.property_information.address_search" |
||||||
|
@depends_on = [{ "is_supported_housing?" => false, "manual_address_entry_selected" => false }] |
||||||
|
@question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max] |
||||||
|
end |
||||||
|
|
||||||
|
def questions |
||||||
|
@questions ||= [ |
||||||
|
Form::Lettings::Questions::AddressSearch.new(nil, nil, self), |
||||||
|
] |
||||||
|
end |
||||||
|
|
||||||
|
QUESTION_NUMBER_FROM_YEAR = { 2024 => 12, 2025 => 16 }.freeze |
||||||
|
end |
@ -0,0 +1,44 @@ |
|||||||
|
class Form::Lettings::Questions::AddressSearch < ::Form::Question |
||||||
|
def initialize(id, hsh, page) |
||||||
|
super |
||||||
|
@id = "uprn" |
||||||
|
@type = "address_search" |
||||||
|
@copy_key = "lettings.property_information.address_search" |
||||||
|
@plain_label = true |
||||||
|
@bottom_guidance_partial = "address_search" |
||||||
|
@question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max] |
||||||
|
@hide_question_number_on_page = true |
||||||
|
end |
||||||
|
|
||||||
|
def answer_options(log = nil, _user = nil) |
||||||
|
return {} unless ActiveRecord::Base.connected? |
||||||
|
return {} unless log&.address_options&.any? |
||||||
|
|
||||||
|
log.address_options.each_with_object({}) do |option, hash| |
||||||
|
hash[option[:uprn]] = { "value" => "#{option[:address]} (#{option[:uprn]})" } |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def get_extra_check_answer_value(log) |
||||||
|
return unless log.uprn_known == 1 |
||||||
|
|
||||||
|
value = [ |
||||||
|
log.address_line1, |
||||||
|
log.address_line2, |
||||||
|
log.town_or_city, |
||||||
|
log.county, |
||||||
|
log.postcode_full, |
||||||
|
(LocalAuthority.find_by(code: log.la)&.name if log.la.present?), |
||||||
|
].select(&:present?) |
||||||
|
|
||||||
|
return unless value.any? |
||||||
|
|
||||||
|
"\n\n#{value.join("\n")}" |
||||||
|
end |
||||||
|
|
||||||
|
def displayed_answer_options(log, user = nil) |
||||||
|
answer_options(log, user).transform_values { |value| value["value"] } || {} |
||||||
|
end |
||||||
|
|
||||||
|
QUESTION_NUMBER_FROM_YEAR = { 2024 => 12, 2025 => 16 }.freeze |
||||||
|
end |
@ -0,0 +1,23 @@ |
|||||||
|
class Form::Sales::Pages::AddressSearch < ::Form::Page |
||||||
|
def initialize(id, hsh, subsection) |
||||||
|
super |
||||||
|
@id = "address_search" |
||||||
|
@copy_key = "sales.property_information.address_search" |
||||||
|
@depends_on = [{ "manual_address_entry_selected" => false }] |
||||||
|
@question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max] |
||||||
|
end |
||||||
|
|
||||||
|
def questions |
||||||
|
@questions ||= [ |
||||||
|
Form::Sales::Questions::AddressSearch.new(nil, nil, self), |
||||||
|
] |
||||||
|
end |
||||||
|
|
||||||
|
def skip_href(log = nil) |
||||||
|
return unless log |
||||||
|
|
||||||
|
"/#{log.log_type.dasherize}s/#{log.id}/property-number-of-bedrooms" |
||||||
|
end |
||||||
|
|
||||||
|
QUESTION_NUMBER_FROM_YEAR = { 2024 => 15, 2025 => 13 }.freeze |
||||||
|
end |
@ -0,0 +1,44 @@ |
|||||||
|
class Form::Sales::Questions::AddressSearch < ::Form::Question |
||||||
|
def initialize(id, hsh, page) |
||||||
|
super |
||||||
|
@id = "uprn" |
||||||
|
@type = "address_search" |
||||||
|
@copy_key = "sales.property_information.address_search" |
||||||
|
@plain_label = true |
||||||
|
@bottom_guidance_partial = "address_search" |
||||||
|
@question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max] |
||||||
|
@hide_question_number_on_page = true |
||||||
|
end |
||||||
|
|
||||||
|
def answer_options(log = nil, _user = nil) |
||||||
|
return {} unless ActiveRecord::Base.connected? |
||||||
|
return {} unless log&.address_options&.any? |
||||||
|
|
||||||
|
log.address_options.each_with_object({}) do |option, hash| |
||||||
|
hash[option[:uprn]] = { "value" => "#{option[:address]} (#{option[:uprn]})" } |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def get_extra_check_answer_value(log) |
||||||
|
return unless log.uprn_known == 1 |
||||||
|
|
||||||
|
value = [ |
||||||
|
log.address_line1, |
||||||
|
log.address_line2, |
||||||
|
log.town_or_city, |
||||||
|
log.county, |
||||||
|
log.postcode_full, |
||||||
|
(LocalAuthority.find_by(code: log.la)&.name if log.la.present?), |
||||||
|
].select(&:present?) |
||||||
|
|
||||||
|
return unless value.any? |
||||||
|
|
||||||
|
"\n\n#{value.join("\n")}" |
||||||
|
end |
||||||
|
|
||||||
|
def displayed_answer_options(log, user = nil) |
||||||
|
answer_options(log, user).transform_values { |value| value["value"] } || {} |
||||||
|
end |
||||||
|
|
||||||
|
QUESTION_NUMBER_FROM_YEAR = { 2024 => 15, 2025 => 13 }.freeze |
||||||
|
end |
@ -0,0 +1,24 @@ |
|||||||
|
<% selected = @log.public_send(question.id) || "" %> |
||||||
|
<% answers = question.displayed_answer_options(@log, current_user).map { |key, value| OpenStruct.new(id: key, name: select_option_name(value), resource: value) } %> |
||||||
|
<%= render partial: "form/guidance/#{question.top_guidance_partial}" if question.top_guidance? %> |
||||||
|
|
||||||
|
<%= f.govuk_select(question.id.to_sym, |
||||||
|
label: legend(question, page_header, conditional), |
||||||
|
"data-controller": "address-search", |
||||||
|
"data-info": { search_url: address_search_url }.to_json, |
||||||
|
caption: caption(caption_text, page_header, conditional), |
||||||
|
hint: { text: question.hint_text&.html_safe }) do %> |
||||||
|
<% if answers.any? %> |
||||||
|
<% answers.each do |answer| %> |
||||||
|
<option value="<%= answer.id %>" |
||||||
|
data-synonyms="<%= answer_option_synonyms(answer.resource) %>" |
||||||
|
data-append="<%= answer_option_append(answer.resource) %>" |
||||||
|
data-hint="<%= answer_option_hint(answer.resource) %>" |
||||||
|
<%= question.answer_selected?(@log, answer) ? "selected" : "" %>><%= answer.name || answer.resource %></option> |
||||||
|
<% end %> |
||||||
|
<% else %> |
||||||
|
<option value="" disabled>Javascript is disabled. Please enter the address manually.</option> |
||||||
|
<% end %> |
||||||
|
<% end %> |
||||||
|
|
||||||
|
<%= render partial: "form/guidance/#{question.bottom_guidance_partial}" if question.bottom_guidance? %> |
@ -0,0 +1,3 @@ |
|||||||
|
<div class="govuk-button-group"> |
||||||
|
<%= govuk_link_to "Clear address and search instead", address_search_input_path(@log.log_type, @log.id), class: "govuk-button govuk-button--secondary" %> |
||||||
|
</div> |
@ -0,0 +1,7 @@ |
|||||||
|
<%= govuk_details(summary_text: I18n.t("forms.#{@log.form.start_date.year}.#{@log.form.type}.guidance.address_search.title")) do %> |
||||||
|
<%= I18n.t("forms.#{@log.form.start_date.year}.#{@log.form.type}.guidance.address_search.content").html_safe %> |
||||||
|
<% end %> |
||||||
|
|
||||||
|
<div class="govuk-button-group"> |
||||||
|
<%= govuk_link_to "Enter the address manually instead", address_manual_input_path(@log.log_type, @log.id), class: "govuk-button govuk-button--secondary" %> |
||||||
|
</div> |
@ -0,0 +1,6 @@ |
|||||||
|
class AddManualAddressEntrySelectedToLogs < ActiveRecord::Migration[7.2] |
||||||
|
def change |
||||||
|
add_column :sales_logs, :manual_address_entry_selected, :boolean, default: false |
||||||
|
add_column :lettings_logs, :manual_address_entry_selected, :boolean, default: false |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,45 @@ |
|||||||
|
require "rails_helper" |
||||||
|
require_relative "helpers" |
||||||
|
|
||||||
|
RSpec.describe "Address Search" do |
||||||
|
include Helpers |
||||||
|
let(:user) { FactoryBot.create(:user) } |
||||||
|
let(:sales_log) do |
||||||
|
FactoryBot.create( |
||||||
|
:sales_log, |
||||||
|
:shared_ownership_setup_complete, |
||||||
|
assigned_to: user, |
||||||
|
manual_address_entry_selected: false, |
||||||
|
) |
||||||
|
end |
||||||
|
|
||||||
|
before do |
||||||
|
sign_in user |
||||||
|
end |
||||||
|
|
||||||
|
context "when using address search feature" do |
||||||
|
before do |
||||||
|
visit("/sales-logs/#{sales_log.id}/address-search") |
||||||
|
end |
||||||
|
|
||||||
|
it "allows searching by a UPRN", js: true do |
||||||
|
find("#sales-log-uprn-field").click.native.send_keys("1", "0", "0", "3", "3", "5", "4", "4", "6", "1", "4", :down) |
||||||
|
expect(find("#sales-log-uprn-field").value).to eq("10033544614") |
||||||
|
end |
||||||
|
|
||||||
|
it "allows searching by address", js: true do |
||||||
|
find("#sales-log-uprn-field").click.native.send_keys("S", "W", "1", "5", :down, :enter) |
||||||
|
expect(find("#sales-log-uprn-field").value).to eq("SW15") |
||||||
|
end |
||||||
|
|
||||||
|
it "displays the placeholder text", js: true do |
||||||
|
expect(find("#sales-log-uprn-field")["placeholder"]).to eq("Start typing to search") |
||||||
|
end |
||||||
|
|
||||||
|
it "displays correct bottom guidance text" do |
||||||
|
find("span.govuk-details__summary-text", text: "Can’t find the address you’re looking for?").click |
||||||
|
expect(page).to have_content("Some properties may not be available yet e.g. new builds; you might need to enter them manually instead") |
||||||
|
expect(page).to have_content("For UPRN (Unique Property Reference Number), please enter the full value exactly") |
||||||
|
end |
||||||
|
end |
||||||
|
end |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,42 @@ |
|||||||
|
require "rails_helper" |
||||||
|
|
||||||
|
RSpec.describe Form::Lettings::Pages::AddressSearch, type: :model do |
||||||
|
subject(:page) { described_class.new(page_id, page_definition, subsection) } |
||||||
|
|
||||||
|
let(:page_id) { nil } |
||||||
|
let(:page_definition) { nil } |
||||||
|
let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date:)) } |
||||||
|
let(:start_date) { Time.utc(2024, 4, 1) } |
||||||
|
|
||||||
|
it "has correct subsection" do |
||||||
|
expect(page.subsection).to eq(subsection) |
||||||
|
end |
||||||
|
|
||||||
|
it "has correct questions" do |
||||||
|
expect(page.questions.map(&:id)).to eq(%w[uprn]) |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct id" do |
||||||
|
expect(page.id).to eq("address_search") |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct description" do |
||||||
|
expect(page.description).to be_nil |
||||||
|
end |
||||||
|
|
||||||
|
it "has correct depends_on" do |
||||||
|
expect(page.depends_on).to eq([{ "is_supported_housing?" => false, "manual_address_entry_selected" => false }]) |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct question number" do |
||||||
|
expect(page.question_number).to eq(12) |
||||||
|
end |
||||||
|
|
||||||
|
context "with 2025/26 form" do |
||||||
|
let(:start_date) { Time.utc(2025, 4, 1) } |
||||||
|
|
||||||
|
it "has the correct question number" do |
||||||
|
expect(page.question_number).to eq(16) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,68 @@ |
|||||||
|
require "rails_helper" |
||||||
|
|
||||||
|
RSpec.describe Form::Lettings::Questions::AddressSearch, type: :model do |
||||||
|
subject(:question) { described_class.new(question_id, question_definition, page) } |
||||||
|
|
||||||
|
let(:question_id) { nil } |
||||||
|
let(:question_definition) { nil } |
||||||
|
let(:page) { instance_double(Form::Page, subsection: instance_double(Form::Subsection, form: instance_double(Form, start_date:))) } |
||||||
|
let(:start_date) { Time.utc(2024, 4, 1) } |
||||||
|
|
||||||
|
it "has correct page" do |
||||||
|
expect(question.page).to eq(page) |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct id" do |
||||||
|
expect(question.id).to eq("uprn") |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct type" do |
||||||
|
expect(question.type).to eq("address_search") |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct question number" do |
||||||
|
expect(question.question_number).to eq(12) |
||||||
|
end |
||||||
|
|
||||||
|
context "with 2025/26 form" do |
||||||
|
let(:start_date) { Time.utc(2025, 4, 1) } |
||||||
|
|
||||||
|
it "has the correct question number" do |
||||||
|
expect(question.question_number).to eq(16) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
describe "get_extra_check_answer_value" do |
||||||
|
context "when address is not present" do |
||||||
|
let(:log) { build(:lettings_log, manual_address_entry_selected: false) } |
||||||
|
|
||||||
|
it "returns nil" do |
||||||
|
expect(question.get_extra_check_answer_value(log)).to be_nil |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
context "when address search is present" do |
||||||
|
let(:log) do |
||||||
|
build( |
||||||
|
:lettings_log, |
||||||
|
:completed, |
||||||
|
address_line1: "19, Charlton Gardens", |
||||||
|
town_or_city: "Bristol", |
||||||
|
postcode_full: "BS10 6LU", |
||||||
|
la: "E06000023", |
||||||
|
uprn_known: 1, |
||||||
|
uprn: 107, |
||||||
|
uprn_confirmed: 1, |
||||||
|
) |
||||||
|
end |
||||||
|
|
||||||
|
context "when uprn known" do |
||||||
|
it "returns formatted value" do |
||||||
|
expect(question.get_extra_check_answer_value(log)).to eq( |
||||||
|
"\n\n19, Charlton Gardens\nBristol\nBS10 6LU\nBristol, City of", |
||||||
|
) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,42 @@ |
|||||||
|
require "rails_helper" |
||||||
|
|
||||||
|
RSpec.describe Form::Sales::Pages::AddressSearch, type: :model do |
||||||
|
subject(:page) { described_class.new(page_id, page_definition, subsection) } |
||||||
|
|
||||||
|
let(:page_id) { nil } |
||||||
|
let(:page_definition) { nil } |
||||||
|
let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date:)) } |
||||||
|
let(:start_date) { Time.utc(2024, 4, 1) } |
||||||
|
|
||||||
|
it "has correct subsection" do |
||||||
|
expect(page.subsection).to eq(subsection) |
||||||
|
end |
||||||
|
|
||||||
|
it "has correct questions" do |
||||||
|
expect(page.questions.map(&:id)).to eq(%w[uprn]) |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct id" do |
||||||
|
expect(page.id).to eq("address_search") |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct description" do |
||||||
|
expect(page.description).to be_nil |
||||||
|
end |
||||||
|
|
||||||
|
it "has correct depends_on" do |
||||||
|
expect(page.depends_on).to eq([{ "manual_address_entry_selected" => false }]) |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct question number" do |
||||||
|
expect(page.question_number).to eq(15) |
||||||
|
end |
||||||
|
|
||||||
|
context "with 2025/26 form" do |
||||||
|
let(:start_date) { Time.utc(2025, 4, 1) } |
||||||
|
|
||||||
|
it "has the correct question number" do |
||||||
|
expect(page.question_number).to eq(13) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,68 @@ |
|||||||
|
require "rails_helper" |
||||||
|
|
||||||
|
RSpec.describe Form::Sales::Questions::AddressSearch, type: :model do |
||||||
|
subject(:question) { described_class.new(question_id, question_definition, page) } |
||||||
|
|
||||||
|
let(:question_id) { nil } |
||||||
|
let(:question_definition) { nil } |
||||||
|
let(:page) { instance_double(Form::Page, subsection: instance_double(Form::Subsection, form: instance_double(Form, start_date:))) } |
||||||
|
let(:start_date) { Time.utc(2024, 4, 1) } |
||||||
|
|
||||||
|
it "has correct page" do |
||||||
|
expect(question.page).to eq(page) |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct id" do |
||||||
|
expect(question.id).to eq("uprn") |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct type" do |
||||||
|
expect(question.type).to eq("address_search") |
||||||
|
end |
||||||
|
|
||||||
|
it "has the correct question number" do |
||||||
|
expect(question.question_number).to eq(15) |
||||||
|
end |
||||||
|
|
||||||
|
context "with 2025/26 form" do |
||||||
|
let(:start_date) { Time.utc(2025, 4, 1) } |
||||||
|
|
||||||
|
it "has the correct question number" do |
||||||
|
expect(question.question_number).to eq(13) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
describe "get_extra_check_answer_value" do |
||||||
|
context "when address is not present" do |
||||||
|
let(:log) { build(:sales_log, manual_address_entry_selected: false) } |
||||||
|
|
||||||
|
it "returns nil" do |
||||||
|
expect(question.get_extra_check_answer_value(log)).to be_nil |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
context "when address search is present" do |
||||||
|
let(:log) do |
||||||
|
build( |
||||||
|
:sales_log, |
||||||
|
:completed, |
||||||
|
address_line1: "19, Charlton Gardens", |
||||||
|
town_or_city: "Bristol", |
||||||
|
postcode_full: "BS10 6LU", |
||||||
|
la: "E06000023", |
||||||
|
uprn_known: 1, |
||||||
|
uprn: 107, |
||||||
|
uprn_confirmed: 1, |
||||||
|
) |
||||||
|
end |
||||||
|
|
||||||
|
context "when uprn known" do |
||||||
|
it "returns formatted value" do |
||||||
|
expect(question.get_extra_check_answer_value(log)).to eq( |
||||||
|
"\n\n19, Charlton Gardens\nBristol\nBS10 6LU\nBristol, City of", |
||||||
|
) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,148 @@ |
|||||||
|
require "rails_helper" |
||||||
|
|
||||||
|
RSpec.describe AddressSearchController, type: :request do |
||||||
|
let(:user) { create(:user) } |
||||||
|
|
||||||
|
before do |
||||||
|
sign_in user |
||||||
|
end |
||||||
|
|
||||||
|
describe "#manual input" do |
||||||
|
context "when no address data is given and user chooses to enter address manually" do |
||||||
|
let(:sales_log) { create(:sales_log, :shared_ownership_setup_complete, manual_address_entry_selected: false, assigned_to: user) } |
||||||
|
|
||||||
|
it "correctly sets address fields" do |
||||||
|
sales_log.reload |
||||||
|
expect(sales_log.manual_address_entry_selected).to eq(false) |
||||||
|
expect(sales_log.uprn_known).to eq(nil) |
||||||
|
expect(sales_log.uprn).to eq(nil) |
||||||
|
expect(sales_log.uprn_confirmed).to eq(nil) |
||||||
|
expect(sales_log.uprn_selection).to eq(nil) |
||||||
|
expect(sales_log.pcodenk).to eq(nil) |
||||||
|
expect(sales_log.postcode_full).to eq(nil) |
||||||
|
expect(sales_log.address_line1).to eq(nil) |
||||||
|
expect(sales_log.address_line2).to eq(nil) |
||||||
|
expect(sales_log.town_or_city).to eq(nil) |
||||||
|
expect(sales_log.la).to eq(nil) |
||||||
|
|
||||||
|
get "/address-search/manual-input/sales_log/#{sales_log.id}" |
||||||
|
|
||||||
|
sales_log.reload |
||||||
|
expect(sales_log.manual_address_entry_selected).to eq(true) |
||||||
|
expect(sales_log.uprn_known).to eq(0) |
||||||
|
expect(sales_log.uprn).to eq(nil) |
||||||
|
expect(sales_log.uprn_confirmed).to eq(nil) |
||||||
|
expect(sales_log.uprn_selection).to eq(nil) |
||||||
|
expect(sales_log.pcodenk).to eq(nil) |
||||||
|
expect(sales_log.postcode_full).to eq(nil) |
||||||
|
expect(sales_log.address_line1).to eq(nil) |
||||||
|
expect(sales_log.address_line2).to eq(nil) |
||||||
|
expect(sales_log.town_or_city).to eq(nil) |
||||||
|
expect(sales_log.la).to eq(nil) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
context "when choosing to manually input an address for a log that has an address searched value" do |
||||||
|
let(:lettings_log) { create(:lettings_log, :completed, manual_address_entry_selected: false, assigned_to: user) } |
||||||
|
|
||||||
|
it "correctly sets address fields" do |
||||||
|
lettings_log.reload |
||||||
|
expect(lettings_log.uprn_known).to eq(1) |
||||||
|
expect(lettings_log.uprn).to eq("10033558653") |
||||||
|
expect(lettings_log.uprn_confirmed).to eq(1) |
||||||
|
expect(lettings_log.uprn_selection).to eq("10033558653") |
||||||
|
expect(lettings_log.postcode_known).to eq(1) |
||||||
|
expect(lettings_log.postcode_full).to eq("SW1A 1AA") |
||||||
|
expect(lettings_log.address_line1).to eq("The Mall, City Of Westminster") |
||||||
|
expect(lettings_log.address_line2).to eq(nil) |
||||||
|
expect(lettings_log.town_or_city).to eq("London") |
||||||
|
expect(lettings_log.la).to eq("E09000033") |
||||||
|
|
||||||
|
get "/address-search/manual-input/lettings_log/#{lettings_log.id}" |
||||||
|
|
||||||
|
lettings_log.reload |
||||||
|
expect(lettings_log.manual_address_entry_selected).to eq(true) |
||||||
|
expect(lettings_log.uprn_known).to eq(0) |
||||||
|
expect(lettings_log.uprn).to eq(nil) |
||||||
|
expect(lettings_log.uprn_confirmed).to eq(nil) |
||||||
|
expect(lettings_log.uprn_selection).to eq(nil) |
||||||
|
expect(lettings_log.postcode_known).to eq(nil) |
||||||
|
expect(lettings_log.postcode_full).to eq(nil) |
||||||
|
expect(lettings_log.address_line1).to eq(nil) |
||||||
|
expect(lettings_log.address_line2).to eq(nil) |
||||||
|
expect(lettings_log.town_or_city).to eq(nil) |
||||||
|
expect(lettings_log.la).to eq(nil) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
describe "#search input" do |
||||||
|
context "when no address is entered manually and choosing to search instead" do |
||||||
|
let(:lettings_log) { create(:lettings_log, :setup_completed, manual_address_entry_selected: true, assigned_to: user) } |
||||||
|
|
||||||
|
it "correctly sets address fields" do |
||||||
|
lettings_log.reload |
||||||
|
expect(lettings_log.manual_address_entry_selected).to eq(true) |
||||||
|
expect(lettings_log.uprn_known).to eq(0) |
||||||
|
expect(lettings_log.uprn).to eq(nil) |
||||||
|
expect(lettings_log.uprn_confirmed).to eq(nil) |
||||||
|
expect(lettings_log.uprn_selection).to eq(nil) |
||||||
|
expect(lettings_log.postcode_known).to eq(nil) |
||||||
|
expect(lettings_log.postcode_full).to eq(nil) |
||||||
|
expect(lettings_log.address_line1).to eq(nil) |
||||||
|
expect(lettings_log.address_line2).to eq(nil) |
||||||
|
expect(lettings_log.town_or_city).to eq(nil) |
||||||
|
expect(lettings_log.la).to eq(nil) |
||||||
|
|
||||||
|
get "/address-search/search-input/lettings_log/#{lettings_log.id}" |
||||||
|
|
||||||
|
lettings_log.reload |
||||||
|
expect(lettings_log.manual_address_entry_selected).to eq(false) |
||||||
|
expect(lettings_log.uprn_known).to eq(nil) |
||||||
|
expect(lettings_log.uprn).to eq(nil) |
||||||
|
expect(lettings_log.uprn_confirmed).to eq(nil) |
||||||
|
expect(lettings_log.uprn_selection).to eq(nil) |
||||||
|
expect(lettings_log.postcode_known).to eq(nil) |
||||||
|
expect(lettings_log.postcode_full).to eq(nil) |
||||||
|
expect(lettings_log.address_line1).to eq(nil) |
||||||
|
expect(lettings_log.address_line2).to eq(nil) |
||||||
|
expect(lettings_log.town_or_city).to eq(nil) |
||||||
|
expect(lettings_log.la).to eq(nil) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
context "when choosing to search for an address for a log that has an address searched value" do |
||||||
|
let(:sales_log) { create(:sales_log, :completed, manual_address_entry_selected: true, town_or_city: "Test Town", assigned_to: user) } |
||||||
|
|
||||||
|
it "correctly sets address fields" do |
||||||
|
sales_log.reload |
||||||
|
expect(sales_log.manual_address_entry_selected).to eq(true) |
||||||
|
expect(sales_log.uprn_known).to eq(0) |
||||||
|
expect(sales_log.uprn).to eq(nil) |
||||||
|
expect(sales_log.uprn_confirmed).to eq(nil) |
||||||
|
expect(sales_log.uprn_selection).to eq(nil) |
||||||
|
expect(sales_log.pcodenk).to eq(0) |
||||||
|
expect(sales_log.postcode_full).to eq("SW1A 1AA") |
||||||
|
expect(sales_log.address_line1).to eq("Address line 1") |
||||||
|
expect(sales_log.address_line2).to eq(nil) |
||||||
|
expect(sales_log.town_or_city).to eq("Test Town") |
||||||
|
expect(sales_log.la).to eq("E09000033") |
||||||
|
|
||||||
|
get "/address-search/search-input/sales_log/#{sales_log.id}" |
||||||
|
|
||||||
|
sales_log.reload |
||||||
|
expect(sales_log.manual_address_entry_selected).to eq(false) |
||||||
|
expect(sales_log.uprn_known).to eq(nil) |
||||||
|
expect(sales_log.uprn).to eq(nil) |
||||||
|
expect(sales_log.uprn_confirmed).to eq(nil) |
||||||
|
expect(sales_log.uprn_selection).to eq(nil) |
||||||
|
expect(sales_log.pcodenk).to eq(nil) |
||||||
|
expect(sales_log.postcode_full).to eq(nil) |
||||||
|
expect(sales_log.address_line1).to eq(nil) |
||||||
|
expect(sales_log.address_line2).to eq(nil) |
||||||
|
expect(sales_log.town_or_city).to eq(nil) |
||||||
|
expect(sales_log.la).to eq(nil) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
Loading…
Reference in new issue