Browse Source

Merge branch 'main' into api_update

pull/48/head
baarkerlounger 4 years ago
parent
commit
35b1a63044
  1. 12
      app/controllers/case_logs_controller.rb
  2. 28
      app/helpers/check_answers_helper.rb
  3. 7
      app/models/form.rb
  4. 28
      app/models/form_handler.rb
  5. 6
      app/views/form/check_answers.html.erb
  6. 3
      config/routes.rb
  7. 27
      doc/adr/adr-007-data-validations.md
  8. 19
      spec/features/case_log_spec.rb
  9. 463
      spec/fixtures/forms/test_form.json
  10. 28
      spec/helpers/check_answers_helper_spec.rb
  11. 3
      spec/helpers/conditional_questions_helper_spec.rb
  12. 3
      spec/helpers/question_attribute_helper_spec.rb
  13. 9
      spec/helpers/tasklist_helper_spec.rb
  14. 27
      spec/models/form_handler_spec.rb
  15. 3
      spec/models/form_spec.rb

12
app/controllers/case_logs_controller.rb

@ -1,6 +1,9 @@
class CaseLogsController < ApplicationController
skip_before_action :verify_authenticity_token, if: :json_api_request?
before_action :authenticate, if: :json_api_request?
# rubocop:disable Style/ClassVars
@@form_handler = FormHandler.instance
# rubocop:enable Style/ClassVars
def index
@submitted_case_logs = CaseLog.where(status: 1)
@ -39,13 +42,13 @@ class CaseLogsController < ApplicationController
end
def edit
@form = Form.new(2021, 2022)
@form = @@form_handler.get_form("2021_2022")
@case_log = CaseLog.find(params[:id])
render :edit
end
def submit_form
form = Form.new(2021, 2022)
form = @@form_handler.get_form("2021_2022")
@case_log = CaseLog.find(params[:id])
previous_page = params[:case_log][:previous_page]
questions_for_page = form.questions_for_page(previous_page)
@ -61,13 +64,14 @@ class CaseLogsController < ApplicationController
end
def check_answers
form = @@form_handler.get_form("2021_2022")
@case_log = CaseLog.find(params[:case_log_id])
current_url = request.env["PATH_INFO"]
subsection = current_url.split("/")[-2]
render "form/check_answers", locals: { subsection: subsection }
render "form/check_answers", locals: { subsection: subsection, form: form }
end
form = Form.new(2021, 2022)
form = @@form_handler.get_form("2021_2022")
form.all_pages.map do |page_key, page_info|
define_method(page_key) do |_errors = {}|
@case_log = CaseLog.find(params[:case_log_id])

28
app/helpers/check_answers_helper.rb

