Browse Source

Refactor log setup into it's own form (#663)

* Refactor log setup into it's own form

* Use factory

* Run workflow on push to PR

* Array matcher on heisenspec
pull/672/head
baarkerlounger 3 years ago committed by GitHub
parent
commit
eb72bc6ffd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      app/models/form.rb
  2. 8
      app/models/form_handler.rb
  3. 132
      config/forms/2021_2022.json
  4. 132
      config/forms/2022_2023.json
  5. 138
      config/forms/setup/log_setup.json
  6. 3
      spec/factories/case_log.rb
  7. 18
      spec/features/form/tasklist_page_spec.rb
  8. 76
      spec/fixtures/forms/2022_2023.json
  9. 71
      spec/fixtures/forms/setup/log_setup.json
  10. 4
      spec/helpers/tasklist_helper_spec.rb
  11. 4
      spec/models/form_handler_spec.rb
  12. 2
      spec/models/organisation_spec.rb
  13. 3
      spec/models/rent_period_spec.rb
  14. 7
      spec/requests/case_logs_controller_spec.rb
  15. 3
      spec/services/imports/case_logs_field_import_service_spec.rb
  16. 5
      spec/services/imports/case_logs_import_service_spec.rb

17
app/models/form.rb

@ -1,19 +1,24 @@
class Form class Form
attr_reader :form_definition, :sections, :subsections, :pages, :questions, attr_reader :form_definition, :sections, :subsections, :pages, :questions,
:start_date, :end_date, :type, :name :start_date, :end_date, :type, :name, :setup_definition,
:setup_sections, :form_sections
def initialize(form_path, name) def initialize(form_path, name, setup_path)
raise "No setup definition file exists for given path".freeze unless File.exist?(setup_path)
raise "No form definition file exists for given year".freeze unless File.exist?(form_path) raise "No form definition file exists for given year".freeze unless File.exist?(form_path)
@form_definition = JSON.parse(File.open(form_path).read)
@name = name @name = name
@start_date = Time.iso8601(form_definition["start_date"]) @setup_definition = JSON.parse(File.open(setup_path).read)
@end_date = Time.iso8601(form_definition["end_date"]) @setup_sections = setup_definition["sections"].map { |id, s| Form::Section.new(id, s, self) } || []
@form_definition = JSON.parse(File.open(form_path).read)
@form_sections = form_definition["sections"].map { |id, s| Form::Section.new(id, s, self) }
@type = form_definition["form_type"] @type = form_definition["form_type"]
@sections = form_definition["sections"].map { |id, s| Form::Section.new(id, s, self) } @sections = setup_sections + form_sections
@subsections = sections.flat_map(&:subsections) @subsections = sections.flat_map(&:subsections)
@pages = subsections.flat_map(&:pages) @pages = subsections.flat_map(&:pages)
@questions = pages.flat_map(&:questions) @questions = pages.flat_map(&:questions)
@start_date = Time.iso8601(form_definition["start_date"])
@end_date = Time.iso8601(form_definition["end_date"])
end end
def get_subsection(id) def get_subsection(id)

8
app/models/form_handler.rb

@ -21,12 +21,18 @@ private
directories.each do |directory| directories.each do |directory|
Dir.glob("#{directory}/*.json").each do |form_path| Dir.glob("#{directory}/*.json").each do |form_path|
form_name = File.basename(form_path, ".json") form_name = File.basename(form_path, ".json")
forms[form_name] = Form.new(form_path, form_name) forms[form_name] = Form.new(form_path, form_name, setup_path)
end end
end end
forms forms
end end
def setup_path
return "spec/fixtures/forms/setup/log_setup.json" if Rails.env.test?
"config/forms/setup/log_setup.json"
end
def directories def directories
Rails.env.test? ? ["spec/fixtures/forms"] : ["config/forms"] Rails.env.test? ? ["spec/fixtures/forms"] : ["config/forms"]
end end

132
config/forms/2021_2022.json

