From 68cb7939d8a45b0b90bba31bd62640952a4a922b Mon Sep 17 00:00:00 2001 From: Richard Lynch Date: Tue, 17 Dec 2024 15:19:17 +0000 Subject: [PATCH] Add stricter address validations Updates the address validations to be stricter. We now require at least a single letter in the street part of the address, only letters and punctuation in the town / city name (no numbers), and at least a letter or digit in the house name / number field. --- app/forms/address_form.rb | 28 ++++++++-- spec/forms/address_form_spec.rb | 92 +++++++++++++++++++++++++++------ 2 files changed, 100 insertions(+), 20 deletions(-) diff --git a/app/forms/address_form.rb b/app/forms/address_form.rb index d71183e67c..3fb7c54775 100644 --- a/app/forms/address_form.rb +++ b/app/forms/address_form.rb @@ -11,6 +11,10 @@ class AddressForm < Form ADDRESS_MAX_CHARS = 100 POSTCODE_MAX_CHARS = 11 + ADDRESS_LINE_1_VALIDATION = /\A(?=.*[a-zA-Z0-9])[\w\s,.'-]+\z/ + ADDRESS_LINE_2_VALIDATION = /\A(?=.*[a-zA-Z])[\w\s,.'-]+\z/ + ADDRESS_LINE_3_VALIDATION = /\A[a-zA-Z\s,.'-]+\z/ + validates :address_line_1, presence: {message: i18n_error_message(:address_line_1_blank)} validates :address_line_2, presence: {message: i18n_error_message(:address_line_2_blank)} validates :address_line_3, presence: {message: i18n_error_message(:address_line_3_blank)} @@ -23,9 +27,9 @@ class AddressForm < Form validates :address_line_4, length: {maximum: ADDRESS_MAX_CHARS, message: i18n_error_message(:address_line_max_chars)} validates :postcode, length: {maximum: POSTCODE_MAX_CHARS, message: i18n_error_message(:postcode_max_chars)} - validates :address_line_1, format: {with: ADDRESS_REGEX_FILTER, message: i18n_error_message(:address_format)} - validates :address_line_2, format: {with: ADDRESS_REGEX_FILTER, message: i18n_error_message(:address_format)} - validates :address_line_3, format: {with: ADDRESS_REGEX_FILTER, message: i18n_error_message(:address_format)} + validate :validate_address_line_1, if: -> { address_line_1.present? } + validate :validate_address_line_2, if: -> { address_line_2.present? } + validate :validate_address_line_3, if: -> { address_line_3.present? } validates :address_line_4, format: {with: ADDRESS_REGEX_FILTER, message: i18n_error_message(:address_format)} validate :postcode_is_valid, if: -> { postcode.present? } @@ -51,4 +55,22 @@ def postcode_is_valid errors.add(:postcode, i18n_errors_path(:postcode_format)) end end + + def validate_address_line_1 + unless ADDRESS_REGEX_FILTER.match(address_line_1) && ADDRESS_LINE_1_VALIDATION.match(address_line_1) + errors.add(:address_line_1, i18n_errors_path(:address_format)) + end + end + + def validate_address_line_2 + unless ADDRESS_REGEX_FILTER.match(address_line_2) && ADDRESS_LINE_2_VALIDATION.match(address_line_2) + errors.add(:address_line_2, i18n_errors_path(:address_format)) + end + end + + def validate_address_line_3 + unless ADDRESS_REGEX_FILTER.match(address_line_3) && ADDRESS_LINE_3_VALIDATION.match(address_line_3) + errors.add(:address_line_3, i18n_errors_path(:address_format)) + end + end end diff --git a/spec/forms/address_form_spec.rb b/spec/forms/address_form_spec.rb index 15a5849773..bc119f4c8a 100644 --- a/spec/forms/address_form_spec.rb +++ b/spec/forms/address_form_spec.rb @@ -53,7 +53,7 @@ end context "address lines too long" do - let(:over_one_hundred_chars) { Array.new(101) { [("a".."z"), ("A".."Z"), ("0".."9")].map(&:to_a).flatten.sample }.join } + let(:over_one_hundred_chars) { Array.new(101) { [("a".."z"), ("A".."Z")].map(&:to_a).flatten.sample }.join } let(:claim_params) do { address_line_1: over_one_hundred_chars, @@ -77,25 +77,83 @@ end context "address lines with format errors" do - let(:claim_params) do - { - address_line_1: "#123", - address_line_2: "Main $treet", - address_line_3: "$ome City", - address_line_4: "$som County", - postcode: "XXX XXXX" - } + context "with unpermitted characters" do + let(:claim_params) do + { + address_line_1: "#123", + address_line_2: "Main $treet", + address_line_3: "$ome City", + address_line_4: "$som County", + postcode: "XXX XXXX" + } + end + + it "is invalid with format errors" do + is_expected.not_to be_valid + + expect(form.errors.size).to eq 5 + expect(form.errors[:address_line_1]).to eq([form.i18n_errors_path(:address_format)]) + expect(form.errors[:address_line_2]).to eq([form.i18n_errors_path(:address_format)]) + expect(form.errors[:address_line_3]).to eq([form.i18n_errors_path(:address_format)]) + expect(form.errors[:address_line_4]).to eq([form.i18n_errors_path(:address_format)]) + expect(form.errors[:postcode]).to eq([form.i18n_errors_path(:postcode_format)]) + end end - it "is invalid with too format errors" do - is_expected.not_to be_valid + context "with invalid looking address" do + context "with an invalid line 1" do + let(:claim_params) do + { + address_line_1: ".", + address_line_2: "10 Downing Street", + address_line_3: "London", + postcode: "SW1A 2AA" + } + end + + it "is invalid with format errors" do + is_expected.not_to be_valid + + expect(form.errors.size).to eq 1 + expect(form.errors[:address_line_1]).to eq([form.i18n_errors_path(:address_format)]) + end + end - expect(form.errors.size).to eq 5 - expect(form.errors[:address_line_1]).to eq([form.i18n_errors_path(:address_format)]) - expect(form.errors[:address_line_2]).to eq([form.i18n_errors_path(:address_format)]) - expect(form.errors[:address_line_3]).to eq([form.i18n_errors_path(:address_format)]) - expect(form.errors[:address_line_4]).to eq([form.i18n_errors_path(:address_format)]) - expect(form.errors[:postcode]).to eq([form.i18n_errors_path(:postcode_format)]) + context "with an invalid line 2" do + let(:claim_params) do + { + address_line_1: "Flat 1", + address_line_2: ".", + address_line_3: "London", + postcode: "SW1A 2AA" + } + end + + it "is invalid with format errors" do + is_expected.not_to be_valid + + expect(form.errors.size).to eq 1 + expect(form.errors[:address_line_2]).to eq([form.i18n_errors_path(:address_format)]) + end + end + + context "with an invalid line 3" do + let(:claim_params) do + { + address_line_1: "Flat 1", + address_line_2: "10 Downing Street", + address_line_3: "123", + postcode: "SW1A 2AA" + } + end + + it "is invalid with format errors" do + is_expected.not_to be_valid + + expect(form.errors.size).to eq 1 + expect(form.errors[:address_line_3]).to eq([form.i18n_errors_path(:address_format)]) + end + end end end end