gless 1.0.1
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 +18 -0
- data/.rvmrc +34 -0
- data/README.md +242 -0
- data/Rakefile +41 -0
- data/TODO +4 -0
- data/TODO-session +65 -0
- data/examples/test_github/features/support/env.rb +27 -0
- data/examples/test_github/features/support/step_definitions/test_github_steps.rb +27 -0
- data/examples/test_github/features/test_github/test_github.feature +12 -0
- data/examples/test_github/lib/config/development.yml +12 -0
- data/examples/test_github/lib/config/development.yml.example +12 -0
- data/examples/test_github/lib/pages/test_github/blog_page.rb +13 -0
- data/examples/test_github/lib/pages/test_github/explore_page.rb +13 -0
- data/examples/test_github/lib/pages/test_github/features_page.rb +13 -0
- data/examples/test_github/lib/pages/test_github/login_page.rb +15 -0
- data/examples/test_github/lib/pages/test_github/repo_page.rb +14 -0
- data/examples/test_github/lib/pages/test_github/search_page.rb +61 -0
- data/examples/test_github/lib/pages/test_github_base_page.rb +11 -0
- data/examples/test_github/lib/startup.rb +16 -0
- data/examples/test_github/lib/test_github.rb +68 -0
- data/gless.gemspec +25 -0
- data/lib/gless/base_page.rb +339 -0
- data/lib/gless/browser.rb +43 -0
- data/lib/gless/config.rb +80 -0
- data/lib/gless/logger.rb +122 -0
- data/lib/gless/session.rb +319 -0
- data/lib/gless/wrap_watir.rb +164 -0
- data/lib/gless.rb +54 -0
- metadata +173 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1,34 @@
|
|
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
|
+
# Only full ruby name is supported here, for short names use:
|
8
|
+
# echo "rvm use 1.9.3" > .rvmrc
|
9
|
+
environment_id="ruby-1.9.3-p194@gless"
|
10
|
+
|
11
|
+
# Uncomment the following lines if you want to verify rvm version per project
|
12
|
+
# rvmrc_rvm_version="1.14.12 (stable)" # 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
|
+
# First we attempt to load the desired environment directly from the environment
|
19
|
+
# file. This is very fast and efficient compared to running through the entire
|
20
|
+
# CLI and selector. If you want feedback on which environment was used then
|
21
|
+
# insert the word 'use' after --create as this triggers verbose mode.
|
22
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
|
23
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
24
|
+
then
|
25
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
26
|
+
[[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
|
27
|
+
\. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
|
28
|
+
else
|
29
|
+
# If the environment file has not yet been created, use the RVM CLI to select.
|
30
|
+
rvm --create "$environment_id" || {
|
31
|
+
echo "Failed to create RVM environment '${environment_id}'."
|
32
|
+
return 1
|
33
|
+
}
|
34
|
+
fi
|
data/README.md
ADDED
@@ -0,0 +1,242 @@
|
|
1
|
+
# Gless #
|
2
|
+
|
3
|
+
A wrapper for Watir (specifically watir-webdriver, which is built on
|
4
|
+
top of selenium-webdriver) based on modelling web page and web site
|
5
|
+
structure. It's intended to make it easier to model complex
|
6
|
+
application workflow in an RSpec or Cucumber web site test suite.
|
7
|
+
|
8
|
+
This gem attempts to provide a more robust model for web application testing,
|
9
|
+
on top of Watir-WebDriver which already has significant improvements over just
|
10
|
+
Selenium or WebDriver, based on describing pages and then interacting with the
|
11
|
+
descriptions.
|
12
|
+
|
13
|
+
Feel free to contact the author at rlpowell@digitalkingdom.org
|
14
|
+
|
15
|
+
## Overview And Motivation ##
|
16
|
+
|
17
|
+
Gless takes Watir elements and collects them into pages. It then
|
18
|
+
inserts a session layer on top of the pages. The session layer is
|
19
|
+
in charge of knowing what page the browser is on, managing
|
20
|
+
transitions, and checking that they worked. On top of this sits an
|
21
|
+
application layer, which is the code that uses Gless for its
|
22
|
+
testing.
|
23
|
+
|
24
|
+
The motivation is seperation of testing types.
|
25
|
+
|
26
|
+
At the page level, which is code provided by a user of Gless, the
|
27
|
+
code has very little error correction, and mostly consists of just
|
28
|
+
the elements themselves, but might have some light code tying
|
29
|
+
elements together. For example, a "log me in" method that simply
|
30
|
+
takes a username and password and clicks the login button, and does
|
31
|
+
no error checking at any step, would go here.
|
32
|
+
|
33
|
+
At the session level, which is part of Gless itself and if you need
|
34
|
+
more features please send me a pull request, are various functions
|
35
|
+
to do page-level error correction. The big one here is long\_wait,
|
36
|
+
which watches a page for changes and only moves on when it sees what
|
37
|
+
it expects.
|
38
|
+
|
39
|
+
At the application level, which is code provided by a user of Gless,
|
40
|
+
you can write any multi-page workflows you like, without having to
|
41
|
+
pay any real attention to what page your on in the code, except in
|
42
|
+
as much as if your interactions don't match the site workflow your
|
43
|
+
tests are likely to fail. :) For example, a method to register an
|
44
|
+
account from scratch and log in with it, which presumably involves
|
45
|
+
several site pages, would go here.
|
46
|
+
|
47
|
+
## An Example ##
|
48
|
+
|
49
|
+
The best way to see how to use this library is to look in the
|
50
|
+
examples/ directory, but here's some stripped down examples.
|
51
|
+
|
52
|
+
A partial page definition:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
element :home , :link , :href => "https://github.com/" , :validator => true , :click_destination => :LoginPage
|
56
|
+
element :explore , :link , :href => "https://github.com/explore" , :validator => true , :click_destination => :ExplorePage
|
57
|
+
element :search , :link , :href => "https://github.com/search" , :validator => true , :click_destination => :SearchPage
|
58
|
+
|
59
|
+
element :search_input , :text_field , :class => 'text' , :validator => true
|
60
|
+
element :search_button , :button , :text => 'Search' , :validator => true
|
61
|
+
|
62
|
+
url %r{^:base_url/search}
|
63
|
+
|
64
|
+
expected_title %r{^(Code Search · GitHub|Search · \S+ · GitHub)$}
|
65
|
+
```
|
66
|
+
|
67
|
+
Given that definition, whenever the session code detects that it
|
68
|
+
*should* be on the search page (i.e. when the "search" element is
|
69
|
+
clicked), all of those elements will be checked for existence, the
|
70
|
+
url will be checked, and the title will be checked.
|
71
|
+
|
72
|
+
All of that is entirely automatic; the code that would trigger all
|
73
|
+
that would just be
|
74
|
+
|
75
|
+
@session.search.click
|
76
|
+
|
77
|
+
An example of page code that might use such a page definition:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
def search_for stuff
|
81
|
+
self.search_input.set stuff
|
82
|
+
self.search_button.click
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
An example of applicaiton level code that might use that page level
|
87
|
+
code (plus some other stuff not shown here):
|
88
|
+
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
def search_and_go name
|
92
|
+
@session.search.click
|
93
|
+
@session.search_for name
|
94
|
+
@session.goto_repository name
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
As you can see, the application level can encode extremely
|
99
|
+
complicated actions, in this case "go to the search page, search for
|
100
|
+
a repository, and go to that repository page", in a compact way that
|
101
|
+
has a sensible abstraction pattern.
|
102
|
+
|
103
|
+
## Writing Code Around Gless ##
|
104
|
+
|
105
|
+
### Configuration File ###
|
106
|
+
|
107
|
+
Gless expects you to have a configuration file named
|
108
|
+
lib/config/development.yml (the word "development" there can be
|
109
|
+
altered by changing the ENVIRONMENT environment variable) under your
|
110
|
+
test application. See examples/ for a detailed example.
|
111
|
+
|
112
|
+
The parts that Gless uses directly, and hence are required:
|
113
|
+
|
114
|
+
```yaml
|
115
|
+
:global: # This tag distinguishes the global config from the per-test configs; *do not remove*
|
116
|
+
:debug: false
|
117
|
+
:thumbnails: false # Whether to create small-ish "thumbnail" pictures on the replay page; requires the imagemagick system package and the mini_magick gem
|
118
|
+
:browser:
|
119
|
+
:type: local # Local or remote
|
120
|
+
:browser: firefox # Which browser to use
|
121
|
+
:port: 4444 # If remote, port to connect to the selenimu server, otherwise ignored
|
122
|
+
```
|
123
|
+
|
124
|
+
### The Pages ###
|
125
|
+
|
126
|
+
All of your site page description classes *must* be descendants of Gless::BasePage.
|
127
|
+
|
128
|
+
It is often useful to have your own base page class as well for
|
129
|
+
headers and footers and so on. See examples/ for a complete example
|
130
|
+
as usual, but here's a partial one:
|
131
|
+
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
rpowell@ut00-s00000> cat examples/test_github/lib/pages/test_github_base_page.rb
|
135
|
+
module TestGithub
|
136
|
+
class TestGithub::BasePage < Gless::BasePage
|
137
|
+
|
138
|
+
element :home , :link , :href => "https://github.com/" , :validator => true , :click_destination => :LoginPage
|
139
|
+
element :explore , :link , :href => "https://github.com/explore" , :validator => true , :click_destination => :ExplorePage
|
140
|
+
element :search , :link , :href => "https://github.com/search" , :validator => true , :click_destination => :SearchPage
|
141
|
+
element :features , :link , :href => "https://github.com/features" , :validator => true , :click_destination => :FeaturesPage
|
142
|
+
element :blog , :link , :href => "https://github.com/blog" , :validator => true , :click_destination => :BlogPage
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
class BlogPage < TestGithub::BasePage
|
147
|
+
|
148
|
+
url %r{^:base_url/blog$}
|
149
|
+
|
150
|
+
expected_title 'The Official GitHub Blog · GitHub'
|
151
|
+
|
152
|
+
# Stub page, but BasePage stuff still works
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
### The Application ###
|
159
|
+
|
160
|
+
Your application layer that sits on top of Gless must itself have
|
161
|
+
certain features, as other aspects of Gless do call back into the
|
162
|
+
application layer and/or make use of it. Here's some minimal
|
163
|
+
boilerplate that you should start with:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
module TestGithub
|
167
|
+
|
168
|
+
class TestGithub::Application
|
169
|
+
include RSpec::Matchers
|
170
|
+
|
171
|
+
attr_accessor :browser
|
172
|
+
attr_accessor :session
|
173
|
+
attr_accessor :site
|
174
|
+
attr_accessor :base_url
|
175
|
+
|
176
|
+
def initialize( browser, config, logger )
|
177
|
+
@logger = logger
|
178
|
+
@browser = browser
|
179
|
+
@config = config
|
180
|
+
|
181
|
+
@session = Gless::Session.new( @browser, @config, @logger, self )
|
182
|
+
|
183
|
+
@session.should be_true
|
184
|
+
end
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
## Debugging Gless Applications/Tests ##
|
189
|
+
|
190
|
+
If your configuration file has ":debug: true", then Gless will
|
191
|
+
produce some pretty verbose logging of what it's doing.
|
192
|
+
|
193
|
+
A less crazy version is ":verbose: true".
|
194
|
+
|
195
|
+
It will also create a replay log directory which is intended to be
|
196
|
+
viewed in a browser. The directory location defaults to
|
197
|
+
~/public_html/watir_replay/test/ ; the initialization of
|
198
|
+
Gless::Logger determines that location. Most actions that Gless
|
199
|
+
performs will cause the replay log to be updated a copy of the HTML
|
200
|
+
source as Gless/Watir/Selenium/WebDriver sees it.
|
201
|
+
|
202
|
+
If you have ":screenshots: true" (along with debugging), screenshots
|
203
|
+
will also be taken showing the visual state of the browser at the
|
204
|
+
time. This is quite slow, especially if the page is large. In
|
205
|
+
addition, if you have imagemagick installed, and the mini_magick
|
206
|
+
gem, and ":thumbnails: true", then smaller pictures will be included
|
207
|
+
on the main replay index page, rather than the full-sized ones.
|
208
|
+
|
209
|
+
## Requirements ##
|
210
|
+
|
211
|
+
Ruby 1.9.3 is used for development of this project.
|
212
|
+
|
213
|
+
Gless expects that you're running tests under RSpec or Cucumber;
|
214
|
+
significant modification would likely be required to make it run
|
215
|
+
otherwise, as it uses RSpec's `should` extensively.
|
216
|
+
|
217
|
+
The following should be sufficient to allow all the rake tasks to
|
218
|
+
run:
|
219
|
+
|
220
|
+
gem install yard-tomdoc redcarpet watir-webdriver rspec
|
221
|
+
|
222
|
+
In addition, you'll need the mini\_magick gem and the imagemagick OS
|
223
|
+
package if you want thumbnails in the logging output.
|
224
|
+
|
225
|
+
## Tests ##
|
226
|
+
|
227
|
+
Gless doesn't have any; if you can tell me how I should test something
|
228
|
+
like this besides "just run the sample app", please feel free to
|
229
|
+
suggest.
|
230
|
+
|
231
|
+
## Documentation ##
|
232
|
+
|
233
|
+
Other than this readme, the internal API documentation is in YARD
|
234
|
+
markup. Various things you can do:
|
235
|
+
|
236
|
+
* `rake doc`
|
237
|
+
+ generate the documentation
|
238
|
+
* `yard list` and `yard ri`
|
239
|
+
+ command line access to the documentation
|
240
|
+
* `yard server`
|
241
|
+
+ pretty web interface to the documentation
|
242
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#require 'rspec/core/rake_task'
|
2
|
+
require 'yard'
|
3
|
+
require 'yard/rake/yardoc_task'
|
4
|
+
require 'rake/clean'
|
5
|
+
|
6
|
+
lib = File.expand_path('../lib/', __FILE__)
|
7
|
+
|
8
|
+
$:.unshift lib unless $:.include?(lib)
|
9
|
+
|
10
|
+
CLEAN.include('gless*.gem')
|
11
|
+
CLOBBER.include('doc/', '.yardoc')
|
12
|
+
|
13
|
+
desc "Build the gless gem."
|
14
|
+
task :build do
|
15
|
+
sh %{gem build gless.gemspec}
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Build then install the gless gem."
|
19
|
+
task :install => :build do
|
20
|
+
require 'gless'
|
21
|
+
sh %{gem install gless-#{Gless::VERSION}.gem}
|
22
|
+
end
|
23
|
+
|
24
|
+
#desc "Run specs for gless gem"
|
25
|
+
#RSpec::Core::RakeTask.new do
|
26
|
+
#end
|
27
|
+
|
28
|
+
desc "Generate yard documentation for the api"
|
29
|
+
YARD::Rake::YardocTask.new do
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Generate yard documentation for the api"
|
33
|
+
YARD::Rake::YardocTask.new :doc do
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "Clean existing gems and re-install"
|
37
|
+
task :devinst do
|
38
|
+
['clean','build','install'].each { |task| Rake::Task[task].invoke }
|
39
|
+
end
|
40
|
+
|
41
|
+
task :default => :install
|
data/TODO
ADDED
data/TODO-session
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
Some old notes about the session object; may or may not still be
|
2
|
+
relevant, likely mostly already be implemented at this point.
|
3
|
+
|
4
|
+
# session.rb
|
5
|
+
#
|
6
|
+
# Provides a proxy to the varous page model objects that are encountered in a
|
7
|
+
# session. Methods that are not specific to the session object are passed
|
8
|
+
# through to the current page model object.
|
9
|
+
#
|
10
|
+
# When the session is instantiated, the type of the session is given. This
|
11
|
+
# type determines what page model collections get loaded (ie for Cloud,
|
12
|
+
# Orchestra, a test app, or github, for example) During this initiation, the
|
13
|
+
# various page model classes of that collection are loaded and queried for what
|
14
|
+
# urls correspond to the page model.
|
15
|
+
#
|
16
|
+
# When a session object creates a page model object, it passes itself to that
|
17
|
+
# object during creation, and stores that object as the current proxy target.
|
18
|
+
#
|
19
|
+
# If a page model object performs an action that will result in a new target
|
20
|
+
# page, and its parent session object is not nil, the page model object will
|
21
|
+
# suggest to the parent session object what the following page will be -- it is
|
22
|
+
# up to the session object to validate that the target has correctly changed
|
23
|
+
# (discuss alternative thoughts?)
|
24
|
+
#
|
25
|
+
# Requirements:
|
26
|
+
# - page model classes have 'path' directive which takes one or more regular
|
27
|
+
# expressions (usually one) to specify a matching url pattern.
|
28
|
+
# - page model classes have a getter method for the path, that can be called
|
29
|
+
# by the session object
|
30
|
+
# - page model objects have a instance variable for the current session, which
|
31
|
+
# is passed in along with the url when being instantiated
|
32
|
+
# - page model objects should cause an exception if they are instantiated with
|
33
|
+
# an incompatible url (maybe? - discuss)
|
34
|
+
# - page model objects can be instantiated with no session or url (ie they are
|
35
|
+
# optional)
|
36
|
+
# - page model objects will tell their parent session object when an action
|
37
|
+
# they take takes the browser to another page, ideally with the new target page
|
38
|
+
# - session objects, when instantiated, will load all of the page model classes
|
39
|
+
# for the passed in type -- for each model loaded this way, the session model
|
40
|
+
# will interrogate it for the matching path pattern and store this for lookup
|
41
|
+
# later.
|
42
|
+
# - session class will have a minimal public methods collection, primarily
|
43
|
+
# acting as a proxy for the contained page object.
|
44
|
+
# - session objects will retain a history of proxy method calls and page
|
45
|
+
# transitions for logging/debugging purposes.
|
46
|
+
# - sessions can be told to go to a url, which will change the current page
|
47
|
+
#model object
|
48
|
+
#
|
49
|
+
# Path syntax:
|
50
|
+
#
|
51
|
+
# In the page model classes, the directive for the path is originally
|
52
|
+
# recommended to be:
|
53
|
+
# path r'/accounts/([0-9]+)/apps'
|
54
|
+
#
|
55
|
+
# However, a more natural language would be preferred, such as:
|
56
|
+
# path '/accounts/:account_id/apps'
|
57
|
+
#
|
58
|
+
# This has the ability to use the provided real path as an argument, and pull
|
59
|
+
# out and name the variable aspect of that path. This is used in sinatra and
|
60
|
+
# rails router code, so it has an established precident. The trick is to be
|
61
|
+
# able to parse that code to change it to the regular expression and variable
|
62
|
+
# list.
|
63
|
+
#
|
64
|
+
# The method provided to query the path pattern would result in the pattern
|
65
|
+
# itself, not the natural language representation.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
load 'lib/startup.rb'
|
2
|
+
|
3
|
+
require 'rspec/expectations'
|
4
|
+
World(RSpec::Matchers)
|
5
|
+
World(RSpec::Expectations)
|
6
|
+
|
7
|
+
Before do
|
8
|
+
require 'gless'
|
9
|
+
|
10
|
+
# FIXME: the tag entry here will have to change for parallel runs.
|
11
|
+
@logger, @config, @browser = Gless.setup( :test )
|
12
|
+
|
13
|
+
if @config.get :global, :debug
|
14
|
+
require 'debugger'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
After do |scenario|
|
19
|
+
if @config.get :global, :debug
|
20
|
+
if scenario.failed?
|
21
|
+
@logger.debug "Since you're in debug mode, and we've just failed out, here's a debugger. #1"
|
22
|
+
debugger
|
23
|
+
end
|
24
|
+
else
|
25
|
+
@browser.close
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Given %r{^I start the application$} do
|
2
|
+
klass = @config.get :global, :site, :class
|
3
|
+
@application = Object.const_get(klass)::Application.new( @browser, @config, @logger )
|
4
|
+
@application.should be_true
|
5
|
+
end
|
6
|
+
|
7
|
+
When %r{^I fall through to the page object$} do
|
8
|
+
@application.session.features.click
|
9
|
+
end
|
10
|
+
|
11
|
+
When 'I go to the Gless repo via the search page' do
|
12
|
+
@application.goto_repository_from_anywhere 'gless', %r{^rlpowell\s*/\s*gless$}
|
13
|
+
end
|
14
|
+
|
15
|
+
When 'I poke lots of buttons' do
|
16
|
+
@application.poke_headers
|
17
|
+
end
|
18
|
+
|
19
|
+
Then 'I am on the Gless repo page' do
|
20
|
+
@application.session.arrived?.should be_true
|
21
|
+
@application.browser.url.should == 'https://github.com/rlpowell/gless'
|
22
|
+
end
|
23
|
+
|
24
|
+
Then %r{^I am on the Features page$} do
|
25
|
+
@application.browser.url.should == 'https://github.com/features/projects'
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Feature: Test Github Searching
|
2
|
+
|
3
|
+
Scenario: Find The Gless Repo
|
4
|
+
Given I start the application
|
5
|
+
When I go to the Gless repo via the search page
|
6
|
+
Then I am on the Gless repo page
|
7
|
+
|
8
|
+
Scenario: Poke Around
|
9
|
+
Given I start the application
|
10
|
+
When I poke lots of buttons
|
11
|
+
And I fall through to the page object
|
12
|
+
Then I am on the Features page
|
@@ -0,0 +1,12 @@
|
|
1
|
+
:global: # This tag distinguishes the global config from the per-test configs; *do not remove*
|
2
|
+
:site:
|
3
|
+
:class: TestGithub
|
4
|
+
:url: https://github.com
|
5
|
+
:browser:
|
6
|
+
:type: remote # Local or remote
|
7
|
+
:browser: chrome # Which browser to use
|
8
|
+
:port: 7444 # If remote, port to connect to the selenimu server, otherwise ignored
|
9
|
+
:verbose: false # Whether to engage in more verbose/info level logging
|
10
|
+
:debug: false # Whether to engage in debug logging
|
11
|
+
:screenshots: false # Whether, if debugging is on, to create screenshots as part of the replay log
|
12
|
+
:thumbnails: false # Whether, if screenshots are on, to create small-ish "thumbnail" pictures on the replay page; requires the imagemagick system package and the mini_magick gem
|
@@ -0,0 +1,12 @@
|
|
1
|
+
:global: # This tag distinguishes the global config from the per-test configs; *do not remove*
|
2
|
+
:site:
|
3
|
+
:class: TestGithub
|
4
|
+
:url: https://github.com
|
5
|
+
:browser:
|
6
|
+
:type: local # local or remote
|
7
|
+
:browser: firefox # Which browser to use
|
8
|
+
:port: 4444 # If remote, port to connect to the selenimu server, otherwise ignored
|
9
|
+
:verbose: false # Whether to engage in more verbose/info level logging
|
10
|
+
:debug: false # Whether to engage in debug logging
|
11
|
+
:screenshots: false # Whether, if debugging is on, to create screenshots as part of the replay log
|
12
|
+
:thumbnails: false # Whether, if screenshots are on, to create small-ish "thumbnail" pictures on the replay page; requires the imagemagick system package and the mini_magick gem
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module TestGithub
|
4
|
+
class LoginPage < TestGithub::BasePage
|
5
|
+
|
6
|
+
url %r{^:base_url/?$}
|
7
|
+
|
8
|
+
set_entry_url ':base_url'
|
9
|
+
|
10
|
+
expected_title 'GitHub · Build software better, together.'
|
11
|
+
|
12
|
+
# Stub page, but BasePage stuff still works
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module TestGithub
|
4
|
+
class SearchPage < TestGithub::BasePage
|
5
|
+
|
6
|
+
element :search_input , :text_field , :class => 'text' , :validator => true
|
7
|
+
element :search_button , :button , :text => 'Search' , :validator => true
|
8
|
+
|
9
|
+
url %r{^:base_url/search}
|
10
|
+
|
11
|
+
expected_title %r{^(Code Search · GitHub|Search · \S+ · GitHub)$}
|
12
|
+
|
13
|
+
def search_for stuff
|
14
|
+
self.search_input.set stuff
|
15
|
+
self.search_button.click
|
16
|
+
end
|
17
|
+
|
18
|
+
def goto_repository name
|
19
|
+
@session.log.debug "SearchPage: goto_repository: name: #{name}"
|
20
|
+
(find_repository name)[:link].click
|
21
|
+
@session.acceptable_pages = TestGithub::RepoPage
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_repository name
|
25
|
+
@session.log.debug "SearchPage: find_repository: name: #{name}"
|
26
|
+
if name.is_a?(Regexp)
|
27
|
+
key = repositories.keys.find { |key| key =~ name }
|
28
|
+
elsif name.is_a?(String)
|
29
|
+
key = name
|
30
|
+
end
|
31
|
+
|
32
|
+
@session.log.debug "SearchPage: find_repository: key: #{key}"
|
33
|
+
|
34
|
+
repositories[key]
|
35
|
+
end
|
36
|
+
|
37
|
+
def repositories
|
38
|
+
repos = self.divs.select { |div| div.class_name == 'result' }
|
39
|
+
|
40
|
+
@session.log.debug "SearchPage: repositories: repos: #{repos.inspect}"
|
41
|
+
|
42
|
+
repositories = Hash.new
|
43
|
+
i = 0
|
44
|
+
repos.each do |repo|
|
45
|
+
link = repo.h2.a
|
46
|
+
data = Hash.new
|
47
|
+
data[:index] = i
|
48
|
+
data[:link] = link
|
49
|
+
data[:url] = link.href
|
50
|
+
data[:name] = link.text
|
51
|
+
repositories[link.text] = data
|
52
|
+
i += 1
|
53
|
+
end
|
54
|
+
|
55
|
+
@session.log.debug "SearchPage: repositories: final: #{repositories.inspect}"
|
56
|
+
|
57
|
+
repositories
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module TestGithub
|
2
|
+
class TestGithub::BasePage < Gless::BasePage
|
3
|
+
|
4
|
+
element :home , :link , :href => "https://github.com/" , :validator => true , :click_destination => :LoginPage
|
5
|
+
element :explore , :link , :href => "https://github.com/explore" , :validator => true , :click_destination => :ExplorePage
|
6
|
+
element :search , :link , :href => "https://github.com/search" , :validator => true , :click_destination => :SearchPage
|
7
|
+
element :features , :link , :href => "https://github.com/features" , :validator => true , :click_destination => :FeaturesPage
|
8
|
+
element :blog , :link , :href => "https://github.com/blog" , :validator => true , :click_destination => :BlogPage
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
$: << File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'optparse'
|
5
|
+
require 'yaml'
|
6
|
+
require 'watir-webdriver'
|
7
|
+
|
8
|
+
require 'gless'
|
9
|
+
|
10
|
+
Gless::EnvConfig.env_dir = File.dirname(__FILE__)
|
11
|
+
|
12
|
+
require 'pages/test_github_base_page'
|
13
|
+
Dir["#{File.dirname(__FILE__)}/pages/*/*_page.rb"].each {|r| load r }
|
14
|
+
Dir["#{File.dirname(__FILE__)}/pages/*_page.rb"].each {|r| load r }
|
15
|
+
|
16
|
+
require 'test_github'
|