capybara-pageobject 0.0.1 → 0.1.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.
- data/.gitignore +4 -0
- data/.rvmrc +81 -0
- data/Rakefile +7 -0
- data/capybara-pageobject.gemspec +7 -3
- data/lib/capybara-pageobject/action.rb +15 -0
- data/lib/capybara-pageobject/attribute.rb +29 -0
- data/lib/capybara-pageobject/capybara_helper.rb +15 -0
- data/lib/capybara-pageobject/element.rb +24 -0
- data/lib/capybara-pageobject/page.rb +49 -0
- data/lib/capybara-pageobject/version.rb +2 -2
- data/lib/capybara-pageobject/website.rb +31 -0
- data/lib/capybara-pageobject.rb +36 -2
- data/lib/monkey-patch/object.rb +13 -0
- data/lib/monkey-patch/string.rb +16 -0
- data/spec/action_spec.rb +19 -0
- data/spec/attribute_spec.rb +33 -0
- data/spec/capybara-pageobject_spec.rb +38 -0
- data/spec/element_spec.rb +26 -0
- data/spec/page_spec.rb +104 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/matchers/delegate.rb +51 -0
- data/spec/support/pages/pages.yml +7 -0
- data/spec/support/test_website.rb +70 -0
- data/spec/website_spec.rb +51 -0
- metadata +79 -7
data/.gitignore
CHANGED
data/.rvmrc
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
+
# development environment upon cd'ing into the directory
|
5
|
+
|
6
|
+
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
|
7
|
+
environment_id="ruby-1.9.3-p0@capybara-pageobject"
|
8
|
+
|
9
|
+
#
|
10
|
+
# Uncomment the following lines if you want to verify rvm version per project
|
11
|
+
#
|
12
|
+
# rvmrc_rvm_version="1.10.1" # 1.10.1 seams as a safe start
|
13
|
+
# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
|
14
|
+
# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
|
15
|
+
# return 1
|
16
|
+
# }
|
17
|
+
#
|
18
|
+
|
19
|
+
#
|
20
|
+
# Uncomment following line if you want options to be set only for given project.
|
21
|
+
#
|
22
|
+
# PROJECT_JRUBY_OPTS=( --1.9 )
|
23
|
+
#
|
24
|
+
# The variable PROJECT_JRUBY_OPTS requires the following to be run in shell:
|
25
|
+
#
|
26
|
+
# chmod +x ${rvm_path}/hooks/after_use_jruby_opts
|
27
|
+
#
|
28
|
+
|
29
|
+
#
|
30
|
+
# First we attempt to load the desired environment directly from the environment
|
31
|
+
# file. This is very fast and efficient compared to running through the entire
|
32
|
+
# CLI and selector. If you want feedback on which environment was used then
|
33
|
+
# insert the word 'use' after --create as this triggers verbose mode.
|
34
|
+
#
|
35
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
|
36
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
37
|
+
then
|
38
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
39
|
+
|
40
|
+
if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
|
41
|
+
then
|
42
|
+
. "${rvm_path:-$HOME/.rvm}/hooks/after_use"
|
43
|
+
fi
|
44
|
+
else
|
45
|
+
# If the environment file has not yet been created, use the RVM CLI to select.
|
46
|
+
if ! rvm --create "$environment_id"
|
47
|
+
then
|
48
|
+
echo "Failed to create RVM environment '${environment_id}'."
|
49
|
+
return 1
|
50
|
+
fi
|
51
|
+
fi
|
52
|
+
|
53
|
+
#
|
54
|
+
# If you use an RVM gemset file to install a list of gems (*.gems), you can have
|
55
|
+
# it be automatically loaded. Uncomment the following and adjust the filename if
|
56
|
+
# necessary.
|
57
|
+
#
|
58
|
+
# filename=".gems"
|
59
|
+
# if [[ -s "$filename" ]]
|
60
|
+
# then
|
61
|
+
# rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
|
62
|
+
# fi
|
63
|
+
|
64
|
+
# If you use bundler, this might be useful to you:
|
65
|
+
# if [[ -s Gemfile ]] && ! command -v bundle >/dev/null
|
66
|
+
# then
|
67
|
+
# printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
|
68
|
+
# gem install bundler
|
69
|
+
# fi
|
70
|
+
# if [[ -s Gemfile ]] && command -v bundle
|
71
|
+
# then
|
72
|
+
# bundle install
|
73
|
+
# fi
|
74
|
+
|
75
|
+
if [[ $- == *i* ]] # check for interactive shells
|
76
|
+
then
|
77
|
+
echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green
|
78
|
+
else
|
79
|
+
echo "Using: $GEM_HOME" # don't use colors in interactive shells
|
80
|
+
fi
|
81
|
+
|
data/Rakefile
CHANGED
data/capybara-pageobject.gemspec
CHANGED
@@ -4,12 +4,12 @@ require "capybara-pageobject/version"
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "capybara-pageobject"
|
7
|
-
s.version = Capybara::
|
7
|
+
s.version = Capybara::PageObject::VERSION
|
8
8
|
s.authors = ["dlewis"]
|
9
9
|
s.email = ["deepak.lewis@gmail.com"]
|
10
10
|
s.homepage = ""
|
11
11
|
s.summary = %q{Easily create page objects to abstract UI Pages}
|
12
|
-
s.description = %q{
|
12
|
+
s.description = %q{Introduce page objects to your capybara-based functional tests}
|
13
13
|
|
14
14
|
s.rubyforge_project = "capybara-pageobject"
|
15
15
|
|
@@ -19,6 +19,10 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
21
|
# specify any dependencies here; for example:
|
22
|
-
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
s.add_development_dependency "mocha"
|
24
|
+
s.add_development_dependency("sinatra", [">= 0.9.4"])
|
25
|
+
s.add_development_dependency "capybara"
|
26
|
+
|
23
27
|
s.add_runtime_dependency("capybara", [">= 1.0.0"])
|
24
28
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'capybara/dsl'
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
module PageObject
|
5
|
+
class Attribute < Element
|
6
|
+
include Capybara::DSL
|
7
|
+
|
8
|
+
def_delegators :element_value, :blank?, :==, :include?
|
9
|
+
def_delegators :element, :set
|
10
|
+
|
11
|
+
def validation_error
|
12
|
+
error_field = @page.all(".field_with_errors").find do |error_field|
|
13
|
+
Capybara.using_wait_time(0) { error_field.has_selector?(@selector) }
|
14
|
+
end
|
15
|
+
error_field.find(".error_message").text if error_field
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"'attribute: #{@name}'"
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def element_value
|
25
|
+
element.tag_name == "input" ? element.value : element.text
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Capybara
|
2
|
+
module PageObject
|
3
|
+
class Element
|
4
|
+
extend Forwardable
|
5
|
+
include CapybaraHelper
|
6
|
+
|
7
|
+
def initialize page, name, selector
|
8
|
+
@page = page
|
9
|
+
@name = name
|
10
|
+
@selector = selector
|
11
|
+
end
|
12
|
+
|
13
|
+
def visible?
|
14
|
+
if_absent(false) { element.visible? }
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def element
|
20
|
+
@page.find(@selector)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Capybara
|
2
|
+
module PageObject
|
3
|
+
class Page
|
4
|
+
include CapybaraHelper
|
5
|
+
|
6
|
+
attr_accessor :context
|
7
|
+
|
8
|
+
def initialize page, page_data
|
9
|
+
@page = page
|
10
|
+
@page_data = page_data
|
11
|
+
page_data["attributes"].present? and page_data["attributes"].each do |attribute, selector|
|
12
|
+
self.class.send(:define_method, attribute) do |value=nil|
|
13
|
+
Capybara::PageObject::Attribute.new(page, attribute, selector).tap { |node| node.set(value) if value }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
page_data["actions"].present? and page_data["actions"].each do |attribute, selector|
|
18
|
+
self.class.send(:define_method, attribute) { Action.new(page, attribute, selector) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def visit
|
23
|
+
@page_data["url"] ? page.visit(@page_data["url"]) : raise("url not defined for page")
|
24
|
+
end
|
25
|
+
|
26
|
+
def visible?
|
27
|
+
@page_data["id"] ? if_absent(false) { page.find(@page_data["id"]).visible? } : raise("id not defined for page")
|
28
|
+
end
|
29
|
+
|
30
|
+
def page_title
|
31
|
+
if_absent("") { page.find("head title").text }
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
"'page: #{@page_data["name"]}'"
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_missing method, *args
|
39
|
+
page.respond_to?(method) ? page.send(method, *args) : context.send(method, *args)
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def page
|
45
|
+
@page
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Capybara
|
2
|
+
module PageObject
|
3
|
+
class Website
|
4
|
+
|
5
|
+
def initialize page, context, page_file
|
6
|
+
@page = page
|
7
|
+
@context = context
|
8
|
+
|
9
|
+
raise "Please specify page file path" unless page_file.present?
|
10
|
+
@pages_data = YAML.load_file(page_file)
|
11
|
+
|
12
|
+
@pages_data.each do |page, page_data|
|
13
|
+
page_class = (page_data["class"] || "Capybara::PageObject::Page").constantize
|
14
|
+
unless page_class.ancestors.include?(Capybara::PageObject::Page)
|
15
|
+
raise "Custom page class '#{page_class}' should extend Capybara::PageObject::Page"
|
16
|
+
end
|
17
|
+
wrapper = lambda { |&page_actions| on_page_perform(page_actions) { page_class.new(@page, page_data.merge("name" => page)) } }
|
18
|
+
self.class.send(:define_method, page, wrapper)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def on_page_perform(page_actions)
|
25
|
+
page = yield
|
26
|
+
page.context = @context
|
27
|
+
page_actions ? page.instance_eval(&page_actions) : page
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/capybara-pageobject.rb
CHANGED
@@ -1,7 +1,41 @@
|
|
1
1
|
require "capybara-pageobject/version"
|
2
|
+
require "monkey-patch/string"
|
3
|
+
require "monkey-patch/object"
|
2
4
|
|
3
5
|
module Capybara
|
4
|
-
module
|
5
|
-
|
6
|
+
module PageObject
|
7
|
+
autoload :Page, 'capybara-pageobject/page'
|
8
|
+
autoload :CapybaraHelper, 'capybara-pageobject/capybara_helper'
|
9
|
+
autoload :Element, 'capybara-pageobject/element'
|
10
|
+
autoload :Attribute, 'capybara-pageobject/attribute'
|
11
|
+
autoload :Action, 'capybara-pageobject/action'
|
12
|
+
autoload :Website, 'capybara-pageobject/website'
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def configure
|
16
|
+
yield self
|
17
|
+
end
|
18
|
+
|
19
|
+
def page_file= file
|
20
|
+
@page_file = file
|
21
|
+
end
|
22
|
+
|
23
|
+
def current_website
|
24
|
+
@website ||= Capybara::PageObject::Website.new(Capybara.current_session, self, @page_file)
|
25
|
+
end
|
26
|
+
|
27
|
+
def website_class= klass
|
28
|
+
raise "website class #{klass} should extend Capybara::PageObject::Website" unless klass.ancestors.include?(Capybara::PageObject::Website)
|
29
|
+
@website = klass.new(Capybara.current_session, self, @page_file)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module IncludedMethods
|
34
|
+
def website
|
35
|
+
Capybara::PageObject.current_website
|
36
|
+
end
|
37
|
+
end
|
6
38
|
end
|
7
39
|
end
|
40
|
+
|
41
|
+
include Capybara::PageObject::IncludedMethods
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module MonkeyPatch
|
2
|
+
module String
|
3
|
+
def constantize
|
4
|
+
names = self.split('::')
|
5
|
+
names.shift if names.empty? || names.first.empty?
|
6
|
+
|
7
|
+
constant = Object
|
8
|
+
names.each do |name|
|
9
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
10
|
+
end
|
11
|
+
constant
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
String.send(:include, MonkeyPatch::String)
|
data/spec/action_spec.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "action" do
|
4
|
+
def action(selector)
|
5
|
+
Capybara::PageObject::Action.new(capybara_page, "action", selector)
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
capybara_page.visit("/form")
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "delegators" do
|
13
|
+
subject { action("#register_submit") }
|
14
|
+
it { should delegate(:click).to(:element) }
|
15
|
+
end
|
16
|
+
|
17
|
+
it { action("#disabled_button").should be_disabled }
|
18
|
+
it { action("#attr1").to_s.should == "'action: action'" }
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Attribute" do
|
4
|
+
def attribute(selector)
|
5
|
+
Capybara::PageObject::Attribute.new(capybara_page, "attr", selector)
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
capybara_page.visit("/form")
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "read value" do
|
13
|
+
it { attribute("#attr1").should == "led zeppelin" }
|
14
|
+
it { attribute("#field1").should == "Creedence Rlearwater Revival" }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "delegators" do
|
18
|
+
subject { attribute("#field1") }
|
19
|
+
it { should delegate(:include?).to(:element_value) }
|
20
|
+
it { should delegate(:blank?).to(:element_value) }
|
21
|
+
it { should delegate(:==).to(:element_value) }
|
22
|
+
it { should delegate(:set).to(:element).with_arguments("foo.bar") }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "validation_error" do
|
26
|
+
it "should extract validation error from form" do
|
27
|
+
capybara_page.visit("/form_with_rails_validation_errors")
|
28
|
+
attribute("#user_email").validation_error.should == "can't be blank"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it { attribute("#attr1").to_s.should == "'attribute: attr'" }
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Capybara::PageObject" do
|
4
|
+
describe "current_website" do
|
5
|
+
it "should pass page file to the website constructor" do
|
6
|
+
Capybara::PageObject.page_file = "foo.bar"
|
7
|
+
YAML.expects(:load_file).with('foo.bar').returns({})
|
8
|
+
Capybara::PageObject.current_website
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should memoize website object" do
|
12
|
+
Capybara::PageObject.current_website.should be_equal Capybara::PageObject.current_website
|
13
|
+
Capybara::PageObject.current_website.should be_equal Capybara::PageObject.current_website
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "website_class" do
|
18
|
+
before {
|
19
|
+
Capybara::PageObject.page_file = "blah"
|
20
|
+
YAML.stubs(:load_file).returns({})
|
21
|
+
}
|
22
|
+
|
23
|
+
it "should fail if website_class does not extend Website" do
|
24
|
+
expect { Capybara::PageObject.website_class = Object }.to raise_error(Exception, "website class Object should extend Capybara::PageObject::Website")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should instantiate website class if provided" do
|
28
|
+
class StubWebsite < Capybara::PageObject::Website
|
29
|
+
end
|
30
|
+
Capybara::PageObject.website_class = StubWebsite
|
31
|
+
Capybara::PageObject.current_website.class.should == StubWebsite
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should create website method in including class" do
|
35
|
+
website.should be
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe "Element" do
|
5
|
+
def element(selector)
|
6
|
+
Capybara::PageObject::Element.new(capybara_page, "attr", selector)
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
capybara_page.visit("/form")
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "visible?" do
|
14
|
+
context "attribute" do
|
15
|
+
it { element("#attr1").should be_visible }
|
16
|
+
it { element("#hidden_attr").should_not be_visible }
|
17
|
+
it { element("#does_not_exist").should_not be_visible }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "field" do
|
21
|
+
it { element("#field1").should be_visible }
|
22
|
+
it { element("#hidden_field").should_not be_visible }
|
23
|
+
it { element("#does_not_exist").should_not be_visible }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/spec/page_spec.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Page" do
|
4
|
+
def page_object(page_data)
|
5
|
+
Capybara::PageObject::Page.new capybara_page, page_data
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "on form page" do
|
9
|
+
let(:page_data) { {
|
10
|
+
"url" => "/form",
|
11
|
+
"attributes" => {
|
12
|
+
"attr1" => "#attr1",
|
13
|
+
"attr2" => "#hidden_attr",
|
14
|
+
"field1" => "#field1",
|
15
|
+
"field2" => "#hidden_field"
|
16
|
+
},
|
17
|
+
"actions" => {
|
18
|
+
"action1" => "#register_submit",
|
19
|
+
"action2" => "#disabled_button",
|
20
|
+
}
|
21
|
+
} }
|
22
|
+
|
23
|
+
before { capybara_page.visit("/form") }
|
24
|
+
let(:page) { page_object(page_data) }
|
25
|
+
subject { page }
|
26
|
+
|
27
|
+
describe "attributes" do
|
28
|
+
its(:attr1) { should == "led zeppelin" }
|
29
|
+
its(:attr2) { should == "the doors" }
|
30
|
+
|
31
|
+
it "should be able to use getter to also set attribute value" do
|
32
|
+
page.field1 "some_value"
|
33
|
+
page.field1.should == "some_value"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "actions" do
|
38
|
+
its(:action1) { should be_visible }
|
39
|
+
its(:action2) { should be_disabled }
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "responds_to" do
|
43
|
+
it { should respond_to(:attr1) }
|
44
|
+
it { should respond_to(:field1) }
|
45
|
+
it { should respond_to(:action1) }
|
46
|
+
it { should respond_to(:action2) }
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "method_missing" do
|
50
|
+
it "should delegate to capybara_page if it has method" do
|
51
|
+
page_object({}).find_by_id("attr1")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should raise method missing if both capybar_page and itself don't have method'" do
|
55
|
+
expect { page_object({}).does_not_exist }.to raise_error(NoMethodError, /undefined method `does_not_exist'/)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "visit" do
|
61
|
+
it "should go to page mentioned in url" do
|
62
|
+
page_object({"url" => "/form_with_rails_validation_errors"}).visit
|
63
|
+
capybara_page.should have_content "Email Address"
|
64
|
+
end
|
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")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "visible?" do
|
72
|
+
it "should return true if id element is visible" do
|
73
|
+
page = page_object({"url" => "/form_with_rails_validation_errors", "id" => "#registration-form"})
|
74
|
+
page.visit
|
75
|
+
page.should be_visible
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should return false if id element is not present" do
|
79
|
+
page = page_object({"url" => "/form_with_rails_validation_errors", "id" => "#does-not-exist"})
|
80
|
+
page.visit
|
81
|
+
page.should_not be_visible
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should fail if id is not specified" do
|
85
|
+
expect { page_object({}).visible? }.to raise_error(Exception, "id not defined for page")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "page_title" do
|
90
|
+
it "should return page title if page has title in head" do
|
91
|
+
page = page_object({"url" => "/form"})
|
92
|
+
page.visit
|
93
|
+
page.page_title.should == "Classic Rock"
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should return empty if title is not defined" do
|
97
|
+
page = page_object({"url" => "/div"})
|
98
|
+
page.visit
|
99
|
+
page.page_title.should be_empty
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it { page_object({"name" => "page"}).to_s.should == "'page: page'" }
|
104
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
$:.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/support/test_website")
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/support/matchers/delegate")
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require "bundler/setup"
|
7
|
+
require 'rspec'
|
8
|
+
require 'capybara'
|
9
|
+
require "mocha"
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.mock_with :mocha
|
13
|
+
|
14
|
+
config.before(:each) do
|
15
|
+
@capybara_page = Capybara::Session.new(:schmoo, TestWebsite)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def capybara_page
|
20
|
+
@capybara_page
|
21
|
+
end
|
22
|
+
|
23
|
+
Capybara.register_driver :schmoo do |app|
|
24
|
+
Capybara::RackTest::Driver.new(app)
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'capybara-pageobject'
|
28
|
+
|
29
|
+
alias :running :lambda
|
30
|
+
|
31
|
+
Capybara.default_wait_time = 0 # less timeout so tests run faster
|
32
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
RSpec::Matchers.define :delegate do |delegated_method|
|
2
|
+
chain :to do |target_method|
|
3
|
+
@target_method = target_method
|
4
|
+
end
|
5
|
+
|
6
|
+
chain :as do |method_on_target|
|
7
|
+
@method_on_target = method_on_target
|
8
|
+
end
|
9
|
+
|
10
|
+
chain :with_arguments do |args|
|
11
|
+
@args = args
|
12
|
+
end
|
13
|
+
|
14
|
+
match do |instance|
|
15
|
+
extend Mocha::API
|
16
|
+
|
17
|
+
@instance = instance
|
18
|
+
@args ||= []
|
19
|
+
return_value = 'stubbed return value'
|
20
|
+
method_on_target = @method_on_target || delegated_method
|
21
|
+
stubbed_target = stub('stubbed_target', method_on_target => return_value)
|
22
|
+
@instance.stubs(@target_method => stubbed_target)
|
23
|
+
begin
|
24
|
+
@instance.send(delegated_method, *@args) == return_value
|
25
|
+
rescue NoMethodError
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
failure_message do
|
31
|
+
if Class === @instance
|
32
|
+
message = "expected #{@instance.name} "
|
33
|
+
prefix = '.'
|
34
|
+
else
|
35
|
+
message = "expected #{@instance.class.name} "
|
36
|
+
prefix = '#'
|
37
|
+
end
|
38
|
+
message << "to delegate #{prefix}#{delegated_method} to #{prefix}#{@target_method}"
|
39
|
+
if @method_on_target
|
40
|
+
message << ".#{@method_on_target}"
|
41
|
+
end
|
42
|
+
message
|
43
|
+
end
|
44
|
+
|
45
|
+
description do
|
46
|
+
d = "delegate #{delegated_method}"
|
47
|
+
d << " to #{@target_method}" if @target_method
|
48
|
+
d << " as #{@method_on_target}" if @method_on_target
|
49
|
+
d
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'rack'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
class TestWebsite < Sinatra::Base
|
6
|
+
set :root, File.dirname(__FILE__)
|
7
|
+
set :static, true
|
8
|
+
|
9
|
+
def page_with
|
10
|
+
<<-BODY
|
11
|
+
<html>
|
12
|
+
<head>
|
13
|
+
<title>Classic Rock</title>
|
14
|
+
</head>
|
15
|
+
<body>
|
16
|
+
<p>Hello World!!</p>
|
17
|
+
#{yield}
|
18
|
+
</body>
|
19
|
+
</html>
|
20
|
+
BODY
|
21
|
+
end
|
22
|
+
|
23
|
+
get '/div' do
|
24
|
+
'<div id="foo1">led zeppelin</div><div id="foo2">the doors</div>'
|
25
|
+
end
|
26
|
+
|
27
|
+
get '/form' do
|
28
|
+
page_with do
|
29
|
+
<<-FORM
|
30
|
+
<div id="attr1">led zeppelin</div>
|
31
|
+
<div id="hidden_attr" style="display:none">the doors</div>
|
32
|
+
<form id="unique_form">
|
33
|
+
<input type="text" id="field1" value="Creedence Rlearwater Revival"/>
|
34
|
+
<input type="text" id="hidden_field" style="display:none"/>
|
35
|
+
<input id="disabled_button" name="commit" type="submit" disabled="disabled" />
|
36
|
+
<input id="register_submit" name="commit" type="submit" value="Register" />
|
37
|
+
<form>
|
38
|
+
FORM
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
get '/form_with_rails_validation_errors' do
|
43
|
+
page_with do
|
44
|
+
<<-FORM
|
45
|
+
<form accept-charset="UTF-8" action="/users" class="standard-form" id="registration-form" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" />
|
46
|
+
<input name="authenticity_token" type="hidden" value="xi5eg4oEiv3mng8ISy0qyYf/nB49pv0heJ93h3SrNtE=" /></div>
|
47
|
+
<ol>
|
48
|
+
<li class="text">
|
49
|
+
<div class="field_with_errors"><label for="user_email">Email Address</label></div>
|
50
|
+
<div class="field_with_errors"><input id="user_email" name="user[email]" size="30" title="Will be used as your username" type="text" value="" /><span class="error_message">can't be blank</span></div>
|
51
|
+
<span class="required">*</span>
|
52
|
+
</li>
|
53
|
+
<li class="text">
|
54
|
+
<div class="field_with_errors"><label for="user_password">Password</label></div>
|
55
|
+
<div class="field_with_errors"><input id="user_password" name="user[password]" size="30" title="At least 8 characters" type="password" /><span class="error_message">doesn't match confirmation</span></div><span class="required">*</span>
|
56
|
+
</li>
|
57
|
+
<li class="submit">
|
58
|
+
<input id="disabled_button" name="commit" type="submit" disabled="disabled" />
|
59
|
+
<input id="register_submit" name="commit" type="submit" value="Register" />
|
60
|
+
</li>
|
61
|
+
</ol>
|
62
|
+
</form>
|
63
|
+
FORM
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if __FILE__ == $0
|
69
|
+
Rack::Handler::WEBrick.run TestWebsite, :Port => 8070
|
70
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
def with_yaml page_data
|
4
|
+
YAML.expects(:load_file).with('pages/pages.yml').returns(page_data)
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "Website" do
|
8
|
+
let(:website) { Capybara::PageObject::Website.new(capybara_page, self, 'pages/pages.yml') }
|
9
|
+
subject { website }
|
10
|
+
|
11
|
+
describe "create getters" do
|
12
|
+
before { with_yaml("home_page" => {}, "login_form" => {}) }
|
13
|
+
it { should respond_to :home_page }
|
14
|
+
it { should respond_to :login_form }
|
15
|
+
|
16
|
+
its(:home_page) { should be }
|
17
|
+
its(:login_form) { should be }
|
18
|
+
|
19
|
+
it "should pass page name in page_data hash" do
|
20
|
+
website.home_page.instance_variable_get(:@page_data)["name"].should == "home_page"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should raise error if page_file is not specified" do
|
25
|
+
expect { Capybara::PageObject::Website.new(capybara_page, self, '') }.to raise_error(Exception, "Please specify page file path")
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "custom page class" do
|
29
|
+
it "should instantiate custom class if specified" do
|
30
|
+
class CustomPage < Capybara::PageObject::Page; end
|
31
|
+
with_yaml("home_page" => {"class" => "CustomPage"})
|
32
|
+
website.home_page.class.should == CustomPage
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should fail if custom class does not extend Page class" do
|
36
|
+
with_yaml("home_page" => {"class" => "Object"})
|
37
|
+
expect { Capybara::PageObject::Website.new(capybara_page, self, 'pages/pages.yml') }.to raise_error(Exception, "Custom page class 'Object' should extend Capybara::PageObject::Page")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "page block" do
|
42
|
+
it "should evaluate calls within the block on page" do
|
43
|
+
with_yaml("home_page" => {"url" => "/form", "attributes" => {"attribute" => "#attr1", "field" => "#hidden_field"}})
|
44
|
+
website.home_page.visit
|
45
|
+
website.home_page do
|
46
|
+
attribute.should == "led zeppelin"
|
47
|
+
field.should_not be_visible
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
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.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,55 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-02-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &2152272000 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2152272000
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: mocha
|
27
|
+
requirement: &2152270840 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2152270840
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: sinatra
|
38
|
+
requirement: &2152267160 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.9.4
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2152267160
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: capybara
|
49
|
+
requirement: &2152190040 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2152190040
|
14
58
|
- !ruby/object:Gem::Dependency
|
15
59
|
name: capybara
|
16
|
-
requirement: &
|
60
|
+
requirement: &2152188600 !ruby/object:Gem::Requirement
|
17
61
|
none: false
|
18
62
|
requirements:
|
19
63
|
- - ! '>='
|
@@ -21,9 +65,8 @@ dependencies:
|
|
21
65
|
version: 1.0.0
|
22
66
|
type: :runtime
|
23
67
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
-
description:
|
26
|
-
functional tests
|
68
|
+
version_requirements: *2152188600
|
69
|
+
description: Introduce page objects to your capybara-based functional tests
|
27
70
|
email:
|
28
71
|
- deepak.lewis@gmail.com
|
29
72
|
executables: []
|
@@ -31,11 +74,30 @@ extensions: []
|
|
31
74
|
extra_rdoc_files: []
|
32
75
|
files:
|
33
76
|
- .gitignore
|
77
|
+
- .rvmrc
|
34
78
|
- Gemfile
|
35
79
|
- Rakefile
|
36
80
|
- capybara-pageobject.gemspec
|
37
81
|
- lib/capybara-pageobject.rb
|
82
|
+
- lib/capybara-pageobject/action.rb
|
83
|
+
- lib/capybara-pageobject/attribute.rb
|
84
|
+
- lib/capybara-pageobject/capybara_helper.rb
|
85
|
+
- lib/capybara-pageobject/element.rb
|
86
|
+
- lib/capybara-pageobject/page.rb
|
38
87
|
- lib/capybara-pageobject/version.rb
|
88
|
+
- lib/capybara-pageobject/website.rb
|
89
|
+
- lib/monkey-patch/object.rb
|
90
|
+
- lib/monkey-patch/string.rb
|
91
|
+
- spec/action_spec.rb
|
92
|
+
- spec/attribute_spec.rb
|
93
|
+
- spec/capybara-pageobject_spec.rb
|
94
|
+
- spec/element_spec.rb
|
95
|
+
- spec/page_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
- spec/support/matchers/delegate.rb
|
98
|
+
- spec/support/pages/pages.yml
|
99
|
+
- spec/support/test_website.rb
|
100
|
+
- spec/website_spec.rb
|
39
101
|
homepage: ''
|
40
102
|
licenses: []
|
41
103
|
post_install_message:
|
@@ -60,4 +122,14 @@ rubygems_version: 1.8.15
|
|
60
122
|
signing_key:
|
61
123
|
specification_version: 3
|
62
124
|
summary: Easily create page objects to abstract UI Pages
|
63
|
-
test_files:
|
125
|
+
test_files:
|
126
|
+
- spec/action_spec.rb
|
127
|
+
- spec/attribute_spec.rb
|
128
|
+
- spec/capybara-pageobject_spec.rb
|
129
|
+
- spec/element_spec.rb
|
130
|
+
- spec/page_spec.rb
|
131
|
+
- spec/spec_helper.rb
|
132
|
+
- spec/support/matchers/delegate.rb
|
133
|
+
- spec/support/pages/pages.yml
|
134
|
+
- spec/support/test_website.rb
|
135
|
+
- spec/website_spec.rb
|