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.
Files changed (51) hide show
  1. data/README.markdown +83 -0
  2. data/VERSION +1 -1
  3. data/capybara-page-object.gemspec +17 -10
  4. data/lib/capybara-page-object.rb +4 -4
  5. data/lib/collections.rb +11 -5
  6. data/lib/delegators.rb +14 -0
  7. data/lib/element.rb +14 -11
  8. data/lib/element/TODO.md +11 -0
  9. data/lib/element/anchor.rb +1 -5
  10. data/lib/element/form.rb +6 -10
  11. data/lib/element/form_field.rb +4 -9
  12. data/lib/element/head.rb +15 -0
  13. data/lib/element/image.rb +6 -11
  14. data/lib/element/input.rb +8 -13
  15. data/lib/element/list.rb +1 -15
  16. data/lib/element/list_item.rb +7 -0
  17. data/lib/element/meta.rb +2 -7
  18. data/lib/element/select.rb +1 -13
  19. data/lib/element/table.rb +11 -4
  20. data/lib/element/table_header.rb +4 -0
  21. data/lib/element/table_row.rb +7 -0
  22. data/lib/element/text_based_input.rb +16 -0
  23. data/lib/element/textarea.rb +5 -11
  24. data/lib/html5_data.rb +3 -7
  25. data/lib/key_value.rb +1 -1
  26. data/lib/node.rb +9 -54
  27. data/lib/page.rb +40 -0
  28. data/spec/common_spec.rb +13 -21
  29. data/spec/element/anchor_spec.rb +2 -2
  30. data/spec/element/base_spec.rb +2 -2
  31. data/spec/element/form_field_spec.rb +4 -4
  32. data/spec/element/form_spec.rb +26 -25
  33. data/spec/element/head_spec.rb +24 -0
  34. data/spec/element/image_spec.rb +5 -5
  35. data/spec/element/input_spec.rb +52 -17
  36. data/spec/element/list_item_spec.rb +19 -0
  37. data/spec/element/list_spec.rb +3 -20
  38. data/spec/element/meta_spec.rb +3 -2
  39. data/spec/element/select_spec.rb +4 -29
  40. data/spec/element/table_row_spec.rb +19 -0
  41. data/spec/element/table_spec.rb +35 -5
  42. data/spec/element/textarea_spec.rb +14 -4
  43. data/spec/node_spec.rb +14 -37
  44. data/spec/page_spec.rb +37 -0
  45. metadata +31 -24
  46. data/README.rdoc +0 -18
  47. data/lib/element/listitem.rb +0 -7
  48. data/lib/extractor/common.rb +0 -42
  49. data/lib/extractor/page_level.rb +0 -15
  50. data/lib/navigation.rb +0 -16
  51. data/spec/element/listitem_spec.rb +0 -25
@@ -0,0 +1,7 @@
1
+ module CapybaraPageObject
2
+ class ListItem < CapybaraPageObject::Node
3
+ def text
4
+ source.text.strip
5
+ end
6
+ end
7
+ end
@@ -1,16 +1,11 @@
1
1
  module CapybaraPageObject
2
2
  class Meta < CapybaraPageObject::Node
3
-
4
- def element_names
5
- ['meta']
6
- end
7
-
8
3
  def key
9
- root_node[:name]
4
+ source[:name]
10
5
  end
11
6
 
12
7
  def value
13
- root_node[:content]
8
+ source[:content]
14
9
  end
15
10
  end
16
11
  end
@@ -1,16 +1,4 @@
1
1
  module CapybaraPageObject
2
- class Select < CapybaraPageObject::Node
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
@@ -1,11 +1,18 @@
1
1
  module CapybaraPageObject
2
2
  class Table < CapybaraPageObject::Node
3
- def rows(attr={})
4
- extract('tr', attr)
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(attr={})
8
- extract('th', attr)
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,4 @@
1
+ module CapybaraPageObject
2
+ class TableHeader < CapybaraPageObject::Node
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module CapybaraPageObject
2
+ class TableRow < CapybaraPageObject::Node
3
+ def header?
4
+ source.all('th').any?
5
+ end
6
+ end
7
+ 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
@@ -1,16 +1,10 @@
1
+ require 'element/text_based_input'
2
+
1
3
  module CapybaraPageObject
2
4
  class Textarea < CapybaraPageObject::Node
3
-
4
- def element_names
5
- ['textarea']
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
@@ -1,14 +1,10 @@
1
1
  module CapybaraPageObject
2
2
  module HTML5Data
3
3
  def data
4
- r = {}
5
- if native.respond_to?(:attributes)
6
- native.attributes.each do |k, v|
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
@@ -1,7 +1,7 @@
1
1
  module CapybaraPageObject
2
2
  module Collections
3
3
  def key
4
- root_node[:id]
4
+ source[:id]
5
5
  end
6
6
 
7
7
  def value
@@ -1,18 +1,13 @@
1
- require File.dirname(__FILE__) + '/collections'
2
- require File.dirname(__FILE__) + '/navigation'
3
- require File.dirname(__FILE__) + '/key_value'
4
- require File.dirname(__FILE__) + '/html5_data'
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 Extractor::Common
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 = root_node[:class] or return []
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
@@ -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
@@ -1,46 +1,38 @@
1
- require File.dirname(__FILE__) + '/helper'
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 an array of Table objects" do
10
+ it "returns a hash of Tables keyed by ID" do
11
11
  tables = @page.tables
12
- tables[0].class.should == CapybaraPageObject::Table
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
- it "returns the ids for the forms" do
26
- @page.forms(:keys => 'id').should =~ ['form_1', 'form_2']
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
- e = Capybara.string('<foo/>')
38
- e.data.should == {}
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
- @page.find('#data').data.should == h
35
+ @fragment.data.should == h
44
36
  end
45
37
  end
46
38
  end
@@ -1,9 +1,9 @@
1
- require File.dirname(__FILE__) + '/../helper'
1
+ require 'helper'
2
2
 
3
3
  describe "Anchor" do
4
4
 
5
5
  before do
6
- @anchor = CapybaraPageObject::Anchor.from_string '<a href="hello.html">'
6
+ @anchor = CapybaraPageObject::Anchor.from_string('<a href="hello.html">', 'a')
7
7
  end
8
8
 
9
9
  context "#link" do
@@ -1,8 +1,8 @@
1
- require File.dirname(__FILE__) + '/../helper'
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 File.dirname(__FILE__) + '/../helper'
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
@@ -1,8 +1,8 @@
1
- require File.dirname(__FILE__) + '/../helper'
1
+ require 'helper'
2
2
 
3
3
  describe "Form" do
4
4
  before do
5
- @form = CapybaraPageObject::Form.from_string <<-EOF
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
- it "return the fields contained in the form - inputs, selects and textareas. Excludes button type inputs (submit, reset, etc.)" do
46
- f = {
47
- 'input_1' => 'value_1',
48
- 'text_input' => 'text_input_value',
49
- 'password_input' => 'password',
50
- 'colour' => 'blue',
51
- 'essay' => 'hello world',
52
- 'checkbox_1' => false,
53
- 'checkbox_2' => true,
54
- 'radio_button_1' => false,
55
- 'radio_button_2' => true,
56
- 'countries' => ['spain', 'germany']
57
- }
58
- @form.fields.should == f
59
- end
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
- @form.essay.should == 'hello world'
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
- @form.should_not respond_to(:nonexistant_field)
68
- end
67
+ # it "doesn't respond to nonexistant fields" do
68
+ # @form.should_not respond_to(:nonexistant_field)
69
+ # end
69
70
  end