capybara-page-object 0.2.1 → 0.3.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 (50) hide show
  1. data/Gemfile +3 -1
  2. data/Gemfile.lock +15 -2
  3. data/Rakefile +27 -13
  4. data/VERSION +1 -1
  5. data/capybara-page-object.gemspec +55 -27
  6. data/lib/capybara-page-object.rb +6 -8
  7. data/lib/collections.rb +11 -0
  8. data/lib/element.rb +11 -0
  9. data/lib/element/anchor.rb +11 -0
  10. data/lib/element/form.rb +64 -0
  11. data/lib/element/form_field.rb +20 -0
  12. data/lib/element/image.rb +20 -0
  13. data/lib/element/input.rb +28 -0
  14. data/lib/element/list.rb +21 -0
  15. data/lib/element/listitem.rb +7 -0
  16. data/lib/element/meta.rb +16 -0
  17. data/lib/element/select.rb +16 -0
  18. data/lib/{table.rb → element/table.rb} +1 -3
  19. data/lib/element/textarea.rb +16 -0
  20. data/lib/{extractors → extractor}/common.rb +3 -11
  21. data/lib/{extractors → extractor}/page_level.rb +3 -13
  22. data/lib/html5_data.rb +14 -0
  23. data/lib/key_value.rb +11 -0
  24. data/lib/navigation.rb +16 -0
  25. data/lib/node.rb +76 -0
  26. data/spec/common_spec.rb +46 -0
  27. data/spec/element/anchor_spec.rb +15 -0
  28. data/spec/element/base_spec.rb +19 -0
  29. data/spec/element/form_field_spec.rb +28 -0
  30. data/spec/element/form_spec.rb +69 -0
  31. data/spec/element/image_spec.rb +30 -0
  32. data/spec/element/input_spec.rb +49 -0
  33. data/spec/element/list_spec.rb +47 -0
  34. data/spec/element/listitem_spec.rb +25 -0
  35. data/spec/element/meta_spec.rb +23 -0
  36. data/spec/element/select_spec.rb +36 -0
  37. data/spec/element/table_spec.rb +30 -0
  38. data/spec/element/textarea_spec.rb +19 -0
  39. data/{test/page.html → spec/fixtures/node.html} +0 -0
  40. data/{test → spec}/helper.rb +2 -11
  41. data/spec/node_spec.rb +45 -0
  42. metadata +120 -109
  43. data/lib/base.rb +0 -29
  44. data/lib/image.rb +0 -13
  45. data/lib/page.rb +0 -15
  46. data/test/image.html +0 -2
  47. data/test/table.html +0 -10
  48. data/test/test_image.rb +0 -20
  49. data/test/test_page.rb +0 -59
  50. data/test/test_table.rb +0 -20
@@ -0,0 +1,21 @@
1
+ module CapybaraPageObject
2
+ class List < CapybaraPageObject::Node
3
+
4
+ # TODO what about DL ?
5
+ def element_names
6
+ ['ul', 'ol']
7
+ end
8
+
9
+ def child_node
10
+ 'li'
11
+ end
12
+
13
+ def items(*args)
14
+ children(*args)
15
+ end
16
+
17
+ def key
18
+ root_node[:id]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ module CapybaraPageObject
2
+ class Listitem < CapybaraPageObject::Node
3
+ def element_names
4
+ ['li']
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ module CapybaraPageObject
2
+ class Meta < CapybaraPageObject::Node
3
+
4
+ def element_names
5
+ ['meta']
6
+ end
7
+
8
+ def key
9
+ root_node[:name]
10
+ end
11
+
12
+ def value
13
+ root_node[:content]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
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
15
+ end
16
+ end
@@ -1,7 +1,5 @@
1
- require File.dirname(__FILE__) + '/base'
2
-
3
1
  module CapybaraPageObject
