From 7ecba902daa0a48e9c82d139563b30714cf3db26 Mon Sep 17 00:00:00 2001 From: Mateusz Grotek Date: Thu, 26 Sep 2024 15:23:12 +0100 Subject: [PATCH] Use breadcrumbs based on organisation if no parent Use breadcrumbs based on ancestors, if the document has a linked parent. Otherwise use breadcrumbs based on the first normal (non-world) organisation the page is linked to. If there are no linked organisations use taxon based breadcrumbs, or if taxons are also not linked to, the default breadcrumbs pointing to the homepage. --- CHANGELOG.md | 1 + .../docs/contextual_breadcrumbs.yml | 3 +- lib/govuk_publishing_components.rb | 1 + .../presenters/breadcrumb_selector.rb | 5 ++ ...tent_breadcrumbs_based_on_organisations.rb | 35 ++++++++ .../presenters/contextual_navigation.rb | 12 +++ .../components/contextual_breadcrumbs_spec.rb | 15 ++++ .../presenters/breadcrumb_selector_spec.rb | 88 +++++++++++++++++++ ...breadcrumbs_based_on_organisations_spec.rb | 24 +++++ .../presenters/contextual_navigation_spec.rb | 81 +++++++++++++++++ 10 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations.rb create mode 100644 spec/lib/govuk_publishing_components/presenters/breadcrumb_selector_spec.rb create mode 100644 spec/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations_spec.rb create mode 100644 spec/lib/govuk_publishing_components/presenters/contextual_navigation_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index bbe2fbf400..bc01e20293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ## Unreleased * Update accessibility criteria in component docs ([PR #4242](https://github.com/alphagov/govuk_publishing_components/pull/4242)) +* Use the first organisation to generate breadcrumbs, if no parent linked ([PR #4270](https://github.com/alphagov/govuk_publishing_components/pull/4270)) ## 43.5.0 diff --git a/app/views/govuk_publishing_components/components/docs/contextual_breadcrumbs.yml b/app/views/govuk_publishing_components/components/docs/contextual_breadcrumbs.yml index 7045bc65ff..bc96261b1f 100644 --- a/app/views/govuk_publishing_components/components/docs/contextual_breadcrumbs.yml +++ b/app/views/govuk_publishing_components/components/docs/contextual_breadcrumbs.yml @@ -4,11 +4,12 @@ body: | This is a complex component that calls other components. For more accurate preview with real data, see the [contextual navigation preview][preview]. - There are 3 main variants of the component: + There are 4 main variants of the component: - Step by step, which uses the [step by step header][header] - Parent breadcrumb, which uses the `parent` link of the page with the [breadcrumbs component][breadcrumbs] - Taxon breadcrumb, which uses the `taxons` link of the page with the [breadcrumbs component][breadcrumbs] + - Organisation breadcrumb, which uses the `organisations` link of the page with the [breadcrumbs component][breadcrumbs] It must always used [together with the contextual sidebar][sidebar] and [footer]. diff --git a/lib/govuk_publishing_components.rb b/lib/govuk_publishing_components.rb index 2f0cb6c4b0..55e6ab342b 100644 --- a/lib/govuk_publishing_components.rb +++ b/lib/govuk_publishing_components.rb @@ -24,6 +24,7 @@ require "govuk_publishing_components/presenters/page_with_step_by_step_navigation" require "govuk_publishing_components/presenters/public_layout_helper" require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_ancestors" +require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations" require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_taxons" require "govuk_publishing_components/presenters/checkboxes_helper" require "govuk_publishing_components/presenters/select_helper" diff --git a/lib/govuk_publishing_components/presenters/breadcrumb_selector.rb b/lib/govuk_publishing_components/presenters/breadcrumb_selector.rb index e301df2e35..f4594034d4 100644 --- a/lib/govuk_publishing_components/presenters/breadcrumb_selector.rb +++ b/lib/govuk_publishing_components/presenters/breadcrumb_selector.rb @@ -55,6 +55,11 @@ def options(navigation) step_by_step: false, breadcrumbs: navigation.breadcrumbs, } + elsif navigation.content_is_a_corporate_information_page? && navigation.content_has_related_organisations? + { + step_by_step: false, + breadcrumbs: navigation.organisation_breadcrumbs, + } elsif navigation.use_taxon_breadcrumbs? { step_by_step: false, diff --git a/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations.rb b/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations.rb new file mode 100644 index 0000000000..1238f1f7e2 --- /dev/null +++ b/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations.rb @@ -0,0 +1,35 @@ +module GovukPublishingComponents + module Presenters + # @private + class ContentBreadcrumbsBasedOnOrganisations + def self.call(content_item) + new(content_item).breadcrumbs + end + + def initialize(content_item) + @content_item = ContentItem.new(content_item) + end + + def breadcrumbs + [ + { title: "Home", url: "/" }, + *organisation_breadcrumbs_items, + ] + end + + private + + attr_reader :content_item + + def organisation_breadcrumbs_items + first_related_organisation = ContentItem.new(content_item.related_organisations.first) + return [] unless first_related_organisation.present? + + [{ + title: first_related_organisation.title, + url: first_related_organisation.base_path, + }] + end + end + end +end diff --git a/lib/govuk_publishing_components/presenters/contextual_navigation.rb b/lib/govuk_publishing_components/presenters/contextual_navigation.rb index 419d850480..04936877c2 100644 --- a/lib/govuk_publishing_components/presenters/contextual_navigation.rb +++ b/lib/govuk_publishing_components/presenters/contextual_navigation.rb @@ -33,6 +33,10 @@ def taxon_breadcrumbs @taxon_breadcrumbs ||= ContentBreadcrumbsBasedOnTaxons.call(content_item) end + def organisation_breadcrumbs + @organisation_breadcrumbs ||= ContentBreadcrumbsBasedOnOrganisations.call(content_item) + end + def breadcrumbs breadcrumbs_based_on_ancestors end @@ -72,6 +76,10 @@ def content_has_curated_related_items? content_item.dig("links", "ordered_related_items").present? && content_item.dig("links", "parent").present? end + def content_has_related_organisations? + ContentItem.new(content_item).related_organisations.present? + end + def content_is_tagged_to_a_live_taxon? content_item.dig("links", "taxons").to_a.any? { |taxon| taxon["phase"] == "live" } end @@ -80,6 +88,10 @@ def content_is_a_specialist_document? content_item["schema_name"] == "specialist_document" end + def content_is_a_corporate_information_page? + content_item["schema_name"] == "corporate_information_page" + end + def content_is_a_html_publication? content_item["document_type"] == "html_publication" end diff --git a/spec/components/contextual_breadcrumbs_spec.rb b/spec/components/contextual_breadcrumbs_spec.rb index 1fe0851c5f..7a1bcd5d9b 100644 --- a/spec/components/contextual_breadcrumbs_spec.rb +++ b/spec/components/contextual_breadcrumbs_spec.rb @@ -97,6 +97,21 @@ def set_live_taxons(content_item) assert_select ".gem-c-breadcrumbs.gem-c-breadcrumbs--inverse" end + it "renders parent-based breadcrumbs if the content item is a corporate information page with a parent" do + content_item = example_document_for("corporate_information_page", "corporate_information_page_complaints") + render_component(content_item:) + assert_select "a", text: "Home" + assert_select "a", text: "Department of Health" + assert_select "a", text: "About us" + end + + it "renders organisation breadcrumbs if the content item is a corporate information page with no parent but with a linked organisation" do + content_item = example_document_for("corporate_information_page", "best-practice-about-page") + render_component(content_item:) + assert_select "a", text: "Home" + assert_select "a", text: "Intellectual Property Office" + end + it "renders no taxon breadcrumbs if they are not live" do content_item = example_document_for("guide", "guide") content_item = remove_mainstream_browse(content_item) diff --git a/spec/lib/govuk_publishing_components/presenters/breadcrumb_selector_spec.rb b/spec/lib/govuk_publishing_components/presenters/breadcrumb_selector_spec.rb new file mode 100644 index 0000000000..75723e1d11 --- /dev/null +++ b/spec/lib/govuk_publishing_components/presenters/breadcrumb_selector_spec.rb @@ -0,0 +1,88 @@ +require "spec_helper" + +RSpec.describe GovukPublishingComponents::Presenters::BreadcrumbSelector do + subject do + described_class.new( + content_item, + request, + prioritise_taxon_breadcrumbs, + disable_ga4, + ) + end + let(:example) { %w[guide guide] } + let(:content_item) { example_document_for(example.first, example.secomd) } + let(:path) { content_item["base_path"] } + let(:query_parameters) { {} } + let(:request) { instance_double("ActionDispatch::Request", path:, query_parameters:) } + let(:prioritise_taxon_breadcrumbs) { false } + let(:disable_ga4) { false } + + def example_document_for(schema_name, example_name) + GovukSchemas::Example.find(schema_name, example_name:) + end + + describe "#initialize" do + it "does not raise exception" do + expect { subject }.not_to raise_error + end + end + + describe "#breadcrumbs" do + context "when content item is corporate information page with parent" do + let(:example) { %w[corporate_information_page corporate_information_page_complaints] } + + it "returns breadcrumbs based on ancestors" do + expect(subject.breadcrumbs).to eq([ + { title: "Home", url: "/" }, + { title: "Department of Health", url: "/government/organisations/department-of-health" }, + { title: "About us", url: "/government/organisations/department-of-health/about" }, + ]) + end + end + + context "when content item is corporate information page without parent but with organisation" do + let(:example) { %w[corporate_information_page best-practice-about-page] } + + it "returns breadcrumbs based on organisation" do + expect(subject.breadcrumbs).to eq([ + { title: "Home", url: "/" }, + { title: "Intellectual Property Office", url: "/government/organisations/intellectual-property-office" }, + ]) + end + end + + context "when content item is corporate information page without parent, organisations but with taxon" do + let(:content_item) do + item = example_document_for("corporate_information_page", "best-practice-about-page") + item.dig("links", "organisations").clear + item["links"]["taxons"] = [{ + "base_path" => "/corporate-information", + "title" => "Corporate information", + "phase" => "live", + }] + item + end + + it "returns breadcrumbs based on taxons" do + expect(subject.breadcrumbs).to eq([ + { title: "Home", url: "/", is_page_parent: false }, + { title: "Corporate information", url: "/corporate-information", is_page_parent: true }, + ]) + end + end + + context "when content item is corporate information page without parent, organisations and taxons" do + let(:content_item) do + item = example_document_for("corporate_information_page", "best-practice-about-page") + item.dig("links", "organisations").clear + item + end + + it "returns default breadcrumbs" do + expect(subject.breadcrumbs).to eq([ + { title: "Home", url: "/" }, + ]) + end + end + end +end diff --git a/spec/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations_spec.rb b/spec/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations_spec.rb new file mode 100644 index 0000000000..ba09ef0c66 --- /dev/null +++ b/spec/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations_spec.rb @@ -0,0 +1,24 @@ +require "spec_helper" + +RSpec.describe GovukPublishingComponents::Presenters::ContentBreadcrumbsBasedOnOrganisations do + subject { described_class.new(content_item) } + let(:content_item) { GovukSchemas::Example.find("document_collection", example_name: "document_collection") } + + describe "#initialize" do + it "does not raise exception" do + expect { subject }.not_to raise_error + end + end + + describe "#breadcrumbs" do + it "returns breadcrumbs based on organisation" do + expect(subject.breadcrumbs).to eq([ + { title: "Home", url: "/" }, + { + title: "Driver and Vehicle Standards Agency", + url: "/government/organisations/driver-and-vehicle-standards-agency", + }, + ]) + end + end +end diff --git a/spec/lib/govuk_publishing_components/presenters/contextual_navigation_spec.rb b/spec/lib/govuk_publishing_components/presenters/contextual_navigation_spec.rb new file mode 100644 index 0000000000..cda5c31652 --- /dev/null +++ b/spec/lib/govuk_publishing_components/presenters/contextual_navigation_spec.rb @@ -0,0 +1,81 @@ +require "spec_helper" + +RSpec.describe GovukPublishingComponents::Presenters::ContextualNavigation do + subject { described_class.new(content_item, request) } + let(:content_item) { GovukSchemas::Example.find("guide", example_name: "guide") } + let(:path) { content_item["base_path"] } + let(:query_parameters) { {} } + let(:request) { instance_double("ActionDispatch::Request", path:, query_parameters:) } + + describe "#initialize" do + it "does not raise exception" do + expect { subject }.not_to raise_error + end + end + + describe "#organisation_breadcrumbs" do + it "calls ContentBreadcrumbsBasedOnOrganisation" do + called_class = GovukPublishingComponents::Presenters::ContentBreadcrumbsBasedOnOrganisations + expect(called_class).to receive(:call) + .with(content_item) + .and_return([]) + subject.organisation_breadcrumbs + end + end + + describe "#content_has_related_organisations?" do + context "when content item is linked to no organisations" do + let(:content_item) do + GovukSchemas::Example.find( + "homepage", + example_name: "homepage_with_popular_links_on_govuk", + ) + end + + it "returns false" do + expect(subject.content_has_related_organisations?).to be(false) + end + end + + context "when content item is only linked to world organisations" do + let(:content_item) do + GovukSchemas::Example.find( + "worldwide_corporate_information_page", + example_name: "worldwide_corporate_information_page", + ) + end + + it "returns false" do + expect(subject.content_has_related_organisations?).to be(false) + end + end + + context "when content item is linked to at least 1 normal organisation" do + let(:content_item) { GovukSchemas::Example.find("document_collection", example_name: "document_collection") } + + it "returns true" do + expect(subject.content_has_related_organisations?).to be(true) + end + end + end + + describe "#content_is_a_corporate_information_page?" do + context "when content item is corporate information page" do + let(:content_item) do + GovukSchemas::Example.find("corporate_information_page", example_name: "corporate_information_page") + end + + it "returns true" do + expect(subject.content_is_a_corporate_information_page?).to be(true) + end + end + + context "when content item is not corporate information page" do + let(:content_item) { GovukSchemas::Example.find("guide", example_name: "guide") } + + it "returns false" do + expect(subject.content_is_a_corporate_information_page?).to be(false) + end + end + end +end