@ -3,138 +3,6 @@
"start_date": "2021-04-01T00:00:00.000+01:00", "start_date": "2021-04-01T00:00:00.000+01:00",
"end_date": "2022-07-01T00:00:00.000+01:00", "end_date": "2022-07-01T00:00:00.000+01:00",
"sections": { "sections": {
"setup": {
"label": "Before you start",
"subsections": {
"setup": {
"label": "Set up this lettings log",
"pages": {
"needs_type": {
"header": "",
"description": "",
"questions": {
"needstype": {
"check_answer_label": "Needs type",
"header": "What is the needs type?",
"hint_text": "General needs housing includes both self-contained and shared housing without support or specific adaptations. Supported housing can include direct access hostels, group homes, residential care and nursing homes.",
"type": "radio",
"answer_options": {
"1": {
"value": "General needs"
},
"2": {
"value": "Supported housing"
}
}
}
},
"depends_on": [
{
"supported_housing_schemes_enabled?" : true
}
]
},
"renewal": {
"header": "",
"description": "",
"questions": {
"renewal": {
"check_answer_label": "Property renewal",
"header": "Is this letting a renewal?",
"hint_text": "A renewal is a letting to the same tenant in the same property.",
"type": "radio",
"answer_options": {
"1": {
"value": "Yes"
},
"0": {
"value": "No"
}
}
}
}
},
"tenancy_start_date": {
"header": "",
"description": "",
"questions": {
"startdate": {
"check_answer_label": "Tenancy start date",
"header": "What is the tenancy start date?",
"type": "date"
}
}
},
"rent_type": {
"header": "",
"description": "",
"questions": {
"rent_type": {
"check_answer_label": "Rent type",
"header": "What is the rent type?",
"hint_text": "",
"type": "radio",
"answer_options": {
"1": {
"value": "Affordable Rent"
},
"2": {
"value": "London Affordable Rent"
},
"4": {
"value": "London Living Rent"
},
"3": {
"value": "Rent to Buy"
},
"0": {
"value": "Social Rent"
},
"5": {
"value": "Other intermediate rent product"
}
},
"conditional_for": {
"irproduct_other": [5]
}
},
"irproduct_other": {
"check_answer_label": "Product name",
"header": "Name of rent product",
"type": "text"
}
}
},
"tenant_code": {
"header": "",
"description": "",
"questions": {
"tenant_code": {
"check_answer_label": "Tenant code",
"header": "What is the tenant code?",
"hint_text": "This is how you usually refer to this tenancy on your own systems.",
"type": "text",
"width": 10
}
}
},
"property_reference": {
"header": "",
"description": "",
"questions": {
"propcode": {
"check_answer_label": "Property reference",
"header": "What is the property reference?",
"hint_text": "This is how you usually refer to this property on your own systems.",
"type": "text",
"width": 10
}
}
}
}
}
}
},
"tenancy_and_property": { "tenancy_and_property": {
"label": "Property and tenancy information", "label": "Property and tenancy information",
"subsections": { "subsections": {

132
config/forms/2022_2023.json

@ -3,138 +3,6 @@
"start_date": "2022-04-01T00:00:00.000+01:00", "start_date": "2022-04-01T00:00:00.000+01:00",
"end_date": "2023-07-01T00:00:00.000+01:00", "end_date": "2023-07-01T00:00:00.000+01:00",
"sections": { "sections": {
"setup": {
"label": "Before you start",
"subsections": {
"setup": {
"label": "Set up this lettings log",
"pages": {
"needs_type": {
"header": "",
"description": "",
"questions": {
"needstype": {
"check_answer_label": "Needs type",
"header": "What is the needs type?",
"hint_text": "General needs housing includes both self-contained and shared housing without support or specific adaptations. Supported housing can include direct access hostels, group homes, residential care and nursing homes.",
"type": "radio",
"answer_options": {
"1": {
"value": "General needs"
},
"2": {
"value": "Supported housing"
}
}
}
},
"depends_on": [
{
"supported_housing_schemes_enabled?" : true
}
]
},
"renewal": {
"header": "",
"description": "",
"questions": {
"renewal": {
"check_answer_label": "Property renewal",
"header": "Is this letting a renewal?",
"hint_text": "A renewal is a letting to the same tenant in the same property.",
"type": "radio",
"answer_options": {
"1": {
"value": "Yes"
},
"0": {
"value": "No"
}
}
}
}
},
"tenancy_start_date": {
"header": "",
"description": "",
"questions": {
"startdate": {
"check_answer_label": "Tenancy start date",
"header": "What is the tenancy start date?",
"type": "date"
}
}
},
"rent_type": {
"header": "",
"description": "",
"questions": {
"rent_type": {
"check_answer_label": "Rent type",
"header": "What is the rent type?",
"hint_text": "",
"type": "radio",
"answer_options": {
"1": {
"value": "Affordable Rent"
},
"2": {
"value": "London Affordable Rent"
},
"4": {
"value": "London Living Rent"
},
"3": {
"value": "Rent to Buy"
},
"0": {
"value": "Social Rent"
},
"5": {
"value": "Other intermediate rent product"
}
},
"conditional_for": {
"irproduct_other": [5]
}
},
"irproduct_other": {
"check_answer_label": "Product name",
"header": "Name of rent product",
"type": "text"
}
}
},
"tenant_code": {
"header": "",
"description": "",
"questions": {
"tenant_code": {
"check_answer_label": "Tenant code",
"header": "What is the tenant code?",
"hint_text": "This is how you usually refer to this tenancy on your own systems.",
"type": "text",
"width": 10
}
}
},
"property_reference": {
"header": "",
"description": "",
"questions": {
"propcode": {
"check_answer_label": "Property reference",
"header": "What is the property reference?",
"hint_text": "This is how you usually refer to this property on your own systems.",
"type": "text",
"width": 10
}
}
}
}
}
}
},
"tenancy_and_property": { "tenancy_and_property": {
"label": "Property and tenancy information", "label": "Property and tenancy information",
"subsections": { "subsections": {

138
config/forms/setup/log_setup.json

@ -0,0 +1,138 @@
{
"form_type": "setup",
"sections": {
"setup": {
"label": "Before you start",
"subsections": {
"setup": {
"label": "Set up this lettings log",
"pages": {
"needs_type": {
"header": "",
"description": "",
"questions": {
"needstype": {
"check_answer_label": "Needs type",
"header": "What is the needs type?",
"hint_text": "",
"type": "radio",
"answer_options": {
"1": {
"value": "General needs"
},
"2": {
"value": "Supported housing"
}
}
}
},
"derived": true,
"depends_on": [
{
"supported_housing_schemes_enabled?" : true
}
]
},
"renewal": {
"header": "",
"description": "",
"questions": {
"renewal": {
"check_answer_label": "Property renewal",
"header": "Is this letting a renewal?",
"hint_text": "A renewal is a letting to the same tenant in the same property.",
"type": "radio",
"answer_options": {
"1": {
"value": "Yes"
},
"0": {
"value": "No"
}
}
}
}
},
"tenancy_start_date": {
"header": "",
"description": "",
"questions": {
"startdate": {
"check_answer_label": "Tenancy start date",
"header": "What is the tenancy start date?",
"type": "date"
}
}
},
"rent_type": {
"header": "",
"description": "",
"questions": {
"rent_type": {
"check_answer_label": "Rent type",
"header": "What is the rent type?",
"hint_text": "",
"type": "radio",
"answer_options": {
"1": {
"value": "Affordable Rent"
},
"2": {
"value": "London Affordable Rent"
},
"4": {
"value": "London Living Rent"
},
"3": {
"value": "Rent to Buy"
},
"0": {
"value": "Social Rent"
},
"5": {
"value": "Other intermediate rent product"
}
},
"conditional_for": {
"irproduct_other": [5]
}
},
"irproduct_other": {
"check_answer_label": "Product name",
"header": "Name of rent product",
"type": "text"
}
}
},
"tenant_code": {
"header": "",
"description": "",
"questions": {
"tenant_code": {
"check_answer_label": "Tenant code",
"header": "What is the tenant code?",
"hint_text": "This is how you usually refer to this tenancy on your own systems.",
"type": "text",
"width": 10
}
}
},
"property_reference": {
"header": "",
"description": "",
"questions": {
"propcode": {
"check_answer_label": "Property reference",
"header": "What is the property reference?",
"hint_text": "This is how you usually refer to this property on your own systems.",
"type": "text",
"width": 10
}
}
}
}
}
}
}
}
}

3
spec/factories/case_log.rb

@ -16,6 +16,9 @@ FactoryBot.define do
ppostcode_full { Faker::Address.postcode } ppostcode_full { Faker::Address.postcode }
age1 { 17 } age1 { 17 }
age2 { 19 } age2 { 19 }
renewal { 1 }
rent_type { 1 }
startdate { Time.zone.local(2021, 5, 1) }
end end
trait :soft_validations_triggered do trait :soft_validations_triggered do
status { 1 } status { 1 }

18
spec/features/form/tasklist_page_spec.rb

@ -27,6 +27,15 @@ RSpec.describe "Task List" do
managing_organisation: user.organisation, managing_organisation: user.organisation,
) )
end end
let(:setup_completed_log) do
FactoryBot.create(
:case_log,
:about_completed,
owning_organisation: user.organisation,
managing_organisation: user.organisation,
startdate: Time.zone.local(2021, 5, 1),
)
end
let(:id) { case_log.id } let(:id) { case_log.id }
let(:status) { case_log.status } let(:status) { case_log.status }
@ -40,14 +49,13 @@ RSpec.describe "Task List" do
end end
it "shows number of completed sections if one section is completed" do it "shows number of completed sections if one section is completed" do
answer_all_questions_in_income_subsection(empty_case_log) visit("/logs/#{setup_completed_log.id}")
visit("/logs/#{empty_case_log.id}") expect(page).to have_content("1 of 10 sections completed.")
expect(page).to have_content("1 of 9 sections completed.")
end end
it "show skip link for next incomplete section" do it "show skip link for next incomplete section" do
answer_all_questions_in_income_subsection(empty_case_log) answer_all_questions_in_income_subsection(setup_completed_log)
visit("/logs/#{empty_case_log.id}") visit("/logs/#{setup_completed_log.id}")
expect(page).to have_link("Skip to next incomplete section", href: /#household-characteristics/) expect(page).to have_link("Skip to next incomplete section", href: /#household-characteristics/)
end end

76
spec/fixtures/forms/2022_2023.json vendored

@ -3,82 +3,6 @@
"start_date": "2022-04-01T00:00:00.000+01:00", "start_date": "2022-04-01T00:00:00.000+01:00",
"end_date": "2023-07-01T00:00:00.000+01:00", "end_date": "2023-07-01T00:00:00.000+01:00",
"sections": { "sections": {
"setup": {
"label": "Before you start",
"subsections": {
"setup": {
"label": "Set up this lettings log",
"pages": {
"renewal": {
"header": "",
"description": "",
"questions": {
"renewal": {
"check_answer_label": "Property renewal",
"header": "Is this a renewal to the same tenant in the same property?",
"hint_text": "",
"type": "radio",
"answer_options": {
"1": "Yes",
"0": "No"
}
}
}
},
"startdate": {
"header": "",
"description": "",
"questions": {
"startdate": {
"check_answer_label": "Tenancy start date",
"header": "What is the tenancy start date?",
"hint_text": "For example, 27 3 2007",
"type": "date"
}
}
},
"about_this_letting": {
"header": "Tell us about this letting",
"description": "",
"questions": {
"rent_type": {
"check_answer_label": "Rent type",
"header": "What is the rent type?",
"hint_text": "",
"type": "radio",
"answer_options": {
"0": "Social rent",
"1": "Affordable rent",
"2": "London Affordable rent",
"3": "Rent to buy",
"4": "London living rent",
"5": "Other intermediate rent product"
},
"conditional_for": {
"intermediate_rent_product_name": [5]
}
},
"intermediate_rent_product_name": {
"check_answer_label": "Product name",
"header": "What is intermediate rent product name?",
"type": "text"
},
"needstype": {
"check_answer_label": "Needs type",
"header": "What is the needs type?",
"hint_text": "",
"type": "radio",
"answer_options": {
"0": "Supported housing",
"1": "General needs"
}
}
}
}
}
}
}
},
"household": { "household": {
"label": "About the household", "label": "About the household",
"subsections": { "subsections": {

71
spec/fixtures/forms/setup/log_setup.json vendored

@ -0,0 +1,71 @@
{
"form_type": "setup",
"sections": {
"setup": {
"label": "Before you start",
"subsections": {
"setup": {
"label": "Set up this lettings log",
"pages": {
"renewal": {
"header": "",
"description": "",
"questions": {
"renewal": {
"check_answer_label": "Property renewal",
"header": "Is this a renewal to the same tenant in the same property?",
"hint_text": "",
"type": "radio",
"answer_options": {
"1": "Yes",
"0": "No"
}
}
}
},
"startdate": {
"header": "",
"description": "",
"questions": {
"startdate": {
"check_answer_label": "Tenancy start date",
"header": "What is the tenancy start date?",
"hint_text": "For example, 27 3 2007",
"type": "date"
}
}
},
"about_this_letting": {
"header": "Tell us about this letting",
"description": "",
"questions": {
"rent_type": {
"check_answer_label": "Rent type",
"header": "What is the rent type?",
"hint_text": "",
"type": "radio",
"answer_options": {
"0": "Social rent",
"1": "Affordable rent",
"2": "London Affordable rent",
"3": "Rent to buy",
"4": "London living rent",
"5": "Other intermediate rent product"
},
"conditional_for": {
"intermediate_rent_product_name": [5]
}
},
"intermediate_rent_product_name": {
"check_answer_label": "Product name",
"header": "What is intermediate rent product name?",
"type": "text"
}
}
}
}
}
}
}
}
}

4
spec/helpers/tasklist_helper_spec.rb

@ -17,7 +17,7 @@ RSpec.describe TasklistHelper do
describe "get sections count" do describe "get sections count" do
it "returns the total of sections if no status is given" do it "returns the total of sections if no status is given" do
expect(get_subsections_count(empty_case_log)).to eq(9) expect(get_subsections_count(empty_case_log)).to eq(10)
end end
it "returns 0 sections for completed sections if no sections are completed" do it "returns 0 sections for completed sections if no sections are completed" do
@ -25,7 +25,7 @@ RSpec.describe TasklistHelper do
end end
it "returns the number of not started sections" do it "returns the number of not started sections" do
expect(get_subsections_count(empty_case_log, :not_started)).to eq(8) expect(get_subsections_count(empty_case_log, :not_started)).to eq(9)
end end
it "returns the number of sections in progress" do it "returns the number of sections in progress" do

4
spec/models/form_handler_spec.rb

@ -17,7 +17,7 @@ RSpec.describe FormHandler do
form_handler = described_class.instance form_handler = described_class.instance
form = form_handler.get_form(test_form_name) form = form_handler.get_form(test_form_name)
expect(form).to be_a(Form) expect(form).to be_a(Form)
expect(form.pages.count).to eq(35) expect(form.pages.count).to eq(38)
end end
end end
@ -32,7 +32,7 @@ RSpec.describe FormHandler do
it "loads the form once at boot time" do it "loads the form once at boot time" do
form_handler = described_class.instance form_handler = described_class.instance
expect(Form).not_to receive(:new).with(:any, test_form_name) expect(Form).not_to receive(:new).with(:any, test_form_name, :any)
expect(form_handler.get_form(test_form_name)).to be_a(Form) expect(form_handler.get_form(test_form_name)).to be_a(Form)
end end
end end

2
spec/models/organisation_spec.rb

@ -87,7 +87,7 @@ RSpec.describe Organisation, type: :model do
end end
it "has case logs" do it "has case logs" do
expect(organisation.case_logs.to_a).to eq([owned_case_log, managed_case_log]) expect(organisation.case_logs.to_a).to match_array([owned_case_log, managed_case_log])
end end
it "has case log status helper methods" do it "has case log status helper methods" do

3
spec/models/rent_period_spec.rb

@ -2,7 +2,8 @@ require "rails_helper"
RSpec.describe RentPeriod, type: :model do RSpec.describe RentPeriod, type: :model do
describe "rent period mapping" do describe "rent period mapping" do
let(:form) { Form.new("spec/fixtures/forms/2021_2022.json", "2021_2022") } let(:setup_path) { "spec/fixtures/forms/setup/log_setup.json" }
let(:form) { Form.new("spec/fixtures/forms/2021_2022.json", "2021_2022", setup_path) }
before do before do
allow(FormHandler.instance).to receive(:current_form).and_return(form) allow(FormHandler.instance).to receive(:current_form).and_return(form)

7
spec/requests/case_logs_controller_spec.rb

@ -288,7 +288,8 @@ RSpec.describe CaseLogsController, type: :request do
mrcdate: Time.zone.local(2022, 2, 1), mrcdate: Time.zone.local(2022, 2, 1),
startdate: Time.zone.local(2022, 12, 1), startdate: Time.zone.local(2022, 12, 1),
tenancy: 6, tenancy: 6,
managing_organisation: organisation) managing_organisation: organisation,
tenant_code: nil)
end end
it "shows case logs for multiple selected statuses and years" do it "shows case logs for multiple selected statuses and years" do
@ -622,7 +623,7 @@ RSpec.describe CaseLogsController, type: :request do
end end
it "displays a section status for a case log" do it "displays a section status for a case log" do
assert_select ".govuk-tag", text: /Not started/, count: 7 assert_select ".govuk-tag", text: /Not started/, count: 8
assert_select ".govuk-tag", text: /In progress/, count: 1 assert_select ".govuk-tag", text: /In progress/, count: 1
assert_select ".govuk-tag", text: /Completed/, count: 0 assert_select ".govuk-tag", text: /Completed/, count: 0
assert_select ".govuk-tag", text: /Cannot start yet/, count: 1 assert_select ".govuk-tag", text: /Cannot start yet/, count: 1
@ -645,7 +646,7 @@ RSpec.describe CaseLogsController, type: :request do
end end
it "displays a section status for a case log" do it "displays a section status for a case log" do
assert_select ".govuk-tag", text: /Not started/, count: 7 assert_select ".govuk-tag", text: /Not started/, count: 8
assert_select ".govuk-tag", text: /Completed/, count: 1 assert_select ".govuk-tag", text: /Completed/, count: 1
assert_select ".govuk-tag", text: /Cannot start yet/, count: 1 assert_select ".govuk-tag", text: /Cannot start yet/, count: 1
end end

3
spec/services/imports/case_logs_field_import_service_spec.rb

@ -6,7 +6,8 @@ RSpec.describe Imports::CaseLogsFieldImportService do
let(:storage_service) { instance_double(StorageService) } let(:storage_service) { instance_double(StorageService) }
let(:logger) { instance_double(ActiveSupport::Logger) } let(:logger) { instance_double(ActiveSupport::Logger) }
let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json", "2021_2022") } let(:real_setup_path) { "config/forms/setup/log_setup.json" }
let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json", "2021_2022", real_setup_path) }
let(:fixture_directory) { "spec/fixtures/softwire_imports/case_logs" } let(:fixture_directory) { "spec/fixtures/softwire_imports/case_logs" }
let(:case_log_id) { "0ead17cb-1668-442d-898c-0d52879ff592" } let(:case_log_id) { "0ead17cb-1668-442d-898c-0d52879ff592" }

5
spec/services/imports/case_logs_import_service_spec.rb

@ -6,8 +6,9 @@ RSpec.describe Imports::CaseLogsImportService do
let(:storage_service) { instance_double(StorageService) } let(:storage_service) { instance_double(StorageService) }
let(:logger) { instance_double(ActiveSupport::Logger) } let(:logger) { instance_double(ActiveSupport::Logger) }
let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json", "2021_2022") } let(:real_setup_path) { "config/forms/setup/log_setup.json" }
let(:real_2022_2023_form) { Form.new("config/forms/2022_2023.json", "2022_2023") } let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json", "2021_2022", real_setup_path) }
let(:real_2022_2023_form) { Form.new("config/forms/2022_2023.json", "2022_2023", real_setup_path) }
let(:fixture_directory) { "spec/fixtures/softwire_imports/case_logs" } let(:fixture_directory) { "spec/fixtures/softwire_imports/case_logs" }
def open_file(directory, filename) def open_file(directory, filename)

Loading…
Cancel
Save