@ -1,16 +1,15 @@
module CheckAnswersHelper
def total_answered_questions(subsection, case_log)
total_questions(subsection, case_log).keys.count do |question_key|
def total_answered_questions(subsection, case_log, form)
total_questions(subsection, case_log, form).keys.count do |question_key|
case_log[question_key].present?
end
end
def total_number_of_questions(subsection, case_log)
total_questions(subsection, case_log).count
def total_number_of_questions(subsection, case_log, form)
total_questions(subsection, case_log, form).count
end
def total_questions(subsection, case_log)
form = Form.new(2021, 2022)
def total_questions(subsection, case_log, form)
questions = form.questions_for_subsection(subsection)
questions_not_applicable = []
questions.reject do |question_key, question|
@ -36,19 +35,14 @@ module CheckAnswersHelper
end
end
def subsection_pages(subsection)
form = Form.new(2021, 2022)
form.pages_for_subsection(subsection)
end
def create_update_answer_link(case_log_answer, case_log_id, page)
link_name = case_log_answer.blank? ? "Answer" : "Change"
link_to(link_name, "/case_logs/#{case_log_id}/#{page}", class: "govuk-link").html_safe
end
def create_next_missing_question_link(case_log_id, subsection, case_log)
def create_next_missing_question_link(case_log_id, subsection, case_log, form)
pages_to_fill_in = []
subsection_pages(subsection).each do |page_title, page_info|
form.pages_for_subsection(subsection).each do |page_title, page_info|
page_info["questions"].any? { |question| case_log[question].blank? }
pages_to_fill_in << page_title
end
@ -56,12 +50,12 @@ module CheckAnswersHelper
link_to("Answer the missing questions", url, class: "govuk-link").html_safe
end
def display_answered_questions_summary(subsection, case_log)
if total_answered_questions(subsection, case_log) == total_number_of_questions(subsection, case_log)
def display_answered_questions_summary(subsection, case_log, form)
if total_answered_questions(subsection, case_log, form) == total_number_of_questions(subsection, case_log, form)
'<p class="govuk-body govuk-!-margin-bottom-7">You answered all the questions</p>'.html_safe
else
"<p class=\"govuk-body govuk-!-margin-bottom-7\">You answered #{total_answered_questions(subsection, case_log)} of #{total_number_of_questions(subsection, case_log)} questions</p>
#{create_next_missing_question_link(case_log['id'], subsection, case_log)}".html_safe
"<p class=\"govuk-body govuk-!-margin-bottom-7\">You answered #{total_answered_questions(subsection, case_log, form)} of #{total_number_of_questions(subsection, case_log, form)} questions</p>
#{create_next_missing_question_link(case_log['id'], subsection, case_log, form)}".html_safe
end
end
end

7
app/models/form.rb

@ -1,11 +1,10 @@
class Form
attr_reader :form_definition
def initialize(start_year, end_year)
form_json = "config/forms/#{start_year}_#{end_year}.json"
raise "No form definition file exists for given year".freeze unless File.exist?(form_json)
def initialize(form_path)
raise "No form definition file exists for given year".freeze unless File.exist?(form_path)
@form_definition = JSON.parse(File.open(form_json).read)
@form_definition = JSON.parse(File.open(form_path).read)
end
# Returns a hash with sections as keys

28
app/models/form_handler.rb

@ -0,0 +1,28 @@
class FormHandler
include Singleton
attr_reader :forms
def initialize
@forms = get_all_forms
end
def get_form(form)
return @forms["test_form"] ||= Form.new("test_form") if ENV["RAILS_ENV"] == "test"
@forms[form] ||= Form.new(form)
end
private
def get_all_forms
forms = {}
directories = ["config/forms", "spec/fixtures/forms"]
directories.each do |directory|
Dir.glob("#{directory}/*.json").each do |form_path|
form_name = form_path.sub(".json", "").split("/")[-1]
forms[form_name] = Form.new(form_path)
end
end
forms
end
end

6
app/views/form/check_answers.html.erb

@ -2,10 +2,10 @@
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<h1 class="govuk-heading-l">Check the answers you gave for <%= subsection.humanize(capitalize: false) %></h1>
<%= display_answered_questions_summary(subsection, @case_log) %>
<% subsection_pages(subsection).each do |page, page_info| %>
<%= display_answered_questions_summary(subsection, @case_log, form) %>
<% form.pages_for_subsection(subsection).each do |page, page_info| %>
<% page_info["questions"].each do |question_title, question_info| %>
<% if total_questions(subsection, @case_log).include?(question_title) %>
<% if total_questions(subsection, case_log, form).include?(question_title) %>
<%= render partial: 'form/check_answers_table', locals: { question_title: question_title, question_info: question_info, case_log: @case_log, page: page } %>
<%end %>
<%end %>

3
config/routes.rb

@ -5,7 +5,8 @@ Rails.application.routes.draw do
post "/case_logs/:id", to: "case_logs#submit_form"
form = Form.new(2021, 2022)
form_handler = FormHandler.instance
form = form_handler.get_form("2021_2022")
resources :case_logs do
form.all_pages.keys.map do |page|
get page.to_s, to: "case_logs##{page}"

27
doc/adr/adr-007-data-validations.md

