-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This refactors the matchers and the helper into modules.
- Loading branch information
1 parent
de855b4
commit 13ef162
Showing
3 changed files
with
248 additions
and
171 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.