site_prism 0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +28 -0
- data/lib/site_prism.rb +8 -0
- data/lib/site_prism/element_container.rb +104 -0
- data/lib/site_prism/exceptions.rb +7 -0
- data/lib/site_prism/page.rb +108 -0
- data/lib/site_prism/section.rb +25 -0
- metadata +71 -0
data/LICENSE
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Copyright (c) 2011, Nathaniel Ritmeyer
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
12
|
+
documentation and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
3. Neither the name Nathaniel Ritmeyer nor the names of contributors to
|
15
|
+
this software may be used to endorse or promote products derived from this
|
16
|
+
software without specific prior written permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
19
|
+
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
20
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
21
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
22
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
23
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
24
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
25
|
+
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
26
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
27
|
+
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
28
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/lib/site_prism.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# Contains methods applicable to both {SitePrism::Page}s and {SitePrism::Section}s. Note that they are mixed into the {SitePrism::Page}
|
2
|
+
# and {SitePrism::Section} classes so the methods below are used as class methods.
|
3
|
+
module SitePrism::ElementContainer
|
4
|
+
|
5
|
+
# Creates two methods; the first method has the same name as the element_name parameter and returns the capybara element
|
6
|
+
# located by the element_locator parameter when the method is called. The second method generated has a name with a format
|
7
|
+
# of: 'has_#\{element_name}?' which returns true if the element as located by the element_locator parameter exists, false
|
8
|
+
# if it doesn't
|
9
|
+
# @param [Symbol] element_name The name of the element
|
10
|
+
# @param [String] element_locator The CSS locator to find the element
|
11
|
+
# @example
|
12
|
+
# class HomePage < SitePrism::Page
|
13
|
+
# element :search_link, 'div.search > a'
|
14
|
+
# end
|
15
|
+
# home = HomePage.new
|
16
|
+
#
|
17
|
+
# #the element method created 2 methods...
|
18
|
+
# home.search_link #=> returns the capybara element located by the element_locator parameter
|
19
|
+
# home.has_search_link? #=> returns true if the capybara element as located by the element_locator exists, false if it doesn't
|
20
|
+
#
|
21
|
+
# #The has_search_link? method allows use of magic matchers in rspec/cucumber:
|
22
|
+
# home.should have_search_link
|
23
|
+
# home.should_not have_search_link
|
24
|
+
def element element_name, element_locator
|
25
|
+
create_existence_checker element_name, element_locator
|
26
|
+
define_method element_name.to_s do
|
27
|
+
find_one element_locator
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Works in the same way as {SitePrism::Page.element} in that it will generate two methods; one to check existence of
|
32
|
+
# the element (in the format 'has_#\{element_name}?'), and another to return not a single element, but an array of elements
|
33
|
+
# found by the css locator
|
34
|
+
# @param [Symbol] collection_name The name of the collection
|
35
|
+
# @param [String] collection_locator The CSS locator that returns the list of elements in the collection
|
36
|
+
# @example
|
37
|
+
# class HomePage < SitePrism::Page
|
38
|
+
# elements :app_links, '.title-links > a'
|
39
|
+
# end
|
40
|
+
# home = HomePage.new
|
41
|
+
#
|
42
|
+
# home.should have_app_links
|
43
|
+
# home.app_links #=> [#<Capybara::Element tag="a">, #<Capybara::Element tag="a">, #<Capybara::Element tag="a">]
|
44
|
+
# home.app_links.map {|link| link.text}.should == ['Finance', 'Maps', 'Blogs']
|
45
|
+
def elements collection_name, collection_locator
|
46
|
+
create_existence_checker collection_name, collection_locator
|
47
|
+
define_method collection_name.to_s do
|
48
|
+
find_all collection_locator
|
49
|
+
end
|
50
|
+
end
|
51
|
+
alias :collection :elements
|
52
|
+
|
53
|
+
# Creates a method that returns an instance of a {SitePrism::Section}. If a page contains a common section (eg: a search area) that
|
54
|
+
# appears on many pages, create a {SitePrism::Section} for it and then expose it in each {SitePrism::Page} that contains the section.
|
55
|
+
# Say a search engine website displays the search field and search button on each page and they always have the same IDs, they should
|
56
|
+
# be extracted into a {SitePrism::Section} that would look something like this:
|
57
|
+
#
|
58
|
+
# class SearchArea < SitePrism::Section
|
59
|
+
# element :search_field, '.q'
|
60
|
+
# element :search_button, '.btnK'
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# ...then that section could be added to any page as follows:
|
64
|
+
#
|
65
|
+
# class SearchPage < SitePrism::Page
|
66
|
+
# section :search_area, SearchArea, '.tsf-p'
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# class SearchResultsPage < SitePrism::Page
|
70
|
+
# section :search_again, SearchArea, '.tsf-p table'
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# The SearchArea section appears on both pages, but can be invoked by methods specific to the page (eg: 'search_area' and 'search_again')
|
74
|
+
# and the root element for the section can be different on the page (eg: '.tsf-p' and '.tsf-p table').
|
75
|
+
# @param [Symbol] the method name to be called against this page or section to return an instance of the {SitePrism::Section} class
|
76
|
+
# @param [Class] the class that models this area of the page
|
77
|
+
# @param [String] the CSS locator for the root element of the section on this page/section
|
78
|
+
def section section_name, section_class, section_locator
|
79
|
+
create_existence_checker section_name, section_locator
|
80
|
+
define_method section_name do
|
81
|
+
section_class.new find_one section_locator
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Works in the same way as {SitePrism::Page.section} but instead of it returning one section, it returns an array of them.
|
86
|
+
def sections section_collection_name, section_class, section_collection_locator
|
87
|
+
create_existence_checker section_collection_name, section_collection_locator
|
88
|
+
define_method section_collection_name do
|
89
|
+
find_all(section_collection_locator).collect do |element|
|
90
|
+
section_class.new element
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# Creates a method used to check for the existence of the element whose details are passed to it
|
98
|
+
# @param
|
99
|
+
def create_existence_checker element_name, element_locator
|
100
|
+
define_method "has_#{element_name.to_s}?" do
|
101
|
+
element_exists? element_locator
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# SitePrism's exceptions...
|
2
|
+
module SitePrism
|
3
|
+
# Raised if you ask a page to load but it hasn't had its url set
|
4
|
+
class NoUrlForPage < StandardError; end
|
5
|
+
# Raised if you check to see if a page is displayed but it hasn't had its url matcher set
|
6
|
+
class NoUrlMatcherForPage < StandardError; end
|
7
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module SitePrism
|
2
|
+
# Subclasses of {SitePrism::Page} represent pages in your app.
|
3
|
+
# class Home < SitePrism::Page
|
4
|
+
# end
|
5
|
+
#
|
6
|
+
# The above is an example of how to make a class representing the home page. There are a number of properties that can be
|
7
|
+
# set on a page - here is an example of a more fully spec'ed out page:
|
8
|
+
# class Home < SitePrism::Page
|
9
|
+
# set_url "/"
|
10
|
+
# set_url_matcher /\/home.htm$/
|
11
|
+
# end
|
12
|
+
class Page
|
13
|
+
include Capybara::DSL
|
14
|
+
extend ElementContainer
|
15
|
+
|
16
|
+
# Visits the url associated with this page
|
17
|
+
# @raise [SitePrism::NoUrlForPage] To load a page the url must be set using {.set_url}
|
18
|
+
def load
|
19
|
+
raise SitePrism::NoUrlForPage if url.nil?
|
20
|
+
visit url
|
21
|
+
end
|
22
|
+
|
23
|
+
# Checks to see if we're on this page or not
|
24
|
+
# @return true if the browser's current url matches the {.url_matcher} that has been set, false if it doesn't
|
25
|
+
# @raise [SitePrism::NoUrlMatcherForPage] To check whether we're on this page or not the url matcher must be set using {.set_url_matcher}
|
26
|
+
# @example
|
27
|
+
# class SearchPage < SitePrism::Page
|
28
|
+
# set_url_matcher /\/search.htm$/
|
29
|
+
# end
|
30
|
+
# search_page = SearchPage.new
|
31
|
+
# search_page.load
|
32
|
+
# puts "We're on the search page" if search_page.displayed?
|
33
|
+
# search_page.should be_displayed
|
34
|
+
def displayed?
|
35
|
+
raise SitePrism::NoUrlMatcherForPage if url_matcher.nil?
|
36
|
+
!(page.current_url =~ url_matcher).nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
# Set the url associated with this page
|
40
|
+
# @param [String] page_url the portion of the url that identifies this page when appended onto Capybara's app_host. Calling {SitePrism::Page#load} causes Capybara to visit this page.
|
41
|
+
# @example
|
42
|
+
# class SearchPage < SitePrism::Page
|
43
|
+
# set_url "/search.htm"
|
44
|
+
# end
|
45
|
+
def self.set_url page_url
|
46
|
+
@url = page_url
|
47
|
+
end
|
48
|
+
|
49
|
+
# Set the url matcher associated with this page
|
50
|
+
# @param [Regexp] page_url_matcher a regular expression that when compared to the current browser url will match if we're on this page or not match if we're not on this page
|
51
|
+
# @example
|
52
|
+
# class SearchPage < SitePrism::Page
|
53
|
+
# set_url_matcher /\/search.htm$/
|
54
|
+
# end
|
55
|
+
def self.set_url_matcher page_url_matcher
|
56
|
+
@url_matcher = page_url_matcher
|
57
|
+
end
|
58
|
+
|
59
|
+
# Get the url associated with this page
|
60
|
+
# @see SitePrism::Page#url
|
61
|
+
# @return [String] the url originally set in {.set_url}
|
62
|
+
def self.url
|
63
|
+
@url
|
64
|
+
end
|
65
|
+
|
66
|
+
# Get the url matcher associated with this page
|
67
|
+
# @see SitePrism::Page#url_matcher
|
68
|
+
# @return [Regexp] the url matcher originally set in {.set_url_matcher}
|
69
|
+
def self.url_matcher
|
70
|
+
@url_matcher
|
71
|
+
end
|
72
|
+
|
73
|
+
# Get the url associated with this page
|
74
|
+
# @see SitePrism::Page.url
|
75
|
+
def url
|
76
|
+
self.class.url
|
77
|
+
end
|
78
|
+
|
79
|
+
# Get the url matcher associated with this page
|
80
|
+
# @see SitePrism::Page.url_matcher
|
81
|
+
def url_matcher
|
82
|
+
self.class.url_matcher
|
83
|
+
end
|
84
|
+
|
85
|
+
# Gets the title of the current page
|
86
|
+
# @return [String, nil] the text value of the title element within the page's head block
|
87
|
+
def title
|
88
|
+
title_selector = 'html > head > title'
|
89
|
+
using_wait_time(0) { page.find(title_selector).text if page.has_selector?(title_selector) }
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# Page specific element finder
|
95
|
+
def find_one locator
|
96
|
+
find locator
|
97
|
+
end
|
98
|
+
|
99
|
+
# Page specific elements finder
|
100
|
+
def find_all locator
|
101
|
+
all locator
|
102
|
+
end
|
103
|
+
|
104
|
+
def element_exists? locator
|
105
|
+
has_selector? locator
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SitePrism
|
2
|
+
class Section
|
3
|
+
extend ElementContainer
|
4
|
+
|
5
|
+
def initialize root_element
|
6
|
+
@root_element = root_element
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Section specific element finder
|
12
|
+
def find_one locator
|
13
|
+
@root_element.find locator
|
14
|
+
end
|
15
|
+
|
16
|
+
# Section specific elements finder
|
17
|
+
def find_all locator
|
18
|
+
@root_element.all locator
|
19
|
+
end
|
20
|
+
|
21
|
+
def element_exists? locator
|
22
|
+
@root_element.has_selector? locator
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: site_prism
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: "0.9"
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nat Ritmeyer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-12-22 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: capybara
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.1.1
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
description: none just yet...
|
27
|
+
email:
|
28
|
+
- nat@natontesting.com
|
29
|
+
executables: []
|
30
|
+
|
31
|
+
extensions: []
|
32
|
+
|
33
|
+
extra_rdoc_files: []
|
34
|
+
|
35
|
+
files:
|
36
|
+
- lib/site_prism/element_container.rb
|
37
|
+
- lib/site_prism/exceptions.rb
|
38
|
+
- lib/site_prism/page.rb
|
39
|
+
- lib/site_prism/section.rb
|
40
|
+
- lib/site_prism.rb
|
41
|
+
- LICENSE
|
42
|
+
homepage: http://github.com/natritmeyer/site_prism
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.8.10
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: none just yet...
|
69
|
+
test_files: []
|
70
|
+
|
71
|
+
has_rdoc:
|