Skip to content

Commit

Permalink
Refactor into modules
Browse files Browse the repository at this point in the history
This refactors the matchers and the helper into modules.
  • Loading branch information
frankieroberto committed Sep 11, 2023
1 parent de855b4 commit 13ef162
Show file tree
Hide file tree
Showing 3 changed files with 248 additions and 171 deletions.
129 changes: 92 additions & 37 deletions lib/click_govuk_link.rb
Original file line number Diff line number Diff line change
@@ -1,55 +1,110 @@
module GovukRspecHelpers
class ClickLink

def click_govuk_link(link_text)
valid_link_classes = ["govuk-link", "govuk-breadcrumbs__link", "govuk-back-link", "govuk-header__link", "govuk-footer__link", "govuk-notification-banner__link", "govuk-skip-link", "govuk-tabs__tab"]
attr_reader :link_text, :page

ambiguous_link_texts = ["Change", "Add", "Remove"]
VALID_LINK_CLASSES = ["govuk-link", "govuk-breadcrumbs__link", "govuk-back-link", "govuk-header__link", "govuk-footer__link", "govuk-notification-banner__link", "govuk-skip-link", "govuk-tabs__tab"]

links = all('a', text: link_text, exact_text: true, normalize_ws: true)
AMIBIGOUS_LINK_TEXTS = ["Change", "Add", "Remove"]

if links.size == 0
links_without_exact_match = all('a', text: link_text)
links_with_href_match = all(:link, href: link_text)
links_with_id_match = all(:link, link_text)
def initialize(page:, link_text:)
@page = page
@link_text = link_text
end

def click
@links = page.all('a', text: link_text, exact_text: true, normalize_ws: true)

if @links.size == 0
check_whether_there_is_an_inexact_match
check_whether_there_is_an_href_match
check_whether_there_is_an_id_match

raise "Unable to find link \"#{link_text}\""
end

check_link_text_is_unique
check_link_text_is_not_ambiguous

@link = @links.first
@link_classes = @link[:class].to_s.split(/\s/).collect(&:strip)

if links_without_exact_match.size > 0
raise "Unable to find link \"#{link_text}\" but did find link with the text \"#{links_without_exact_match.first.text}\" - include the full link text including any visually-hidden text"
elsif links_with_href_match.size > 0
raise "Use the full link text within click_govuk_link() instead of the link href"
elsif links_with_id_match.size > 0
raise "Use the full link text within click_govuk_link() instead of the link id"
else
raise "Unable to find link \"#{link_text}\""
check_link_is_not_styled_as_button
check_link_warns_if_opening_in_a_new_tab
check_link_does_not_contain_a_button
check_link_has_a_valid_class

@link.click
end

elsif links.size > 1
raise "There are #{links.size} links with the link text \"#{link_text}\" - links should be unique within a page"
end
private

if ambiguous_link_texts.include?(link_text.strip)
raise "The link was found, but the text \"#{link_text}\" is ambiguous if heard out of context - add some visually-hidden text"
end
def check_whether_there_is_an_inexact_match
links_without_exact_match = page.all('a', text: link_text)
if page.all('a', text: link_text).size > 0
raise "Unable to find link \"#{link_text}\" but did find link with the text \"#{links_without_exact_match.first.text}\" - include the full link text including any visually-hidden text"
end
end

def check_whether_there_is_an_href_match
links_with_href_match = page.all(:link, href: link_text)
if links_with_href_match.size > 0
raise "Use the full link text within click_govuk_link() instead of the link href"
end
end

link = links.first
def check_whether_there_is_an_id_match
links_with_id_match = page.all(:link, link_text)
if links_with_id_match.size > 0
raise "Use the full link text within click_govuk_link() instead of the link id"
end
end

link_classes = link[:class].to_s.split(/\s/).collect(&:strip)
def check_link_text_is_not_ambiguous
if AMIBIGOUS_LINK_TEXTS.include?(link_text.strip)
raise "The link was found, but the text \"#{link_text}\" is ambiguous if heard out of context - add some visually-hidden text"
end
end

