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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: be9bad759531fd16a4b26cdf4e238cce2f281dca
4
- data.tar.gz: bbc8da45da489a6ec0f2953d7fe1060b8c2f16c2
3
+ metadata.gz: 063894fc2a6cee418888abc8d731448a22653c5c
4
+ data.tar.gz: 1cc13f20d0951eaed6451b75575124f558f4d063
5
5
  SHA512:
6
- metadata.gz: 3a0e659899dd36b90f10427bac985977121bf8b7f6f1dcbee88d7b1362e293b32f90a66e89be9758bd77254439f2c81832e6aff29c520adbc53dcf7a48bd7aff
7
- data.tar.gz: 702df87e3d3675511d09c8f8337334bce794cf31cbf1d16d274d494a51fa461406316ad94d24fb8b1bf2100f7dd74a48b96c6cc0cbf6a5f8c29848651727e429
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 facade over Selenium intended for non-developers'
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
@@ -1,4 +1,4 @@
1
- Sat, 25 Jan 2014 12:24:37 -0300
1
+ Sat, 25 Jan 2014 13:18:13 -0300
2
2
  lib/bauxite/core/Action.rb Sat, 25 Jan 2014 12:19:06 -0300
3
3
  lib/bauxite/core/Context.rb Sat, 25 Jan 2014 12:19:06 -0300
4
4
  lib/bauxite/core/Errors.rb Sat, 25 Jan 2014 12:19:06 -0300
@@ -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(60) + 'Time'.ljust(6) + 'Status'.ljust(7)+'Error'
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(60) + t[:time].round(3).to_s.ljust(6) + t[:status].ljust(7) + error
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
@@ -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
@@ -22,7 +22,7 @@
22
22
 
23
23
  #--
24
24
  module Bauxite
25
- VERSION = "0.1.0"
25
+ VERSION = "0.2.0"
26
26
  end
27
27
  #++
28
28
 
@@ -0,0 +1,12 @@
1
+ class Bauxite::Action
2
+ def hello()
3
+ lambda { puts 'Hello World!' }
4
+ end
5
+ end
6
+
7
+ class Bauxite::Selector
8
+ def by_attr(value)
9
+ attr "by_attr:#{value}"
10
+ end
11
+ end
12
+
@@ -0,0 +1,5 @@
1
+ <html>
2
+ <body>
3
+ <input by_attr="attr_value">
4
+ </body>
5
+ </html>
@@ -0,0 +1,4 @@
1
+ hello
2
+ open "file://${__DIR__}/extension/page.html"
3
+ assert "by_attr=attr_value" hello
4
+
data/test/test.bxt.manual CHANGED
@@ -1,4 +1,5 @@
1
1
  test test/test1.bxt
2
2
  test test/test2.bxt "broken test"
3
+ test test/test2.bxt "broken again"
3
4
  test test/test1.bxt "final test"
4
5
 
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.1.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 facade over Selenium intended for non-developers
197
+ summary: Bauxite is a façade over Selenium intended for non-developers
194
198
  test_files: []