Daniel Baark
3 years ago
committed by
GitHub
40 changed files with 752 additions and 580 deletions
@ -1,57 +1,20 @@ |
|||||||
module CheckAnswersHelper |
module CheckAnswersHelper |
||||||
def total_answered_questions(subsection, case_log, form) |
def display_answered_questions_summary(subsection, case_log) |
||||||
total_questions(subsection, case_log, form).keys.count do |question_key| |
total = subsection.applicable_questions_count(case_log) |
||||||
case_log[question_key].present? |
answered = subsection.answered_questions_count(case_log) |
||||||
end |
if total == answered |
||||||
end |
'<p class="govuk-body govuk-!-margin-bottom-7">You answered all the questions</p>'.html_safe |
||||||
|
else |
||||||
def total_number_of_questions(subsection, case_log, form) |
"<p class=\"govuk-body govuk-!-margin-bottom-7\">You answered #{answered} of #{total} questions</p> |
||||||
total_questions(subsection, case_log, form).count |
#{create_next_missing_question_link(subsection, case_log)}".html_safe |
||||||
end |
|
||||||
|
|
||||||
def total_questions(subsection, case_log, form) |
|
||||||
questions = form.questions_for_subsection(subsection) |
|
||||||
form.filter_conditional_questions(questions, case_log) |
|
||||||
end |
|
||||||
|
|
||||||
def get_next_page_name(form, page_name, case_log) |
|
||||||
page = form.all_pages[page_name] |
|
||||||
if page.key?("conditional_route_to") |
|
||||||
page["conditional_route_to"].each do |conditional_page_name, condition| |
|
||||||
unless condition.any? { |field, value| case_log[field].blank? || !value.include?(case_log[field]) } |
|
||||||
return conditional_page_name |
|
||||||
end |
|
||||||
end |
|
||||||
end |
end |
||||||
form.next_page(page_name) |
|
||||||
end |
end |
||||||
|
|
||||||
def create_update_answer_link(question_title, question_info, case_log, form) |
private |
||||||
page = form.page_for_question(question_title) |
|
||||||
link_name = if question_info["type"] == "checkbox" |
|
||||||
question_info["answer_options"].keys.any? { |key| case_log[key] == "Yes" } ? "Change" : "Answer" |
|
||||||
else |
|
||||||
case_log[question_title].blank? ? "Answer" : "Change" |
|
||||||
end |
|
||||||
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, form) |
def create_next_missing_question_link(subsection, case_log) |
||||||
pages_to_fill_in = [] |
pages_to_fill_in = subsection.unanswered_questions(case_log).map(&:page) |
||||||
form.pages_for_subsection(subsection).each do |page_title, page_info| |
url = "/case_logs/#{case_log.id}/#{pages_to_fill_in.first.id}" |
||||||
page_info["questions"].any? { |question| case_log[question].blank? } |
|
||||||
pages_to_fill_in << page_title |
|
||||||
end |
|
||||||
url = "/case_logs/#{case_log_id}/#{pages_to_fill_in.first}" |
|
||||||
link_to("Answer the missing questions", url, class: "govuk-link").html_safe |
link_to("Answer the missing questions", url, class: "govuk-link").html_safe |
||||||
end |
end |
||||||
|
|
||||||
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, 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 |
end |
||||||
|
@ -1,11 +1,9 @@ |
|||||||
module ConditionalQuestionsHelper |
module ConditionalQuestionsHelper |
||||||
def conditional_questions_for_page(page) |
def conditional_questions_for_page(page) |
||||||
page["questions"].values.map { |question| |
page.questions.map(&:conditional_for).compact.map(&:keys).flatten |
||||||
question["conditional_for"] |
|
||||||
}.compact.map(&:keys).flatten |
|
||||||
end |
end |
||||||
|
|
||||||
def display_question_key_div(page_info, question_key) |
def display_question_key_div(page, question) |
||||||
"style='display:none;'".html_safe if conditional_questions_for_page(page_info).include?(question_key) |
"style='display:none;'".html_safe if conditional_questions_for_page(page).include?(question.id) |
||||||
end |
end |
||||||
end |
end |
||||||
|
@ -0,0 +1,30 @@ |
|||||||
|
class Form::Page |
||||||
|
attr_accessor :id, :header, :description, :questions, :soft_validations, |
||||||
|
:depends_on, :subsection |
||||||
|
|
||||||
|
def initialize(id, hsh, subsection) |
||||||
|
@id = id |
||||||
|
@header = hsh["header"] |
||||||
|
@description = hsh["description"] |
||||||
|
@questions = hsh["questions"].map { |q_id, q| Form::Question.new(q_id, q, self) } |
||||||
|
@depends_on = hsh["depends_on"] |
||||||
|
@soft_validations = hsh["soft_validations"]&.map { |v_id, s| Form::Question.new(v_id, s, self) } |
||||||
|
@subsection = subsection |
||||||
|
end |
||||||
|
|
||||||
|
def expected_responses |
||||||
|
questions + (soft_validations || []) |
||||||
|
end |
||||||
|
|
||||||
|
def has_soft_validations? |
||||||
|
soft_validations.present? |
||||||
|
end |
||||||
|
|
||||||
|
def routed_to?(case_log) |
||||||
|
return true unless depends_on |
||||||
|
|
||||||
|
depends_on.all? do |question, value| |
||||||
|
case_log[question].present? && case_log[question] == value |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,80 @@ |
|||||||
|
class Form::Question |
||||||
|
attr_accessor :id, :header, :hint_text, :description, :questions, |
||||||
|
:type, :min, :max, :step, :fields_to_add, :result_field, |
||||||
|
:conditional_for, :readonly, :answer_options, :page, :check_answer_label |
||||||
|
|
||||||
|
def initialize(id, hsh, page) |
||||||
|
@id = id |
||||||
|
@check_answer_label = hsh["check_answer_label"] |
||||||
|
@header = hsh["header"] |
||||||
|
@hint_text = hsh["hint_text"] |
||||||
|
@type = hsh["type"] |
||||||
|
@min = hsh["min"] |
||||||
|
@max = hsh["max"] |
||||||
|
@step = hsh["step"] |
||||||
|
@fields_to_add = hsh["fields-to-add"] |
||||||
|
@result_field = hsh["result-field"] |
||||||
|
@readonly = hsh["readonly"] |
||||||
|
@answer_options = hsh["answer_options"] |
||||||
|
@conditional_for = hsh["conditional_for"] |
||||||
|
@page = page |
||||||
|
end |
||||||
|
|
||||||
|
delegate :subsection, to: :page |
||||||
|
delegate :form, to: :subsection |
||||||
|
|
||||||
|
def answer_label(case_log) |
||||||
|
return checkbox_answer_label(case_log) if type == "checkbox" |
||||||
|
|
||||||
|
case_log[id].to_s |
||||||
|
end |
||||||
|
|
||||||
|
def read_only? |
||||||
|
!!readonly |
||||||
|
end |
||||||
|
|
||||||
|
def conditional_on |
||||||
|
@conditional_on ||= form.conditional_question_conditions.select do |condition| |
||||||
|
condition[:to] == id |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def enabled?(case_log) |
||||||
|
return true if conditional_on.blank? |
||||||
|
|
||||||
|
conditional_on.map { |condition| evaluate_condition(condition, case_log) }.all? |
||||||
|
end |
||||||
|
|
||||||
|
def update_answer_link_name(case_log) |
||||||
|
if type == "checkbox" |
||||||
|
answer_options.keys.any? { |key| case_log[key] == "Yes" } ? "Change" : "Answer" |
||||||
|
else |
||||||
|
case_log[id].blank? ? "Answer" : "Change" |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
private |
||||||
|
|
||||||
|
def checkbox_answer_label(case_log) |
||||||
|
answer = [] |
||||||
|
answer_options.each { |key, value| case_log[key] == "Yes" ? answer << value : nil } |
||||||
|
answer.join(", ") |
||||||
|
end |
||||||
|
|
||||||
|
def evaluate_condition(condition, case_log) |
||||||
|
case page.questions.find { |q| q.id == condition[:from] }.type |
||||||
|
when "numeric" |
||||||
|
operator = condition[:cond][/[<>=]+/].to_sym |
||||||
|
operand = condition[:cond][/\d+/].to_i |
||||||
|
case_log[condition[:from]].present? && case_log[condition[:from]].send(operator, operand) |
||||||
|
when "text" |
||||||
|
case_log[condition[:from]].present? && condition[:cond].include?(case_log[condition[:from]]) |
||||||
|
when "radio" |
||||||
|
case_log[condition[:from]].present? && condition[:cond].include?(case_log[condition[:from]]) |
||||||
|
when "select" |
||||||
|
case_log[condition[:from]].present? && condition[:cond].include?(case_log[condition[:from]]) |
||||||
|
else |
||||||
|
raise "Not implemented yet" |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,10 @@ |
|||||||
|
class Form::Section |
||||||
|
attr_accessor :id, :label, :subsections, :form |
||||||
|
|
||||||
|
def initialize(id, hsh, form) |
||||||
|
@id = id |
||||||
|
@label = hsh["label"] |
||||||
|
@form = form |
||||||
|
@subsections = hsh["subsections"].map { |s_id, s| Form::Subsection.new(s_id, s, self) } |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,65 @@ |
|||||||
|
class Form::Subsection |
||||||
|
attr_accessor :id, :label, :section, :pages, :depends_on, :form |
||||||
|
|
||||||
|
def initialize(id, hsh, section) |
||||||
|
@id = id |
||||||
|
@label = hsh["label"] |
||||||
|
@depends_on = hsh["depends_on"] |
||||||
|
@pages = hsh["pages"].map { |s_id, p| Form::Page.new(s_id, p, self) } |
||||||
|
@section = section |
||||||
|
end |
||||||
|
|
||||||
|
delegate :form, to: :section |
||||||
|
|
||||||
|
def questions |
||||||
|
@questions ||= pages.flat_map(&:questions) |
||||||
|
end |
||||||
|
|
||||||
|
def enabled?(case_log) |
||||||
|
return true unless depends_on |
||||||
|
|
||||||
|
depends_on.all? do |subsection_id, dependent_status| |
||||||
|
form.get_subsection(subsection_id).status(case_log) == dependent_status.to_sym |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def status(case_log) |
||||||
|
unless enabled?(case_log) |
||||||
|
return :cannot_start_yet |
||||||
|
end |
||||||
|
|
||||||
|
qs = applicable_questions(case_log) |
||||||
|
return :not_started if qs.all? { |question| case_log[question.id].blank? } |
||||||
|
return :completed if qs.all? { |question| case_log[question.id].present? } |
||||||
|
|
||||||
|
:in_progress |
||||||
|
end |
||||||
|
|
||||||
|
def is_incomplete?(case_log) |
||||||
|
%i[not_started in_progress].include?(status(case_log)) |
||||||
|
end |
||||||
|
|
||||||
|
def is_started?(case_log) |
||||||
|
%i[in_progress completed].include?(status(case_log)) |
||||||
|
end |
||||||
|
|
||||||
|
def applicable_questions_count(case_log) |
||||||
|
applicable_questions(case_log).count |
||||||
|
end |
||||||
|
|
||||||
|
def answered_questions_count(case_log) |
||||||
|
answered_questions(case_log).count |
||||||
|
end |
||||||
|
|
||||||
|
def applicable_questions(case_log) |
||||||
|
questions.select { |q| q.page.routed_to?(case_log) && q.enabled?(case_log) } |
||||||
|
end |
||||||
|
|
||||||
|
def answered_questions(case_log) |
||||||
|
applicable_questions(case_log).select { |question| case_log[question.id].present? } |
||||||
|
end |
||||||
|
|
||||||
|
def unanswered_questions(case_log) |
||||||
|
applicable_questions(case_log) - answered_questions(case_log) |
||||||
|
end |
||||||
|
end |
@ -1,11 +1,11 @@ |
|||||||
<div class="govuk-summary-list__row"> |
<div class="govuk-summary-list__row"> |
||||||
<dt class="govuk-summary-list__key"> |
<dt class="govuk-summary-list__key"> |
||||||
<%= question_info["check_answer_label"].to_s.present? ? question_info["check_answer_label"].to_s : question_info["header"].to_s%> |
<%= question.check_answer_label.to_s.present? ? question.check_answer_label.to_s : question.header.to_s %> |
||||||
<dt> |
<dt> |
||||||
<dd class="govuk-summary-list__value"> |
<dd class="govuk-summary-list__value"> |
||||||
<%= form.get_answer_label(@case_log, question_title) %> |
<%= question.answer_label(@case_log) %> |
||||||
</dd> |
</dd> |
||||||
<dd class="govuk-summary-list__actions"> |
<dd class="govuk-summary-list__actions"> |
||||||
<%= create_update_answer_link(question_title, question_info, @case_log, form) %> |
<%= link_to(question.update_answer_link_name(@case_log), "/case_logs/#{@case_log.id}/#{question.page.id}", class: "govuk-link").html_safe %> |
||||||
</dd> |
</dd> |
||||||
</div> |
</div> |
||||||
|
@ -1,6 +1,6 @@ |
|||||||
<%= f.govuk_date_field question_key, |
<%= f.govuk_date_field question.id.to_sym, |
||||||
hint: { text: question["hint_text"] }, |
hint: { text: question.hint_text }, |
||||||
legend: { text: question["header"].html_safe, size: "l"}, |
legend: { text: question.header.html_safe, size: "l"}, |
||||||
width: 20, |
width: 20, |
||||||
**stimulus_html_attributes(question) |
**stimulus_html_attributes(question) |
||||||
%> |
%> |
||||||
|
@ -1,7 +1,7 @@ |
|||||||
<%= f.govuk_number_field question_key, |
<%= f.govuk_number_field question.id.to_sym, |
||||||
hint: { text: question["hint_text"] }, |
hint: { text: question.hint_text }, |
||||||
label: { text: question["header"].html_safe, size: "l"}, |
label: { text: question.header.html_safe, size: "l"}, |
||||||
min: question["min"], max: question["max"], step: question["step"], |
min: question.min, max: question.max, step: question.step, |
||||||
width: 20, :readonly => question["readonly"], |
width: 20, :readonly => question.read_only?, |
||||||
**stimulus_html_attributes(question) |
**stimulus_html_attributes(question) |
||||||
%> |
%> |
||||||
|
@ -1,13 +1,13 @@ |
|||||||
<%= f.govuk_radio_buttons_fieldset question_key, |
<%= f.govuk_radio_buttons_fieldset question.id.to_sym, |
||||||
legend: { text: question["header"].html_safe, size: "l" }, |
legend: { text: question.header.html_safe, size: "l" }, |
||||||
hint: { text: question["hint_text"] }, |
hint: { text: question.hint_text }, |
||||||
small: (question["answer_options"].size > 5) do %> |
small: (question.answer_options.size > 5) do %> |
||||||
|
|
||||||
<% question["answer_options"].map do |key, val| %> |
<% question.answer_options.map do |key, val| %> |
||||||
<% if key.starts_with?("divider") %> |
<% if key.starts_with?("divider") %> |
||||||
<%= f.govuk_radio_divider %> |
<%= f.govuk_radio_divider %> |
||||||
<% else %> |
<% else %> |
||||||
<%= f.govuk_radio_button question_key, val, label: { text: val }, **stimulus_html_attributes(question) %> |
<%= f.govuk_radio_button question.id, val, label: { text: val }, **stimulus_html_attributes(question) %> |
||||||
<% end %> |
<% end %> |
||||||
<% end %> |
<% end %> |
||||||
<% end %> |
<% end %> |
||||||
|
@ -1,6 +1,6 @@ |
|||||||
<%= f.govuk_text_field question_key, |
<%= f.govuk_text_field question.id.to_sym, |
||||||
hint: { text: question["hint_text"] }, |
hint: { text: question.hint_text }, |
||||||
label: { text: question["header"].html_safe, size: "l"}, |
label: { text: question.header.html_safe, size: "l"}, |
||||||
width: 20, |
width: 20, |
||||||
**stimulus_html_attributes(question) |
**stimulus_html_attributes(question) |
||||||
%> |
%> |
||||||
|
@ -0,0 +1,10 @@ |
|||||||
|
### ADR - 011: Splitting the form parsing into objects |
||||||
|
|
||||||
|
Initially a single "Form" class handled the parsing of the form definition JSON as well as a lot of the logic around what different sections meant. This works fine but led to a lot of places in code where we're passing around arguments to determine whether a page or section should or shouldn't do something rather than being able to ask it directly. Refactoring this into smaller form domain object classes has several benefits: |
||||||
|
|
||||||
|
- It's easier to compare the form definition JSON to the code classes and reason about what fields can be passed and what effect they'll have |
||||||
|
- It moves business logic out of the helpers and keeps them to just dealing with display logic |
||||||
|
- It makes it easier to unit test form functionality, and group that into smaller chunks |
||||||
|
- It allows for less passing of arguments. e.g. `page.routed_to?(case_log)` vs `form.was_page_routed_to?(page, case_log)` |
||||||
|
|
||||||
|
This abstraction is likely still not the best (the form vs case log split) but this seems like an improvement that can be iterated on. |
@ -0,0 +1,66 @@ |
|||||||
|
require "rails_helper" |
||||||
|
|
||||||
|
RSpec.describe Form::Page, type: :model do |
||||||
|
let(:form) { FormHandler.instance.get_form("test_form") } |
||||||
|
let(:section_id) { "rent_and_charges" } |
||||||
|
let(:section_definition) { form.form_definition["sections"][section_id] } |
||||||
|
let(:section) { Form::Section.new(section_id, section_definition, form) } |
||||||
|
let(:subsection_id) { "income_and_benefits" } |
||||||
|
let(:subsection_definition) { section_definition["subsections"][subsection_id] } |
||||||
|
let(:subsection) { Form::Subsection.new(subsection_id, subsection_definition, section) } |
||||||
|
let(:page_id) { "net_income" } |
||||||
|
let(:page_definition) { subsection_definition["pages"][page_id] } |
||||||
|
subject { Form::Page.new(page_id, page_definition, subsection) } |
||||||
|
|
||||||
|
it "has an id" do |
||||||
|
expect(subject.id).to eq(page_id) |
||||||
|
end |
||||||
|
|
||||||
|
it "has a header" do |
||||||
|
expect(subject.header).to eq("Test header") |
||||||
|
end |
||||||
|
|
||||||
|
it "has a description" do |
||||||
|
expect(subject.description).to eq("Some extra text for the page") |
||||||
|
end |
||||||
|
|
||||||
|
it "has questions" do |
||||||
|
expected_questions = %w[earnings incfreq] |
||||||
|
expect(subject.questions.map(&:id)).to eq(expected_questions) |
||||||
|
end |
||||||
|
|
||||||
|
it "has soft validations" do |
||||||
|
expected_soft_validations = %w[override_net_income_validation] |
||||||
|
expect(subject.soft_validations.map(&:id)).to eq(expected_soft_validations) |
||||||
|
end |
||||||
|
|
||||||
|
it "has a soft_validation helper" do |
||||||
|
expect(subject.has_soft_validations?).to be true |
||||||
|
end |
||||||
|
|
||||||
|
it "has expected form responses" do |
||||||
|
expected_responses = %w[earnings incfreq override_net_income_validation] |
||||||
|
expect(subject.expected_responses.map(&:id)).to eq(expected_responses) |
||||||
|
end |
||||||
|
|
||||||
|
context "for a given case log" do |
||||||
|
let(:case_log) { FactoryBot.build(:case_log, :in_progress) } |
||||||
|
|
||||||
|
it "knows if it's been routed to" do |
||||||
|
expect(subject.routed_to?(case_log)).to be true |
||||||
|
end |
||||||
|
|
||||||
|
context "given routing conditions" do |
||||||
|
let(:page_id) { "dependent_page" } |
||||||
|
|
||||||
|
it "evaluates not met conditions correctly" do |
||||||
|
expect(subject.routed_to?(case_log)).to be false |
||||||
|
end |
||||||
|
|
||||||
|
it "evaluates not conditions correctly" do |
||||||
|
case_log.incfreq = "Weekly" |
||||||
|
expect(subject.routed_to?(case_log)).to be true |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,140 @@ |
|||||||
|
require "rails_helper" |
||||||
|
|
||||||
|
RSpec.describe Form::Question, type: :model do |
||||||
|
let(:form) { FormHandler.instance.get_form("test_form") } |
||||||
|
let(:section_id) { "rent_and_charges" } |
||||||
|
let(:section_definition) { form.form_definition["sections"][section_id] } |
||||||
|
let(:section) { Form::Section.new(section_id, section_definition, form) } |
||||||
|
let(:subsection_id) { "income_and_benefits" } |
||||||
|
let(:subsection_definition) { section_definition["subsections"][subsection_id] } |
||||||
|
let(:subsection) { Form::Subsection.new(subsection_id, subsection_definition, section) } |
||||||
|
let(:page_id) { "net_income" } |
||||||
|
let(:page_definition) { subsection_definition["pages"][page_id] } |
||||||
|
let(:page) { Form::Page.new(page_id, page_definition, subsection) } |
||||||
|
let(:question_id) { "earnings" } |
||||||
|
let(:question_definition) { page_definition["questions"][question_id] } |
||||||
|
subject { Form::Question.new(question_id, question_definition, page) } |
||||||
|
|
||||||
|
it "has an id" do |
||||||
|
expect(subject.id).to eq(question_id) |
||||||
|
end |
||||||
|
|
||||||
|
it "has a header" do |
||||||
|
expect(subject.header).to eq("What is the tenant’s /and partner’s combined income after tax?") |
||||||
|
end |
||||||
|
|
||||||
|
it "has a check answers label" do |
||||||
|
expect(subject.check_answer_label).to eq("Income") |
||||||
|
end |
||||||
|
|
||||||
|
it "has a question type" do |
||||||
|
expect(subject.type).to eq("numeric") |
||||||
|
end |
||||||
|
|
||||||
|
it "belongs to a page" do |
||||||
|
expect(subject.page).to eq(page) |
||||||
|
end |
||||||
|
|
||||||
|
it "belongs to a subsection" do |
||||||
|
expect(subject.subsection).to eq(subsection) |
||||||
|
end |
||||||
|
|
||||||
|
it "has a read only helper" do |
||||||
|
expect(subject.read_only?).to be false |
||||||
|
end |
||||||
|
|
||||||
|
context "when type is numeric" do |
||||||
|
it "has a min value" do |
||||||
|
expect(subject.min).to eq(0) |
||||||
|
end |
||||||
|
|
||||||
|
it "has a step value" do |
||||||
|
expect(subject.step).to eq(1) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
context "when type is radio" do |
||||||
|
let(:question_id) { "incfreq" } |
||||||
|
|
||||||
|
it "has answer options" do |
||||||
|
expected_answer_options = { "0" => "Weekly", "1" => "Monthly", "2" => "Yearly" } |
||||||
|
expect(subject.answer_options).to eq(expected_answer_options) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
context "when type is checkbox" do |
||||||
|
let(:page_id) { "dependent_page" } |
||||||
|
let(:question_id) { "dependent_question" } |
||||||
|
|
||||||
|
it "has answer options" do |
||||||
|
expected_answer_options = { "0" => "Option A", "1" => "Option B" } |
||||||
|
expect(subject.answer_options).to eq(expected_answer_options) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
context "when the question is read only" do |
||||||
|
let(:subsection_id) { "rent" } |
||||||
|
let(:page_id) { "rent" } |
||||||
|
let(:question_id) { "tcharge" } |
||||||
|
|
||||||
|
it "has a read only helper" do |
||||||
|
expect(subject.read_only?).to be true |
||||||
|
end |
||||||
|
|
||||||
|
context "when the answer is part of a sum" do |
||||||
|
let(:question_id) { "pscharge" } |
||||||
|
|
||||||
|
it "has a result_field" do |
||||||
|
expect(subject.result_field).to eq("tcharge") |
||||||
|
end |
||||||
|
|
||||||
|
it "has fields to sum" do |
||||||
|
expected_fields_to_sum = %w[brent scharge pscharge supcharg] |
||||||
|
expect(subject.fields_to_add).to eq(expected_fields_to_sum) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
context "for a given case log" do |
||||||
|
let(:case_log) { FactoryBot.build(:case_log, :in_progress) } |
||||||
|
|
||||||
|
it "has an answer label" do |
||||||
|
case_log.earnings = 100 |
||||||
|
expect(subject.answer_label(case_log)).to eq("100") |
||||||
|
end |
||||||
|
|
||||||
|
it "has an update answer link text helper" do |
||||||
|
expect(subject.update_answer_link_name(case_log)).to eq("Answer") |
||||||
|
case_log[question_id] = 5 |
||||||
|
expect(subject.update_answer_link_name(case_log)).to eq("Change") |
||||||
|
end |
||||||
|
|
||||||
|
context "when type is checkbox" do |
||||||
|
let(:section_id) { "household" } |
||||||
|
let(:subsection_id) { "household_needs" } |
||||||
|
let(:page_id) { "accessibility_requirements" } |
||||||
|
let(:question_id) { "accessibility_requirements" } |
||||||
|
|
||||||
|
it "has a joined answers label" do |
||||||
|
case_log.housingneeds_a = 1 |
||||||
|
case_log.housingneeds_c = 1 |
||||||
|
expected_answer_label = "Fully wheelchair accessible housing, Level access housing" |
||||||
|
expect(subject.answer_label(case_log)).to eq(expected_answer_label) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
context "when a condition is present" do |
||||||
|
let(:page_id) { "housing_benefit" } |
||||||
|
let(:question_id) { "conditional_question" } |
||||||
|
|
||||||
|
it "knows whether it is enabled or not for unmet conditions" do |
||||||
|
expect(subject.enabled?(case_log)).to be false |
||||||
|
end |
||||||
|
|
||||||
|
it "knows whether it is enabled or not for met conditions" do |
||||||
|
case_log.hb = "Housing Benefit, but not Universal Credit" |
||||||
|
expect(subject.enabled?(case_log)).to be true |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,21 @@ |
|||||||
|
require "rails_helper" |
||||||
|
|
||||||
|
RSpec.describe Form::Section, type: :model do |
||||||
|
let(:form) { FormHandler.instance.get_form("test_form") } |
||||||
|
let(:section_id) { "household" } |
||||||
|
let(:section_definition) { form.form_definition["sections"][section_id] } |
||||||
|
subject { Form::Section.new(section_id, section_definition, form) } |
||||||
|
|
||||||
|
it "has an id" do |
||||||
|
expect(subject.id).to eq(section_id) |
||||||
|
end |
||||||
|
|
||||||
|
it "has a label" do |
||||||
|
expect(subject.label).to eq("About the household") |
||||||
|
end |
||||||
|
|
||||||
|
it "has subsections" do |
||||||
|
expected_subsections = %w[household_characteristics household_needs] |
||||||
|
expect(subject.subsections.map(&:id)).to eq(expected_subsections) |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,72 @@ |
|||||||
|
require "rails_helper" |
||||||
|
|
||||||
|
RSpec.describe Form::Subsection, type: :model do |
||||||
|
let(:form) { FormHandler.instance.get_form("test_form") } |
||||||
|
let(:section_id) { "household" } |
||||||
|
let(:section_definition) { form.form_definition["sections"][section_id] } |
||||||
|
let(:section) { Form::Section.new(section_id, section_definition, form) } |
||||||
|
let(:subsection_id) { "household_characteristics" } |
||||||
|
let(:subsection_definition) { section_definition["subsections"][subsection_id] } |
||||||
|
subject { Form::Subsection.new(subsection_id, subsection_definition, section) } |
||||||
|
|
||||||
|
it "has an id" do |
||||||
|
expect(subject.id).to eq(subsection_id) |
||||||
|
end |
||||||
|
|
||||||
|
it "has a label" do |
||||||
|
expect(subject.label).to eq("Household characteristics") |
||||||
|
end |
||||||
|
|
||||||
|
it "has pages" do |
||||||
|
expected_pages = %w[tenant_code person_1_age person_1_gender household_number_of_other_members] |
||||||
|
expect(subject.pages.map(&:id)).to eq(expected_pages) |
||||||
|
end |
||||||
|
|
||||||
|
it "has questions" do |
||||||
|
expected_questions = %w[tenant_code age1 sex1 other_hhmemb relat2 age2 sex2 ecstat2] |
||||||
|
expect(subject.questions.map(&:id)).to eq(expected_questions) |
||||||
|
end |
||||||
|
|
||||||
|
context "for a given in progress case log" do |
||||||
|
let(:case_log) { FactoryBot.build(:case_log, :in_progress) } |
||||||
|
|
||||||
|
it "has a status" do |
||||||
|
expect(subject.status(case_log)).to eq(:in_progress) |
||||||
|
end |
||||||
|
|
||||||
|
it "has status helpers" do |
||||||
|
expect(subject.is_incomplete?(case_log)).to be(true) |
||||||
|
expect(subject.is_started?(case_log)).to be(true) |
||||||
|
end |
||||||
|
|
||||||
|
it "has question helpers for the number of applicable questions" do |
||||||
|
expected_questions = %w[tenant_code age1 sex1 other_hhmemb] |
||||||
|
expect(subject.applicable_questions(case_log).map(&:id)).to eq(expected_questions) |
||||||
|
expect(subject.applicable_questions_count(case_log)).to eq(4) |
||||||
|
end |
||||||
|
|
||||||
|
it "has question helpers for the number of answered questions" do |
||||||
|
expected_questions = %w[tenant_code age1] |
||||||
|
expect(subject.answered_questions(case_log).map(&:id)).to eq(expected_questions) |
||||||
|
expect(subject.answered_questions_count(case_log)).to eq(2) |
||||||
|
end |
||||||
|
|
||||||
|
it "has a question helpers for the unanswered questions" do |
||||||
|
expected_questions = %w[sex1 other_hhmemb] |
||||||
|
expect(subject.unanswered_questions(case_log).map(&:id)).to eq(expected_questions) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
context "for a given completed case log" do |
||||||
|
let(:case_log) { FactoryBot.build(:case_log, :completed) } |
||||||
|
|
||||||
|
it "has a status" do |
||||||
|
expect(subject.status(case_log)).to eq(:completed) |
||||||
|
end |
||||||
|
|
||||||
|
it "has status helpers" do |
||||||
|
expect(subject.is_incomplete?(case_log)).to be(false) |
||||||
|
expect(subject.is_started?(case_log)).to be(true) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
Loading…
Reference in new issue