capybara-page-object 0.3.0 → 0.5.0

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