Skip to content

Commit

Permalink
Merge pull request #1437 from alphagov/faq-page-arbitrary-depth
Browse files Browse the repository at this point in the history
Make FAQs look deeper in the page for questions
  • Loading branch information
sihugh authored Apr 16, 2020
2 parents 2416784 + bee6294 commit 1bbf14c
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
useful summary for people upgrading their application, not a replication
of the commit log.

## Unreleased

* Make FAQs look deeper in the page for questions ([PR #1437](https://github.com/alphagov/govuk_publishing_components/pull/1437))

## 21.41.1

* Fix button alignment on cookie-banner ([PR #1450](https://github.com/alphagov/govuk_publishing_components/pull/1450))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,42 @@ def question_and_answers(html)

question = page.title

# rubocop:disable Style/IfInsideElse
doc.xpath("html/body").children.each_with_object({}) do |element, q_and_as|
if question_element?(element)
question = element.text
q_and_as[question] = { anchor: element["id"] }
else
if question_hash_is_unset?(q_and_as, question)
q_and_as[question] = { answer: element.to_s }
elsif answer_is_unset?(q_and_as, question)
q_and_as[question][:answer] = element.to_s
else
q_and_as[question][:answer] << element.to_s
_q_and_as, question = recursive_question_and_answers(element, question, q_and_as)
end
end

def recursive_question_and_answers(element, question, q_and_as)
if is_a_question?(element)
question = element.text
q_and_as[question] = { anchor: element["id"] }
else
q_and_as = add_answer_to_question(q_and_as, element, question)
element.children.each do |child_element|
if child_element.element?
q_and_as, question = recursive_question_and_answers(child_element, question, q_and_as)
end
end
end
# rubocop:enable Style/IfInsideElse

[q_and_as, question]
end

def add_answer_to_question(q_and_as, element, question)
if no_questions_in_subtree?(element)
if question_hash_is_unset?(q_and_as, question)
q_and_as[question] = { answer: element.to_s }
elsif answer_is_unset?(q_and_as, question)
q_and_as[question][:answer] = element.to_s
else
q_and_as[question][:answer] << element.to_s
end
end
q_and_as
end

def no_questions_in_subtree?(element)
element.search(QUESTION_TAG).none?
end

def question_hash_is_unset?(q_and_as, question)
Expand All @@ -86,7 +106,7 @@ def answer_is_unset?(q_and_as, question)
# we use H2 tags as the "question" and the html between them as the "answer"
QUESTION_TAG = "h2".freeze

def question_element?(element)
def is_a_question?(element)
element.name == QUESTION_TAG
end

Expand Down
36 changes: 36 additions & 0 deletions spec/lib/govuk_publishing_components/presenters/schema_org_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,42 @@ def transaction_content_item(organisations = [], ordered_related_items = [])
expect(q_and_a.map { |faq| faq["name"] }).to_not include("Step two")
end

it "parses nested questions" do
part_body = "<div>
<main>
<h2 id='step-one'>Step one</h2>
<p>First catch your dragon</p>
<h2 id='step-two'>Step two</h2>
<p>Give it a treat</p>
<h2 id='step-three'>Step three</h2>
<p>Give it a pat (wear gloves)</p>
</main>
</div>
"

content_item = dragon_guide

q_and_a = generate_structured_data(
content_item: content_item,
schema: :faq,
body: part_body,
).structured_data["mainEntity"]

expect(q_and_a.count).to eq(3)

expect(q_and_a.first["url"]).to eq("http://www.dev.gov.uk/how-to-train-your-dragon#step-one")
expect(q_and_a.second["url"]).to eq("http://www.dev.gov.uk/how-to-train-your-dragon#step-two")

expect(q_and_a.first["name"]).to eq("Step one")
expect(q_and_a.first["acceptedAnswer"]["text"].strip).to eq("<p>First catch your dragon</p>")

expect(q_and_a.second["name"]).to eq("Step two")
expect(q_and_a.second["acceptedAnswer"]["text"].strip).to eq("<p>Give it a treat</p>")

expect(q_and_a.third["name"]).to eq("Step three")
expect(q_and_a.third["acceptedAnswer"]["text"].strip).to eq("<p>Give it a pat (wear gloves)</p>")
end

it "handles an empty body to ensure that preview works OK" do
empty_part_body = ""
content_item = dragon_guide
Expand Down

0 comments on commit 1bbf14c

Please sign in to comment.