diff --git a/app/models/benchmarking_ab_test_request.rb b/app/models/benchmarking_ab_test_request.rb new file mode 100644 index 000000000..58d3c147e --- /dev/null +++ b/app/models/benchmarking_ab_test_request.rb @@ -0,0 +1,22 @@ +class BenchmarkingAbTestRequest + attr_accessor :requested_variant + + delegate :analytics_meta_tag, to: :requested_variant + + def initialize(request) + dimension = Rails.application.config.benchmarking_ab_test_dimension + ab_test = GovukAbTesting::AbTest.new( + "Benchmarking", + dimension: dimension + ) + @requested_variant = ab_test.requested_variant(request.headers) + end + + def in_benchmarking? + requested_variant.variant_b? + end + + def set_response_vary_header(response) + requested_variant.configure_response(response) + end +end diff --git a/app/presenters/specialist_document_presenter.rb b/app/presenters/specialist_document_presenter.rb index feaa9f0d2..6c13c6c9b 100644 --- a/app/presenters/specialist_document_presenter.rb +++ b/app/presenters/specialist_document_presenter.rb @@ -15,8 +15,132 @@ def title_and_context end end + def metadata + super.tap do |m| + facets_with_values.each do |facet| + m[:other][facet['name']] = join_facets(facet) + end + end + end + + def document_footer + super.tap do |m| + m[:other_dates] = {} + facets_with_values.each do |facet| + type = facet['type'] == 'date' ? :other_dates : :other + m[type][facet['name']] = join_facets(facet) + end + end + end + + def breadcrumbs + return [] unless finder + + [ + { + title: "Home", + url: "/", + }, + { + title: finder['title'], + url: finder['base_path'], + } + ] + end + private + def join_facets(facet) + facet['values'].join(', ') + end + + def finder + first_finder = content_item.dig("links", "finder", 0) + Airbrake.notify("Finder not found", + error_message: + "All specialist documents should have at least one finder" + ) if first_finder.nil? + first_finder + end + + def facets + return nil unless finder + finder.dig('details', 'facets') + end + + def facet_values + # Metadata is a required field + content_item["details"]["metadata"] + end + + def facets_with_values + return [] unless facets && facet_values.any? + only_facets_with_values = facets.select { |f| facet_values[f['key']] } + + only_facets_with_values.map do |facet| + facet_key = facet['key'] + # Cast all values into an array + values = [facet_values[facet_key]].flatten + + facet['values'] = case facet['type'] + when 'date' + friendly_facet_date(values) + when 'text' + friendly_facet_text(facet, values) + else + values + end + + facet + end + end + + def friendly_facet_date(dates) + dates.map { |date| display_date(date) } + end + + def friendly_facet_text(facet, values) + if facet['allowed_values'] && facet['allowed_values'].any? + check_allowed_values(facet, values) + facet_blocks(facet, values) + else + values + end + end + + def check_allowed_values(facet, values) + allowed_values = facet['allowed_values'].map { |av| av["value"] } + not_allowed = "facet value not in list of allowed values" + + values.each do |v| + Airbrake.notify(not_allowed) unless allowed_values.include?(v) + end + end + + # the facet value comes back bare, and without a label + # so we use the value in the url, and cross reference + # the allowed_values to get the label ##funky + def facet_blocks(facet, values) + values.map do |value| + values_with_label = facet["allowed_values"] + allowed_value = values_with_label.select { |av| + av["value"] == value + }.first + facet_block(facet, allowed_value) + end + end + + def facet_block(facet, allowed_value) + return allowed_value['label'] unless facet['filterable'] + facet_link(allowed_value['label'], allowed_value['value'], facet['key']) + end + + def facet_link(label, value, key) + finder_base_path = finder['base_path'] + link_to(label, "#{finder_base_path}?#{key}%5B%5D=#{value}") + end + + # first_published_at does not have reliable data # at time of writing dates could be after public_updated_at # details.first_public_at is not provided @@ -27,4 +151,14 @@ def first_public_at changes = reverse_chronological_change_history changes.any? ? changes.last[:timestamp] : nil end + + # specialist document change history can have a modified date that is + # slightly different to the public_updated_at, eg milliseconds different + # this means the direct comparison in updatable gives a false positive + # Use change_history as specialist-frontend did + # + # Can be removed when first_published_at is reliable + def any_updates? + change_history.size > 1 + end end diff --git a/test/integration/specialist_document_test.rb b/test/integration/specialist_document_test.rb index bb48f43cd..346fee9eb 100644 --- a/test/integration/specialist_document_test.rb +++ b/test/integration/specialist_document_test.rb @@ -1,6 +1,13 @@ require 'test_helper' class SpecialistDocumentTest < ActionDispatch::IntegrationTest + test "random but valid items do not error" do + setup_and_visit_random_content_item(document_type: 'aaib_report') + setup_and_visit_random_content_item(document_type: 'raib_report') + setup_and_visit_random_content_item(document_type: 'tax_tribunal_decision') + setup_and_visit_random_content_item(document_type: 'cma_case') + end + test "renders title, description and body" do setup_and_visit_content_item('aaib-reports') @@ -33,13 +40,65 @@ class SpecialistDocumentTest < ActionDispatch::IntegrationTest within shared_component_selector("document_footer") do component_args = JSON.parse(page.text) history = component_args.fetch("history") - assert_equal history.first["note"], @content_item["details"]["change_history"].last["note"] assert_equal history.last["note"], @content_item["details"]["change_history"].first["note"] assert_equal history.size, @content_item["details"]["change_history"].size end end + test "renders text facets correctly" do + setup_and_visit_content_item('countryside-stewardship-grants') + + def test_meta(component) + within shared_component_selector(component) do + component_args = JSON.parse(page.text) + assert_equal component_args["other"]["Grant type"], "Option" + assert_equal component_args["other"]["Tiers or standalone items"], + ["Higher Tier", + "Mid Tier"].join(", ") + assert_equal component_args["other"]["Land use"], + ["Arable land", + "Wildlife package", + "Water quality", + "Wildlife package"].join(", ") + assert_equal component_args["other"]["Funding (per unit per year)"], + "More than £500" + end + end + test_meta("document_footer") + test_meta("metadata") + end + + test "renders date facets correctly" do + setup_and_visit_content_item('drug-device-alerts') + + within shared_component_selector("document_footer") do + component_args = JSON.parse(page.text) + assert_equal component_args["other_dates"]["Issued"], "6 July 2015" + end + + within shared_component_selector("metadata") do + component_args = JSON.parse(page.text) + assert_equal component_args["other"]["Issued"], "6 July 2015" + end + end + + + test "renders when no facet or finder" do + setup_and_visit_content_item('business-finance-support-scheme') + assert_has_component_metadata_pair("first_published", "9 July 2015") + + within shared_component_selector("document_footer") do + component_args = JSON.parse(page.text) + assert_equal component_args["other_dates"], {} + end + + within shared_component_selector("metadata") do + component_args = JSON.parse(page.text) + assert_equal component_args["other"], {} + end + end + test "renders a contents list" do setup_and_visit_content_item('aaib-reports') diff --git a/test/presenters/specialist_document_presenter_test.rb b/test/presenters/specialist_document_presenter_test.rb index a861c398a..20926d6f0 100644 --- a/test/presenters/specialist_document_presenter_test.rb +++ b/test/presenters/specialist_document_presenter_test.rb @@ -26,6 +26,31 @@ class PresentedSpecialistDocument < SpecialistDocumentTestCase assert presented_item('aaib-reports').is_a?(ContentsList) end + test 'presents updates based on change history' do + example = schema_item('aaib-reports') + example["details"]["change_history"] = [ + { + "note" => "First published", + "public_timestamp" => "2003-03-03" + } + ] + + refute present_example(example).updated + + example["details"]["change_history"] = [ + { + "note" => "First published", + "public_timestamp" => "2003-03-03" + }, + { + "note" => "Modified since first published", + "public_timestamp" => "2013-04-05" + } + ] + + assert present_example(example).updated + end + test 'presents the published date using the oldest date in the change history' do example = schema_item('aaib-reports') example["first_published_at"] = "2001-01-01" @@ -58,4 +83,144 @@ class PresentedSpecialistDocument < SpecialistDocumentTestCase assert_equal title_component_params, presented_item('aaib-reports').title_and_context end end + + class PresentedSpecialistDocumentWithFinderFacets < SpecialistDocumentTestCase + def example_with_finder_facets(facets = [], values = {}) + example = schema_item('aaib-reports') + example_finder = { + "base_path" => "/finder-base-path", + "title" => "Finder title", + "details" => { + "document_noun" => "case", + "filter" => { + "document_type" => "cma_case" + }, + "format_name" => "Competition and Markets Authority case", + "facets" => facets, + }, + } + + example['details']['metadata'] = values + example['links']['finder'] = [example_finder] + example + end + + def example_facet(overrides = {}) + { + "name" => "Facet name", + "key" => "facet-key", + "type" => "text", + "filterable" => false + }.merge(overrides) + end + + test 'includes non-filterable facet as text in metadata and document footer' do + values = { "facet-key" => "document-value" } + example = example_with_finder_facets([example_facet], values) + + presented = present_example(example) + assert_equal "document-value", presented.metadata[:other]["Facet name"] + assert_equal "document-value", presented.document_footer[:other]["Facet name"] + end + + test 'includes friendly label for facet value in metadata and document footer' do + overrides = { + "allowed_values" => [ + { + "label" => "Document value from label", + "value" => "document-value" + } + ] + } + + values = { "facet-key" => "document-value" } + example = example_with_finder_facets([example_facet(overrides)], values) + + presented = present_example(example) + assert_equal "Document value from label", presented.metadata[:other]["Facet name"] + assert_equal "Document value from label", presented.document_footer[:other]["Facet name"] + end + + test 'handles multiple values for facets' do + overrides = { + "allowed_values" => [ + { + "label" => "One", + "value" => "one" + }, + { + "label" => "Two", + "value" => "two" + } + ] + } + + values = { "facet-key" => %w{one two} } + example = example_with_finder_facets([example_facet(overrides)], values) + + presented = present_example(example) + assert_equal "One, Two", presented.metadata[:other]["Facet name"] + assert_equal "One, Two", presented.document_footer[:other]["Facet name"] + end + + test 'creates links for filterable friendly values' do + overrides = { + "filterable" => true, + "allowed_values" => [ + { + "label" => "Something", + "value" => "something" + } + ] + } + + values = { "facet-key" => "something" } + example = example_with_finder_facets([example_facet(overrides)], values) + + presented = present_example(example) + expected_link = "Something" + assert_equal expected_link, presented.metadata[:other]["Facet name"] + assert_equal expected_link, presented.document_footer[:other]["Facet name"] + end + + test 'includes friendly dates for date facets in metadata' do + overrides = { "type" => "date" } + values = { "facet-key" => "2010-01-01" } + example = example_with_finder_facets([example_facet(overrides)], values) + + presented_metadata = present_example(example).metadata[:other] + assert_equal "1 January 2010", presented_metadata["Facet name"] + end + + test 'includes friendly dates in other_dates for date facets in document footer' do + overrides = { "type" => "date" } + values = { "facet-key" => "2010-01-01" } + example = example_with_finder_facets([example_facet(overrides)], values) + + presented_metadata = present_example(example).document_footer[:other_dates] + assert_equal "1 January 2010", presented_metadata["Facet name"] + end + + test 'breadcrumbs' do + assert_equal [ + { + title: "Home", + url: "/" + }, + { + title: "Finder title", + url: "/finder-base-path" + } + ], present_example(example_with_finder_facets).breadcrumbs + end + + test 'no breadcrumbs render with no finder' do + example = schema_item('aaib-reports') + example['links']['finder'] = [] + assert_equal [], present_example(example).breadcrumbs + + example['links'].delete('finder') + assert_equal [], present_example(example).breadcrumbs + end + end end