spec: isolate custom selenium rspec matchers to only selenium specs
so they don't interfere with like-named matchers that other specs may rely on Change-Id: Ic08a22309209a9aec0fd778dcdf52ad1c8ff2867 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/276954 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: James Butters <jbutters@instructure.com> QA-Review: Cody Cutrer <cody@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
This commit is contained in:
parent
7aa5ab381b
commit
6434cb4b80
|
@ -51,6 +51,7 @@ module SeleniumDependencies
|
|||
include SeleniumDriverSetup
|
||||
include OtherHelperMethods
|
||||
include CustomSeleniumActions
|
||||
include CustomSeleniumRSpecMatchers
|
||||
include CustomAlertActions
|
||||
include CustomPageLoaders
|
||||
include CustomScreenActions
|
||||
|
|
|
@ -24,440 +24,444 @@
|
|||
# expect(headers[0]).to have_class('ui-state-active')
|
||||
# headers[1].click
|
||||
# expect(headers[0]).to have_class('ui-state-default')
|
||||
RSpec::Matchers.define :have_class do |class_name|
|
||||
match do |element|
|
||||
wait_for(method: :have_class) do
|
||||
element.attribute('class').match(class_name)
|
||||
module CustomSeleniumRSpecMatchers
|
||||
extend RSpec::Matchers::DSL
|
||||
|
||||
matcher :have_class do |class_name|
|
||||
match do |element|
|
||||
wait_for(method: :have_class) do
|
||||
element.attribute('class').match(class_name)
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :have_class) do
|
||||
!element.attribute('class').match(class_name)
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
"expected #{element.inspect} to have class #{class_name}, actual class names: #{element.attribute('class')}"
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
"expected #{element.inspect} to NOT have class #{class_name}, actual class names: #{element.attribute('class')}"
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :have_class) do
|
||||
!element.attribute('class').match(class_name)
|
||||
matcher :have_text_absent do
|
||||
match do |element|
|
||||
wait_for(method: :have_text_absent) do
|
||||
element.text.blank?
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} text to be absent but was instead present.
|
||||
|
||||
Actual text was: "#{element.text}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
"expected #{element.inspect} to have class #{class_name}, actual class names: #{element.attribute('class')}"
|
||||
end
|
||||
matcher :have_text_present do
|
||||
match do |element|
|
||||
wait_for(method: :have_text_present) do
|
||||
element.text.present?
|
||||
end
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
"expected #{element.inspect} to NOT have class #{class_name}, actual class names: #{element.attribute('class')}"
|
||||
end
|
||||
end
|
||||
failure_message do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} text to be present but was instead blank.
|
||||
|
||||
RSpec::Matchers.define :have_text_absent do
|
||||
match do |element|
|
||||
wait_for(method: :have_text_absent) do
|
||||
element.text.blank?
|
||||
Actual text was: "#{element.text}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} text to be absent but was instead present.
|
||||
matcher :include_text do |text|
|
||||
match do |element|
|
||||
wait_for(method: :include_text) do
|
||||
element.text.include?(text)
|
||||
end
|
||||
end
|
||||
|
||||
Actual text was: "#{element.text}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
end
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :include_text) do
|
||||
element.text.exclude?(text)
|
||||
end
|
||||
end
|
||||
|
||||
RSpec::Matchers.define :have_text_present do
|
||||
match do |element|
|
||||
wait_for(method: :have_text_present) do
|
||||
element.text.present?
|
||||
failure_message do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} text to include "#{text}".
|
||||
|
||||
Actual text was: "#{element.text}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} text not to include "#{text}".
|
||||
|
||||
Actual text was: "#{element.text}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} text to be present but was instead blank.
|
||||
# assert the presence (or absence) of certain text within the
|
||||
# element's value attribute. will return as soon as the
|
||||
# expectation is met, e.g.
|
||||
#
|
||||
# expect(f('#name_input')).to have_value('Bob')
|
||||
#
|
||||
matcher :have_value do |value_attribute|
|
||||
match do |element|
|
||||
wait_for(method: :have_value) do
|
||||
element.attribute('value').match(value_attribute)
|
||||
end
|
||||
end
|
||||
|
||||
Actual text was: "#{element.text}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
end
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :have_value) do
|
||||
!element.attribute('value').match(value_attribute)
|
||||
end
|
||||
end
|
||||
|
||||
RSpec::Matchers.define :include_text do |text|
|
||||
match do |element|
|
||||
wait_for(method: :include_text) do
|
||||
element.text.include?(text)
|
||||
failure_message do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} to have value "#{value_attribute}".
|
||||
|
||||
Actual value was: "#{element.attribute('value')}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} not to have value "#{value_attribute}".
|
||||
|
||||
Actual value was: "#{element.attribute('value')}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :include_text) do
|
||||
element.text.exclude?(text)
|
||||
# assert the presence (or absence) of an attribute, optionally asserting
|
||||
# its exact value or against a regex. will return as soon as the
|
||||
# expectation is met, e.g.
|
||||
#
|
||||
# # must have something set
|
||||
# expect(f('.fc-event .fc-time')).to have_attribute('data-start')
|
||||
#
|
||||
# # must have a particular value set
|
||||
# expect(f('.fc-event .fc-time')).to have_attribute('data-start', '11:45')
|
||||
#
|
||||
# # must match a regex
|
||||
# expect(f('.fc-event .fc-time')).to have_attribute('data-start', /\A\d\d?:\d\d\z/)
|
||||
#
|
||||
# # must not have anything set
|
||||
# expect(f('.fc-event .fc-time')).not_to have_attribute('data-start')
|
||||
#
|
||||
# # must not have this particular value set (can be a different value, or no value)
|
||||
# expect(f('.fc-event .fc-time')).not_to have_attribute('data-start', '11:45')
|
||||
#
|
||||
# # must not match a regex
|
||||
# expect(f('.fc-event .fc-time')).not_to have_attribute('data-start', /\A\d\d?:\d\d\z/)
|
||||
#
|
||||
matcher :have_attribute do |*args|
|
||||
attribute = args.first
|
||||
expected_specified = args.size > 1
|
||||
expected = args[1]
|
||||
|
||||
attribute_matcher = ->(actual) do
|
||||
if expected_specified
|
||||
actual.respond_to?(:match) ? actual.match(expected) : actual == expected
|
||||
else
|
||||
!actual.nil?
|
||||
end
|
||||
end
|
||||
|
||||
match do |element|
|
||||
wait_for(method: :have_attribute) do
|
||||
attribute_matcher.call(element.attribute(attribute))
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :have_attribute) do
|
||||
!attribute_matcher.call(element.attribute(attribute))
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
"expected #{element.inspect}'s #{attribute} attribute to have value of #{expected || 'not nil'}, "\
|
||||
"actual #{attribute} attribute value: #{element.attribute(attribute.to_s)}"
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
"expected #{element.inspect}'s #{attribute} attribute to NOT have value of #{expected || 'not nil'}, "\
|
||||
"actual #{attribute} attribute type: #{element.attribute(attribute.to_s)}"
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} text to include "#{text}".
|
||||
# assert whether or not an element is disabled.
|
||||
# will return as soon as the expectation is met, e.g.
|
||||
#
|
||||
# expect(f("#assignment_group_category_id")).to be_disabled
|
||||
#
|
||||
matcher :be_disabled do
|
||||
match do |element|
|
||||
wait_for(method: :be_disabled) do
|
||||
element.attribute(:disabled) == "true" || element.attribute("aria-disabled") == "true"
|
||||
end
|
||||
end
|
||||
|
||||
Actual text was: "#{element.text}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :be_disabled) do
|
||||
element.attribute(:disabled) != "true" && element.attribute("aria-disabled") != "true"
|
||||
end
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} text not to include "#{text}".
|
||||
failure_message do |element|
|
||||
"expected #{element.inspect}'s disabled attribute to be true, actual disabled attribute value: #{element.attribute(:disabled)}"
|
||||
end
|
||||
|
||||
Actual text was: "#{element.text}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
end
|
||||
|
||||
# assert the presence (or absence) of certain text within the
|
||||
# element's value attribute. will return as soon as the
|
||||
# expectation is met, e.g.
|
||||
#
|
||||
# expect(f('#name_input')).to have_value('Bob')
|
||||
#
|
||||
RSpec::Matchers.define :have_value do |value_attribute|
|
||||
match do |element|
|
||||
wait_for(method: :have_value) do
|
||||
element.attribute('value').match(value_attribute)
|
||||
failure_message_when_negated do |element|
|
||||
"expected #{element.inspect}'s disabled attribute to NOT be true, actual disabled attribute type: #{element.attribute(:disabled)}"
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :have_value) do
|
||||
!element.attribute('value').match(value_attribute)
|
||||
# assert whether or not an element has an aria-diabled value of "true".
|
||||
# will return as soon as the expectation is met, e.g.
|
||||
#
|
||||
# expect(element).to be_aria_disabled
|
||||
#
|
||||
matcher :be_aria_disabled do
|
||||
match do |element|
|
||||
wait_for(method: :be_aria_disabled) do
|
||||
element.attribute('aria-disabled') == 'true'
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :be_aria_disabled) do
|
||||
element.attribute('aria-disabled') != 'true'
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect}'s aria-disabled attribute to be true.
|
||||
|
||||
Actual aria-disabled attribute value: "#{element.attribute('aria-disabled')}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect}'s aria-disabled attribute to be false.
|
||||
|
||||
Actual aria-disabled attribute value: "#{element.attribute('aria-disabled')}"
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} to have value "#{value_attribute}".
|
||||
# assert the presence (or absence) of something inside the element via css
|
||||
# selector. will return as soon as the expectation is met, e.g.
|
||||
#
|
||||
# expect(f('#courses')).to contain_css("#course_123")
|
||||
# f('#delete_course').click
|
||||
# expect(f('#courses')).not_to contain_css("#course_123")
|
||||
#
|
||||
matcher :contain_css do |selector|
|
||||
match do |element|
|
||||
begin
|
||||
# rely on implicit_wait
|
||||
f(selector, element)
|
||||
true
|
||||
rescue Selenium::WebDriver::Error::NoSuchElementError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
Actual value was: "#{element.attribute('value')}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect} not to have value "#{value_attribute}".
|
||||
|
||||
Actual value was: "#{element.attribute('value')}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
end
|
||||
|
||||
# assert the presence (or absence) of an attribute, optionally asserting
|
||||
# its exact value or against a regex. will return as soon as the
|
||||
# expectation is met, e.g.
|
||||
#
|
||||
# # must have something set
|
||||
# expect(f('.fc-event .fc-time')).to have_attribute('data-start')
|
||||
#
|
||||
# # must have a particular value set
|
||||
# expect(f('.fc-event .fc-time')).to have_attribute('data-start', '11:45')
|
||||
#
|
||||
# # must match a regex
|
||||
# expect(f('.fc-event .fc-time')).to have_attribute('data-start', /\A\d\d?:\d\d\z/)
|
||||
#
|
||||
# # must not have anything set
|
||||
# expect(f('.fc-event .fc-time')).not_to have_attribute('data-start')
|
||||
#
|
||||
# # must not have this particular value set (can be a different value, or no value)
|
||||
# expect(f('.fc-event .fc-time')).not_to have_attribute('data-start', '11:45')
|
||||
#
|
||||
# # must not match a regex
|
||||
# expect(f('.fc-event .fc-time')).not_to have_attribute('data-start', /\A\d\d?:\d\d\z/)
|
||||
#
|
||||
RSpec::Matchers.define :have_attribute do |*args|
|
||||
attribute = args.first
|
||||
expected_specified = args.size > 1
|
||||
expected = args[1]
|
||||
|
||||
attribute_matcher = ->(actual) do
|
||||
if expected_specified
|
||||
actual.respond_to?(:match) ? actual.match(expected) : actual == expected
|
||||
else
|
||||
!actual.nil?
|
||||
match_when_negated do |element|
|
||||
wait_for_no_such_element(method: :contain_css) { f(selector, element) }
|
||||
end
|
||||
end
|
||||
|
||||
match do |element|
|
||||
wait_for(method: :have_attribute) do
|
||||
attribute_matcher.call(element.attribute(attribute))
|
||||
# assert the presence (or absence) of something inside the element via
|
||||
# fake-jquery-css selector. will return as soon as the expectation is met,
|
||||
# e.g.
|
||||
#
|
||||
# expect(f('#weird-ui')).to contain_css(".something:visible")
|
||||
# f('#hide-things').click
|
||||
# expect(f('#weird-ui')).not_to contain_css(".something:visible")
|
||||
#
|
||||
matcher :contain_jqcss do |selector|
|
||||
match do |element|
|
||||
wait_for(method: :contain_jqcss) { find_with_jquery(selector, element) }
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :contain_jqcss) { !find_with_jquery(selector, element) }
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :have_attribute) do
|
||||
!attribute_matcher.call(element.attribute(attribute))
|
||||
# assert the presence (or absence) of a link with certain text inside the
|
||||
# element. will return as soon as the expectation is met, e.g.
|
||||
#
|
||||
# expect(f('#weird-ui')).to contain_link("Click Here")
|
||||
# f('#hide-things').click
|
||||
# expect(f('#weird-ui')).not_to contain_link("Click Here")
|
||||
#
|
||||
matcher :contain_link do |text|
|
||||
match do |element|
|
||||
begin
|
||||
# rely on implicit_wait
|
||||
fln(text, element)
|
||||
true
|
||||
rescue Selenium::WebDriver::Error::NoSuchElementError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for_no_such_element(method: :contain_link) { fln(text, element) }
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
"expected #{element.inspect}'s #{attribute} attribute to have value of #{expected || 'not nil'}, "\
|
||||
"actual #{attribute} attribute value: #{element.attribute(attribute.to_s)}"
|
||||
end
|
||||
# assert the presence (or absence) of a link with certain partial text inside the
|
||||
# element. will return as soon as the expectation is met, e.g.
|
||||
#
|
||||
# given <a href="...">Click Here/a>
|
||||
# expect(f('#weird-ui')).to contain_link_partial_text("Here")
|
||||
# f('#hide-things').click
|
||||
# expect(f('#weird-ui')).not_to contain_link_partial_text("Here")
|
||||
#
|
||||
matcher :contain_link_partial_text do |text|
|
||||
match do |element|
|
||||
begin
|
||||
# rely on implicit_wait
|
||||
flnpt(text, element)
|
||||
true
|
||||
rescue Selenium::WebDriver::Error::NoSuchElementError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
"expected #{element.inspect}'s #{attribute} attribute to NOT have value of #{expected || 'not nil'}, "\
|
||||
"actual #{attribute} attribute type: #{element.attribute(attribute.to_s)}"
|
||||
end
|
||||
end
|
||||
|
||||
# assert whether or not an element is disabled.
|
||||
# will return as soon as the expectation is met, e.g.
|
||||
#
|
||||
# expect(f("#assignment_group_category_id")).to be_disabled
|
||||
#
|
||||
RSpec::Matchers.define :be_disabled do
|
||||
match do |element|
|
||||
wait_for(method: :be_disabled) do
|
||||
element.attribute(:disabled) == "true" || element.attribute("aria-disabled") == "true"
|
||||
match_when_negated do |element|
|
||||
wait_for_no_such_element(method: :contain_link) { flnpt(text, element) }
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :be_disabled) do
|
||||
element.attribute(:disabled) != "true" && element.attribute("aria-disabled") != "true"
|
||||
# assert whether or not an element meets the desired contrast ratio.
|
||||
# will wait up to TIMEOUTS[:finder] seconds
|
||||
require_relative '../helpers/color_common'
|
||||
matcher :meet_contrast_ratio do |ratio = 3.5|
|
||||
match do |element|
|
||||
wait_for(method: :be_displayed) do
|
||||
LuminosityContrast.ratio(
|
||||
ColorCommon.rgba_to_hex(element.style('background-color')),
|
||||
ColorCommon.rgba_to_hex(element.style('color'))
|
||||
) >= ratio
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :be_displayed) do
|
||||
LuminosityContrast.ratio(
|
||||
ColorCommon.rgba_to_hex(element.style('background-color')),
|
||||
ColorCommon.rgba_to_hex(element.style('color'))
|
||||
) < ratio
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
"expected #{element.inspect}'s disabled attribute to be true, actual disabled attribute value: #{element.attribute(:disabled)}"
|
||||
end
|
||||
# assert whether or not an element is displayed. will wait up to
|
||||
# TIMEOUTS[:finder] seconds
|
||||
matcher :be_displayed do
|
||||
match do |element|
|
||||
wait_for(method: :be_displayed) { element.displayed? }
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
"expected #{element.inspect}'s disabled attribute to NOT be true, actual disabled attribute type: #{element.attribute(:disabled)}"
|
||||
end
|
||||
end
|
||||
|
||||
# assert whether or not an element has an aria-diabled value of "true".
|
||||
# will return as soon as the expectation is met, e.g.
|
||||
#
|
||||
# expect(element).to be_aria_disabled
|
||||
#
|
||||
RSpec::Matchers.define :be_aria_disabled do
|
||||
match do |element|
|
||||
wait_for(method: :be_aria_disabled) do
|
||||
element.attribute('aria-disabled') == 'true'
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :be_displayed) { !element.displayed? }
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :be_aria_disabled) do
|
||||
element.attribute('aria-disabled') != 'true'
|
||||
# assert the size of the collection. will wait up to TIMEOUTS[:finder]
|
||||
# seconds, and will reload the collection if it can (i.e. if it's the
|
||||
# result of a ff/ffj call)
|
||||
matcher :have_size do |size|
|
||||
match do |collection|
|
||||
wait_for(method: :have_size) do
|
||||
collection.reload! if collection.size != size && collection.respond_to?(:reload!)
|
||||
collection.size == size
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |collection|
|
||||
wait_for(method: :have_size) do
|
||||
collection.reload! if collection.size == size && collection.respond_to?(:reload!)
|
||||
collection.size != size
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect}'s aria-disabled attribute to be true.
|
||||
|
||||
Actual aria-disabled attribute value: "#{element.attribute('aria-disabled')}".
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
|
||||
failure_message_when_negated do |element|
|
||||
<<~FAILURE_MESSAGE
|
||||
Expected #{element.inspect}'s aria-disabled attribute to be false.
|
||||
|
||||
Actual aria-disabled attribute value: "#{element.attribute('aria-disabled')}"
|
||||
FAILURE_MESSAGE
|
||||
end
|
||||
end
|
||||
|
||||
# assert the presence (or absence) of something inside the element via css
|
||||
# selector. will return as soon as the expectation is met, e.g.
|
||||
#
|
||||
# expect(f('#courses')).to contain_css("#course_123")
|
||||
# f('#delete_course').click
|
||||
# expect(f('#courses')).not_to contain_css("#course_123")
|
||||
#
|
||||
RSpec::Matchers.define :contain_css do |selector|
|
||||
match do |element|
|
||||
begin
|
||||
# rely on implicit_wait
|
||||
f(selector, element)
|
||||
# wait for something to become a new value. useful for those times when
|
||||
# other implicit waits cannot be used, e.g.
|
||||
#
|
||||
# # trigger some ajax
|
||||
# expect { User.count }.to become(1)
|
||||
matcher :become do
|
||||
def supports_block_expectations?
|
||||
true
|
||||
rescue Selenium::WebDriver::Error::NoSuchElementError
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for_no_such_element(method: :contain_css) { f(selector, element) }
|
||||
end
|
||||
end
|
||||
|
||||
# assert the presence (or absence) of something inside the element via
|
||||
# fake-jquery-css selector. will return as soon as the expectation is met,
|
||||
# e.g.
|
||||
#
|
||||
# expect(f('#weird-ui')).to contain_css(".something:visible")
|
||||
# f('#hide-things').click
|
||||
# expect(f('#weird-ui')).not_to contain_css(".something:visible")
|
||||
#
|
||||
RSpec::Matchers.define :contain_jqcss do |selector|
|
||||
match do |element|
|
||||
wait_for(method: :contain_jqcss) { find_with_jquery(selector, element) }
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :contain_jqcss) { !find_with_jquery(selector, element) }
|
||||
end
|
||||
end
|
||||
|
||||
# assert the presence (or absence) of a link with certain text inside the
|
||||
# element. will return as soon as the expectation is met, e.g.
|
||||
#
|
||||
# expect(f('#weird-ui')).to contain_link("Click Here")
|
||||
# f('#hide-things').click
|
||||
# expect(f('#weird-ui')).not_to contain_link("Click Here")
|
||||
#
|
||||
RSpec::Matchers.define :contain_link do |text|
|
||||
match do |element|
|
||||
begin
|
||||
# rely on implicit_wait
|
||||
fln(text, element)
|
||||
true
|
||||
rescue Selenium::WebDriver::Error::NoSuchElementError
|
||||
false
|
||||
[:==, :<, :<=, :>=, :>, :===, :=~].each do |operator|
|
||||
chain operator do |value|
|
||||
@operator = operator
|
||||
@value = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for_no_such_element(method: :contain_link) { fln(text, element) }
|
||||
end
|
||||
end
|
||||
failure_message do |actual|
|
||||
actual_value = actual.call
|
||||
|
||||
# assert the presence (or absence) of a link with certain partial text inside the
|
||||
# element. will return as soon as the expectation is met, e.g.
|
||||
#
|
||||
# given <a href="...">Click Here/a>
|
||||
# expect(f('#weird-ui')).to contain_link_partial_text("Here")
|
||||
# f('#hide-things').click
|
||||
# expect(f('#weird-ui')).not_to contain_link_partial_text("Here")
|
||||
#
|
||||
RSpec::Matchers.define :contain_link_partial_text do |text|
|
||||
match do |element|
|
||||
begin
|
||||
# rely on implicit_wait
|
||||
flnpt(text, element)
|
||||
true
|
||||
rescue Selenium::WebDriver::Error::NoSuchElementError
|
||||
false
|
||||
unless defined? @operator
|
||||
"expected #{actual_value} to become #{expected}"
|
||||
else
|
||||
"expected #{actual_value} to become #{@operator} #{@value}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for_no_such_element(method: :contain_link) { flnpt(text, element) }
|
||||
end
|
||||
end
|
||||
match do |actual|
|
||||
raise "The `become` matcher expects a block, e.g. `expect { actual }.to become(value)`, NOT `expect(actual).to become(value)`" unless actual.is_a? Proc
|
||||
|
||||
# assert whether or not an element meets the desired contrast ratio.
|
||||
# will wait up to TIMEOUTS[:finder] seconds
|
||||
require_relative '../helpers/color_common'
|
||||
RSpec::Matchers.define :meet_contrast_ratio do |ratio = 3.5|
|
||||
match do |element|
|
||||
wait_for(method: :be_displayed) do
|
||||
LuminosityContrast.ratio(
|
||||
ColorCommon.rgba_to_hex(element.style('background-color')),
|
||||
ColorCommon.rgba_to_hex(element.style('color'))
|
||||
) >= ratio
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :be_displayed) do
|
||||
LuminosityContrast.ratio(
|
||||
ColorCommon.rgba_to_hex(element.style('background-color')),
|
||||
ColorCommon.rgba_to_hex(element.style('color'))
|
||||
) < ratio
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# assert whether or not an element is displayed. will wait up to
|
||||
# TIMEOUTS[:finder] seconds
|
||||
RSpec::Matchers.define :be_displayed do
|
||||
match do |element|
|
||||
wait_for(method: :be_displayed) { element.displayed? }
|
||||
end
|
||||
|
||||
match_when_negated do |element|
|
||||
wait_for(method: :be_displayed) { !element.displayed? }
|
||||
end
|
||||
end
|
||||
|
||||
# assert the size of the collection. will wait up to TIMEOUTS[:finder]
|
||||
# seconds, and will reload the collection if it can (i.e. if it's the
|
||||
# result of a ff/ffj call)
|
||||
RSpec::Matchers.define :have_size do |size|
|
||||
match do |collection|
|
||||
wait_for(method: :have_size) do
|
||||
collection.reload! if collection.size != size && collection.respond_to?(:reload!)
|
||||
collection.size == size
|
||||
end
|
||||
end
|
||||
|
||||
match_when_negated do |collection|
|
||||
wait_for(method: :have_size) do
|
||||
collection.reload! if collection.size == size && collection.respond_to?(:reload!)
|
||||
collection.size != size
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# wait for something to become a new value. useful for those times when
|
||||
# other implicit waits cannot be used, e.g.
|
||||
#
|
||||
# # trigger some ajax
|
||||
# expect { User.count }.to become(1)
|
||||
RSpec::Matchers.define :become do
|
||||
def supports_block_expectations?
|
||||
true
|
||||
end
|
||||
|
||||
[:==, :<, :<=, :>=, :>, :===, :=~].each do |operator|
|
||||
chain operator do |value|
|
||||
@operator = operator
|
||||
@value = value
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |actual|
|
||||
actual_value = actual.call
|
||||
|
||||
unless defined? @operator
|
||||
"expected #{actual_value} to become #{expected}"
|
||||
else
|
||||
"expected #{actual_value} to become #{@operator} #{@value}"
|
||||
end
|
||||
end
|
||||
|
||||
match do |actual|
|
||||
raise "The `become` matcher expects a block, e.g. `expect { actual }.to become(value)`, NOT `expect(actual).to become(value)`" unless actual.is_a? Proc
|
||||
|
||||
wait_for(method: :become) do
|
||||
disable_implicit_wait do
|
||||
unless defined? @operator
|
||||
actual.call == expected
|
||||
else
|
||||
actual.call.__send__ @operator, @value
|
||||
wait_for(method: :become) do
|
||||
disable_implicit_wait do
|
||||
unless defined? @operator
|
||||
actual.call == expected
|
||||
else
|
||||
actual.call.__send__ @operator, @value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec::Matchers.define :become_between do |min, max|
|
||||
def supports_block_expectations?
|
||||
true
|
||||
end
|
||||
matcher :become_between do |min, max|
|
||||
def supports_block_expectations?
|
||||
true
|
||||
end
|
||||
|
||||
match do |actual|
|
||||
raise "The `become` matcher expects a block, e.g. `expect { actual }.to become(value)`, NOT `expect(actual).to become(value)`" unless actual.is_a? Proc
|
||||
match do |actual|
|
||||
raise "The `become` matcher expects a block, e.g. `expect { actual }.to become(value)`, NOT `expect(actual).to become(value)`" unless actual.is_a? Proc
|
||||
|
||||
wait_for(method: :become) do
|
||||
disable_implicit_wait { a = actual.call; min < a && a < max }
|
||||
wait_for(method: :become) do
|
||||
disable_implicit_wait { a = actual.call; min < a && a < max }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue