domkey 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.
- 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
|