diff --git a/app/models/validations/shared_validations.rb b/app/models/validations/shared_validations.rb index 79fc95158..f3b0a9c34 100644 --- a/app/models/validations/shared_validations.rb +++ b/app/models/validations/shared_validations.rb @@ -16,6 +16,16 @@ module Validations::SharedValidations end end + def validate_numeric_input(record) + record.form.numeric_questions.each do |question| + next unless record[question.id] && question.page.routed_to?(record, nil) + next if record.send("#{question.id}_before_type_cast").to_s.match?(/\A\d+(\.\d+)?\z/) + + field = question.check_answer_label || question.id + record.errors.add question.id.to_sym, I18n.t("validations.numeric.format", field:) + end + end + def validate_numeric_min_max(record) record.form.numeric_questions.each do |question| next unless question.min || question.max diff --git a/app/views/form/_numeric_question.html.erb b/app/views/form/_numeric_question.html.erb index aafa68d93..aa147767b 100644 --- a/app/views/form/_numeric_question.html.erb +++ b/app/views/form/_numeric_question.html.erb @@ -1,6 +1,6 @@ <%= render partial: "form/guidance/#{question.top_guidance_partial}" if question.top_guidance? %> -<%= f.govuk_number_field( +<%= f.govuk_text_field( question.id.to_sym, caption: caption(caption_text, page_header, conditional), label: legend(question, page_header, conditional), @@ -13,6 +13,8 @@ prefix_text: question.prefix.to_s, suffix_text: question.suffix_label(@log), value: format_money_input(log: @log, question:), + inputmode: "numeric", + pattern: "\d*\.?\d*", **stimulus_html_attributes(question), ) %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 51ddfdc36..35e2fcd96 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -231,6 +231,7 @@ en: nearest_ten: "%{field} must be given to the nearest ten" nearest_hundredth: "%{field} must be given to the nearest hundredth" normal_format: "Enter a number" + format: "%{field} must be a number" date: invalid_date: "Enter a date in the correct format, for example 31 1 2022" diff --git a/spec/models/validations/shared_validations_spec.rb b/spec/models/validations/shared_validations_spec.rb index 97cb621cb..fb389d175 100644 --- a/spec/models/validations/shared_validations_spec.rb +++ b/spec/models/validations/shared_validations_spec.rb @@ -215,4 +215,36 @@ RSpec.describe Validations::SharedValidations do end end end + + describe "validate numeric question input" do + it "does not allow letters" do + sales_log.income1 = "abc" + shared_validator.validate_numeric_input(sales_log) + expect(sales_log.errors[:income1]).to include I18n.t("validations.numeric.format", field: "Buyer 1’s gross annual income") + end + + it "does not allow special characters" do + sales_log.income1 = "3%5" + shared_validator.validate_numeric_input(sales_log) + expect(sales_log.errors[:income1]).to include I18n.t("validations.numeric.format", field: "Buyer 1’s gross annual income") + end + + it "allows a digit" do + sales_log.income1 = "300" + shared_validator.validate_numeric_input(sales_log) + expect(sales_log.errors[:income1]).to be_empty + end + + it "allows a decimal point" do + sales_log.income1 = "300.78" + shared_validator.validate_numeric_input(sales_log) + expect(sales_log.errors[:income1]).to be_empty + end + + it "does not allow decimal point in a wrong format" do + sales_log.income1 = "300.09.78" + shared_validator.validate_numeric_input(sales_log) + expect(sales_log.errors[:income1]).to include I18n.t("validations.numeric.format", field: "Buyer 1’s gross annual income") + end + end end