4
- class Table < CapybaraPageObject::Base
2
+ class Table < CapybaraPageObject::Node
5
3
  def rows(attr={})
6
4
  extract('tr', attr)
7
5
  end
@@ -0,0 +1,16 @@
1
+ module CapybaraPageObject
2
+ 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
14
+ end
15
+ end
16
+ end
@@ -1,4 +1,4 @@
1
- module Extractors
1
+ module Extractor
2
2
 
3
3
  module Common
4
4
  def extract(element, attr={}, page_object_class=nil)
@@ -28,16 +28,8 @@ module Extractors
28
28
  end
29
29
  end
30
30
  end
31
-
32
- def data
33
- r = {}
34
- native.attributes.each do |k, v|
35
- next unless k.start_with?('data-')
36
- r[k.gsub('data-', '')] = v.value
37
- end
38
- r
39
- end
40
-
31
+
32
+ # TODO use method_missing o handle these?
41
33
  def all(*args)
42
34
  source.all(*args)
43
35
  end
@@ -1,19 +1,9 @@
1
- module Extractors
2
- module PageLevel
3
- include Common
4
-
1
+ module Extractor
2
+ module PageLevel
5
3
  def title
6
4
  find('title').text
7
5
  end
8
6
 
9
- def tables(attr={})
10
- extract('table', attr, CapybaraPageObject::Table)
11
- end
12
-
13
- def forms(attr={})
14
- extract('form', attr)
15
- end
16
-
17
7
  def meta_description
18
8
  extract('meta', :by => 'name')['description']['content']
19
9
  end
@@ -22,4 +12,4 @@ module Extractors
22
12
  extract('meta', :by => 'name')['keywords']['content'].split(',').collect(&:strip)
23
13
  end
24
14
  end
