bauxite 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +239 -0
- data/Rakefile +33 -11
- data/doc/created.rid +1 -1
- data/lib/bauxite/application.rb +11 -3
- data/lib/bauxite/core/Context.rb +11 -0
- data/lib/bauxite.rb +1 -1
- data/test/extension/custom.rb +12 -0
- data/test/extension/page.html +5 -0
- data/test/extension.bxt.manual +4 -0
- data/test/test.bxt.manual +1 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 063894fc2a6cee418888abc8d731448a22653c5c
|
4
|
+
data.tar.gz: 1cc13f20d0951eaed6451b75575124f558f4d063
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c4e04c8976ba0a5a5b018dc62fac88d1204c7415114159527e3b03581e94a7119dd70f51dec32c6e3b255a8b690a2729f2ae7815810254ef0d3e1094a9b3c7d8
|
7
|
+
data.tar.gz: 37f4ec249b6139fd33b968d387eb5f043b5b0ccae3bbffefd47c710bb753b19784c1247e53e62b81f6b91120b4553bb494964e65d50adc6cd348f0029bcc30b0
|
data/README.md
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
bauxite
|
2
|
+
=======
|
3
|
+
|
4
|
+
Bauxite is a façade over Selenium intended for non-developers
|
5
|
+
|
6
|
+
The idea behind this project was to create a tool that allows non-developers to write web tests in a human-readable language. Another major requirement is to be able to easily extend the test language to create functional abstractions over technical details.
|
7
|
+
|
8
|
+
Take a look at the following Ruby excerpt from http://code.google.com/p/selenium/wiki/RubyBindings:
|
9
|
+
```ruby
|
10
|
+
require "selenium-webdriver"
|
11
|
+
|
12
|
+
driver = Selenium::WebDriver.for :firefox
|
13
|
+
driver.navigate.to "http://google.com"
|
14
|
+
|
15
|
+
element = driver.find_element(:name, 'q')
|
16
|
+
element.send_keys "Hello WebDriver!"
|
17
|
+
element.submit
|
18
|
+
|
19
|
+
puts driver.title
|
20
|
+
|
21
|
+
driver.quit
|
22
|
+
```
|
23
|
+
While developers might find that code expressive enough, non-developers might be a bit shocked.
|
24
|
+
|
25
|
+
The equivalent Bauxite test is easier on the eyes:
|
26
|
+
```
|
27
|
+
open "http://google.com"
|
28
|
+
write name=q "Hello WebDriver!"
|
29
|
+
click gbqfb
|
30
|
+
```
|
31
|
+
Installation
|
32
|
+
------------
|
33
|
+
|
34
|
+
In a nutshell:
|
35
|
+
```
|
36
|
+
gem install bauxite
|
37
|
+
```
|
38
|
+
|
39
|
+
Remember you'll also need Ruby 2.x installed and Firefox (you can use other browsers or Selenium server by specifying the `-p` switch to the `bauxite` executable).
|
40
|
+
|
41
|
+
Hello World
|
42
|
+
-----------
|
43
|
+
|
44
|
+
(This section assumes that Bauxite and its dependencies are installed in the system. Refer to the [Installation](#installation) section below for more details).
|
45
|
+
|
46
|
+
Paste the following text into `hello.bxt`:
|
47
|
+
```
|
48
|
+
open "http://www.gnu.org/fun/jokes/helloworld.html"
|
49
|
+
```
|
50
|
+
|
51
|
+
Launch a console and type:
|
52
|
+
```
|
53
|
+
bauxite hello.bxt
|
54
|
+
```
|
55
|
+
|
56
|
+
Documentation
|
57
|
+
-------------
|
58
|
+
|
59
|
+
The Bauxite language is composed of two elements `Actions` and `Selectors`: Actions are testing operations such as "open this page", "click this button", "write this text into that textbox", etc. Selectors are ways of locating interesting elements of a page such as a button, a textbox, a label, etc.
|
60
|
+
|
61
|
+
A typical Bauxite test is a plain text file that contains a series of Actions (one per line). Depending on the Action, a few action arguments might need to be specified as well. For example in:
|
62
|
+
```
|
63
|
+
open "http://google.com"
|
64
|
+
write name=q "Hello WebDriver!"
|
65
|
+
click gbqfb
|
66
|
+
```
|
67
|
+
|
68
|
+
`open`, `write` and `click` are Actions:
|
69
|
+
- `open` takes a single URL argument (`"http://google.com"`) and opens that URL in the browser.
|
70
|
+
- `write` takes two arguments, a Selector (`name=q`, more on this in a bit) and a text (`"Hello WebDriver!"`), and writes the text into the element specified by the Selector.
|
71
|
+
- `click` takes a single Selector argument (`gbqfb`) and clicks the element specified by the Selector.
|
72
|
+
|
73
|
+
In general, Action arguments can be surrounded by optional double quote characters (`"`). If an argument contains a space character, the quotes are mandatory (this is the case for the second argument to `write` in the example above).
|
74
|
+
|
75
|
+
Some Actions operate on page elements (e.g. `write`, `click`, etc.). In order to locate these elements, Bauxite uses Selectors.
|
76
|
+
|
77
|
+
The trivial Selector is just a text that matches the last portion of the `id` attribute of the target element.
|
78
|
+
|
79
|
+
For example, in this HTML fragment:
|
80
|
+
```html
|
81
|
+
<input type="submit" id="gbqfb" value="Search" />
|
82
|
+
```
|
83
|
+
|
84
|
+
If we want to click the "Search" button we can do the following:
|
85
|
+
```
|
86
|
+
click gbqfb
|
87
|
+
```
|
88
|
+
|
89
|
+
Bauxite supports several other Selectors such as `name=` in the example above. The `name` Selector finds elements whose `name` attribute matches the text following the `=` sign.
|
90
|
+
|
91
|
+
For example, in this HTML fragment:
|
92
|
+
```html
|
93
|
+
<input type="text" name="q" />
|
94
|
+
```
|
95
|
+
|
96
|
+
If we want to type the text "Hello WebDriver!" in textbox we can do the following:
|
97
|
+
```
|
98
|
+
write name=q "Hello WebDriver!"
|
99
|
+
```
|
100
|
+
|
101
|
+
This section presented a brief introduction into the basic Bauxite concepts. For more details and a list of every Action and Selector available, refer to the RDoc generated documentation in:
|
102
|
+
- [Available Actions](http://pzavolinsky.github.io/bauxite/Bauxite/Action.html#Action+Methods)
|
103
|
+
- [Available Bauxite Selectors](http://pzavolinsky.github.io/bauxite/Bauxite/Selector.html#Selector+Methods)
|
104
|
+
- [Selenium Standard Selectors](http://pzavolinsky.github.io/bauxite/Bauxite/Selector.html#class-Bauxite::Selector-label-Standard+Selenium+Selectors)
|
105
|
+
- [Creating new Actions](http://pzavolinsky.github.io/bauxite/Bauxite/Action.html)
|
106
|
+
- [Creating new Selectors](http://pzavolinsky.github.io/bauxite/Bauxite/Selector.html)
|
107
|
+
|
108
|
+
Installing Ruby
|
109
|
+
---------------
|
110
|
+
|
111
|
+
I won't cover all the details of installing Ruby on your system (Google knows best), but the following should probably work.
|
112
|
+
|
113
|
+
In GNU/Linux, you can install [RVM](http://rvm.io/), then Ruby:
|
114
|
+
```
|
115
|
+
curl -sSL https://get.rvm.io | bash -s stable
|
116
|
+
source ~/.rvm/scripts/rvm
|
117
|
+
rvm install ruby-2.1.0
|
118
|
+
```
|
119
|
+
|
120
|
+
In Windows, you can install Ruby 2.x with [RubyInstaller](http://rubyinstaller.org/downloads/) but you'll probably need to install a Ruby 2.x Development Kit. After everything is installed, launch the Ruby terminal (or the MSYS terminal from the DevKit).
|
121
|
+
|
122
|
+
Regadless of your OS, you should be able to install Bauxite with:
|
123
|
+
|
124
|
+
```
|
125
|
+
gem install bauxite
|
126
|
+
```
|
127
|
+
|
128
|
+
Additionally, if you are using GNU/Linux, you might want to install `ruby-terminfo` to improve the terminal output(i.e. handle more than 80 chars):
|
129
|
+
|
130
|
+
```
|
131
|
+
gem install ruby-terminfo
|
132
|
+
```
|
133
|
+
|
134
|
+
Implementation
|
135
|
+
--------------
|
136
|
+
|
137
|
+
Bauxite is both a console program and a library. You can use the program to run Bauxite tests directly from a terminal, or you can embed the library in your own application.
|
138
|
+
|
139
|
+
The console program is called `bauxite` and has a few command-line options (run `bauxite -h` to see them all).
|
140
|
+
|
141
|
+
If you are looking to embed Bauxite in your application take a look a the code in `lib/bauxite/application.rb`, that should give you a full example of how to create a Bauxite Context and execute some actions.
|
142
|
+
|
143
|
+
Extending Bauxite
|
144
|
+
-----------------
|
145
|
+
|
146
|
+
Bauxite supports two types of extensions: functional extensions and coded plugins.
|
147
|
+
|
148
|
+
### Functional extensions
|
149
|
+
|
150
|
+
Functional extensions are composite constructs created using existing Bauxite actions to convey functional meaning. For example, imagine a login form:
|
151
|
+
|
152
|
+
```html
|
153
|
+
<!-- http://hostname/login.html -->
|
154
|
+
<form>
|
155
|
+
<input id="username" name="username" type="text" />
|
156
|
+
<input id="password" name="password" type="password" />
|
157
|
+
<input id="login" type="submit" value="Login"/>
|
158
|
+
</form>
|
159
|
+
```
|
160
|
+
|
161
|
+
The Bauxite code to login into this site would be:
|
162
|
+
```
|
163
|
+
open "http://hostname/login.html"
|
164
|
+
write username "jdoe"
|
165
|
+
write password "hello world!"
|
166
|
+
click login
|
167
|
+
```
|
168
|
+
|
169
|
+
If we were creating a suite of automated web tests for our *hostname* site, we'll probably need to login into the site several times. This would mean copy/pasting the four lines above into every test in our suite.
|
170
|
+
|
171
|
+
Of course we can do better. We can split Bauxite tests into many files and include one test into another with the `load` action.
|
172
|
+
|
173
|
+
```
|
174
|
+
# my_test.bxt (by the way, this is a comment)
|
175
|
+
load other_test_fragment.bxt
|
176
|
+
...
|
177
|
+
```
|
178
|
+
|
179
|
+
Back to our login example, first we can package the login part of our tests into a separate Bauxite file:
|
180
|
+
```
|
181
|
+
# login.bxt
|
182
|
+
open "http://hostname/login.html"
|
183
|
+
write username "jdoe"
|
184
|
+
write password "hello world!"
|
185
|
+
click login
|
186
|
+
```
|
187
|
+
|
188
|
+
Of course we would like to be able to login with different username/password combinations, so we can replace the literals in `login.bxt` with variables:
|
189
|
+
```
|
190
|
+
# login.bxt
|
191
|
+
open "http://hostname/login.html"
|
192
|
+
write username "${username}"
|
193
|
+
write password "${password}"
|
194
|
+
click login
|
195
|
+
```
|
196
|
+
|
197
|
+
Now, we would like to assert that both `username` and `password` variables are set before calling our test (just in case someone forgets). We can do this with `params`
|
198
|
+
```
|
199
|
+
# login.bxt
|
200
|
+
params username password
|
201
|
+
open "http://hostname/login.html"
|
202
|
+
write username "${username}"
|
203
|
+
write password "${password}"
|
204
|
+
click login
|
205
|
+
```
|
206
|
+
|
207
|
+
In our main test we can load `login.bxt` and specify the variables required using this code:
|
208
|
+
```
|
209
|
+
# main_test.bxt
|
210
|
+
load login.bxt username=jdoe "password=hello world!"
|
211
|
+
|
212
|
+
# additional actions go here
|
213
|
+
```
|
214
|
+
|
215
|
+
We could improve this even further by creating an `alias` to simplify the login process. To do this, lets create an new file called `alias.bxt`:
|
216
|
+
```
|
217
|
+
# alias.bxt
|
218
|
+
alias login load login.bxt "username=${1}" "password=${2}"
|
219
|
+
```
|
220
|
+
|
221
|
+
Note that the `alias` action supports positional arguments.
|
222
|
+
|
223
|
+
Now we can change our main test to use our alias:
|
224
|
+
```
|
225
|
+
# main_test.bxt
|
226
|
+
load alias.bxt
|
227
|
+
|
228
|
+
login jdoe "hello world!"
|
229
|
+
|
230
|
+
# additional actions go here
|
231
|
+
```
|
232
|
+
|
233
|
+
That was a bit of work but the resulting test is purely functional (minus the load alias part, of course).
|
234
|
+
|
235
|
+
### Coded plugins
|
236
|
+
|
237
|
+
Coded plugins can be used to extend Bauxite actions, selectors and loggers. Coded plugins are Ruby files placed in the respective directory. See any of the current artifacts for a reference implementation.
|
238
|
+
|
239
|
+
|
data/Rakefile
CHANGED
@@ -4,27 +4,26 @@ task :default => [:test, :doc]
|
|
4
4
|
require 'rubygems'
|
5
5
|
require 'rubygems/package_task'
|
6
6
|
|
7
|
-
PKG_FILES = FileList[
|
8
|
-
'LICENSE',
|
9
|
-
'Rakefile',
|
10
|
-
'bin/*',
|
11
|
-
'lib/**/*.rb',
|
12
|
-
'test/**/*',
|
13
|
-
'doc/**/*'
|
14
|
-
]
|
15
|
-
|
16
7
|
spec = Gem::Specification.new do |s|
|
17
8
|
s.name = 'bauxite'
|
18
|
-
s.summary = 'Bauxite is a
|
9
|
+
s.summary = 'Bauxite is a façade over Selenium intended for non-developers'
|
19
10
|
s.author = 'Patricio Zavolinsky'
|
20
11
|
s.email = 'pzavolinsky at yahoo dot com dot ar'
|
21
12
|
s.homepage = 'http://rubygems.org/gems/bauxite'
|
22
13
|
s.license = 'MIT'
|
23
14
|
s.version = `ruby -Ilib bin/bauxite --version`.gsub(/^.* /, '')
|
24
|
-
s.files = PKG_FILES
|
25
15
|
s.executables = ["bauxite"]
|
26
16
|
s.add_runtime_dependency 'selenium-webdriver', '~> 2.39'
|
27
17
|
s.add_development_dependency 'rake' , '~> 10.1'
|
18
|
+
s.files = FileList[
|
19
|
+
'LICENSE',
|
20
|
+
'README.md',
|
21
|
+
'Rakefile',
|
22
|
+
'bin/*',
|
23
|
+
'lib/**/*.rb',
|
24
|
+
'test/**/*',
|
25
|
+
'doc/**/*'
|
26
|
+
]
|
28
27
|
end
|
29
28
|
|
30
29
|
Gem::PackageTask.new(spec) do |pkg|
|
@@ -40,6 +39,11 @@ desc "Run integration tests"
|
|
40
39
|
task :test do
|
41
40
|
test_files = Dir[File.join('test', '*.bxt')].select { |f| not File.directory? f }.join(' ')
|
42
41
|
ruby "-Ilib bin/bauxite -v #{test_files}"
|
42
|
+
|
43
|
+
ruby "-Ilib bin/bauxite -v -e #{File.join('test', 'extension')} #{File.join('test', 'extension.bxt.manual')}"
|
44
|
+
|
45
|
+
system("ruby -Ilib bin/bauxite #{File.join('test', 'test.bxt.manual')}")
|
46
|
+
fail "The 'test' action test failed to return the expected exit status: the exit status was #{$?.exitstatus}" unless $?.exitstatus == 2
|
43
47
|
end
|
44
48
|
|
45
49
|
# === Documentation ========================================================= #
|
@@ -66,4 +70,22 @@ task :inject_license do
|
|
66
70
|
content = license + File.open(f, 'r') { |f| f.read }
|
67
71
|
#File.open(f, 'w') { |f| f.write content }
|
68
72
|
end
|
73
|
+
end
|
74
|
+
|
75
|
+
desc "Helper: Update Bauxite version"
|
76
|
+
task :update_version do
|
77
|
+
content = File.open('lib/bauxite.rb', 'r') { |f| f.read }
|
78
|
+
version = nil
|
79
|
+
content = content.each_line.map do |line|
|
80
|
+
match = line.match(/(.*VERSION = ")(.*)(".*)/)
|
81
|
+
next line unless match
|
82
|
+
version = match[2].split('.')
|
83
|
+
version[1] = (version[1].to_i + 1).to_s
|
84
|
+
version = version.join('.')
|
85
|
+
"#{match[1]}#{version}#{match[3]}\n"
|
86
|
+
end.join
|
87
|
+
if version
|
88
|
+
puts "Updated version to #{version}"
|
89
|
+
File.open('lib/bauxite.rb', 'w') { |f| f.write content }
|
90
|
+
end
|
69
91
|
end
|
data/doc/created.rid
CHANGED
data/lib/bauxite/application.rb
CHANGED
@@ -35,7 +35,8 @@ module Bauxite
|
|
35
35
|
:timeout => 10,
|
36
36
|
:reset => false,
|
37
37
|
:driver_opt => {},
|
38
|
-
:logger_opt => {}
|
38
|
+
:logger_opt => {},
|
39
|
+
:extensions => []
|
39
40
|
}
|
40
41
|
|
41
42
|
OptionParser.new do |opts|
|
@@ -79,6 +80,7 @@ module Bauxite
|
|
79
80
|
options[:driver] = 'remote'
|
80
81
|
options[:driver_opt][:url] = v
|
81
82
|
end
|
83
|
+
opts.on("-e", "--extension DIR", "Load extensions from DIR") { |v| options[:extensions] << v }
|
82
84
|
opts.on("--version", "Show version") do
|
83
85
|
puts "bauxite #{Bauxite::VERSION}"
|
84
86
|
exit
|
@@ -134,15 +136,21 @@ module Bauxite
|
|
134
136
|
ctx.start(actions)
|
135
137
|
ensure
|
136
138
|
if ctx.tests.any?
|
139
|
+
|
140
|
+
failed = 0
|
141
|
+
|
137
142
|
puts
|
138
143
|
puts 'Test summary:'
|
139
144
|
puts '============='
|
140
|
-
puts 'Name'.ljust(
|
145
|
+
puts 'Name'.ljust(40 ) + ' Time'.ljust(7 ) + ' Status'.ljust(7)+' Error'
|
146
|
+
puts ''.ljust(40, '-') + ' '.ljust(7, '-') + ' '.ljust(7, '-' )+' '.ljust(5, '-')
|
141
147
|
ctx.tests.each do |t|
|
142
148
|
error = t[:error]
|
143
149
|
error = error ? error.message : ''
|
144
|
-
puts t[:name].ljust(
|
150
|
+
puts t[:name].ljust(40) + ' ' + t[:time].round(2).to_s.rjust(6) + ' ' + t[:status].ljust(6) + ' ' + error
|
151
|
+
failed += 1 if t[:status] != 'OK'
|
145
152
|
end
|
153
|
+
exit failed if failed > 0
|
146
154
|
end
|
147
155
|
end
|
148
156
|
end
|
data/lib/bauxite/core/Context.rb
CHANGED
@@ -65,6 +65,7 @@ module Bauxite
|
|
65
65
|
# [:verbose] if +true+, show verbose error information (e.g. backtraces) if an error occurs (defaults to +false+)
|
66
66
|
# [:debug] if +true+, break into the #debug console if an error occurs (defaults to +false+)
|
67
67
|
# [:wait] if +true+, call ::wait before stopping the test engine with #stop (defaults to +false+)
|
68
|
+
# [:extensions] an array of directories that contain extensions to be loaded
|
68
69
|
#
|
69
70
|
def initialize(options)
|
70
71
|
@options = options
|
@@ -75,6 +76,8 @@ module Bauxite
|
|
75
76
|
@aliases = {}
|
76
77
|
@tests = []
|
77
78
|
|
79
|
+
_load_extensions(options[:extensions] || [])
|
80
|
+
|
78
81
|
handle_errors do
|
79
82
|
@logger = Context::load_logger(options[:logger], options[:logger_opt])
|
80
83
|
end
|
@@ -540,6 +543,14 @@ module Bauxite
|
|
540
543
|
end
|
541
544
|
.select { |item| item != nil }
|
542
545
|
end
|
546
|
+
|
547
|
+
def _load_extensions(dirs)
|
548
|
+
dirs.each do |d|
|
549
|
+
d = File.join(Dir.pwd, d) unless Dir.exists? d
|
550
|
+
d = File.absolute_path(d)
|
551
|
+
Dir[File.join(d, '**', '*.rb')].each { |file| require file }
|
552
|
+
end
|
553
|
+
end
|
543
554
|
|
544
555
|
# ======================================================================= #
|
545
556
|
# Hacks required to overcome the String#split(' ') behavior of folding the
|
data/lib/bauxite.rb
CHANGED
data/test/test.bxt.manual
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bauxite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patricio Zavolinsky
|
@@ -46,6 +46,7 @@ extensions: []
|
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
48
|
- LICENSE
|
49
|
+
- README.md
|
49
50
|
- Rakefile
|
50
51
|
- bin/bauxite
|
51
52
|
- doc/Bauxite.html
|
@@ -149,6 +150,9 @@ files:
|
|
149
150
|
- test/delay.bxt
|
150
151
|
- test/delay/page.html
|
151
152
|
- test/exec.bxt
|
153
|
+
- test/extension.bxt.manual
|
154
|
+
- test/extension/custom.rb
|
155
|
+
- test/extension/page.html
|
152
156
|
- test/format.bxt
|
153
157
|
- test/format/page.html
|
154
158
|
- test/frame.bxt
|
@@ -190,5 +194,5 @@ rubyforge_project:
|
|
190
194
|
rubygems_version: 2.2.1
|
191
195
|
signing_key:
|
192
196
|
specification_version: 4
|
193
|
-
summary: Bauxite is a
|
197
|
+
summary: Bauxite is a façade over Selenium intended for non-developers
|
194
198
|
test_files: []
|