bauxite 0.1.0 → 0.2.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 +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: []
|