diff --git a/.gitignore b/.gitignore index bc97d1d63..93d1e2481 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,7 @@ yarn-debug.log* # Code coverage results /coverage + +#IDE specific files +/.idea +/.idea/* diff --git a/app/helpers/tasklist_helper.rb b/app/helpers/tasklist_helper.rb new file mode 100644 index 000000000..4c831029c --- /dev/null +++ b/app/helpers/tasklist_helper.rb @@ -0,0 +1,49 @@ +module TasklistHelper + STATUSES = { + not_started: "Not started", + cannot_start_yet: "Cannot start yet", + completed: "Completed", + in_progress: "In progress", + }.freeze + + STYLES = { + not_started: "govuk-tag--grey", + cannot_start_yet: "govuk-tag--grey", + completed: "", + in_progress: "govuk-tag--blue", + }.freeze + + def get_subsection_status(subsection_name, case_log, questions) + if subsection_name == "declaration" + return all_questions_completed(case_log) ? :not_started : :cannot_start_yet + end + + return :not_started if questions.all? { |question| case_log[question].blank? } + return :completed if questions.all? { |question| case_log[question].present? } + + :in_progress + end + + def get_next_incomplete_section(form, case_log) + subsections = form.all_subsections.keys + subsections.find { |subsection| is_incomplete?(subsection, case_log, form.questions_for_subsection(subsection).keys) } + end + + def get_sections_count(form, case_log, status = :all) + subsections = form.all_subsections.keys + return subsections.count if status == :all + + subsections.count { |subsection| get_subsection_status(subsection, case_log, form.questions_for_subsection(subsection).keys) == status } + end + +private + + def all_questions_completed(case_log) + case_log.attributes.all? { |_question, answer| answer.present? } + end + + def is_incomplete?(subsection, case_log, questions) + status = get_subsection_status(subsection, case_log, questions) + %i[not_started in_progress].include?(status) + end +end diff --git a/app/models/form.rb b/app/models/form.rb index 00c3503af..586df20f5 100644 --- a/app/models/form.rb +++ b/app/models/form.rb @@ -60,4 +60,8 @@ class Form pages_for_subsection(subsection).keys[current_page_idx - 1] end + + def questions_for_subsection(subsection) + pages_for_subsection(subsection).map { |title, _value| questions_for_page(title) }.reduce(:merge) + end end diff --git a/app/views/case_logs/_tasklist.html.erb b/app/views/case_logs/_tasklist.html.erb index d0e60c396..dbbeb6321 100644 --- a/app/views/case_logs/_tasklist.html.erb +++ b/app/views/case_logs/_tasklist.html.erb @@ -8,11 +8,12 @@
You've completed 0 of 9 sections.
+You've completed <%= get_sections_count(@form, @case_log, :completed) %> of <%= get_sections_count(@form, @case_log, :all) %> sections.
- Skip to next incomplete section + Skip to next incomplete section
<%= render "tasklist", locals: { form: @form } %> diff --git a/spec/features/case_log_spec.rb b/spec/features/case_log_spec.rb index fa3cfbbf1..8ae4b06b4 100644 --- a/spec/features/case_log_spec.rb +++ b/spec/features/case_log_spec.rb @@ -15,6 +15,17 @@ RSpec.describe "Test Features" do household_number_of_other_members: { type: "numeric", answer: 2 }, } + def answer_all_questions_in_income_subsection + visit("/case_logs/#{empty_case_log.id}/net_income") + fill_in("net_income", with: 18_000) + choose("net-income-frequency-yearly-field") + click_button("Save and continue") + choose("net-income-uc-proportion-all-field") + click_button("Save and continue") + choose("housing-benefit-housing-benefit-but-not-universal-credit-field") + click_button("Save and continue") + end + describe "Create new log" do it "redirects to the task list for the new log" do visit("/case_logs") @@ -25,10 +36,45 @@ RSpec.describe "Test Features" do end describe "Viewing a log" do - it "displays a tasklist header" do - visit("/case_logs/#{id}") - expect(page).to have_content("Tasklist for log #{id}") - expect(page).to have_content("This submission is #{status}") + context "tasklist page" do + it "displays a tasklist header" do + visit("/case_logs/#{id}") + expect(page).to have_content("Tasklist for log #{id}") + expect(page).to have_content("This submission is #{status}") + end + + 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: /Completed/, count: 0 + assert_selector ".govuk-tag", text: /Cannot start yet/, count: 1 + end + + it "shows the correct status if one section is completed" 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: /Completed/, count: 1 + assert_selector ".govuk-tag", text: /Cannot start yet/, count: 1 + end + + it "skips to the first section if no answers are completed" do + visit("/case_logs/#{empty_case_log.id}") + expect(page).to have_link("Skip to next incomplete section", href: /#household_characteristics/) + end + + 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.") + 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.") + end end it "displays the household questions when you click into that section" do @@ -108,17 +154,6 @@ RSpec.describe "Test Features" do click_button("Save and continue") end - def answer_all_questions_in_income_subsection - visit("/case_logs/#{empty_case_log.id}/net_income") - fill_in("net_income", with: 18_000) - choose("net-income-frequency-yearly-field") - click_button("Save and continue") - choose("net-income-uc-proportion-all-field") - click_button("Save and continue") - choose("housing-benefit-housing-benefit-but-not-universal-credit-field") - click_button("Save and continue") - end - it "can be visited by URL" do visit("case_logs/#{id}/#{subsection}/check_answers") expect(page).to have_content("Check the answers you gave for #{subsection.tr('_', ' ')}") diff --git a/spec/helpers/tasklist_helper_spec.rb b/spec/helpers/tasklist_helper_spec.rb new file mode 100644 index 000000000..b8fbaae0f --- /dev/null +++ b/spec/helpers/tasklist_helper_spec.rb @@ -0,0 +1,84 @@ +require "rails_helper" + +RSpec.describe TasklistHelper do + describe "get subsection status" do + @form = Form.new(2021, 2022) + income_and_benefits_questions = @form.questions_for_subsection("income_and_benefits").keys + declaration_questions = @form.questions_for_subsection("declaration").keys + local_authority_questions = @form.questions_for_subsection("local_authority").keys + let!(:case_log) { FactoryBot.create(:case_log) } + + it "returns not started if none of the questions in the subsection are answered" do + status = get_subsection_status("income_and_benefits", case_log, income_and_benefits_questions) + expect(status).to eq(:not_started) + end + + it "returns cannot start yet if the subsection is declaration" do + status = get_subsection_status("declaration", case_log, declaration_questions) + expect(status).to eq(:cannot_start_yet) + end + + it "returns in progress if some of the questions have been answered" do + case_log["previous_postcode"] = "P0 5TT" + status = get_subsection_status("local_authority", case_log, local_authority_questions) + expect(status).to eq(:in_progress) + end + + it "returns completed if all the questions in the subsection have been answered" do + %w[net_income net_income_frequency net_income_uc_proportion housing_benefit].each { |x| case_log[x] = "value" } + status = get_subsection_status("income_and_benefits", case_log, income_and_benefits_questions) + expect(status).to eq(:completed) + end + + it "returns not started if the subsection is declaration and all the questions are completed" do + completed_case_log = CaseLog.new(case_log.attributes.map { |key, value| Hash[key, value || "value"] }.reduce(:merge)) + status = get_subsection_status("declaration", completed_case_log, declaration_questions) + expect(status).to eq(:not_started) + end + end + + describe "get next incomplete section" do + let!(:case_log) { FactoryBot.create(:case_log) } + + it "returns the first subsection name if it is not completed" do + @form = Form.new(2021, 2022) + expect(get_next_incomplete_section(@form, case_log)).to eq("household_characteristics") + end + + it "returns the first subsection name if it is partially completed" do + @form = Form.new(2021, 2022) + case_log["tenant_code"] = 123 + expect(get_next_incomplete_section(@form, case_log)).to eq("household_characteristics") + end + end + + describe "get sections count" do + let!(:empty_case_log) { FactoryBot.create(:case_log) } + let!(:case_log) { FactoryBot.create(:case_log, :in_progress) } + + it "returns the total of sections if no status is given" do + @form = Form.new(2021, 2022) + expect(get_sections_count(@form, empty_case_log)).to eq(9) + end + + it "returns 0 sections for completed sections if no sections are completed" do + @form = Form.new(2021, 2022) + expect(get_sections_count(@form, empty_case_log, :completed)).to eq(0) + end + + it "returns the number of not started sections" do + @form = Form.new(2021, 2022) + expect(get_sections_count(@form, empty_case_log, :not_started)).to eq(8) + end + + it "returns the number of sections in progress" do + @form = Form.new(2021, 2022) + expect(get_sections_count(@form, case_log, :in_progress)).to eq(1) + end + + it "returns 0 for invalid state" do + @form = Form.new(2021, 2022) + expect(get_sections_count(@form, case_log, :fake)).to eq(0) + end + end +end diff --git a/spec/models/form_spec.rb b/spec/models/form_spec.rb index 912370b1e..019c483ce 100644 --- a/spec/models/form_spec.rb +++ b/spec/models/form_spec.rb @@ -32,4 +32,13 @@ RSpec.describe Form, type: :model do end end end + + describe ".questions_for_subsection" do + let(:subsection) { "income_and_benefits" } + it "returns all questions for subsection" do + result = form.questions_for_subsection(subsection) + expect(result.length).to eq(4) + expect(result.keys).to eq(%w[net_income net_income_frequency net_income_uc_proportion housing_benefit]) + end + end end