25
- end
15
+ end
data/lib/html5_data.rb ADDED
@@ -0,0 +1,14 @@
1
+ module CapybaraPageObject
2
+ module HTML5Data
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
10
+ end
11
+ r
12
+ end
13
+ end
14
+ end
data/lib/key_value.rb ADDED
@@ -0,0 +1,11 @@
1
+ module CapybaraPageObject
2
+ module Collections
3
+ def key
4
+ root_node[:id]
5
+ end
6
+
7
+ def value
8
+ text
9
+ end
10
+ end
11
+ end
data/lib/navigation.rb ADDED
@@ -0,0 +1,16 @@
1
+ module CapybaraPageObject
2
+ module Navigation
3
+ def path(*args)
4
+ raise MissingPath, "You need to override this"
5
+ end
6
+
7
+ def prefix
8
+ ''
9
+ end
10
+
11
+ def visit
12
+ source.visit prefix + path
13
+ self
14
+ end
15
+ end
16
+ end
data/lib/node.rb ADDED
@@ -0,0 +1,76 @@
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'
7
+
8
+ module CapybaraPageObject
9
+ class Node
10
+ include Extractor::Common
11
+ include Extractor::PageLevel
12
+ include CapybaraPageObject::Collections
13
+ include CapybaraPageObject::Navigation
14
+ include CapybaraPageObject::HTML5Data
15
+ include Extractor::PageLevel
16
+
17
+ attr_accessor :source
18
+
19
+ def initialize(source=nil)
20
+ source ||= Capybara.current_session
21
+ @source = source
22
+ end
23
+
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)
30
+ end
31
+
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
+ def classes
41
+ classes_list = root_node[:class] or return []
42
+ classes_list.split(' ')
43
+ 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
+ end
73
+
74
+ class MissingPath < RuntimeError
75
+ end
76
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ describe "Page" do
4
+ before do
5
+ html = File.open(File.dirname(__FILE__) + '/fixtures/node.html').read
6
+ @page = CapybaraPageObject::Node.from_string html
7
+ end
8
+
9
+ context "#tables" do
10
+ it "returns an array of Table objects" do
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')
18
+ 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
+ end
22
+ end
23
+
24
+ context "#forms" do
25
+ it "returns the ids for the forms" do
26
+ @page.forms(:keys => 'id').should =~ ['form_1', 'form_2']
27
+ end
28
+ end
29
+
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
+ context "#data" do
36
+ it "returns an empty hash if the element has no HTML5 data attributes" do
37
+ e = Capybara.string('<foo/>')
38
+ e.data.should == {}
39
+ end
40
+
41
+ it "returns a hash of the elements HTML5 data attributes" do
42
+ h = {'foo' => 'a', 'bar' => 'b', 'cat' => ''}
43
+ @page.find('#data').data.should == h
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+
3
+ describe "Anchor" do
4
+
5
+ before do
6
+ @anchor = CapybaraPageObject::Anchor.from_string '<a href="hello.html">'
7
+ end
8
+
9
+ context "#link" do
10
+ it "return a URI object" do
11
+ @anchor.link.class.should == URI::Generic
12
+ @anchor.link.path.should == 'hello.html'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+
3
+ describe "Base" do
4
+ before do
5
+ @tag = CapybaraPageObject::Anchor.from_string '<a id="bar">content</a>'
6
+ end
7
+
8
+ context "#key" do
9
+ it "default to the ID if not overridden" do
10
+ @tag.key.should == 'bar'
11
+ end
12
+ end
13
+
14
+ context "#value" do
15
+ it "default to the text if not overridden" do
16
+ @tag.value.should == 'content'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+
3
+ describe "FormField" do
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>'
8
+ end
9
+
10
+ context "#value" do
11
+ it "delegates" do
12
+ @input.value.should == 'hello'
13
+ @textarea.value.should == 'foo'
14
+ end
15
+ end
16
+
17
+ context "#blank" do
18
+ it "is false if there is an input value" do
19
+ @input.should_not be_blank
20
+ end
21
+ it "is false if there is textarea content" do
22
+ @textarea.should_not be_blank
23
+ end
24
+ it "is true if there is no textarea content" do
25
+ @blank_textarea.should be_blank
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,69 @@
1
+ require File.dirname(__FILE__) + '/../helper'
2
+
3
+ describe "Form" do
4
+ before do
5
+ @form = CapybaraPageObject::Form.from_string <<-EOF
6
+ <form>
7
+ <input name="input_1" value="value_1">
8
+ <input type="text" name="text_input" value="text_input_value">
9
+
10
+ <input type="password" name="password_input" value="password">
11
+
12
+ <select name="colour">
13
+ <option>red</option>
14
+ <option selected>blue</option>
15
+ </select>
16
+
17
+ <select name="countries" multiple>
18
+ <option>france</option>
19
+ <option selected>spain</option>
20
+ <option selected>germany</option>
21
+ </select>
22
+
23
+ <textarea name="essay">hello world</textarea>
24
+ <input type="checkbox" name="checkbox_1" value="checkbox_value_1">
25
+ <input type="checkbox" name="checkbox_2" value="checkbox_value_2" checked>
26
+
27
+ <input type="radio" name="radio_button_1" value="radio_value_1">
28
+ <input type="radio" name="radio_button_2" value="radio_value_2" checked>
29
+
30
+ <input type="submit" value="submit button"></input>
31
+ <input type="reset" value="reset button"></input>
32
+ <input type="button" value="button button"></input>
33
+ <button>button 2</button>
34
+ </form>
35
+ EOF
36
+ end
37
+
38
+ context "#buttons" do
39
+ it "return the buttons contained in the form" do
40
+ @form.buttons.size.should == 4
41
+ end
42
+ end
43
+
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
61
+
62
+ it "provides direct read access to form's fields" do
63
+ @form.essay.should == 'hello world'
64
+ end
65
+
66
+ it "doesn't respond to nonexistant fields" do
67
+ @form.should_not respond_to(:nonexistant_field)
68
+ end
69
+ end