site_prism 0.9
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/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:
|