capybara-page-object 0.2.1 → 0.3.0

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