@ -0,0 +1,27 @@
### ADR - 007: Data Validations
Data validations that happen in CORE at the point of data collection fall into two categories:
- Presence checks (i.e. does a response exist for this question)
- Validity check (i.e. is the response allowed and correct)
These are handled slightly differently:
##### Validity checks
These run for all submitted data. Every time a form page (in the UI is submitted), the fields related to that form page will be checked to ensure that any responses given are valid. If they are not, an error message will be shown on screen, and it will not be possible to "Save and continue" until the response is fixed or removed.
Similarly if an API request is made to create a case log with data that contains _invalid_ fields, that data will be rejected, and an error message will be returned.
##### Presence checks
These are not strictly error checks since it's possible to submit partial data. In the form UI it is possible to click "Save and continue" and move past questions that you might not know right now, and leave them to come back to later. We shouldn't prevent this workflow.
Similar the API client (3rd party software system) may not have all the required data and may only be submitting a partial log. This is still a valid use case so we should not be enforcing presence checks and returning errors based on them for either submission type.
Instead we determine the _status_ of the case log based the presence checks. Every time data is submitted (via a form page, bulk upload or API), before saving the data, the system will check whether all fields have been completed *and* pass validity checks. If so, the case log will be marked as *completed*, if not it will be marked as *in progress*.
By default all fields that a Case Log has will be assumed to be required unless explicitly marked as not required (for example as a result of other answers rendering a question inapplicable).
On the form UI this will work by by not allowing you to "submit" the form, until all presence checks have been satisfied, but all other navigation is allowed. On the API this will work by returning a Case Log that is "in progress" if you've submitted a partial log, or "completed" if you've submitted a full log, or "Errors" if you've submitted an invalid log.

19
spec/features/case_log_spec.rb

@ -9,9 +9,6 @@ RSpec.describe "Test Features" do
tenant_code: { type: "text", answer: "BZ737" },
tenant_age: { type: "numeric", answer: 25 },
tenant_gender: { type: "radio", answer: "Female" },
tenant_ethnic_group: { type: "radio", answer: "Prefer not to say" },
tenant_nationality: { type: "radio", answer: "Lithuania" },
tenant_economic_status: { type: "radio", answer: "Jobseeker" },
household_number_of_other_members: { type: "numeric", answer: 2 },
}
@ -52,7 +49,7 @@ RSpec.describe "Test Features" do
it "displays a section status" do
visit("/case_logs/#{empty_case_log.id}")
assert_selector ".govuk-tag", text: /Not started/, count: 8
assert_selector ".govuk-tag", text: /Not started/, count: 7
assert_selector ".govuk-tag", text: /Completed/, count: 0
assert_selector ".govuk-tag", text: /Cannot start yet/, count: 1
end
@ -61,7 +58,7 @@ RSpec.describe "Test Features" do
answer_all_questions_in_income_subsection
visit("/case_logs/#{empty_case_log.id}")
assert_selector ".govuk-tag", text: /Not started/, count: 7
assert_selector ".govuk-tag", text: /Not started/, count: 6
assert_selector ".govuk-tag", text: /Completed/, count: 1
assert_selector ".govuk-tag", text: /Cannot start yet/, count: 1
end
@ -73,13 +70,13 @@ RSpec.describe "Test Features" do
it "shows the number of completed sections if no sections are completed" do
visit("/case_logs/#{empty_case_log.id}")
expect(page).to have_content("You've completed 0 of 9 sections.")
expect(page).to have_content("You've completed 0 of 8 sections.")
end
it "shows the number of completed sections if one section is completed" do
answer_all_questions_in_income_subsection
visit("/case_logs/#{empty_case_log.id}")
expect(page).to have_content("You've completed 1 of 9 sections.")
expect(page).to have_content("You've completed 1 of 8 sections.")
end
end
@ -206,7 +203,7 @@ RSpec.describe "Test Features" do
it "has question headings based on the subsection" do
visit("case_logs/#{id}/#{subsection}/check_answers")
question_labels = ["Tenant code", "Tenant's age", "Tenant's gender", "Ethnicity", "Nationality", "Work", "Number of Other Household Members"]
question_labels = ["Tenant code", "Tenant's age", "Tenant's gender", "Number of Other Household Members"]
question_labels.each do |label|
expect(page).to have_content(label)
end
@ -223,7 +220,7 @@ RSpec.describe "Test Features" do
it "should have an answer link for questions missing an answer" do
visit("case_logs/#{empty_case_log.id}/#{subsection}/check_answers")
assert_selector "a", text: /Answer\z/, count: 7
assert_selector "a", text: /Answer\z/, count: 4
assert_selector "a", text: "Change", count: 0
expect(page).to have_link("Answer", href: "/case_logs/#{empty_case_log.id}/tenant_age")
end
@ -231,14 +228,14 @@ RSpec.describe "Test Features" do
it "should have a change link for answered questions" do
fill_in_number_question(empty_case_log.id, "tenant_age", 28)
visit("/case_logs/#{empty_case_log.id}/#{subsection}/check_answers")
assert_selector "a", text: /Answer\z/, count: 6
assert_selector "a", text: /Answer\z/, count: 3
assert_selector "a", text: "Change", count: 1
expect(page).to have_link("Change", href: "/case_logs/#{empty_case_log.id}/tenant_age")
end
it "should have a link pointing to the first question if no questions are answered" do
visit("/case_logs/#{empty_case_log.id}/#{subsection}/check_answers")
expect(page).to have_content("You answered 0 of 7 questions")
expect(page).to have_content("You answered 0 of 4 questions")
expect(page).to have_link("Answer the missing questions", href: "/case_logs/#{empty_case_log.id}/tenant_code")
end

