Daniel Baark
3 years ago
committed by
GitHub
40 changed files with 752 additions and 580 deletions
@ -1,57 +1,20 @@
|
||||
module CheckAnswersHelper |
||||
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, form) |
||||
total_questions(subsection, case_log, form).count |
||||
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 |
||||
def display_answered_questions_summary(subsection, case_log) |
||||
total = subsection.applicable_questions_count(case_log) |
||||
answered = subsection.answered_questions_count(case_log) |
||||
if total == answered |
||||
'<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 #{answered} of #{total} questions</p> |
||||
#{create_next_missing_question_link(subsection, case_log)}".html_safe |
||||
end |
||||
form.next_page(page_name) |
||||
end |
||||
|
||||
def create_update_answer_link(question_title, question_info, case_log, form) |
||||
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 |
||||
private |
||||
|
||||
def create_next_missing_question_link(case_log_id, subsection, case_log, form) |
||||
pages_to_fill_in = [] |
||||
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 |
||||
url = "/case_logs/#{case_log_id}/#{pages_to_fill_in.first}" |
||||
def create_next_missing_question_link(subsection, case_log) |
||||
pages_to_fill_in = subsection.unanswered_questions(case_log).map(&:page) |
||||
url = "/case_logs/#{case_log.id}/#{pages_to_fill_in.first.id}" |
||||
link_to("Answer the missing questions", url, class: "govuk-link").html_safe |
||||
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 |
||||
|
@ -1,11 +1,9 @@
|
||||
module ConditionalQuestionsHelper |
||||
def conditional_questions_for_page(page) |
||||
page["questions"].values.map { |question| |
||||
question["conditional_for"] |
||||
}.compact.map(&:keys).flatten |
||||
page.questions.map(&:conditional_for).compact.map(&:keys).flatten |
||||
end |
||||
|
||||
def display_question_key_div(page_info, question_key) |
||||
"style='display:none;'".html_safe if conditional_questions_for_page(page_info).include?(question_key) |
||||
def display_question_key_div(page, question) |
||||
"style='display:none;'".html_safe if conditional_questions_for_page(page).include?(question.id) |
||||
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"> |
||||
<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> |
||||
<dd class="govuk-summary-list__value"> |
||||
<%= form.get_answer_label(@case_log, question_title) %> |
||||
<%= question.answer_label(@case_log) %> |
||||
</dd> |
||||
<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> |
||||
</div> |
||||
|
@ -1,6 +1,6 @@
|
||||
<%= f.govuk_date_field question_key, |
||||
hint: { text: question["hint_text"] }, |
||||
legend: { text: question["header"].html_safe, size: "l"}, |
||||
<%= f.govuk_date_field question.id.to_sym, |
||||
hint: { text: question.hint_text }, |
||||
legend: { text: question.header.html_safe, size: "l"}, |
||||
width: 20, |
||||
**stimulus_html_attributes(question) |
||||
%> |
||||
|
@ -1,7 +1,7 @@
|
||||
<%= f.govuk_number_field question_key, |
||||
hint: { text: question["hint_text"] }, |
||||
label: { text: question["header"].html_safe, size: "l"}, |
||||
min: question["min"], max: question["max"], step: question["step"], |
||||
width: 20, :readonly => question["readonly"], |
||||
<%= f.govuk_number_field question.id.to_sym, |
||||
hint: { text: question.hint_text }, |
||||
label: { text: question.header.html_safe, size: "l"}, |
||||
min: question.min, max: question.max, step: question.step, |
||||
width: 20, :readonly => question.read_only?, |
||||
**stimulus_html_attributes(question) |
||||
%> |
||||
|
@ -1,13 +1,13 @@
|
||||
<%= f.govuk_radio_buttons_fieldset question_key, |
||||
legend: { text: question["header"].html_safe, size: "l" }, |
||||
hint: { text: question["hint_text"] }, |
||||
small: (question["answer_options"].size > 5) do %> |
||||
<%= f.govuk_radio_buttons_fieldset question.id.to_sym, |
||||
legend: { text: question.header.html_safe, size: "l" }, |
||||
hint: { text: question.hint_text }, |
||||
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") %> |
||||
<%= f.govuk_radio_divider %> |
||||
<% 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 %> |
||||
|
@ -1,6 +1,6 @@
|
||||
<%= f.govuk_text_field question_key, |
||||
hint: { text: question["hint_text"] }, |
||||
label: { text: question["header"].html_safe, size: "l"}, |
||||
<%= f.govuk_text_field question.id.to_sym, |
||||
hint: { text: question.hint_text }, |
||||
label: { text: question.header.html_safe, size: "l"}, |
||||
width: 20, |
||||
**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