capybara-page-object 0.3.0 → 0.5.0
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/README.markdown +83 -0
- data/VERSION +1 -1
- data/capybara-page-object.gemspec +17 -10
- data/lib/capybara-page-object.rb +4 -4
- data/lib/collections.rb +11 -5
- data/lib/delegators.rb +14 -0
- data/lib/element.rb +14 -11
- data/lib/element/TODO.md +11 -0
- data/lib/element/anchor.rb +1 -5
- data/lib/element/form.rb +6 -10
- data/lib/element/form_field.rb +4 -9
- data/lib/element/head.rb +15 -0
- data/lib/element/image.rb +6 -11
- data/lib/element/input.rb +8 -13
- data/lib/element/list.rb +1 -15
- data/lib/element/list_item.rb +7 -0
- data/lib/element/meta.rb +2 -7
- data/lib/element/select.rb +1 -13
- data/lib/element/table.rb +11 -4
- data/lib/element/table_header.rb +4 -0
- data/lib/element/table_row.rb +7 -0
- data/lib/element/text_based_input.rb +16 -0
- data/lib/element/textarea.rb +5 -11
- data/lib/html5_data.rb +3 -7
- data/lib/key_value.rb +1 -1
- data/lib/node.rb +9 -54
- data/lib/page.rb +40 -0
- data/spec/common_spec.rb +13 -21
- data/spec/element/anchor_spec.rb +2 -2
- data/spec/element/base_spec.rb +2 -2
- data/spec/element/form_field_spec.rb +4 -4
- data/spec/element/form_spec.rb +26 -25
- data/spec/element/head_spec.rb +24 -0
- data/spec/element/image_spec.rb +5 -5
- data/spec/element/input_spec.rb +52 -17
- data/spec/element/list_item_spec.rb +19 -0
- data/spec/element/list_spec.rb +3 -20
- data/spec/element/meta_spec.rb +3 -2
- data/spec/element/select_spec.rb +4 -29
- data/spec/element/table_row_spec.rb +19 -0
- data/spec/element/table_spec.rb +35 -5
- data/spec/element/textarea_spec.rb +14 -4
- data/spec/node_spec.rb +14 -37
- data/spec/page_spec.rb +37 -0
- metadata +31 -24
- data/README.rdoc +0 -18
- data/lib/element/listitem.rb +0 -7
- data/lib/extractor/common.rb +0 -42
- data/lib/extractor/page_level.rb +0 -15
- data/lib/navigation.rb +0 -16
- data/spec/element/listitem_spec.rb +0 -25
data/lib/element/meta.rb
CHANGED
data/lib/element/select.rb
CHANGED
@@ -1,16 +1,4 @@
|
|
1
1
|
module CapybaraPageObject
|
2
|
-
class Select < CapybaraPageObject::
|
3
|
-
|
4
|
-
def element_names
|
5
|
-
['select']
|
6
|
-
end
|
7
|
-
|
8
|
-
def key
|
9
|
-
root_node[:name]
|
10
|
-
end
|
11
|
-
|
12
|
-
def value
|
13
|
-
root_node.value
|
14
|
-
end
|
2
|
+
class Select < CapybaraPageObject::FormField
|
15
3
|
end
|
16
4
|
end
|
data/lib/element/table.rb
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
module CapybaraPageObject
|
2
2
|
class Table < CapybaraPageObject::Node
|
3
|
-
def rows
|
4
|
-
|
3
|
+
def rows
|
4
|
+
all('tr').each_with_object({}) do |e, hash|
|
5
|
+
tr = CapybaraPageObject::TableRow.new(e)
|
6
|
+
next if tr.header?
|
7
|
+
hash[tr.key] = tr
|
8
|
+
end
|
5
9
|
end
|
6
10
|
|
7
|
-
def headers
|
8
|
-
|
11
|
+
def headers
|
12
|
+
all('th').each_with_object({}) do |e, hash|
|
13
|
+
th = CapybaraPageObject::TableHeader.new(e)
|
14
|
+
hash[th.key] = th
|
15
|
+
end
|
9
16
|
end
|
10
17
|
end
|
11
18
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# TODO where should this file be?
|
2
|
+
module CapybaraPageObject
|
3
|
+
module TextBasedInput
|
4
|
+
def clear!
|
5
|
+
source.fill_in key, :with => ''
|
6
|
+
end
|
7
|
+
|
8
|
+
def value=(value)
|
9
|
+
source.fill_in key, :with => value
|
10
|
+
end
|
11
|
+
|
12
|
+
def key
|
13
|
+
source[:name]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/element/textarea.rb
CHANGED
@@ -1,16 +1,10 @@
|
|
1
|
+
require 'element/text_based_input'
|
2
|
+
|
1
3
|
module CapybaraPageObject
|
2
4
|
class Textarea < CapybaraPageObject::Node
|
3
|
-
|
4
|
-
def
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
def key
|
9
|
-
root_node[:name]
|
10
|
-
end
|
11
|
-
|
12
|
-
def value
|
13
|
-
text
|
5
|
+
include TextBasedInput
|
6
|
+
def blank?
|
7
|
+
'' == text
|
14
8
|
end
|
15
9
|
end
|
16
10
|
end
|
data/lib/html5_data.rb
CHANGED
@@ -1,14 +1,10 @@
|
|
1
1
|
module CapybaraPageObject
|
2
2
|
module HTML5Data
|
3
3
|
def data
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
next unless k.start_with?('data-')
|
8
|
-
r[k.gsub('data-', '')] = v.value
|
9
|
-
end
|
4
|
+
source.native.attributes.each_with_object({}) do |(k, v), hash|
|
5
|
+
next unless k.start_with?('data-')
|
6
|
+
hash[k.gsub('data-', '')] = v.value
|
10
7
|
end
|
11
|
-
r
|
12
8
|
end
|
13
9
|
end
|
14
10
|
end
|
data/lib/key_value.rb
CHANGED
data/lib/node.rb
CHANGED
@@ -1,18 +1,13 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require File.dirname(__FILE__) + '/extractor/common'
|
6
|
-
require File.dirname(__FILE__) + '/extractor/page_level'
|
1
|
+
require 'collections'
|
2
|
+
require 'key_value'
|
3
|
+
require 'html5_data'
|
4
|
+
require 'delegators'
|
7
5
|
|
8
6
|
module CapybaraPageObject
|
9
|
-
class Node
|
10
|
-
include
|
11
|
-
include Extractor::PageLevel
|
7
|
+
class Node < Capybara::Node::Element
|
8
|
+
include Delegators
|
12
9
|
include CapybaraPageObject::Collections
|
13
|
-
include CapybaraPageObject::Navigation
|
14
10
|
include CapybaraPageObject::HTML5Data
|
15
|
-
include Extractor::PageLevel
|
16
11
|
|
17
12
|
attr_accessor :source
|
18
13
|
|
@@ -21,54 +16,14 @@ module CapybaraPageObject
|
|
21
16
|
@source = source
|
22
17
|
end
|
23
18
|
|
24
|
-
def self.from_string(string)
|
25
|
-
new(Capybara.string(string))
|
26
|
-
end
|
27
|
-
|
28
|
-
def respond_to?(sym)
|
29
|
-
source.respond_to?(sym) || super(sym)
|
19
|
+
def self.from_string(string, target)
|
20
|
+
new(Capybara.string(string).find(target))
|
30
21
|
end
|
31
22
|
|
32
|
-
def method_missing(sym, *args, &block)
|
33
|
-
if source.respond_to?(sym)
|
34
|
-
source.send(sym)
|
35
|
-
else
|
36
|
-
super(sym, *args, &block)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
23
|
def classes
|
41
|
-
classes_list =
|
24
|
+
classes_list = source[:class] or return []
|
42
25
|
classes_list.split(' ')
|
43
26
|
end
|
44
|
-
|
45
|
-
def children(opts={})
|
46
|
-
factory = opts[:factory]
|
47
|
-
return all(child_node) unless factory
|
48
|
-
r = []
|
49
|
-
all(child_node).each do |li|
|
50
|
-
r << factory.new(li)
|
51
|
-
end
|
52
|
-
r
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def element_names
|
58
|
-
raise "You need to override element_names"
|
59
|
-
end
|
60
|
-
|
61
|
-
def root_node
|
62
|
-
# TODO still don't fully understand why we need both approaches
|
63
|
-
element_names.each do |element_name|
|
64
|
-
if source.native.name == element_name
|
65
|
-
return source.native
|
66
|
-
elsif source.has_css?(element_name)
|
67
|
-
return find(element_name)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
raise "No element matches for #{element_names.join(', ')}"
|
71
|
-
end
|
72
27
|
end
|
73
28
|
|
74
29
|
class MissingPath < RuntimeError
|
data/lib/page.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module CapybaraPageObject
|
2
|
+
class Page < CapybaraPageObject::Node
|
3
|
+
|
4
|
+
def initialize(attr={}, source=nil)
|
5
|
+
super(source)
|
6
|
+
@attr = attr
|
7
|
+
visit
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def path(*args)
|
12
|
+
raise MissingPath, "You need to override #path in #{self.class}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def refresh
|
16
|
+
visit
|
17
|
+
end
|
18
|
+
|
19
|
+
def prefix
|
20
|
+
''
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def visit
|
26
|
+
target = prefix + path
|
27
|
+
if @attr
|
28
|
+
pairs = []
|
29
|
+
@attr.each do |k, v|
|
30
|
+
pairs << "#{k}=#{v}"
|
31
|
+
end
|
32
|
+
target += '?' + pairs.join('&') if pairs.any?
|
33
|
+
end
|
34
|
+
if target == source.current_path
|
35
|
+
raise "Detected repeat of page load - use #reload instead"
|
36
|
+
end
|
37
|
+
source.visit target
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/common_spec.rb
CHANGED
@@ -1,46 +1,38 @@
|
|
1
|
-
require
|
1
|
+
require 'helper'
|
2
2
|
|
3
3
|
describe "Page" do
|
4
4
|
before do
|
5
5
|
html = File.open(File.dirname(__FILE__) + '/fixtures/node.html').read
|
6
|
-
@page = CapybaraPageObject::Node.from_string html
|
6
|
+
@page = CapybaraPageObject::Node.from_string html, 'body'
|
7
7
|
end
|
8
8
|
|
9
9
|
context "#tables" do
|
10
|
-
it "returns
|
10
|
+
it "returns a hash of Tables keyed by ID" do
|
11
11
|
tables = @page.tables
|
12
|
-
tables
|
13
|
-
tables[0].class.should == CapybaraPageObject::Table
|
14
|
-
end
|
15
|
-
|
16
|
-
it "returns a hash of Tables keyed by id" do
|
17
|
-
tables = @page.tables(:by => 'id')
|
12
|
+
tables.keys.should == ['table_1', 'table_2']
|
18
13
|
tables['table_1'].class.should == CapybaraPageObject::Table
|
19
|
-
tables['table_2'].class.should == CapybaraPageObject::Table
|
20
|
-
# TODO: support @page.tables[:table_1] ? perhaps have a default_key override?
|
21
14
|
end
|
22
15
|
end
|
23
16
|
|
24
17
|
context "#forms" do
|
25
|
-
|
26
|
-
@page.forms
|
18
|
+
pending "returns a hash of Forms keyed by ID" do
|
19
|
+
@page.forms.should == ['form_1', 'form_2']
|
20
|
+
@page.forms['form_1'].class.should == CapybaraPageObject::Form
|
27
21
|
end
|
28
22
|
end
|
29
23
|
|
30
|
-
it "return the elements as a hash" do
|
31
|
-
@page.tables(:keys => 'id').should =~ ['table_1', 'table_2']
|
32
|
-
@page.tables(:keys => 'class').should =~ ['table_1_class', 'table_2_class']
|
33
|
-
end
|
34
|
-
|
35
24
|
context "#data" do
|
36
25
|
it "returns an empty hash if the element has no HTML5 data attributes" do
|
37
|
-
|
38
|
-
|
26
|
+
html = '<div foo="bar"/>'
|
27
|
+
@fragment = CapybaraPageObject::Node.from_string html, 'div'
|
28
|
+
@fragment.data.should == {}
|
39
29
|
end
|
40
30
|
|
41
31
|
it "returns a hash of the elements HTML5 data attributes" do
|
32
|
+
html = '<div id="data" data-foo="a" data-bar="b" data-cat>Some data</div>'
|
33
|
+
@fragment = CapybaraPageObject::Node.from_string html, 'div'
|
42
34
|
h = {'foo' => 'a', 'bar' => 'b', 'cat' => ''}
|
43
|
-
@
|
35
|
+
@fragment.data.should == h
|
44
36
|
end
|
45
37
|
end
|
46
38
|
end
|
data/spec/element/anchor_spec.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
1
|
+
require 'helper'
|
2
2
|
|
3
3
|
describe "Anchor" do
|
4
4
|
|
5
5
|
before do
|
6
|
-
@anchor = CapybaraPageObject::Anchor.from_string
|
6
|
+
@anchor = CapybaraPageObject::Anchor.from_string('<a href="hello.html">', 'a')
|
7
7
|
end
|
8
8
|
|
9
9
|
context "#link" do
|
data/spec/element/base_spec.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require 'helper'
|
2
2
|
|
3
3
|
describe "Base" do
|
4
4
|
before do
|
5
|
-
@tag = CapybaraPageObject::Anchor.from_string '<a id="bar">content</a>'
|
5
|
+
@tag = CapybaraPageObject::Anchor.from_string '<a id="bar">content</a>', 'a'
|
6
6
|
end
|
7
7
|
|
8
8
|
context "#key" do
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require 'helper'
|
2
2
|
|
3
3
|
describe "FormField" do
|
4
4
|
before do
|
5
|
-
@input = CapybaraPageObject::FormField.from_string '<input value="hello">'
|
6
|
-
@textarea = CapybaraPageObject::FormField.from_string '<textarea>foo</textarea>'
|
7
|
-
@blank_textarea = CapybaraPageObject::FormField.from_string '<textarea></textarea>'
|
5
|
+
@input = CapybaraPageObject::FormField.from_string '<input value="hello">', 'input'
|
6
|
+
@textarea = CapybaraPageObject::FormField.from_string '<textarea>foo</textarea>', 'textarea'
|
7
|
+
@blank_textarea = CapybaraPageObject::FormField.from_string '<textarea></textarea>', 'textarea'
|
8
8
|
end
|
9
9
|
|
10
10
|
context "#value" do
|
data/spec/element/form_spec.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require 'helper'
|
2
2
|
|
3
3
|
describe "Form" do
|
4
4
|
before do
|
5
|
-
|
5
|
+
html = <<-EOF
|
6
6
|
<form>
|
7
7
|
<input name="input_1" value="value_1">
|
8
8
|
<input type="text" name="text_input" value="text_input_value">
|
@@ -33,6 +33,7 @@ describe "Form" do
|
|
33
33
|
<button>button 2</button>
|
34
34
|
</form>
|
35
35
|
EOF
|
36
|
+
@form = CapybaraPageObject::Form.from_string html, 'form'
|
36
37
|
end
|
37
38
|
|
38
39
|
context "#buttons" do
|
@@ -41,29 +42,29 @@ describe "Form" do
|
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
|
-
context "#fields" do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
45
|
+
# context "#fields" do
|
46
|
+
# it "return the fields contained in the form - inputs, selects and textareas. Excludes button type inputs (submit, reset, etc.)" do
|
47
|
+
# f = {
|
48
|
+
# 'input_1' => 'value_1',
|
49
|
+
# 'text_input' => 'text_input_value',
|
50
|
+
# 'password_input' => 'password',
|
51
|
+
# 'colour' => 'blue',
|
52
|
+
# 'essay' => 'hello world',
|
53
|
+
# 'checkbox_1' => false,
|
54
|
+
# 'checkbox_2' => true,
|
55
|
+
# 'radio_button_1' => false,
|
56
|
+
# 'radio_button_2' => true,
|
57
|
+
# 'countries' => ['spain', 'germany']
|
58
|
+
# }
|
59
|
+
# @form.fields.should == f
|
60
|
+
# end
|
61
|
+
# end
|
61
62
|
|
62
|
-
it "provides direct read access to form's fields" do
|
63
|
-
|
64
|
-
end
|
63
|
+
# it "provides direct read access to form's fields" do
|
64
|
+
# @form.essay.should == 'hello world'
|
65
|
+
# end
|
65
66
|
|
66
|
-
it "doesn't respond to nonexistant fields" do
|
67
|
-
|
68
|
-
end
|
67
|
+
# it "doesn't respond to nonexistant fields" do
|
68
|
+
# @form.should_not respond_to(:nonexistant_field)
|
69
|
+
# end
|
69
70
|
end
|