463
spec/fixtures/forms/test_form.json vendored

@ -0,0 +1,463 @@
{
"form_type": "lettings",
"sections": {
"household": {
"label": "About the household",
"subsections": {
"household_characteristics": {
"label": "Household characteristics",
"pages": {
"tenant_code": {
"questions": {
"tenant_code": {
"check_answer_label": "Tenant code",
"header": "What is the tenant code?",
"type": "text"
}
}
},
"tenant_age": {
"questions": {
"tenant_age": {
"check_answer_label": "Tenant's age",
"header": "What is the tenant's age?",
"type": "numeric",
"min": 0,
"max": 150,
"step": 1
}
}
},
"tenant_gender": {
"questions": {
"tenant_gender": {
"check_answer_label": "Tenant's gender",
"header": "Which of these best describes the tenant's gender identity?",
"type": "radio",
"answer_options": {
"0": "Female",
"1": "Male",
"2": "Non-binary",
"3": "Prefer not to say"
}
}
}
},
"household_number_of_other_members": {
"questions": {
"household_number_of_other_members": {
"check_answer_label": "Number of Other Household Members",
"header": "How many other people are there in the household?",
"hint_text": "The maximum number of others is 1",
"type": "numeric",
"min": 0,
"max": 1,
"step": 1,
"conditional_for": {
"person_2_relationship": ">0",
"person_2_age": ">0",
"person_2_gender": ">0",
"person_2_economic_status": ">0"
}
},
"person_2_relationship": {
"check_answer_label": "Person 2's relationship to lead tenant",
"header": "What's person 2's relationship to lead tenant",
"type": "radio",
"answer_options": {
"0": "Other",
"1": "Prefer not to say"
}
},
"person_2_age": {
"check_answer_label": "Person 2's age",
"header": "What's person 2's age",
"type": "numeric",
"min": 0,
"max": 150,
"step": 1
},
"person_2_gender": {
"check_answer_label": "Person 2's gender",
"header": "Which of these best describes person 2's gender identity?",
"type": "radio",
"answer_options": {
"0": "Female",
"1": "Male",
"2": "Non-binary",
"3": "Prefer not to say"
}
},
"person_2_economic_status": {
"check_answer_label": "Person 2's Work",
"header": "Which of these best describes person 2's working situation?",
"type": "radio",
"answer_options": {
"0": "Other",
"1": "Prefer not to say"
}
}
}
}
}
},
"household_needs": {
"label": "Household needs",
"pages": {
"armed_forces": {
"header": "Experience of the UK Armed Forces",
"questions": {
"armed_forces": {
"header": "Has the tenant ever served in the UK armed forces?",
"type": "radio",
"check_answer_label": "Armed Forces",
"answer_options": {
"0": "Yes - a regular",
"1": "Yes - a reserve",
"2": "No",
"3": "Prefer not to say"
},
"conditional_for": {
"armed_forces_active": [
"Yes - a regular",
"Yes - a reserve"
],
"armed_forces_injured": [
"Yes - a regular",
"Yes - a reserve"
]
}
},
"armed_forces_active": {
"header": "Are they still serving?",
"type": "radio",
"check_answer_label": "When did they leave the Armed Forces?",
"answer_options": {
"0": "Yes",
"1": "No - they left up to 5 years ago",
"2": "No - they left more than 5 years ago",
"3": "Prefer not to say"
}
},
"armed_forces_injured": {
"header": "Were they seriously injured or ill as a result of their service?",
"type": "radio",
"check_answer_label": "Has anyone in the household been seriously injured or ill as a result of their service in the armed forces?",
"answer_options": {
"0": "Yes",
"1": "No",
"2": "Prefer not to say"
}
}
}
},
"medical_conditions": {
"questions": {
"medical_conditions": {
"header": "Does anyone in the household have any of the following that they expect to last for 12 months or more:<ul><li>Physical Condition</li><li>Mental Health Condition</li><li>Other Illness</li></ul>",
"type": "radio",
"check_answer_label": "Physical, mental health or illness in the household",
"answer_options": {
"0": "Yes",
"1": "No",
"2": "Do not know",
"3": "Prefer not to say"
}
}
}
},
"accessibility_requirements": {
"questions": {
"accessibility_requirements": {
"header": "Are any of these affected by their condition or illness?",
"hint_text": "Select all that apply",
"type": "checkbox",
"check_answer_label": "Disability requirements",
"answer_options": {
"accessibility_requirements_fully_wheelchair_accessible_housing": "Fully wheelchair accessible housing",
"accessibility_requirements_wheelchair_access_to_essential_rooms": "Wheelchair access to essential rooms",
"accessibility_requirements_level_access_housing": "Level access housing",
"divider_a": true,
"accessibility_requirements_do_not_know": "Do not know"
}
}
}
},
"condition_effects": {
"questions": {
"condition_effects": {
"header": "Are any of these affected by their condition or illness?",
"hint_text": "Select all that apply",
"type": "checkbox",
"check_answer_label": "Conditions or illnesses",
"answer_options": {
"condition_effects_vision": "Vision - such as blindness or partial sight",
"condition_effects_hearing": "Hearing - such as deafness or partial hearing"
}
}
}
}
}
}
}
},
"tenancy_and_property": {
"label": "Tenancy and property information",
"subsections": {
"tenancy_information": {
"label": "Tenancy information",
"pages": {
"tenancy_code": {
"questions": {
"tenancy_code": {
"check_answer_label": "What is the tenancy code?",
"header": "What is the tenancy code?",
"type": "text"
}
}
}
}
},
"property_information": {
"label": "Property information",
"pages": {
"property_wheelchair_accessible": {
"questions": {
"property_wheelchair_accessible": {
"check_answer_label": "Is property built or adapted to wheelchair user standards?",
"header": "Is property built or adapted to wheelchair user standards?",
"type": "radio",
"answer_options": {
"0": "Yes",
"1": "No"
}
}
}
}
}
}
}
},
"rent_and_charges": {
"label": "Rent and charges",
"subsections": {
"income_and_benefits": {
"label": "Income and benefits",
"pages": {
"net_income": {
"questions": {
"net_income": {
"check_answer_label": "Income",
"header": "What is the tenant’s /and partner’s combined income after tax?",
"type": "numeric",
"min": 0,
"step": "1"
},
"net_income_frequency": {
"check_answer_label": "Income Frequency",
"header": "How often do they receive this income?",
"type": "radio",
"answer_options": {
"0": "Weekly",
"1": "Monthly",
"2": "Yearly"
}
}
}
},
"net_income_uc_proportion": {
"questions": {
"net_income_uc_proportion": {
"check_answer_label": "Benefits as a proportion of income",
"header": "How much of the tenant’s income is from Universal Credit, state pensions or benefits?",
"type": "radio",
"answer_options": {
"0": "All",
"1": "Some"
}
}
}
},
"housing_benefit": {
"questions": {
"housing_benefit": {
"check_answer_label": "Universal Credit & Housing Benefit",
"header": "Is the tenant likely to be in receipt of any of these housing-related benefits?",
"type": "radio",
"answer_options": {
"0": "Housing Benefit, but not Universal Credit",
"1": "Prefer not to say"
}
}
}
}
}
},
"rent": {
"label": "Rent",
"pages": {
"rent": {
"questions": {
"rent_frequency": {
"check_answer_label": "Rent Period",
"header": "Which period are rent and other charges due?",
"type": "radio",
"answer_options": {
"0": "Weekly for 52 weeks",
"1": "Fortnightly"
}
},
"basic_rent": {
"check_answer_label": "Basic Rent",
"header": "What is the basic rent?",
"hint_text": "Eligible for housing benefit or Universal Credit",
"type": "numeric",
"min": 0,
"step": 1,
"fields-to-add": [
"basic_rent",
"service_charge",
"personal_service_charge",
"support_charge"
],
"result-field": "total_charge"
},
"service_charge": {
"check_answer_label": "Service Charge",
"header": "What is the service charge?",
"hint_text": "Eligible for housing benefit or Universal Credit",
"type": "numeric",
"min": 0,
"step": 1,
"fields-to-add": [
"basic_rent",
"service_charge",
"personal_service_charge",
"support_charge"
],
"result-field": "total_charge"
},
"personal_service_charge": {
"check_answer_label": "Personal Service Charge",
"header": "What is the personal service charge?",
"hint_text": "Not eligible for housing benefit or Universal Credit. For example, hot water excluding water rates.",
"type": "numeric",
"min": 0,
"step": 1,
"fields-to-add": [
"basic_rent",
"service_charge",
"personal_service_charge",
"support_charge"
],
"result-field": "total_charge"
},
"support_charge": {
"check_answer_label": "Support Charge",
"header": "What is the support charge?",
"hint_text": "This is to fund housing-related support services included in the tenancy agreement",
"type": "numeric",
"min": 0,
"step": 1,
"fields-to-add": [
"basic_rent",
"service_charge",
"personal_service_charge",
"support_charge"
],
"result-field": "total_charge"
},
"total_charge": {
"check_answer_label": "Total Charge",
"header": "Total charge?",
"hint_text": "This is the total of rent and all charges",
"type": "numeric",
"min": 0,
"step": 1,
"readonly": true
}
}
}
}
}
}
},
"local_authority": {
"label": "Local authority",
"subsections": {
"local_authority": {
"label": "Local authority",
"pages": {
"time_lived_in_la": {
"questions": {
"time_lived_in_la": {
"check_answer_label": "How long has the household continuously lived in the local authority area where the new letting is located?",
"header": "How long has the household continuously lived in the local authority area where the new letting is located?",
"type": "radio",
"answer_options": {
"0": "Just moved to local authority area",
"1": "Less than 1 year",
"2": "1 to 2 years",
"3": "2 to 3 years",
"4": "3 to 4 years",
"5": "4 to 5 years",
"6": "5 years or more",
"7": "Do not know"
}
}
}
},
"time_on_la_waiting_list": {
"questions": {
"time_on_la_waiting_list": {
"check_answer_label": "How long has the household been on the local authority waiting list where the new letting is located?",
"header": "How long has the household been on the local authority waiting list where the new letting is located?",
"type": "radio",
"answer_options": {
"0": "Just moved to local authority area",
"1": "Less than 1 year",
"2": "1 to 2 years",
"3": "2 to 3 years",
"4": "3 to 4 years",
"5": "4 to 5 years",
"6": "5 years or more",
"7": "Do not know"
}
}
}
},
"previous_postcode": {
"questions": {
"previous_postcode": {
"check_answer_label": "Postcode of previous accomodation if the household has moved from settled accommodation",
"header": "Postcode for the previous accommodation",
"hint_text": "If the household has moved from settled accommodation immediately prior to being re-housed",
"type": "text"
}
}
}
}
}
}
},
"submission": {
"label": "Submission",
"subsections": {
"declaration": {
"label": "Declaration",
"pages": {
"declaration": {
"questions": {
"declaration": {
"check_answer_label": "",
"header": "What is the tenant code?",
"type": "text"
}
}
}
}
}
}
}
}
}

