From 287e1f913b53413c0afe2e2d8c586e4d5630fe05 Mon Sep 17 00:00:00 2001 From: Laurence de Bruxelles Date: Mon, 19 May 2025 11:10:45 +0300 Subject: [PATCH 1/3] Add CsvReportService --- app/services/reports/csv_report_service.rb | 38 +++++++++++++++++++ .../reports/csv_report_service_spec.rb | 34 +++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 app/services/reports/csv_report_service.rb create mode 100644 spec/services/reports/csv_report_service_spec.rb diff --git a/app/services/reports/csv_report_service.rb b/app/services/reports/csv_report_service.rb new file mode 100644 index 000000000..942d8a1cd --- /dev/null +++ b/app/services/reports/csv_report_service.rb @@ -0,0 +1,38 @@ +class Reports::CsvReportService + delegate :csv, to: :@csv_service + + def initialize(records) + record_type = detect_record_type(records) + @csv_service = csv_service_class(record_type).new(records) + end + +private + + class NilCsvService + def initialize(_records); end + + def csv + "" + end + end + + def csv_service_class(record_type) + return NilCsvService if record_type.nil? + + "Reports::#{record_type.capitalize}CsvReportService".constantize + end + + def detect_record_type(records) + return if records.blank? + + type = records.first.fetch("type", "form") + + if type == "form" + :forms + elsif type == "question_page" + :questions + else + raise "type of records '#{type}' is not one of 'forms', 'question_page'" unless type + end + end +end diff --git a/spec/services/reports/csv_report_service_spec.rb b/spec/services/reports/csv_report_service_spec.rb new file mode 100644 index 000000000..2a6106f17 --- /dev/null +++ b/spec/services/reports/csv_report_service_spec.rb @@ -0,0 +1,34 @@ +require "rails_helper" + +RSpec.describe Reports::CsvReportService do + subject(:csv_report_service) do + described_class.new(records) + end + + describe "#csv" do + context "when records is an empty list" do + let(:records) { [] } + + it "returns an empty string" do + expect(csv_report_service.csv).to eq "" + end + end + + context "when records is a list of form documents" do + let(:records) { JSON.parse(file_fixture("form_documents_response.json").read) } + + it "returns a CSV of forms" do + expect(csv_report_service.csv).to eq Reports::FormsCsvReportService.new(records).csv + end + end + + context "when records is a list of question page documents" do + let(:records) { Reports::FeatureReportService.new(form_documents).questions } + let(:form_documents) { JSON.parse(file_fixture("form_documents_response.json").read) } + + it "returns a CSV of questions" do + expect(csv_report_service.csv).to eq Reports::QuestionsCsvReportService.new(records).csv + end + end + end +end From 763fe2c061f6b289764dd8942916ce61fb3458e6 Mon Sep 17 00:00:00 2001 From: Laurence de Bruxelles Date: Mon, 19 May 2025 11:50:17 +0300 Subject: [PATCH 2/3] Combine routes for feature reports Instead of having a controller action for each feature report, use a single action which gets the report to generate from a dynamic segment in the path. This should mean that in future adding a new feature report should require only adding a new method to FeatureReportService. --- app/controllers/reports_controller.rb | 49 +++---------------- app/views/reports/features.html.erb | 8 +-- config/routes.rb | 7 +-- spec/requests/reports_controller_spec.rb | 32 ++++++------ spec/routing/reports_routing_spec.rb | 42 ++++++++-------- .../reports/feature_report.html.erb_spec.rb | 10 ++-- 6 files changed, 55 insertions(+), 93 deletions(-) diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index f083a4ce7..b1e171b0c 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -19,55 +19,20 @@ def questions_with_answer_type render template: "reports/questions_with_answer_type", locals: { answer_type:, questions: } end - def questions_with_add_another_answer - forms = Reports::FormDocumentsService.live_form_documents - questions = Reports::FeatureReportService.new(forms).questions_with_add_another_answer - - if params[:format] == "csv" - send_data Reports::QuestionsCsvReportService.new(questions).csv, - type: "text/csv; charset=iso-8859-1", - disposition: "attachment; filename=#{csv_filename('live_questions_with_add_another_answer_report')}" - else - render template: "reports/feature_report", locals: { report: params[:action], records: questions } - end - end - - def forms_with_routes - forms = Reports::FormDocumentsService.live_form_documents - forms = Reports::FeatureReportService.new(forms).forms_with_routes - - if params[:format] == "csv" - send_data Reports::FormsCsvReportService.new(forms).csv, - type: "text/csv; charset=iso-8859-1", - disposition: "attachment; filename=#{csv_filename('live_forms_with_routes_report')}" - else - render template: "reports/feature_report", locals: { report: params[:action], records: forms } - end - end - - def forms_with_payments - forms = Reports::FormDocumentsService.live_form_documents - forms = Reports::FeatureReportService.new(forms).forms_with_payments + def feature_report + report = params[:report].underscore - if params[:format] == "csv" - send_data Reports::FormsCsvReportService.new(forms).csv, - type: "text/csv; charset=iso-8859-1", - disposition: "attachment; filename=#{csv_filename('live_forms_with_payments_report')}" - else - render template: "reports/feature_report", locals: { report: params[:action], records: forms } - end - end + raise ActionController::RoutingError unless Reports::FeatureReportService.method_defined? report - def forms_with_csv_submission_enabled forms = Reports::FormDocumentsService.live_form_documents - forms = Reports::FeatureReportService.new(forms).forms_with_csv_submission_enabled + records = Reports::FeatureReportService.new(forms).send report if params[:format] == "csv" - send_data Reports::FormsCsvReportService.new(forms).csv, + send_data Reports::CsvReportService.new(records).csv, type: "text/csv; charset=iso-8859-1", - disposition: "attachment; filename=#{csv_filename('live_forms_with_csv_submission_enabled_report')}" + disposition: "attachment; filename=#{csv_filename("live_#{report}_report")}" else - render template: "reports/feature_report", locals: { report: params[:action], records: forms } + render template: "reports/feature_report", locals: { report:, records: } end end diff --git a/app/views/reports/features.html.erb b/app/views/reports/features.html.erb index 725646a7c..ee7368fda 100644 --- a/app/views/reports/features.html.erb +++ b/app/views/reports/features.html.erb @@ -12,19 +12,19 @@ <% end %> <%= summary_list.with_row do |row| %> <%= row.with_key(text: t(".features.live_forms_with_routes")) %> - <%= row.with_value(text: govuk_link_to(data[:forms_with_routing], report_forms_with_routes_path, no_visited_state: true)) %> + <%= row.with_value(text: govuk_link_to(data[:forms_with_routing], feature_report_path(report: "forms-with-routes"), no_visited_state: true)) %> <% end %> <%= summary_list.with_row do |row| %> <%= row.with_key(text: t(".features.live_forms_with_payments")) %> - <%= row.with_value(text: govuk_link_to(data[:forms_with_payment], report_forms_with_payments_path, no_visited_state: true)) %> + <%= row.with_value(text: govuk_link_to(data[:forms_with_payment], feature_report_path(report: "forms-with-payments"), no_visited_state: true)) %> <% end %> <%= summary_list.with_row do |row| %> <%= row.with_key(text: t(".features.live_forms_with_add_another_answer")) %> - <%= row.with_value(text: govuk_link_to(data[:forms_with_add_another_answer], report_questions_with_add_another_answer_path, no_visited_state: true)) %> + <%= row.with_value(text: govuk_link_to(data[:forms_with_add_another_answer], feature_report_path(report: "questions-with-add-another-answer"), no_visited_state: true)) %> <% end %> <%= summary_list.with_row do |row| %> <%= row.with_key(text: t(".features.live_forms_with_csv_submission_enabled")) %> - <%= row.with_value(text: govuk_link_to(data[:forms_with_csv_submission_enabled], report_forms_with_csv_submission_enabled_path, no_visited_state: true)) %> + <%= row.with_value(text: govuk_link_to(data[:forms_with_csv_submission_enabled], feature_report_path(report: "forms-with-csv-submission-enabled"), no_visited_state: true)) %> <% end %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index f5733054a..ff790334f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -197,11 +197,8 @@ scope "/features" do get "/", to: "reports#features", as: :report_features - get "questions-with-answer-type/:answer_type", to: "reports#questions_with_answer_type", as: :report_questions_with_answer_type - get "questions-with-add-another-answer", to: "reports#questions_with_add_another_answer", as: :report_questions_with_add_another_answer - get "forms-with-routes", to: "reports#forms_with_routes", as: :report_forms_with_routes - get "forms-with-payments", to: "reports#forms_with_payments", as: :report_forms_with_payments - get "forms-with-csv-submission-enabled", to: "reports#forms_with_csv_submission_enabled", as: :report_forms_with_csv_submission_enabled + get "/questions-with-answer-type/:answer_type", to: "reports#questions_with_answer_type", as: :report_questions_with_answer_type + get "/:report", to: "reports#feature_report", as: :feature_report end get "users", to: "reports#users", as: :report_users diff --git a/spec/requests/reports_controller_spec.rb b/spec/requests/reports_controller_spec.rb index 68321ff9e..7fcdce372 100644 --- a/spec/requests/reports_controller_spec.rb +++ b/spec/requests/reports_controller_spec.rb @@ -193,7 +193,7 @@ before do login_as_standard_user - get report_questions_with_add_another_answer_path + get feature_report_path(report: "questions-with-add-another-answer") end it "returns http code 403" do @@ -209,7 +209,7 @@ before do login_as_organisation_admin_user - get report_questions_with_add_another_answer_path + get feature_report_path(report: "questions-with-add-another-answer") end it "returns http code 403" do @@ -225,7 +225,7 @@ before do login_as_super_admin_user - get report_questions_with_add_another_answer_path + get feature_report_path(report: "questions-with-add-another-answer") end it "returns http code 200" do @@ -251,7 +251,7 @@ before do login_as_standard_user - get report_forms_with_routes_path + get feature_report_path(report: "forms-with-routes") end it "returns http code 403" do @@ -267,7 +267,7 @@ before do login_as_organisation_admin_user - get report_forms_with_routes_path + get feature_report_path(report: "forms-with-routes") end it "returns http code 403" do @@ -283,7 +283,7 @@ before do login_as_super_admin_user - get report_forms_with_routes_path + get feature_report_path(report: "forms-with-routes") end it "returns http code 200" do @@ -309,7 +309,7 @@ before do login_as_standard_user - get report_forms_with_payments_path + get feature_report_path(report: "forms-with-payments") end it "returns http code 403" do @@ -325,7 +325,7 @@ before do login_as_organisation_admin_user - get report_forms_with_payments_path + get feature_report_path(report: "forms-with-payments") end it "returns http code 403" do @@ -341,7 +341,7 @@ before do login_as_super_admin_user - get report_forms_with_payments_path + get feature_report_path(report: "forms-with-payments") end it "returns http code 200" do @@ -367,7 +367,7 @@ before do login_as_standard_user - get report_forms_with_csv_submission_enabled_path + get feature_report_path(report: "forms-with-csv-submission-enabled") end it "returns http code 403" do @@ -383,7 +383,7 @@ before do login_as_organisation_admin_user - get report_forms_with_csv_submission_enabled_path + get feature_report_path(report: "forms-with-csv-submission-enabled") end it "returns http code 403" do @@ -399,7 +399,7 @@ before do login_as_super_admin_user - get report_forms_with_csv_submission_enabled_path + get feature_report_path(report: "forms-with-csv-submission-enabled") end it "returns http code 200" do @@ -736,7 +736,7 @@ travel_to Time.utc(2025, 5, 15, 15, 31, 57) - get report_forms_with_routes_path(format: :csv) + get feature_report_path(report: "forms-with-routes", format: :csv) end it_behaves_like "csv response" @@ -762,7 +762,7 @@ travel_to Time.utc(2025, 5, 15, 15, 31, 57) - get report_forms_with_payments_path(format: :csv) + get feature_report_path(report: "forms-with-payments", format: :csv) end it_behaves_like "csv response" @@ -787,7 +787,7 @@ travel_to Time.utc(2025, 5, 15, 15, 31, 57) - get report_forms_with_csv_submission_enabled_path(format: :csv) + get feature_report_path(report: "forms-with-csv-submission-enabled", format: :csv) end it_behaves_like "csv response" @@ -834,7 +834,7 @@ travel_to Time.utc(2025, 5, 15, 15, 31, 57) - get report_questions_with_add_another_answer_path(format: :csv) + get feature_report_path(report: "questions-with-add-another-answer", format: :csv) end it_behaves_like "csv response" diff --git a/spec/routing/reports_routing_spec.rb b/spec/routing/reports_routing_spec.rb index c2aad0ddd..cf01d03dc 100644 --- a/spec/routing/reports_routing_spec.rb +++ b/spec/routing/reports_routing_spec.rb @@ -7,58 +7,58 @@ expect(get: "/reports/features").to route_to("reports#features") end - it "routes to #questions_with_answer_type" do + it "routes to questions_with_answer_type" do expect(get: "/reports/features/questions-with-answer-type/text").to route_to("reports#questions_with_answer_type", answer_type: "text") end - it "routes to #questions_with_add_another_answer" do - expect(get: "/reports/features/questions-with-add-another-answer").to route_to("reports#questions_with_add_another_answer") + it "routes to #feature_report with questions_with_add_another_answer" do + expect(get: "/reports/features/questions-with-add-another-answer").to route_to("reports#feature_report", report: "questions-with-add-another-answer") end - it "routes to #questions_with_add_another_answer with csv format" do - expect(get: "/reports/features/questions-with-add-another-answer.csv").to route_to("reports#questions_with_add_another_answer", format: "csv") + it "routes to #feature_report with questions_with_add_another_answer and csv format" do + expect(get: "/reports/features/questions-with-add-another-answer.csv").to route_to("reports#feature_report", report: "questions-with-add-another-answer", format: "csv") end - it "routes to #forms_with_routes" do - expect(get: "/reports/features/forms-with-routes").to route_to("reports#forms_with_routes") + it "routes to #feature_report with forms_with_routes" do + expect(get: "/reports/features/forms-with-routes").to route_to("reports#feature_report", report: "forms-with-routes") end - it "routes to #forms_with_routes with csv format" do - expect(get: "/reports/features/forms-with-routes.csv").to route_to("reports#forms_with_routes", format: "csv") + it "routes to #feature_report with forms_with_routes and csv format" do + expect(get: "/reports/features/forms-with-routes.csv").to route_to("reports#feature_report", report: "forms-with-routes", format: "csv") end - it "routes to #forms_with_payments" do - expect(get: "/reports/features/forms-with-payments").to route_to("reports#forms_with_payments") + it "routes to #feature_report with forms_with_payments" do + expect(get: "/reports/features/forms-with-payments").to route_to("reports#feature_report", report: "forms-with-payments") end - it "routes to #forms_with_payments with csv format" do - expect(get: "/reports/features/forms-with-payments.csv").to route_to("reports#forms_with_payments", format: "csv") + it "routes to #feature_report with forms_with_payments and csv format" do + expect(get: "/reports/features/forms-with-payments.csv").to route_to("reports#feature_report", report: "forms-with-payments", format: "csv") end - it "routes to #forms_with_csv_submission_enabled" do - expect(get: "/reports/features/forms-with-csv-submission-enabled").to route_to("reports#forms_with_csv_submission_enabled") + it "routes to #feature_report with forms_with_csv_submission_enabled" do + expect(get: "/reports/features/forms-with-csv-submission-enabled").to route_to("reports#feature_report", report: "forms-with-csv-submission-enabled") end - it "routes to #forms_with_csv_submission_enabled with csv format" do - expect(get: "/reports/features/forms-with-csv-submission-enabled.csv").to route_to("reports#forms_with_csv_submission_enabled", format: "csv") + it "routes to #feature_report with forms_with_csv_submission_enabled and csv format" do + expect(get: "/reports/features/forms-with-csv-submission-enabled.csv").to route_to("reports#feature_report", report: "forms-with-csv-submission-enabled", format: "csv") end end describe "path helpers" do it "routes to #questions_with_add_another_answer as csv" do - expect(get: report_questions_with_add_another_answer_path(format: :csv)).to route_to("reports#questions_with_add_another_answer", format: "csv") + expect(get: feature_report_path(report: "questions-with-add-another-answer", format: :csv)).to route_to("reports#feature_report", report: "questions-with-add-another-answer", format: "csv") end it "routes to #forms_with_routes as csv" do - expect(get: report_forms_with_routes_path(format: :csv)).to route_to("reports#forms_with_routes", format: "csv") + expect(get: feature_report_path(report: "forms-with-routes", format: :csv)).to route_to("reports#feature_report", report: "forms-with-routes", format: "csv") end it "routes to #forms_with_payments as csv" do - expect(get: report_forms_with_payments_path(format: :csv)).to route_to("reports#forms_with_payments", format: "csv") + expect(get: feature_report_path(report: "forms-with-payments", format: :csv)).to route_to("reports#feature_report", report: "forms-with-payments", format: "csv") end it "routes to #forms_with_csv_submission_enabled as csv" do - expect(get: report_forms_with_csv_submission_enabled_path(format: :csv)).to route_to("reports#forms_with_csv_submission_enabled", format: "csv") + expect(get: feature_report_path(report: "forms-with-csv-submission-enabled", format: :csv)).to route_to("reports#feature_report", report: "forms-with-csv-submission-enabled", format: "csv") end end end diff --git a/spec/views/reports/feature_report.html.erb_spec.rb b/spec/views/reports/feature_report.html.erb_spec.rb index 9d8cd48ca..095b9b3f4 100644 --- a/spec/views/reports/feature_report.html.erb_spec.rb +++ b/spec/views/reports/feature_report.html.erb_spec.rb @@ -5,7 +5,7 @@ let(:records) { [] } before do - controller.request.path_parameters[:action] = report + controller.request.path_parameters[:report] = report.dasherize render locals: { report:, records: } end @@ -30,7 +30,7 @@ end it "has a link to download the CSV" do - expect(rendered).to have_link("Download data about all live forms with CSV submission enabled as a CSV file", href: report_forms_with_csv_submission_enabled_path(format: :csv)) + expect(rendered).to have_link("Download data about all live forms with CSV submission enabled as a CSV file", href: feature_report_path(report: "forms-with-csv-submission-enabled", format: :csv)) end describe "questions table" do @@ -76,7 +76,7 @@ end it "has a link to download the CSV" do - expect(rendered).to have_link("Download data about all live forms with payments as a CSV file", href: report_forms_with_payments_path(format: :csv)) + expect(rendered).to have_link("Download data about all live forms with payments as a CSV file", href: feature_report_path(report: "forms-with-payments", format: :csv)) end describe "questions table" do @@ -122,7 +122,7 @@ end it "has a link to download the CSV" do - expect(rendered).to have_link("Download data about all live forms with routes as a CSV file", href: report_forms_with_routes_path(format: :csv)) + expect(rendered).to have_link("Download data about all live forms with routes as a CSV file", href: feature_report_path(report: "forms-with-routes", format: :csv)) end describe "questions table" do @@ -171,7 +171,7 @@ end it "has a link to download the CSV" do - expect(rendered).to have_link("Download all questions with add another answer in live forms as a CSV file", href: report_questions_with_add_another_answer_path(format: :csv)) + expect(rendered).to have_link("Download all questions with add another answer in live forms as a CSV file", href: feature_report_path(report: "questions-with-add-another-answer", format: :csv)) end describe "questions table" do From 1d6cda5e6bec96fd97bb2f188b25c51b56857102 Mon Sep 17 00:00:00 2001 From: Laurence de Bruxelles Date: Tue, 20 May 2025 13:04:06 +0300 Subject: [PATCH 3/3] Add constraints for feature report routes Rather than allowing any method on FeatureReportService to be called (and potentially opening up a security hole), this commit adds some metaprogramming machinery to manage a list of methods which are feature reports and adds methods to allow that to be used safely, both to constrain the parameters in the routes and to prevent arbitrary methods from being called from the controller. --- app/controllers/reports_controller.rb | 4 +- .../reports/feature_report_service.rb | 36 ++++++++++++-- config/routes.rb | 2 +- spec/routing/reports_routing_spec.rb | 4 ++ .../reports/feature_report_service_spec.rb | 49 +++++++++++++++++++ 5 files changed, 86 insertions(+), 9 deletions(-) diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index b1e171b0c..22a4332e7 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -22,10 +22,8 @@ def questions_with_answer_type def feature_report report = params[:report].underscore - raise ActionController::RoutingError unless Reports::FeatureReportService.method_defined? report - forms = Reports::FormDocumentsService.live_form_documents - records = Reports::FeatureReportService.new(forms).send report + records = Reports::FeatureReportService.new(forms).report report if params[:format] == "csv" send_data Reports::CsvReportService.new(records).csv, diff --git a/app/services/reports/feature_report_service.rb b/app/services/reports/feature_report_service.rb index f8ebbb1b1..49f1346b0 100644 --- a/app/services/reports/feature_report_service.rb +++ b/app/services/reports/feature_report_service.rb @@ -1,11 +1,37 @@ class Reports::FeatureReportService + def self.define_report(name, &block) + @reports ||= [] + @reports << name + + define_method(name, &block) + end + + def self.matches_report?(name) + @reports.include? name.to_sym + end + + class Constraint + def self.matches?(request) + name = request.params[:report].underscore + Reports::FeatureReportService.matches_report? name + end + end + + private_class_method :define_report + attr_reader :form_documents def initialize(form_documents) @form_documents = form_documents end - def report + def report(name = nil) + unless name.nil? + raise "'#{name}' is not a defined report" unless self.class.matches_report?(name) + + return send(name) + end + report = { total_forms: 0, forms_with_payment: 0, @@ -54,7 +80,7 @@ def questions_with_answer_type(answer_type) end end - def questions_with_add_another_answer + define_report :questions_with_add_another_answer do form_documents.flat_map do |form| form["content"]["steps"] .select { |step| step["data"]["is_repeatable"] } @@ -62,19 +88,19 @@ def questions_with_add_another_answer end end - def forms_with_routes + define_report :forms_with_routes do form_documents .select { |form| Reports::FormDocumentsService.has_routes?(form) } .map { |form| form_with_routes_details(form) } end - def forms_with_payments + define_report :forms_with_payments do form_documents .select { |form| Reports::FormDocumentsService.has_payments?(form) } .map { |form| form_details(form) } end - def forms_with_csv_submission_enabled + define_report :forms_with_csv_submission_enabled do form_documents .select { |form| Reports::FormDocumentsService.has_csv_submission_enabled?(form) } .map { |form| form_details(form) } diff --git a/config/routes.rb b/config/routes.rb index ff790334f..554cf79c7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -198,7 +198,7 @@ scope "/features" do get "/", to: "reports#features", as: :report_features get "/questions-with-answer-type/:answer_type", to: "reports#questions_with_answer_type", as: :report_questions_with_answer_type - get "/:report", to: "reports#feature_report", as: :feature_report + get "/:report", constraints: Reports::FeatureReportService::Constraint, to: "reports#feature_report", as: :feature_report end get "users", to: "reports#users", as: :report_users diff --git a/spec/routing/reports_routing_spec.rb b/spec/routing/reports_routing_spec.rb index cf01d03dc..77ab3808d 100644 --- a/spec/routing/reports_routing_spec.rb +++ b/spec/routing/reports_routing_spec.rb @@ -42,6 +42,10 @@ it "routes to #feature_report with forms_with_csv_submission_enabled and csv format" do expect(get: "/reports/features/forms-with-csv-submission-enabled.csv").to route_to("reports#feature_report", report: "forms-with-csv-submission-enabled", format: "csv") end + + it "does not route to #feature_report if param does not match defined report" do + expect(get: "/reports/features/foobar").not_to route_to("reports#feature_report", report: "foobar") + end end describe "path helpers" do diff --git a/spec/services/reports/feature_report_service_spec.rb b/spec/services/reports/feature_report_service_spec.rb index 949228e2d..caec6b18a 100644 --- a/spec/services/reports/feature_report_service_spec.rb +++ b/spec/services/reports/feature_report_service_spec.rb @@ -11,6 +11,32 @@ GroupForm.create!(form_id: 4, group:) end + describe "Constraint" do + it "returns true if given the name of a defined report in slug format" do + expect(described_class::Constraint.matches?(OpenStruct.new(params: { report: "forms-with-routes" }))).to be true + expect(described_class::Constraint.matches?(OpenStruct.new(params: { report: "questions-with-add-another-answer" }))).to be true + end + + it "returns false if names does not match a defined report" do + expect(described_class.matches_report?(OpenStruct.new(params: { report: "report" }))).to be false + expect(described_class.matches_report?(OpenStruct.new(params: { report: "inspect" }))).to be false + expect(described_class.matches_report?(OpenStruct.new(params: { report: "display" }))).to be false + end + end + + describe ".matches_report?" do + it "returns true if given the name of a defined report" do + expect(described_class.matches_report?(:forms_with_routes)).to be true + expect(described_class.matches_report?(:questions_with_add_another_answer)).to be true + end + + it "returns false if names does not match a defined report" do + expect(described_class.matches_report?(:report)).to be false + expect(described_class.matches_report?(:inspect)).to be false + expect(described_class.matches_report?(:display)).to be false + end + end + describe "#report" do it "returns the feature report" do report = described_class.new(form_documents).report @@ -44,6 +70,29 @@ }, }) end + + context "with the name of a feature report" do + it "returns that report" do + report = [] + feature_report_service = described_class.new(form_documents) + allow(feature_report_service).to receive(:forms_with_routes).and_return report + + expect(feature_report_service.report(:forms_with_routes)).to be report + + expect(feature_report_service).to have_received(:forms_with_routes) + end + end + + context "with the name of a method that is not a feature report" do + it "raises an error" do + feature_report_service = described_class.new(form_documents) + allow(feature_report_service).to receive(:display) + + expect { feature_report_service.report(:display) }.to raise_error(/not a defined report/) + + expect(feature_report_service).not_to have_received(:display) + end + end end describe "#questions" do