locator 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|