28
spec/helpers/check_answers_helper_spec.rb

@ -6,7 +6,7 @@ RSpec.describe CheckAnswersHelper do
FactoryBot.create(
:case_log,
:in_progress,
household_number_of_other_members: 2,
household_number_of_other_members: 1,
person_2_relationship: "Partner",
)
end
@ -16,32 +16,35 @@ RSpec.describe CheckAnswersHelper do
let(:subsection) { "income_and_benefits" }
let(:subsection_with_numeric_conditionals) { "household_characteristics" }
let(:subsection_with_radio_conditionals) { "household_needs" }
form_handler = FormHandler.instance
let(:form) { form_handler.get_form("test_form") }
describe "Get answered questions total" do
it "returns 0 if no questions are answered" do
expect(total_answered_questions(subsection, case_log)).to equal(0)
expect(total_answered_questions(subsection, case_log, form)).to equal(0)
end
it "returns 1 if 1 question gets answered" do
case_log["net_income"] = "123"
expect(total_answered_questions(subsection, case_log)).to equal(1)
expect(total_answered_questions(subsection, case_log, form)).to equal(1)
end
it "ignores questions with unmet numeric conditions" do
case_log["tenant_code"] = "T1234"
expect(total_answered_questions(subsection_with_numeric_conditionals, case_log)).to equal(1)
expect(total_answered_questions(subsection_with_numeric_conditionals, case_log, form)).to equal(1)
end
it "includes conditional questions with met numeric conditions" do
expect(total_answered_questions(
subsection_with_numeric_conditionals,
case_log_with_met_numeric_condition,
form,
)).to equal(4)
end
it "ignores questions with unmet radio conditions" do
case_log["armed_forces"] = "No"
expect(total_answered_questions(subsection_with_radio_conditionals, case_log)).to equal(1)
expect(total_answered_questions(subsection_with_radio_conditionals, case_log, form)).to equal(1)
end
it "includes conditional questions with met radio conditions" do
@ -50,35 +53,38 @@ RSpec.describe CheckAnswersHelper do
expect(total_answered_questions(
subsection_with_radio_conditionals,
case_log_with_met_radio_condition,
form,
)).to equal(3)
end
end
describe "Get total number of questions" do
it "returns the total number of questions for a subsection" do
expect(total_number_of_questions(subsection, case_log)).to eq(4)
expect(total_number_of_questions(subsection, case_log, form)).to eq(4)
end
it "ignores questions with unmet numeric conditions" do
expect(total_number_of_questions(subsection_with_numeric_conditionals, case_log)).to eq(7)
expect(total_number_of_questions(subsection_with_numeric_conditionals, case_log, form)).to eq(4)
end
it "includes conditional questions with met numeric conditions" do
expect(total_number_of_questions(
subsection_with_numeric_conditionals,
case_log_with_met_numeric_condition,
)).to eq(15)
form,
)).to eq(8)
end
it "ignores questions with unmet radio conditions" do
expect(total_number_of_questions(subsection_with_radio_conditionals, case_log)).to eq(6)
expect(total_number_of_questions(subsection_with_radio_conditionals, case_log, form)).to eq(4)
end
it "includes conditional questions with met radio conditions" do
expect(total_number_of_questions(
subsection_with_radio_conditionals,
case_log_with_met_radio_condition,
)).to eq(8)
form,
)).to eq(6)
end
context "conditional questions with type that hasn't been implemented yet" do
@ -99,7 +105,7 @@ RSpec.describe CheckAnswersHelper do
it "raises an error" do
allow_any_instance_of(Form).to receive(:questions_for_subsection).and_return(unimplemented_conditional)
expect { total_number_of_questions(subsection, case_log) }.to raise_error(RuntimeError, "Not implemented yet")
expect { total_number_of_questions(subsection, case_log, form) }.to raise_error(RuntimeError, "Not implemented yet")
end
end
end

