gless 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|