capybara-pageobject 0.1.1 → 0.1.2

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/.gitignore CHANGED
@@ -6,3 +6,4 @@ pkg/*
6
6
  *.iml
7
7
  *.ipr
8
8
  *.iws
9
+ doc/
@@ -0,0 +1,112 @@
1
+ = Capybara-PageObject
2
+
3
+ capybara-pageobject helps you easily define page objects for capybara based tests.
4
+ Page objects allow you to abstract your tests from low-level UI bindings.
5
+ This allows you to easily adapt your tests to UI changes.
6
+
7
+ == Setup
8
+
9
+ Install as a gem:
10
+
11
+ sudo gem install capybara-pageobject
12
+
13
+ == Usage
14
+
15
+ Add the following section to your env.rb or acceptance_helper:
16
+
17
+ Capybara::PageObject.configure do |config|
18
+ config.page_file = 'support/pages/pages.yml'
19
+ end
20
+
21
+ The gem makes a method 'website' available to your tests.
22
+
23
+
24
+ == Page definitions
25
+
26
+ Page definitions are specified in a YAML file. for eg:
27
+
28
+ home_page:
29
+ id: "#header_banner"
30
+ url: "/"
31
+ login_form:
32
+ id: "#login-form"
33
+ url: "/sign_in"
34
+ attributes:
35
+ email_address: "#email"
36
+ password: "#password.red"
37
+ error_message: "#alert_message"
38
+ actions:
39
+ login_button: "#login_submit"
40
+
41
+ === page
42
+ Each first-level definition specifies a page.
43
+ The above YAML declares that you have two pages home_page and login_form.
44
+
45
+ === url
46
+ The url attribute specifies the url of the page.
47
+ You can navigate to these pages as below:
48
+
49
+ website.home_page.visit
50
+ website.login_form.visit
51
+
52
+ === Dynamic urls
53
+ For RESTful dynamci urls, use the following definition:
54
+ comment_page:
55
+ url: "/users/:user_id/comments/:comment_id"
56
+
57
+ You can then visit the comments page as below:
58
+
59
+ website.comments_page.visit user_id: 3, comment_id: 1
60
+
61
+ === id
62
+ The id attribute specifies the CSS3 selector which uniquely identifies that the page is loaded.
63
+ You can use this as below:
64
+
65
+ website.login_form.visit
66
+ website.login_form.should be_visible
67
+
68
+ === attributes
69
+ Each attribute on the page is specified alongwith the CSS3 selector to uniquely identify it.
70
+ Each attribute definition can be used as below:
71
+
72
+ website.login_form.email_address "foo bar" #Set email address to 'foo bar'
73
+ website.login_form.some_checkbox true #Check checkbox
74
+ website.login_form.email_address.should == "foo bar" #Assert email address is equal to 'foo bar'
75
+ website.login_form.email_address.should be_visible #Assert email address is visible
76
+
77
+ Attributes also work with text content. for eg:
78
+
79
+ website.login_form.error_message.should == "Some error occurred"
80
+
81
+ === actions
82
+ Any clickable (button or link) element on the page is defined as an action.
83
+ Each action definition can be used as below:
84
+
85
+ website.login_form.login_button.click
86
+ website.login_form.login_button.should be_disabled
87
+ website.login_form.login_button.should be_visible
88
+
89
+ ==Page block mode
90
+ To make your tests more readable, you can specify page interactions within a block. for eg:
91
+
92
+ website.login_form do
93
+ email_address 'foo@example.com'
94
+ password 'testing'
95
+ login_button.click
96
+ error_message.should be_visible
97
+ end
98
+
99
+ ===Custom Page Class
100
+ If you need to define custom actions on the page, add a class which extends Capybara::PageObject::Page
101
+ You can them specify it in the YAML file as below:
102
+
103
+ login_form:
104
+ id: "#login-form"
105
+ url: "/sign_in"
106
+ class: CustomLoginForm
107
+
108
+ ===TODO
109
+ * XPath selectors
110
+ * Standard setters ie website.login_form.email_address = "foo bar"
111
+
112
+
@@ -1,9 +1,11 @@
1
1
  require "capybara-pageobject/version"
2
2
  require "monkey-patch/string"
3
3
  require "monkey-patch/object"
4
+ require "monkey-patch/hash"
4
5
 
5
6
  module Capybara
6
7
  module PageObject
8
+ autoload :UrlParser, 'capybara-pageobject/url_parser'
7
9
  autoload :Page, 'capybara-pageobject/page'
8
10
  autoload :CapybaraHelper, 'capybara-pageobject/capybara_helper'
9
11
  autoload :Element, 'capybara-pageobject/element'
@@ -1,8 +1,11 @@
1
+ require 'capybara/rspec/matchers'
2
+
1
3
  module Capybara
2
4
  module PageObject
3
5
  class Page
4
6
  include CapybaraHelper
5
7
  include RSpec::Matchers
8
+ include Capybara::RSpecMatchers
6
9
 
7
10
  attr_accessor :context
8
11
 
@@ -20,14 +23,18 @@ module Capybara
20
23
  end
21
24
  end
22
25
 
23
- def visit
24
- @page_data["url"] ? page.visit(@page_data["url"]) : raise("url not defined for page")
26
+ def visit url_params={}
27
+ page.visit(UrlParser.new(@page_data["url"]).format(url_params))
25
28
  end
26
29
 
27
30
  def visible?
28
31
  @page_data["id"] ? if_absent(false) { page.find(@page_data["id"]).visible? } : raise("id not defined for page")
29
32
  end
30
33
 
34
+ def has_content? content
35
+ page.has_content?(content.to_s)
36
+ end
37
+
31
38
  def page_title
32
39
  if_absent("") { page.find("head title").text }
33
40
  end
@@ -0,0 +1,26 @@
1
+ module Capybara
2
+ module PageObject
3
+ class UrlParser
4
+
5
+ def initialize url
6
+ raise 'url is not defined' if url.blank?
7
+ @url = url.dup
8
+ end
9
+
10
+ def format url_params
11
+ url_params.symbolize_keys!
12
+ dynamic_params = parse_params(@url)
13
+
14
+ raise "Please pass url parameters: #{dynamic_params}" unless url_params.keys.sort == dynamic_params.sort
15
+ url_params.each_pair { |param, value| @url.gsub!(":#{param}", value.to_s) }
16
+ @url
17
+ end
18
+
19
+ private
20
+
21
+ def parse_params url
22
+ url.scan(/:(\w+)/).flatten.map { |p| p.to_sym }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,5 @@
1
1
  module Capybara
2
2
  module PageObject
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
@@ -0,0 +1,12 @@
1
+ module MonkeyPatch
2
+ module Hash
3
+ def symbolize_keys!
4
+ keys.each do |key|
5
+ self[(key.to_sym rescue key) || key] = delete(key)
6
+ end
7
+ self
8
+ end
9
+ end
10
+ end
11
+
12
+ Hash.send(:include, MonkeyPatch::Hash)
@@ -63,8 +63,9 @@ describe "Page" do
63
63
  capybara_page.should have_content "Email Address"
64
64
  end
65
65
 
66
- it "should fail if url is not specified" do
67
- expect { page_object({}).visit }.to raise_error(Exception, "url not defined for page")
66
+ it "should visit pages with dynamic urls" do
67
+ page_object({"url" => "/users/:user_id/comments/:id"}).visit(user_id: 3, id: 2)
68
+ capybara_page.should have_content "User data"
68
69
  end
69
70
  end
70
71
 
@@ -86,6 +87,20 @@ describe "Page" do
86
87
  end
87
88
  end
88
89
 
90
+ describe "has_content?" do
91
+ before(:each) do
92
+ @page = page_object({"url" => "/form"})
93
+ @page.visit
94
+ end
95
+ it "should return true if content is present" do
96
+ @page.should have_content "led zeppelin"
97
+ end
98
+
99
+ it "should handle dates" do
100
+ @page.should have_content Date.parse("1983-01-01")
101
+ end
102
+ end
103
+
89
104
  describe "page_title" do
90
105
  it "should return page title if page has title in head" do
91
106
  page = page_object({"url" => "/form"})
@@ -24,10 +24,15 @@ class TestWebsite < Sinatra::Base
24
24
  '<div id="foo1">led zeppelin</div><div id="foo2">the doors</div>'
25
25
  end
26
26
 
27
+ get '/users/3/comments/2' do
28
+ '<div id="user_home">User data</div>'
29
+ end
30
+
27
31
  get '/form' do
28
32
  page_with do
29
33
  <<-FORM
30
34
  <div id="attr1">led zeppelin</div>
35
+ <div>1983-01-01</div>
31
36
  <div id="hidden_attr" style="display:none">the doors</div>
32
37
  <form id="unique_form">
33
38
  <input type="text" id="field1" value="Creedence Rlearwater Revival"/>
@@ -0,0 +1,39 @@
1
+ require "spec_helper"
2
+
3
+ describe "UrlParser" do
4
+ describe "format" do
5
+ it "should return url if it is static" do
6
+ Capybara::PageObject::UrlParser.new("/users/1").format({}).should == "/users/1"
7
+ end
8
+
9
+ it "should duplicate url string" do
10
+ url = "/users/:user_id"
11
+ parser = Capybara::PageObject::UrlParser.new(url)
12
+ parser.format(user_id: 2)
13
+ url.should == "/users/:user_id"
14
+ end
15
+
16
+ it "should raise error if dynamic url is called without params" do
17
+ expect { Capybara::PageObject::UrlParser.new("/users/:id").format({}) }.to raise_error(Exception, 'Please pass url parameters: [:id]')
18
+ end
19
+
20
+ it "should raise error if number of parameters does not match" do
21
+ expect { Capybara::PageObject::UrlParser.new("/users/:user_id/actions/:id").format({id: 1}) }.to raise_error(Exception, 'Please pass url parameters: [:user_id, :id]')
22
+ end
23
+
24
+ it "should raise error if parameter names don't match" do
25
+ expect { Capybara::PageObject::UrlParser.new("/users/:user_id").format({id: 1}) }.to raise_error(Exception, 'Please pass url parameters: [:user_id]')
26
+ end
27
+
28
+ it "should substitute url parameters" do
29
+ Capybara::PageObject::UrlParser.new("/users/:id").format({id: 2}).should == "/users/2"
30
+ end
31
+
32
+ it "should substitute multiple url parameters and ignore order" do
33
+ Capybara::PageObject::UrlParser.new("/users/:user_id/actions/:id").format({id: 2, user_id: 3}).should == "/users/3/actions/2"
34
+ end
35
+
36
+ it { expect { Capybara::PageObject::UrlParser.new(nil) }.to raise_error(Exception, 'url is not defined') }
37
+ it { expect { Capybara::PageObject::UrlParser.new("") }.to raise_error(Exception, 'url is not defined') }
38
+ end
39
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-pageobject
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-02-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &2156144500 !ruby/object:Gem::Requirement
16
+ requirement: &2161878000 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2156144500
24
+ version_requirements: *2161878000
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: mocha
27
- requirement: &2156141140 !ruby/object:Gem::Requirement
27
+ requirement: &2161877580 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2156141140
35
+ version_requirements: *2161877580
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: sinatra
38
- requirement: &2156139320 !ruby/object:Gem::Requirement
38
+ requirement: &2161877060 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 0.9.4
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2156139320
46
+ version_requirements: *2161877060
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: capybara
49
- requirement: &2156062360 !ruby/object:Gem::Requirement
49
+ requirement: &2161876640 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2156062360
57
+ version_requirements: *2161876640
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: capybara
60
- requirement: &2156061060 !ruby/object:Gem::Requirement
60
+ requirement: &2161876080 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.0.0
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *2156061060
68
+ version_requirements: *2161876080
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec-expectations
71
- requirement: &2156059420 !ruby/object:Gem::Requirement
71
+ requirement: &2161875660 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,7 +76,7 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *2156059420
79
+ version_requirements: *2161875660
80
80
  description: Introduce page objects to your capybara-based functional tests
81
81
  email:
82
82
  - deepak.lewis@gmail.com
@@ -87,6 +87,7 @@ files:
87
87
  - .gitignore
88
88
  - .rvmrc
89
89
  - Gemfile
90
+ - README.rdoc
90
91
  - Rakefile
91
92
  - capybara-pageobject.gemspec
92
93
  - lib/capybara-pageobject.rb
@@ -95,8 +96,10 @@ files:
95
96
  - lib/capybara-pageobject/capybara_helper.rb
96
97
  - lib/capybara-pageobject/element.rb
97
98
  - lib/capybara-pageobject/page.rb
99
+ - lib/capybara-pageobject/url_parser.rb
98
100
  - lib/capybara-pageobject/version.rb
99
101
  - lib/capybara-pageobject/website.rb
102
+ - lib/monkey-patch/hash.rb
100
103
  - lib/monkey-patch/object.rb
101
104
  - lib/monkey-patch/string.rb
102
105
  - spec/action_spec.rb
@@ -108,6 +111,7 @@ files:
108
111
  - spec/support/matchers/delegate.rb
109
112
  - spec/support/pages/pages.yml
110
113
  - spec/support/test_website.rb
114
+ - spec/url_parser_spec.rb
111
115
  - spec/website_spec.rb
112
116
  homepage: ''
113
117
  licenses: []
@@ -143,4 +147,5 @@ test_files:
143
147
  - spec/support/matchers/delegate.rb
144
148
  - spec/support/pages/pages.yml
145
149
  - spec/support/test_website.rb
150
+ - spec/url_parser_spec.rb
146
151
  - spec/website_spec.rb