3
spec/helpers/conditional_questions_helper_spec.rb

@ -1,7 +1,8 @@
require "rails_helper"
RSpec.describe ConditionalQuestionsHelper do
let(:form) { Form.new(2021, 2022) }
form_handler = FormHandler.instance
let(:form) { form_handler.get_form("test_form") }
let(:page_key) { "armed_forces" }
let(:page) { form.all_pages[page_key] }

3
spec/helpers/question_attribute_helper_spec.rb

@ -1,7 +1,8 @@
require "rails_helper"
RSpec.describe QuestionAttributeHelper do
let(:form) { Form.new(2021, 2022) }
form_handler = FormHandler.instance
let(:form) { form_handler.get_form("test_form") }
let(:questions) { form.questions_for_page("rent") }
describe "html attributes" do

9
spec/helpers/tasklist_helper_spec.rb

@ -3,7 +3,8 @@ require "rails_helper"
RSpec.describe TasklistHelper do
let!(:empty_case_log) { FactoryBot.create(:case_log) }
let!(:case_log) { FactoryBot.create(:case_log, :in_progress) }
let(:form) { Form.new(2021, 2022) }
form_handler = FormHandler.instance
let(:form) { form_handler.get_form("test_form") }
describe "get subsection status" do
let(:section) { "income_and_benefits" }
@ -53,7 +54,7 @@ RSpec.describe TasklistHelper do
describe "get sections count" do
it "returns the total of sections if no status is given" do
expect(get_sections_count(form, empty_case_log)).to eq(9)
expect(get_sections_count(form, empty_case_log)).to eq(8)
end
it "returns 0 sections for completed sections if no sections are completed" do
@ -61,11 +62,11 @@ RSpec.describe TasklistHelper do
end
it "returns the number of not started sections" do
expect(get_sections_count(form, empty_case_log, :not_started)).to eq(8)
expect(get_sections_count(form, empty_case_log, :not_started)).to eq(7)
end
it "returns the number of sections in progress" do
expect(get_sections_count(form, case_log, :in_progress)).to eq(3)
expect(get_sections_count(form, case_log, :in_progress)).to eq(2)
end
it "returns 0 for invalid state" do

27
spec/models/form_handler_spec.rb

@ -0,0 +1,27 @@
require "rails_helper"
RSpec.describe FormHandler do
describe "Get all forms" do
it "should be able to load all the forms" do
form_handler = FormHandler.instance
all_forms = form_handler.forms
expect(all_forms.count).to be >= 1
expect(all_forms["test_form"]).to be_a(Form)
end
end
describe "Get specific form" do
it "should be able to load a specific form" do
form_handler = FormHandler.instance
form = form_handler.get_form("test_form")
expect(form).to be_a(Form)
expect(form.all_pages.count).to eq(18)
end
end
it "should only load the form once at boot time" do
form_handler = FormHandler.instance
expect(Form).not_to receive(:new).with("test_form")
expect(form_handler.get_form("test_form")).to be_a(Form)
end
end

3
spec/models/form_spec.rb

@ -1,7 +1,8 @@
require "rails_helper"
RSpec.describe Form, type: :model do
let(:form) { Form.new(2021, 2022) }
form_handler = FormHandler.instance
let(:form) { form_handler.get_form("test_form") }
describe ".next_page" do
let(:previous_page) { "tenant_age" }

Loading…
Cancel
Save