domkey 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +37 -0
- data/Rakefile +11 -0
- data/domkey.gemspec +30 -0
- data/lib/domkey.rb +18 -0
- data/lib/domkey/browser_session.rb +14 -0
- data/lib/domkey/exception.rb +6 -0
- data/lib/domkey/version.rb +3 -0
- data/lib/domkey/view.rb +39 -0
- data/lib/domkey/view/page_object.rb +120 -0
- data/lib/domkey/view/page_object_collection.rb +78 -0
- data/spec/browser_spec.rb +23 -0
- data/spec/html/test.html +53 -0
- data/spec/page_object_collection_spec.rb +130 -0
- data/spec/page_object_decorators_spec.rb +211 -0
- data/spec/page_object_spec.rb +130 -0
- data/spec/page_spec.rb +90 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/view_dom_spec.rb +57 -0
- data/spec/view_doms_spec.rb +49 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4e084e3b9ec1fd8d799b054c5c7621ff614cbe25
|
4
|
+
data.tar.gz: cc50953f3c169a28d21346e076681fb7e3dcc099
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 708a161af1039a64b5beed49e5b8b3ea354387624ceae4fa810f9c52993aa21fb41b493778f6bd816a75a751a55ba060d2b86c4d743ff75fbdd58e4dece13aa8
|
7
|
+
data.tar.gz: 49e6a0ff0391b95355d136dcc44d9fae71acf7413829ea52cf3e0008d16a11de06d002a714071558b0f31a22bfe487a1f11289523e928f3f600c06238c70d095
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 rubytester
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Domain Specifc PageObject for Selenium Watir-Webdriver
|
2
|
+
|
3
|
+
PageObject that models business domain first and browser code second.
|
4
|
+
|
5
|
+
Watir-Webdriver is the Bee's Knees! Now with Domain Specific PageObject Factory!
|
6
|
+
|
7
|
+
Watir-Webdriver is the Bee's Knees! Now with Domain Specific PageObject Factory!
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'domkey'
|
14
|
+
|
15
|
+
or this line to use gem directly from github
|
16
|
+
|
17
|
+
gem 'domkey', git: "git://github.com/rubytester/domkey.git"
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it from rubygems.org as:
|
24
|
+
|
25
|
+
$ gem install domkey
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
TODO: Write usage instructions here
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
|
33
|
+
1. Fork it ( http://github.com/<my-github-username>/domkey/fork )
|
34
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
35
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
36
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
37
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/domkey.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'domkey/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'domkey'
|
8
|
+
spec.version = Domkey::VERSION
|
9
|
+
spec.authors = ["rubytester", "marekj"]
|
10
|
+
spec.email = ["github@rubytester.com"]
|
11
|
+
spec.summary = %q{Domain Specifc PageObject for Selenium Watir-Webdriver}
|
12
|
+
spec.description = %q{Domain Specifc PageObject for Selenium Watir-Webdriver. PageObject that models business domain first and browser code second}
|
13
|
+
spec.homepage = ''
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.required_ruby_version = '~> 2.0'
|
22
|
+
|
23
|
+
spec.add_dependency 'watir-webdriver', '~> 0.6.4'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 2.14'
|
28
|
+
spec.add_development_dependency 'simplecov'
|
29
|
+
|
30
|
+
end
|
data/lib/domkey.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'domkey/version'
|
2
|
+
require 'watir-webdriver'
|
3
|
+
require 'domkey/browser_session'
|
4
|
+
require 'domkey/view'
|
5
|
+
require 'domkey/exception'
|
6
|
+
|
7
|
+
module Domkey
|
8
|
+
|
9
|
+
# current browser for testing session
|
10
|
+
def self.browser
|
11
|
+
BrowserSession.instance.browser
|
12
|
+
end
|
13
|
+
|
14
|
+
# sets current browser for testing session
|
15
|
+
def self.browser=(b)
|
16
|
+
BrowserSession.instance.browser=b
|
17
|
+
end
|
18
|
+
end
|
data/lib/domkey/view.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'domkey/view/page_object'
|
2
|
+
require 'domkey/view/page_object_collection'
|
3
|
+
module Domkey
|
4
|
+
|
5
|
+
module View
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
|
9
|
+
# PageObjectCollection factory
|
10
|
+
def doms(key, &watirproc)
|
11
|
+
send :define_method, key do
|
12
|
+
PageObjectCollection.new watirproc, Proc.new { browser }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# PageObject factory
|
17
|
+
def dom(key, &watirproc)
|
18
|
+
send :define_method, key do
|
19
|
+
PageObject.new watirproc, Proc.new { browser }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.included(klass)
|
25
|
+
klass.extend(ClassMethods)
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_accessor :browser
|
29
|
+
|
30
|
+
def initialize browser=nil
|
31
|
+
@browser = browser
|
32
|
+
end
|
33
|
+
|
34
|
+
def browser
|
35
|
+
@browser ||= Domkey.browser
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module Domkey
|
2
|
+
|
3
|
+
module View
|
4
|
+
|
5
|
+
class PageObject
|
6
|
+
|
7
|
+
attr_accessor :watirproc, :container
|
8
|
+
|
9
|
+
# PageObject represents an semantically essential area in a View
|
10
|
+
# It is an object that responds to set and value as the main way of sending data to it.
|
11
|
+
# it is composed of one or more watir elements.
|
12
|
+
# PageObject encapuslates the widgetry of DOM elements to provide semantic interfact to the user of the widgetry
|
13
|
+
#
|
14
|
+
# Compose PageObject with watirproc and container
|
15
|
+
#
|
16
|
+
# What is a container? it's a proc, a callable object that plays a role of a container for watirproc widgetry
|
17
|
+
# container can be one of:
|
18
|
+
# - browser (default)
|
19
|
+
# - a pageobject
|
20
|
+
#
|
21
|
+
# What is watirproc? it's a proc of DOM elements widgetry that can be found inside the container
|
22
|
+
# watirproc can be one of the following:
|
23
|
+
# - definition of single watir element i.e. `-> { text_field(:id, 'foo')}`
|
24
|
+
# - a pageobject i.e. previously instantiated definition
|
25
|
+
# - hash where key defines subelement and value a definition or pageobject
|
26
|
+
#
|
27
|
+
# Usage:
|
28
|
+
# Clients would not usually instantate this class.
|
29
|
+
# A client class which acts as a View would use a :dom factory method to create PageObjects
|
30
|
+
# Example:
|
31
|
+
#
|
32
|
+
# class MyView
|
33
|
+
# include Domkey::View
|
34
|
+
#
|
35
|
+
# dom(:headline) { text_field(id:, 'some_desc_text') }
|
36
|
+
#
|
37
|
+
# def property
|
38
|
+
# PropertyPanel.new browser.div(id: 'container')
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# class PropertyPanel
|
43
|
+
# include Domkey::View
|
44
|
+
# dom(:headline) { text_field(class: 'headline_for_house') }
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# view = MyView.new
|
48
|
+
# view.headline.set 'HomeAway Rules!'
|
49
|
+
# view.value #=> returns 'HomeAway Rules!'
|
50
|
+
# view.property.headline.set 'Awesome Vactaion Home'
|
51
|
+
# view.property.headline.value #=> returns 'Awesome Vaction Home'
|
52
|
+
#
|
53
|
+
def initialize watirproc, container=lambda { Domkey.browser }
|
54
|
+
@container = container
|
55
|
+
@watirproc = initialize_this watirproc
|
56
|
+
end
|
57
|
+
|
58
|
+
def set value
|
59
|
+
return instantiator.set(value) unless value.respond_to?(:each_pair)
|
60
|
+
value.each_pair { |k, v| watirproc.fetch(k).set(v) }
|
61
|
+
end
|
62
|
+
|
63
|
+
def value
|
64
|
+
return instantiator.value unless watirproc.respond_to?(:each_pair)
|
65
|
+
Hash[watirproc.map { |key, pageobject| [key, pageobject.value] }]
|
66
|
+
end
|
67
|
+
|
68
|
+
# access widgetry of watir elements composing this page object
|
69
|
+
def element(key=false)
|
70
|
+
return instantiator unless watirproc.respond_to?(:each_pair)
|
71
|
+
return watirproc.fetch(key).element if key
|
72
|
+
Hash[watirproc.map { |key, watirproc| [key, watirproc.element] }]
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
# recursive
|
78
|
+
def initialize_this watirproc
|
79
|
+
if watirproc.respond_to?(:each_pair) #hash
|
80
|
+
Hash[watirproc.map { |key, watirproc| [key, PageObject.new(watirproc, container)] }]
|
81
|
+
else
|
82
|
+
if watirproc.respond_to?(:call) #proc
|
83
|
+
begin
|
84
|
+
# peek inside suitcase that is proc. XXX ouch, ugly
|
85
|
+
peeked_inside = watirproc.call
|
86
|
+
rescue NoMethodError
|
87
|
+
return watirproc #suitecase exploded, proc returned
|
88
|
+
end
|
89
|
+
if peeked_inside.respond_to?(:each_pair) # hash
|
90
|
+
return initialize_this peeked_inside
|
91
|
+
elsif peeked_inside.respond_to?(:wd) # watir element
|
92
|
+
return lambda { peeked_inside }
|
93
|
+
elsif peeked_inside.respond_to?(:watirproc) #pageobject
|
94
|
+
return peeked_inside.watirproc
|
95
|
+
else
|
96
|
+
fail Exception::Error, "watirproc must be kind of hash, watirelement or pageobject but I got this: #{watirproc}"
|
97
|
+
end
|
98
|
+
elsif watirproc.respond_to?(:watirproc) #pageobject
|
99
|
+
return watirproc.watirproc
|
100
|
+
else
|
101
|
+
fail Exception::Error, "watirproc must be kind of hash, watirelement or pageobject but I got this: #{watirproc}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# talk to the browser executor.
|
107
|
+
# returns runtime element in a specified container
|
108
|
+
# expects that element to respond to set and value
|
109
|
+
def instantiator
|
110
|
+
container_instantiator.instance_exec(&watirproc)
|
111
|
+
end
|
112
|
+
|
113
|
+
# talk to the browser
|
114
|
+
# returns runtime container element in a browser/driver
|
115
|
+
def container_instantiator
|
116
|
+
container.respond_to?(:call) ? container.call : container.send(:instantiator)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Domkey
|
2
|
+
|
3
|
+
module View
|
4
|
+
|
5
|
+
class PageObjectCollection
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
attr_accessor :watirproc, :container
|
9
|
+
|
10
|
+
# PageObjectCollection see PageObject for detailes.
|
11
|
+
# Compose PageObjectCollection with watirproc and container
|
12
|
+
#
|
13
|
+
# What is a container? see PageObject container
|
14
|
+
#
|
15
|
+
# What is watirproc? see PageObject watirproc except the following:
|
16
|
+
# watirproc can be one of the following:
|
17
|
+
# - definition of watir elements collection i.e. `-> { text_fields(:class, /^foo/)}`
|
18
|
+
# - a pageobject i.e. previously instantiated definition watir elements collection
|
19
|
+
# - hash where key defines subelement and value a definition or pageobject
|
20
|
+
# Usage:
|
21
|
+
# Clients would not usually instantate this class.
|
22
|
+
# A client class which acts as a View would use a :doms factory method to create PageObjectCollection
|
23
|
+
# Example:
|
24
|
+
#
|
25
|
+
def initialize watirproc, container=lambda { Domkey.browser }
|
26
|
+
@container = container
|
27
|
+
@watirproc = initialize_this watirproc
|
28
|
+
end
|
29
|
+
|
30
|
+
def element(key=false)
|
31
|
+
return instantiator unless watirproc.respond_to?(:each_pair)
|
32
|
+
return watirproc.fetch(key).element if key
|
33
|
+
Hash[watirproc.map { |key, watirproc| [key, watirproc.element] }]
|
34
|
+
end
|
35
|
+
|
36
|
+
def each(&blk)
|
37
|
+
if watirproc.respond_to?(:each_pair)
|
38
|
+
watirproc.map { |k, v| [k, PageObjectCollection.new(lambda { v }, @container)] }.each { |k, v| yield Hash[k, v] }
|
39
|
+
else
|
40
|
+
instantiator.each { |e| yield PageObject.new(lambda { e }, @container) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def [] idx
|
45
|
+
to_a[idx]
|
46
|
+
end
|
47
|
+
|
48
|
+
alias_method :size, :count
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# --
|
53
|
+
# recursive
|
54
|
+
def initialize_this watirproc
|
55
|
+
if watirproc.respond_to?(:each_pair) #hash
|
56
|
+
Hash[watirproc.map { |key, watirproc| [key, PageObjectCollection.new(watirproc, container)] }]
|
57
|
+
else
|
58
|
+
if watirproc.respond_to?(:call) #proc
|
59
|
+
watirproc
|
60
|
+
elsif watirproc.respond_to?(:watirproc)
|
61
|
+
watirproc.watirproc
|
62
|
+
else
|
63
|
+
fail Exception::Error, "watirproc must be kind of hash, watirelement or pageobject but I got this: #{watirproc}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def instantiator
|
69
|
+
container_at_runtime.instance_exec(&watirproc)
|
70
|
+
end
|
71
|
+
|
72
|
+
def container_at_runtime
|
73
|
+
container.respond_to?(:call) ? container.call : container.send(:instantiator)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Domkey::BrowserSession do
|
4
|
+
|
5
|
+
context 'when no browsers present in the system' do
|
6
|
+
|
7
|
+
it 'browser gives us default browser' do
|
8
|
+
#ugly setup with singleton
|
9
|
+
Domkey::BrowserSession.instance.browser.close
|
10
|
+
Domkey::browser=nil
|
11
|
+
|
12
|
+
fakebrowser = double('browser')
|
13
|
+
fakebrowser.stub(:exist?).and_return(true)
|
14
|
+
Watir::Browser.should_receive(:new).once.and_return(fakebrowser)
|
15
|
+
b = Domkey.browser
|
16
|
+
b.should eq fakebrowser
|
17
|
+
b2 = Domkey.browser
|
18
|
+
b.should eql b2
|
19
|
+
Domkey::BrowserSession.instance.browser=nil
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|