locator 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/core_ext/hash/except.rb +1 -1
- data/lib/locator.rb +46 -21
- data/lib/locator/dom.rb +3 -1
- data/lib/locator/dom/htmlunit/element.rb +1 -1
- data/lib/locator/dom/nokogiri/element.rb +22 -2
- data/lib/locator/element.rb +15 -10
- data/lib/locator/element/content.rb +10 -0
- data/lib/locator/element/file.rb +1 -1
- data/lib/locator/element/form.rb +1 -1
- data/lib/locator/matcher.rb +70 -0
- data/lib/locator/matcher/have_tag.rb +51 -0
- data/lib/locator/version.rb +1 -1
- data/test/all.rb +4 -1
- data/test/locator/element_test.rb +12 -5
- data/test/locator/matcher/have_content_test.rb +29 -0
- data/test/locator/matcher/have_tag_test.rb +161 -0
- data/test/locator_test.rb +16 -16
- metadata +9 -2
data/lib/core_ext/hash/except.rb
CHANGED
data/lib/locator.rb
CHANGED
@@ -4,9 +4,16 @@ module Locator
|
|
4
4
|
autoload :Boolean, 'locator/boolean'
|
5
5
|
autoload :Dom, 'locator/dom'
|
6
6
|
autoload :Element, 'locator/element'
|
7
|
+
autoload :Matcher, 'locator/matcher'
|
7
8
|
autoload :Result, 'locator/result'
|
8
9
|
autoload :Xpath, 'locator/xpath'
|
9
10
|
|
11
|
+
class ElementNotFound < StandardError
|
12
|
+
def initialize(*args)
|
13
|
+
super "could not find element type: #{args.map { |arg| arg.inspect }.join(', ') }"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
10
17
|
class << self
|
11
18
|
def [](type)
|
12
19
|
locators[type.to_sym] || raise("unknown locator type: #{type}")
|
@@ -26,49 +33,67 @@ module Locator
|
|
26
33
|
end
|
27
34
|
end
|
28
35
|
|
36
|
+
def scopes
|
37
|
+
@scopes ||= []
|
38
|
+
end
|
39
|
+
|
29
40
|
def xpath(*args)
|
30
41
|
type = args.shift if args.first.is_a?(Symbol)
|
31
42
|
Locator[type].new.xpath(*args)
|
32
43
|
end
|
33
44
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
options = Hash === args.last ? args.last : {}
|
38
|
-
result = if scope = options.delete(:within)
|
39
|
-
within(*Array(scope)) { locate(dom, *args) }
|
40
|
-
else
|
41
|
-
type = args.shift if args.first.is_a?(Symbol)
|
42
|
-
Locator.build(type).locate(current_scope(dom), *args)
|
43
|
-
end
|
45
|
+
def all(dom, *args)
|
46
|
+
lookup(:all, dom, *args)
|
47
|
+
end
|
44
48
|
|
45
|
-
|
49
|
+
def locate(dom, *args, &block)
|
50
|
+
lookup(:locate, dom, *args, &block)
|
46
51
|
end
|
47
52
|
|
48
|
-
def within(*
|
49
|
-
scopes.
|
50
|
-
|
53
|
+
def within(*args)
|
54
|
+
dom = dom?(args.first) ? args.shift : scopes.pop
|
55
|
+
scopes << resolve_scope(dom, args)
|
56
|
+
yield(scopes.last)
|
51
57
|
end
|
52
58
|
|
53
59
|
protected
|
54
60
|
|
55
|
-
def
|
56
|
-
|
61
|
+
def lookup(method, *args, &block)
|
62
|
+
options = Hash === args.last ? args.last : {}
|
63
|
+
dom = args.shift if dom?(args.first)
|
64
|
+
type = args.shift if args.first.is_a?(Symbol)
|
65
|
+
|
66
|
+
scope = resolve_scope(dom, options.delete(:within)) if options[:within]
|
67
|
+
scope = scope || scopes.pop || dom
|
68
|
+
|
69
|
+
result = Locator.build(type).send(method, scope, *args)
|
70
|
+
result = result && block_given? ? within(result) { yield(result) } : result
|
71
|
+
end
|
57
72
|
|
58
|
-
|
73
|
+
def resolve_scope(dom, scope)
|
74
|
+
dom = Locator::Dom.page(dom) unless dom.respond_to?(:elements_by_xpath)
|
75
|
+
scope = Array(scope)
|
76
|
+
|
77
|
+
case scope.first
|
59
78
|
when NilClass
|
60
79
|
dom
|
61
80
|
when %r(^\.?//)
|
62
|
-
dom.
|
81
|
+
dom.element_by_xpath(scope.first)
|
63
82
|
when String
|
64
|
-
dom.
|
83
|
+
dom.element_by_css(scope.first)
|
84
|
+
when Dom::Element
|
85
|
+
scope.first.to_s
|
65
86
|
else
|
66
87
|
locate(dom, *scope)
|
67
88
|
end
|
68
89
|
end
|
69
90
|
|
70
|
-
def
|
71
|
-
|
91
|
+
def dom?(arg)
|
92
|
+
arg.is_a?(Dom::Element) || html?(arg)
|
93
|
+
end
|
94
|
+
|
95
|
+
def html?(arg)
|
96
|
+
arg.is_a?(String) && arg =~ /<[^>]+>/
|
72
97
|
end
|
73
98
|
|
74
99
|
extend(self)
|
data/lib/locator/dom.rb
CHANGED
@@ -4,7 +4,7 @@ module Locator
|
|
4
4
|
module Dom
|
5
5
|
autoload :Htmlunit, 'locator/dom/htmlunit'
|
6
6
|
autoload :Nokogiri, 'locator/dom/nokogiri'
|
7
|
-
|
7
|
+
|
8
8
|
class << self
|
9
9
|
def adapter
|
10
10
|
@@adapter ||= Nokogiri
|
@@ -18,5 +18,7 @@ module Locator
|
|
18
18
|
adapter::Page.new(html)
|
19
19
|
end
|
20
20
|
end
|
21
|
+
|
22
|
+
class Element ; end
|
21
23
|
end
|
22
24
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Locator
|
2
2
|
module Dom
|
3
3
|
module Nokogiri
|
4
|
-
class Element
|
4
|
+
class Element < Dom::Element
|
5
5
|
attr_reader :element, :matches
|
6
6
|
|
7
7
|
def initialize(element)
|
@@ -29,6 +29,22 @@ module Locator
|
|
29
29
|
element.content
|
30
30
|
end
|
31
31
|
|
32
|
+
def value
|
33
|
+
case name
|
34
|
+
when 'input'
|
35
|
+
element.attribute('value').value
|
36
|
+
when 'select'
|
37
|
+
selected = element.children.select { |option| option.attribute('selected') }
|
38
|
+
values = selected.map { |option| option.attribute('value') || option.content }
|
39
|
+
element.attribute('multiple') ? values.strip : values.first.strip
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def checked
|
44
|
+
checked = element.attribute('checked')
|
45
|
+
checked ? checked.value : nil
|
46
|
+
end
|
47
|
+
|
32
48
|
def inner_html
|
33
49
|
element.inner_html
|
34
50
|
end
|
@@ -48,11 +64,15 @@ module Locator
|
|
48
64
|
def element_by_xpath(xpath)
|
49
65
|
elements_by_xpath(xpath).first
|
50
66
|
end
|
51
|
-
|
67
|
+
|
52
68
|
def elements_by_xpath(*xpaths)
|
53
69
|
element.xpath(*xpaths).map { |element| Element.new(element) }
|
54
70
|
end
|
55
71
|
|
72
|
+
def element_by_css(rule)
|
73
|
+
elements_by_css(rule).first
|
74
|
+
end
|
75
|
+
|
56
76
|
def elements_by_css(*rules)
|
57
77
|
element.css(*rules).map { |element| Element.new(element) }
|
58
78
|
end
|
data/lib/locator/element.rb
CHANGED
@@ -6,6 +6,7 @@ module Locator
|
|
6
6
|
autoload :Area, 'locator/element/area'
|
7
7
|
autoload :Button, 'locator/element/button'
|
8
8
|
autoload :CheckBox, 'locator/element/check_box'
|
9
|
+
autoload :Content, 'locator/element/content'
|
9
10
|
autoload :ElementsList, 'locator/element/elements_list'
|
10
11
|
autoload :Field, 'locator/element/field'
|
11
12
|
autoload :File, 'locator/element/file'
|
@@ -24,14 +25,12 @@ module Locator
|
|
24
25
|
attr_reader :name, :css, :locatables, :attributes
|
25
26
|
|
26
27
|
def initialize(*args)
|
27
|
-
attributes, name = args.last.is_a?(Hash) ? args.pop : {}, args.pop
|
28
|
-
@
|
29
|
-
@attributes = attributes
|
30
|
-
@locatables = ((attributes.delete(:matches) || [:content]) + [:id]).uniq
|
28
|
+
@attributes, @name = args.last.is_a?(Hash) ? args.pop : {}, args.pop
|
29
|
+
@locatables = (attributes.delete(:matches) || [:content]) << :id
|
31
30
|
end
|
32
31
|
|
33
32
|
def locate(*args)
|
34
|
-
all(*args).first
|
33
|
+
all(*args).first # || raise(ElementNotFound.new(*args))
|
35
34
|
end
|
36
35
|
|
37
36
|
def all(scope, *args)
|
@@ -41,17 +40,23 @@ module Locator
|
|
41
40
|
result
|
42
41
|
end
|
43
42
|
|
44
|
-
def xpath(
|
45
|
-
|
43
|
+
def xpath(*args)
|
44
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
45
|
+
attributes = self.attributes.merge(options.except(:xpath, :css)) # TODO move to Xpath?
|
46
|
+
xpath, css = options.values_at(:xpath, :css)
|
47
|
+
|
48
|
+
xpath ||= css ? ::Nokogiri::CSS.xpath_for(*css).first : args.pop
|
49
|
+
Xpath.new(xpath || name || '*', attributes).to_s
|
46
50
|
end
|
47
51
|
|
48
52
|
protected
|
49
53
|
|
50
54
|
def lookup(scope, selector, attributes = {})
|
51
55
|
scope = scope.respond_to?(:elements_by_xpath) ? scope : Locator::Dom.page(scope)
|
52
|
-
xpath
|
53
|
-
xpath =
|
54
|
-
|
56
|
+
xpath = xpath(attributes)
|
57
|
+
xpath = ".#{xpath}" unless xpath[0, 1] == '.'
|
58
|
+
|
59
|
+
elements = scope.elements_by_xpath(xpath)
|
55
60
|
Result.new(elements).filter!(selector, locatables)
|
56
61
|
end
|
57
62
|
end
|
data/lib/locator/element/file.rb
CHANGED
data/lib/locator/element/form.rb
CHANGED
@@ -0,0 +1,70 @@
|
|
1
|
+
module Locator
|
2
|
+
module Matcher
|
3
|
+
autoload :HaveTag, 'locator/matcher/have_tag'
|
4
|
+
|
5
|
+
# Matches an HTML document with whatever string is given
|
6
|
+
def contain(*args)
|
7
|
+
HaveTag.new(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Asserts that the response body contains the given string or regexp
|
11
|
+
def assert_contain(*args)
|
12
|
+
matcher = contain(*args)
|
13
|
+
assert matcher.matches?(response.body), matcher.failure_message
|
14
|
+
end
|
15
|
+
|
16
|
+
# Asserts that the response body does not contain the given string or regexp
|
17
|
+
def assert_not_contain(*args)
|
18
|
+
matcher = contain(*args)
|
19
|
+
assert !matcher.matches?(response.body), matcher.negative_failure_message
|
20
|
+
end
|
21
|
+
|
22
|
+
def have_tag(*args, &block)
|
23
|
+
HaveTag.new(*args, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def assert_have_tag(html, *args, &block)
|
27
|
+
matcher = have_tag(*args, &block)
|
28
|
+
assert matcher.matches?(response.body), matcher.failure_message
|
29
|
+
end
|
30
|
+
|
31
|
+
def assert_have_no_tag(html, *args, &block)
|
32
|
+
matcher = have_tag(*args, &block)
|
33
|
+
assert !matcher.matches?(response.body), matcher.negative_failure_message
|
34
|
+
end
|
35
|
+
|
36
|
+
# Matches HTML content against an XPath
|
37
|
+
def have_xpath(xpath, options = {}, &block)
|
38
|
+
HaveTag.new(options.delete(:content), options.merge(:xpath => xpath), &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Asserts that the response body matches the given XPath
|
42
|
+
def assert_have_xpath(html, *args, &block)
|
43
|
+
matcher = have_xpath(*args, &block)
|
44
|
+
assert matcher.matches?(response.body), matcher.failure_message
|
45
|
+
end
|
46
|
+
|
47
|
+
# Asserts that the response body does not match the given XPath
|
48
|
+
def assert_have_no_xpath(html, *args, &block)
|
49
|
+
matcher = have_xpath(*args, &block)
|
50
|
+
assert !matcher.matches?(response.body), matcher.negative_failure_message
|
51
|
+
end
|
52
|
+
|
53
|
+
# Matches HTML content against a CSS selector.
|
54
|
+
def have_css(css, options = {}, &block)
|
55
|
+
HaveTag.new(options.delete(:content), options.merge(:css => css), &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Asserts that the response body matches the given CSS selector
|
59
|
+
def assert_have_css(html, *args, &block)
|
60
|
+
matcher = have_css(*args, &block)
|
61
|
+
assert matcher.matches?(response.body), matcher.failure_message
|
62
|
+
end
|
63
|
+
|
64
|
+
# Asserts that the response body does not match the given CSS selector
|
65
|
+
def assert_have_no_css(html, *args, &block)
|
66
|
+
matcher = have_css(*args, &block)
|
67
|
+
assert !matcher.matches?(response.body), matcher.negative_failure_message
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Locator
|
2
|
+
module Matcher
|
3
|
+
class HaveTag
|
4
|
+
attr_reader :selector, :options, :count, :block, :target
|
5
|
+
|
6
|
+
def initialize(*args, &block)
|
7
|
+
@options = args.last.is_a?(Hash) ? args.pop : {}
|
8
|
+
@selector = args.pop
|
9
|
+
@count = options.delete(:count)
|
10
|
+
@block = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def matches?(target = nil)
|
14
|
+
@target = target
|
15
|
+
count ? match_count : !!match_element
|
16
|
+
end
|
17
|
+
|
18
|
+
def match_count
|
19
|
+
elements = Locator.all(target, selector, options)
|
20
|
+
elements = elements.select(&block) if block
|
21
|
+
elements.size == count.to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
def match_element
|
25
|
+
element = Locator.locate(target, selector, options)
|
26
|
+
element && block ? Locator.within(element) { block.call(element) } : element
|
27
|
+
end
|
28
|
+
|
29
|
+
def failure_message # TODO
|
30
|
+
"expected following text to match selector #{selector.inspect} and #{options.inspect}:\n#{target}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def negative_failure_message
|
34
|
+
"expected following text to not match selector #{selector.inspect} and #{options.inspect}:\n#{target}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# def squeeze_space(inner_text)
|
38
|
+
# (inner_text || '').gsub(/^\s*$/, "").squeeze("\n")
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# def content_message
|
42
|
+
# case @content
|
43
|
+
# when String
|
44
|
+
# "include \"#{@content}\""
|
45
|
+
# when Regexp
|
46
|
+
# "match #{@content.inspect}"
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/locator/version.rb
CHANGED
data/test/all.rb
CHANGED
@@ -9,29 +9,36 @@ class LocatorElementTest < Test::Unit::TestCase
|
|
9
9
|
assert_equal './/*', Element.new.xpath
|
10
10
|
end
|
11
11
|
|
12
|
-
test "xpath with a node name" do
|
12
|
+
test "xpath of an element with a node name" do
|
13
13
|
xpath = Element.new(:div).xpath
|
14
14
|
assert_equal './/div', xpath
|
15
15
|
end
|
16
16
|
|
17
|
-
test "xpath with attributes" do
|
17
|
+
test "xpath of an element with attributes" do
|
18
18
|
xpath = Element.new(nil, :type => 'type', :class => 'class').xpath
|
19
19
|
assert_equal ".//*[@type=\"type\"][contains(concat(' ', @class, ' '), concat(' ', \"class\", ' '))]", xpath
|
20
20
|
end
|
21
21
|
|
22
|
-
test "xpath with node name and attributes" do
|
22
|
+
test "xpath of an element with node name and attributes" do
|
23
23
|
xpath = Element.new(:div, :type => 'type', :class => 'class').xpath
|
24
24
|
assert_equal ".//div[@type=\"type\"][contains(concat(' ', @class, ' '), concat(' ', \"class\", ' '))]", xpath
|
25
25
|
end
|
26
26
|
|
27
|
-
test "xpath with multiple node name and attributes" do
|
27
|
+
test "xpath of an element with multiple node name and attributes" do
|
28
28
|
xpath = Element.new([:div, :p], :type => 'type').xpath
|
29
29
|
assert_equal ".//div[@type=\"type\"] | .//p[@type=\"type\"]", xpath
|
30
30
|
end
|
31
31
|
|
32
32
|
test "xpath merges given attributes with element attributes" do
|
33
33
|
xpath = Element.new(:div, :foo => 'foo').xpath(:bar => 'bar')
|
34
|
-
|
34
|
+
assert xpath.include?(".//div")
|
35
|
+
assert xpath.include?("[@foo=\"foo\"]") # humpf, unsorted hash
|
36
|
+
assert xpath.include?("[@bar=\"bar\"]")
|
37
|
+
end
|
38
|
+
|
39
|
+
test "xpath with given xpath and attributes" do
|
40
|
+
xpath = Element.new.xpath('.//div', :foo => 'foo')
|
41
|
+
assert_equal ".//div[@foo=\"foo\"]", xpath
|
35
42
|
end
|
36
43
|
|
37
44
|
# all
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.expand_path('../../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class LocatorMatcherHaveContentTest < Test::Unit::TestCase
|
4
|
+
include Locator::Matcher
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@html = '<p><a class="foo">The link</a></p>'
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'target matches a given text' do
|
11
|
+
assert contain('The link').matches?(@html)
|
12
|
+
end
|
13
|
+
|
14
|
+
test 'target does not match a given text' do
|
15
|
+
assert !contain('No link').matches?(@html)
|
16
|
+
end
|
17
|
+
|
18
|
+
test 'target matches a given regex' do
|
19
|
+
assert contain(/The\slink/).matches?(@html)
|
20
|
+
end
|
21
|
+
|
22
|
+
test 'target does not match a given regex' do
|
23
|
+
assert !contain(/No\slink/).matches?(@html)
|
24
|
+
end
|
25
|
+
|
26
|
+
test 'treats newslines as spaces' do
|
27
|
+
assert contain('Some text').matches?("<p>Some\ntext</p>")
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require File.expand_path('../../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class LocatorMatcherHaveTagTest < Test::Unit::TestCase
|
4
|
+
include Locator::Matcher
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@html = '<p><a class="foo">The link</a></p>'
|
8
|
+
end
|
9
|
+
|
10
|
+
# given a selector
|
11
|
+
|
12
|
+
test 'target matches a given selector' do
|
13
|
+
assert have_tag('The link').matches?(@html)
|
14
|
+
end
|
15
|
+
|
16
|
+
test 'target does not match a given selector' do
|
17
|
+
assert !have_tag('No link').matches?(@html)
|
18
|
+
end
|
19
|
+
|
20
|
+
# given an xpath
|
21
|
+
|
22
|
+
test 'target matches a given xpath' do
|
23
|
+
assert have_tag(:xpath => '//p/a[@class="foo"]').matches?(@html)
|
24
|
+
end
|
25
|
+
|
26
|
+
test 'target does not match a given xpath' do
|
27
|
+
assert !have_tag(:xpath => '//p/a[@id="foo"]').matches?(@html)
|
28
|
+
end
|
29
|
+
|
30
|
+
# given a css selector
|
31
|
+
|
32
|
+
test 'target matches a given css' do
|
33
|
+
assert have_tag(:css => 'p a.foo').matches?(@html)
|
34
|
+
end
|
35
|
+
|
36
|
+
test 'target does not match a given css' do
|
37
|
+
assert !have_tag(:css => 'p a#foo').matches?(@html)
|
38
|
+
end
|
39
|
+
|
40
|
+
# given a selector and xpath
|
41
|
+
|
42
|
+
test 'target matches a given selector and xpath' do
|
43
|
+
assert have_tag('The link', :xpath => '//p/a').matches?(@html)
|
44
|
+
end
|
45
|
+
|
46
|
+
test 'target does not match a given (wrong) selector and xpath' do
|
47
|
+
assert !have_tag('No link', :xpath => '//p/a').matches?(@html)
|
48
|
+
end
|
49
|
+
|
50
|
+
test 'target does not match a given selector and (wrong) xpath' do
|
51
|
+
assert !have_tag('The link', :xpath => '//p/div').matches?(@html)
|
52
|
+
end
|
53
|
+
|
54
|
+
# given a selector and css selector
|
55
|
+
|
56
|
+
test 'target matches a given selector and css selector' do
|
57
|
+
assert have_tag('The link', :css => 'p a').matches?(@html)
|
58
|
+
end
|
59
|
+
|
60
|
+
test 'target does not match a given (wrong) selector and css selector' do
|
61
|
+
assert !have_tag('No link', :css => 'p a').matches?(@html)
|
62
|
+
end
|
63
|
+
|
64
|
+
test 'target does not match a given selector and (wrong) css selector' do
|
65
|
+
assert !have_tag('The link', :css => 'p div').matches?(@html)
|
66
|
+
end
|
67
|
+
|
68
|
+
# given an xpath and attributes
|
69
|
+
|
70
|
+
test 'target matches a given xpath and attributes' do
|
71
|
+
assert have_tag(:xpath => '//p/a', :class => 'foo').matches?(@html)
|
72
|
+
end
|
73
|
+
|
74
|
+
test 'target does not match a given (wrong) xpath and attributes' do
|
75
|
+
assert !have_tag(:xpath => '//p/div', :class => 'foo').matches?(@html)
|
76
|
+
end
|
77
|
+
|
78
|
+
test 'target does not match a given xpath and (wrong) attributes' do
|
79
|
+
assert !have_tag(:xpath => '//p/a', :id => 'foo').matches?(@html)
|
80
|
+
end
|
81
|
+
|
82
|
+
# given selector, xpath and attributes
|
83
|
+
|
84
|
+
test 'target matches a given selector, xpath and attributes' do
|
85
|
+
assert have_tag('The link', :xpath => '//p/a', :class => 'foo').matches?(@html)
|
86
|
+
end
|
87
|
+
|
88
|
+
test 'target does not match a given (wrong) selector, xpath and attributes' do
|
89
|
+
assert !have_tag('The link', :xpath => '//p/div', :class => 'foo').matches?(@html)
|
90
|
+
end
|
91
|
+
|
92
|
+
test 'target does not match a given selector, (wrong) xpath and attributes' do
|
93
|
+
assert !have_tag('No link', :xpath => '//p/a', :class => 'foo').matches?(@html)
|
94
|
+
end
|
95
|
+
|
96
|
+
test 'target does not match a given selector, xpath and (wrong) attributes' do
|
97
|
+
assert !have_tag('The link', :xpath => '//p/a', :class => 'bar').matches?(@html)
|
98
|
+
end
|
99
|
+
|
100
|
+
# given a selector, css selector and attributes
|
101
|
+
|
102
|
+
test 'target matches a given selector, css selector and attributes' do
|
103
|
+
assert have_tag('The link', :css => 'p a', :class => 'foo').matches?(@html)
|
104
|
+
end
|
105
|
+
|
106
|
+
test 'target does not match a given (wrong) selector, css selector and attributes' do
|
107
|
+
assert !have_tag('The link', :css => 'p div', :class => 'foo').matches?(@html)
|
108
|
+
end
|
109
|
+
|
110
|
+
test 'target does not match a given selector, (wrong) css selector and attributes' do
|
111
|
+
assert !have_tag('No link', :css => 'p a', :class => 'foo').matches?(@html)
|
112
|
+
end
|
113
|
+
|
114
|
+
test 'target does not match a given selector, css selector and (wrong) attributes' do
|
115
|
+
assert !have_tag('The link', :css => 'p a', :class => 'bar').matches?(@html)
|
116
|
+
end
|
117
|
+
|
118
|
+
# using a block
|
119
|
+
|
120
|
+
# test 'given block selects from matched elements (block yields true)' do
|
121
|
+
# assert have_tag(:xpath => '//p') { true }.matches?(@html)
|
122
|
+
# end
|
123
|
+
#
|
124
|
+
# test 'given block selects from matched elements (block yields false)' do
|
125
|
+
# assert !have_tag(:xpath => '//p') { false }.matches?(@html)
|
126
|
+
# end
|
127
|
+
|
128
|
+
test 'can use have_path in the given block' do
|
129
|
+
assert have_tag(:xpath => '//p') { assert have_tag(:xpath => '//a').matches?(nil); true }.matches?(@html)
|
130
|
+
end
|
131
|
+
|
132
|
+
test 'uses a relative path when called in a block' do
|
133
|
+
assert have_tag(:xpath => '//p') { assert have_tag(:xpath => '//a').matches?(nil); true }.matches?(@html)
|
134
|
+
end
|
135
|
+
|
136
|
+
test 'does not match parent tags called in a block' do
|
137
|
+
assert have_tag(:xpath => '//a') { assert !have_tag(:xpath => '//p').matches?(nil); true }.matches?(@html)
|
138
|
+
end
|
139
|
+
|
140
|
+
# counting matches
|
141
|
+
|
142
|
+
test 'target contains the given number of elements' do
|
143
|
+
assert have_tag(:xpath => '//p/a', :count => 1).matches?(@html)
|
144
|
+
end
|
145
|
+
|
146
|
+
test 'target does not contain the given number of elements' do
|
147
|
+
assert !have_tag(:xpath => '//p/a', :count => 2).matches?(@html)
|
148
|
+
end
|
149
|
+
|
150
|
+
test 'target contains the given number of elements when used with a block' do
|
151
|
+
assert have_tag(:xpath => '//p/a', :count => 1) { |element| element.name == 'a' }.matches?(@html)
|
152
|
+
end
|
153
|
+
|
154
|
+
test 'target does not contain the given number of elements when used with a block (too few elements)' do
|
155
|
+
assert !have_tag(:xpath => '//p/a', :count => 2) { |element| element.name == 'a' }.matches?(@html)
|
156
|
+
end
|
157
|
+
|
158
|
+
test 'target does not contain the given number of elements when used with a block (block does not match)' do
|
159
|
+
assert !have_tag(:xpath => '//p/a', :count => 1) { |element| element.name == 'div' }.matches?(@html)
|
160
|
+
end
|
161
|
+
end
|
data/test/locator_test.rb
CHANGED
@@ -3,18 +3,18 @@ require File.expand_path('../test_helper', __FILE__)
|
|
3
3
|
class LocatorTest < Test::Unit::TestCase
|
4
4
|
include Locator
|
5
5
|
|
6
|
-
test "returns the element if given an element" do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
6
|
+
# test "returns the element if given an element" do
|
7
|
+
# html = '<p></p>'
|
8
|
+
# element = locate(html, :p)
|
9
|
+
# assert_equal element, locate(html, element)
|
10
|
+
# end
|
11
11
|
|
12
12
|
test "looks up a locator/element class by type" do
|
13
13
|
assert_equal Locator::Element::Field, Locator[:field]
|
14
14
|
end
|
15
15
|
|
16
16
|
test "generates an xpath for type and given args" do
|
17
|
-
xpath =
|
17
|
+
xpath = xpath(:form, :id => 'bar')
|
18
18
|
assert_equal './/form[@id="bar"]', xpath
|
19
19
|
end
|
20
20
|
|
@@ -22,13 +22,13 @@ class LocatorTest < Test::Unit::TestCase
|
|
22
22
|
|
23
23
|
test "locates the first element by node name" do
|
24
24
|
html = '<html><body><form id="foo"></form><form id="bar"></form></body></html>'
|
25
|
-
element =
|
25
|
+
element = locate(html, :form)
|
26
26
|
assert_equal 'foo', element.attribute('id')
|
27
27
|
end
|
28
28
|
|
29
29
|
test "locates the first element by xpath" do
|
30
30
|
html = '<html><body><form id="foo"></form><form id="bar"></form></body></html>'
|
31
|
-
element =
|
31
|
+
element = locate(html, :xpath => '//form')
|
32
32
|
assert_equal 'foo', element.attribute('id')
|
33
33
|
end
|
34
34
|
|
@@ -36,49 +36,49 @@ class LocatorTest < Test::Unit::TestCase
|
|
36
36
|
|
37
37
|
test "within scopes to a locator" do
|
38
38
|
html = '<form></form><div id="bar"><form id="foo"></form></div>'
|
39
|
-
element =
|
39
|
+
element = within(html, :div, :id => 'bar') { locate(:form) }
|
40
40
|
assert_equal 'foo', element.attribute('id')
|
41
41
|
end
|
42
42
|
|
43
43
|
test "within scopes to a css selector" do
|
44
44
|
html = '<form></form><div id="bar"><form id="foo"></form></div>'
|
45
|
-
element =
|
45
|
+
element = within(html, '#bar') { locate(:form) }
|
46
46
|
assert_equal 'foo', element.attribute('id')
|
47
47
|
end
|
48
48
|
|
49
49
|
test "within scopes to an xpath" do
|
50
50
|
html = '<form></form><div id="bar"><form id="foo"></form></div>'
|
51
|
-
element =
|
51
|
+
element = within(html, '//div[@id="bar"]') { locate(:form) }
|
52
52
|
assert_equal 'foo', element.attribute('id')
|
53
53
|
end
|
54
54
|
|
55
55
|
test "nested within blocks" do
|
56
56
|
html = '<form></form><div><form><p id="foo"><p></form></div>'
|
57
|
-
element =
|
57
|
+
element = within(html, :div) { within(:form) { locate(:p) } }
|
58
58
|
assert_equal 'foo', element.attribute('id')
|
59
59
|
end
|
60
60
|
|
61
61
|
test "locates scopes to :within option (css selector)" do
|
62
62
|
html = '<form></form><div><form id="foo"></form></div>'
|
63
|
-
element =
|
63
|
+
element = locate(html, :form, :within => 'div')
|
64
64
|
assert_equal 'foo', element.attribute('id')
|
65
65
|
end
|
66
66
|
|
67
67
|
test "locates scopes to :within option (xpath)" do
|
68
68
|
html = '<form></form><div><form id="foo"></form></div>'
|
69
|
-
element =
|
69
|
+
element = locate(html, :form, :within => '//div')
|
70
70
|
assert_equal 'foo', element.attribute('id')
|
71
71
|
end
|
72
72
|
|
73
73
|
test "within/locate with module included" do
|
74
74
|
html = '<form></form><div><form id="foo"></form></div>'
|
75
|
-
element = within(:div) { locate(
|
75
|
+
element = within(html, :div) { locate(:form) }
|
76
76
|
assert_equal 'foo', element.attribute('id')
|
77
77
|
end
|
78
78
|
|
79
79
|
test "locate when given a block scopes the block to the located element" do
|
80
80
|
html = '<p id="foo"><p><form></form><div><form><p id="bar"><p></form></div>'
|
81
|
-
element = locate(html, :div) { locate(
|
81
|
+
element = locate(html, :div) { locate(:form) { locate(:p) } }
|
82
82
|
assert_equal 'bar', element.attribute('id')
|
83
83
|
end
|
84
84
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: locator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sven Fuchs
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-28 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- lib/locator/element/area.rb
|
43
43
|
- lib/locator/element/button.rb
|
44
44
|
- lib/locator/element/check_box.rb
|
45
|
+
- lib/locator/element/content.rb
|
45
46
|
- lib/locator/element/elements_list.rb
|
46
47
|
- lib/locator/element/field.rb
|
47
48
|
- lib/locator/element/file.rb
|
@@ -56,6 +57,8 @@ files:
|
|
56
57
|
- lib/locator/element/select.rb
|
57
58
|
- lib/locator/element/select_option.rb
|
58
59
|
- lib/locator/element/text_area.rb
|
60
|
+
- lib/locator/matcher.rb
|
61
|
+
- lib/locator/matcher/have_tag.rb
|
59
62
|
- lib/locator/result.rb
|
60
63
|
- lib/locator/version.rb
|
61
64
|
- lib/locator/xpath.rb
|
@@ -73,6 +76,8 @@ files:
|
|
73
76
|
- test/locator/element/select_test.rb
|
74
77
|
- test/locator/element/text_area_test.rb
|
75
78
|
- test/locator/element_test.rb
|
79
|
+
- test/locator/matcher/have_content_test.rb
|
80
|
+
- test/locator/matcher/have_tag_test.rb
|
76
81
|
- test/locator/xpath_test.rb
|
77
82
|
- test/locator_test.rb
|
78
83
|
- test/test_helper.rb
|
@@ -119,6 +124,8 @@ test_files:
|
|
119
124
|
- test/locator/element/select_test.rb
|
120
125
|
- test/locator/element/text_area_test.rb
|
121
126
|
- test/locator/element_test.rb
|
127
|
+
- test/locator/matcher/have_content_test.rb
|
128
|
+
- test/locator/matcher/have_tag_test.rb
|
122
129
|
- test/locator/xpath_test.rb
|
123
130
|
- test/locator_test.rb
|
124
131
|
- test/test_helper.rb
|