if link_classes.include?('govuk-button')
raise "The link was found, but is styled as a button. Use `click_govuk_button` instead."
end
def check_link_text_is_unique
if @links.size > 1
raise "There are #{@links.size} links with the link text \"#{link_text}\" - links should be unique within a page"
end
end

def check_link_is_not_styled_as_button
if @link_classes.include?('govuk-button')
raise "The link was found, but is styled as a button. Use `click_govuk_button` instead."
end
end

if link[:target] == "_blank" && !link_text.include?("opens in new tab")
raise "The link was found, but is set to open in a new tab. Either remove this, or add \"(opens in new tab)\" to the link text"
def check_link_warns_if_opening_in_a_new_tab
if @link[:target] == "_blank" && !link_text.include?("opens in new tab")
raise "The link was found, but is set to open in a new tab. Either remove this, or add \"(opens in new tab)\" to the link text"
end
end

def check_link_does_not_contain_a_button
if @link.all('button').any?
raise "The link was found, but it contains a button – use either a link or button but not both"
end
end

def check_link_has_a_valid_class
if @link_classes.empty?
raise "\"#{link_text}\" link is missing a class, should contain \"govuk-link\""
elsif !@link_classes.any? {|link_class| VALID_LINK_CLASSES.include?(link_class) }
raise "\"#{link_text}\" link is missing a govuk-link class, contains #{@link_classes.join(', ')}"
end
end
end

if link.all('button').any?
raise "The link was found, but it contains a button – use either a link or button but not both"
def click_govuk_link(link_text)
ClickLink.new(page: page, link_text: link_text).click
end

if link_classes.any? {|link_class| valid_link_classes.include?(link_class) }
link.click
elsif link_classes.empty?
raise "\"#{link_text}\" link is missing a class, should contain \"govuk-link\""
else
raise "\"#{link_text}\" link is missing a govuk-link class, contains #{link_classes.join(', ')}"
RSpec.configure do |rspec|
rspec.include self
end

end
184 changes: 97 additions & 87 deletions lib/summarise_errors_matcher.rb
Original file line number Diff line number Diff line change
@@ -1,109 +1,119 @@
RSpec::Matchers.define :summarise_errors do |expected|
match do |_actual|
title_contains_prefix &&
error_summary_title &&
expected.all? do |expected_error|
error_messages && error_messages[expected.index(expected_error)] == expected_error
end && expected.size == error_messages.size &&
all_error_messages_contain_links &&
all_error_messages_links_are_valid
end
module GovukRspecHelpers
module SummariseErrorsMatcher

extend RSpec::Matchers::DSL

define :summarise_errors do |expected|
match do |_actual|
title_contains_prefix &&
error_summary_title &&
expected.all? do |expected_error|
error_messages && error_messages[expected.index(expected_error)] == expected_error
end && expected.size == error_messages.size &&
all_error_messages_contain_links &&
all_error_messages_links_are_valid
end

failure_message do |actual|
missing_error = expected.find {|expected_error| !error_messages.include?(expected_error) }
if !title
"Missing <title> tag"
elsif !title_contains_prefix
"Title tag is missing the error prefix: ‘#{title}’"
elsif !error_summary_title
"Missing an error summary title"
elsif missing_error
"Missing error message: ‘#{missing_error}’"
elsif !all_error_messages_contain_links
"Error message ‘#{error_message_missing_link}’ isn’t linked to anything"
elsif !all_error_messages_links_are_valid
"Error message ‘#{error_message_with_invalid_link.text(normalize_ws: true)}’ links to ##{error_message_with_invalid_link[:href].split('#').last} but no input field has this ID or name"
elsif expected.size == error_messages.size
"Error messages appear in a different order"
elsif expected.size < error_messages.size
"An extra error message is present"
else
"Unexpected error"
end
end
failure_message do |actual|
missing_error = expected.find {|expected_error| !error_messages.include?(expected_error) }
if !title
"Missing <title> tag"
elsif !title_contains_prefix
"Title tag is missing the error prefix: ‘#{title}’"
elsif !error_summary_title
"Missing an error summary title"
elsif missing_error
"Missing error message: ‘#{missing_error}’"
elsif !all_error_messages_contain_links
"Error message ‘#{error_message_missing_link}’ isn’t linked to anything"
elsif !all_error_messages_links_are_valid
"Error message ‘#{error_message_with_invalid_link.text(normalize_ws: true)}’ links to ##{error_message_with_invalid_link[:href].split('#').last} but no input field has this ID or name"
elsif expected.size == error_messages.size
"Error messages appear in a different order"
elsif expected.size < error_messages.size
"An extra error message is present"
else
"Unexpected error"
end
end

def html
@html ||= Capybara::Node::Simple.new(actual.is_a?(String) ? actual : actual.html)
end
def html
@html ||= Capybara::Node::Simple.new(actual.is_a?(String) ? actual : actual.html)
end

def title
@title ||= html.title
end
def title
@title ||= html.title
end

def title_contains_prefix
title.to_s.start_with?("Error: ")
end
def title_contains_prefix
title.to_s.start_with?("Error: ")
end

def all_error_messages_contain_links
error_message_items.all? do |error_message_item|
error_message_item.all(:link).first
end
end
def all_error_messages_contain_links
error_message_items.all? do |error_message_item|
error_message_item.all(:link).first
end
end

def all_error_messages_links_are_valid
error_message_items.all? do |error_message_item|
link = error_message_item.all(:link).first
def all_error_messages_links_are_valid
error_message_items.all? do |error_message_item|
link = error_message_item.all(:link).first

if link
link_fragment = link[:href].split('#').last
if link
link_fragment = link[:href].split('#').last

link_target= html.all(id: link_fragment).first || html.all(:field, name: link_fragment).first
link_target= html.all(id: link_fragment).first || html.all(:field, name: link_fragment).first

link_target
else
false
link_target
else
false
end
end
end
end
end

def error_message_with_invalid_link
invalid_link = error_message_links.find do |error_message_link|
link_fragment = error_message_link[:href].split('#').last
def error_message_with_invalid_link
invalid_link = error_message_links.find do |error_message_link|
link_fragment = error_message_link[:href].split('#').last

link_target= html.all(id: link_fragment).first || html.all(:field, name: link_fragment).first
link_target= html.all(id: link_fragment).first || html.all(:field, name: link_fragment).first

!link_target
end
end
!link_target
end
end

def error_message_missing_link
error_message_items.find do |error_message_item|
!error_message_item.all(:link).first
end.text(normalize_ws: true)
end
def error_message_missing_link
error_message_items.find do |error_message_item|
!error_message_item.all(:link).first
end.text(normalize_ws: true)
end

def error_messages
@error_messages ||= (error_summary_list && error_summary_list.all('li').collect {|li| li.text(normalize_ws: true) } || [])
end
def error_messages
@error_messages ||= (error_summary_list && error_summary_list.all('li').collect {|li| li.text(normalize_ws: true) } || [])
end

def error_message_links
@error_message_links ||= error_message_items.collect {|item| item.all(:link).first }
end
def error_message_links
@error_message_links ||= error_message_items.collect {|item| item.all(:link).first }
end

def error_message_items
@error_message_items ||= (error_summary_list && error_summary_list.all('li') || [])
end
def error_message_items
@error_message_items ||= (error_summary_list && error_summary_list.all('li') || [])
end

def error_summary_list
@error_summary_list ||= (error_summary && error_summary.all('.govuk-error-summary__list').first)
end
def error_summary_list
@error_summary_list ||= (error_summary && error_summary.all('.govuk-error-summary__list').first)
end

def error_summary_title
@error_summary_title ||= error_summary.all('h2.govuk-error-summary__title').first
end
def error_summary_title
@error_summary_title ||= error_summary.all('h2.govuk-error-summary__title').first
end

def error_summary
@error_summary ||= html.all('.govuk-error-summary').first
end
def error_summary
@error_summary ||= html.all('.govuk-error-summary').first
end
end

RSpec.configure do |rspec|
rspec.include self
end
end
end
Loading

0 comments on commit 13ef162

Please sign in to comment.