rubidium 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ pkg/*
2
+ tmp/*
3
+
4
+ # bundler
5
+ # bin/*
6
+ # vendor/gems/*
7
+ # !vendor/gems/cache/
8
+
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ # disable_system_gems
2
+ clear_sources
3
+ source 'http://gemcutter.org'
4
+ source 'http://gems.github.com'
5
+ source 'http://gems.rubyforge.org'
6
+
7
+ gem "rake"
8
+ gem "selenium-client", "1.2.7", :require_as => 'selenium/client'
9
+ gem "nokogiri", ">= 1.4.0"
10
+ #gem "jeweler"
11
+
12
+ gem "rspec", "1.1.8", :require_as => 'spec', :only => :never
13
+ gem "deep_test", "1.2.2"
14
+ gem "ruby-debug"
15
+ gem "syntax"
16
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Incite
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,8 @@
1
+ gem install bundler
2
+ gem bundle
3
+ rake spec
4
+ rake generate
5
+
6
+ (start up a selenium hub & remotes)
7
+
8
+ rake tests:run_in_parallel
@@ -0,0 +1,18 @@
1
+ = rubidium
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but
13
+ bump version in a commit by itself I can ignore when I pull)
14
+ * Send me a pull request. Bonus points for topic branches.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2009 davidlee. See LICENSE for details.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require File.join(File.dirname(__FILE__), '../init')
4
+
5
+ options = {}
6
+
7
+ optparse = OptionParser.new do |opts|
8
+
9
+ # Set a banner, displayed at the top
10
+ # of the help screen.
11
+ opts.banner = "Usage: rubidium [options] source_folder destination_folder"
12
+
13
+ opts.separator ""
14
+ opts.separator "Specific options:"
15
+
16
+ # Define the options, and what they do
17
+ options[:verbose] = false
18
+ opts.on( '-v', '--verbose', 'Output more information' ) do
19
+ options[:verbose] = true
20
+ end
21
+
22
+ # This displays the help screen, all programs are
23
+ # assumed to have this option.
24
+ opts.on( '-h', '--help', 'You\'re looking at it' ) do
25
+ puts opts
26
+ exit
27
+ end
28
+
29
+ # Mandatory argument.
30
+ opts.on("-i", "--input FOLDER",
31
+ "Find and convert all test suites in FOLDER") do |src|
32
+ options[:source] << src
33
+ end
34
+
35
+ opts.on("-o", "--output FOLDER",
36
+ "Find and convert all test suites in FOLDER") do |dest|
37
+ options[:destination] << dest
38
+ end
39
+
40
+ end
41
+
42
+ optparse.parse!
43
+
44
+ p options
45
+ p ARGV
46
+
47
+ options[:source] ||= ARGV.shift
48
+ options[:destination] ||= ARGV.shift
49
+
50
+ if options[:source] && options[:destination]
51
+ Rubidium::Converter.new(options[:source]).write!(options[:destination])
52
+ end
53
+
54
+
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta content="text/html; charset=UTF-8" http-equiv="content-type" />
6
+ <title>Test Suite</title>
7
+ </head>
8
+ <body>
9
+ <table id="suiteTable" cellpadding="1" cellspacing="1" border="1" class="selenium"><tbody>
10
+ <tr><td><b>Test Suite</b></td></tr>
11
+ <tr><td><a href="sanityTest.html">sanityTest</a></td></tr>
12
+ </tbody></table>
13
+ </body>
14
+ </html>
@@ -0,0 +1,58 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head profile="http://selenium-ide.openqa.org/profiles/test-case">
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <link rel="selenium.base" href="http://www.google.com.au/" />
7
+ <title>sanityTest</title>
8
+ </head>
9
+ <body>
10
+ <table cellpadding="1" cellspacing="1" border="1">
11
+ <thead>
12
+ <tr><td rowspan="1" colspan="3">sanityTest</td></tr>
13
+ </thead><tbody>
14
+ <!--testing google loads-->
15
+ <tr>
16
+ <td>open</td>
17
+ <td>/</td>
18
+ <td></td>
19
+ </tr>
20
+ <tr>
21
+ <td>assertTextPresent</td>
22
+ <td>Google</td>
23
+ <td></td>
24
+ </tr>
25
+ <tr>
26
+ <td>assertTextNotPresent</td>
27
+ <td>Bing</td>
28
+ <td></td>
29
+ </tr>
30
+ <tr>
31
+ <td>type</td>
32
+ <td>q</td>
33
+ <td>wikipedia</td>
34
+ </tr>
35
+ <tr>
36
+ <td>keyPress</td>
37
+ <td>q</td>
38
+ <td>\13</td>
39
+ </tr>
40
+ <tr>
41
+ <td>waitForElementPresent</td>
42
+ <td>css=a.l</td>
43
+ <td></td>
44
+ </tr>
45
+ <tr>
46
+ <td>verifyTextPresent</td>
47
+ <td>Wikipedia, the free encyclopedia</td>
48
+ <td></td>
49
+ </tr>
50
+ <tr>
51
+ <td>assertElementPresent</td>
52
+ <td>link=Wikipedia, the free encyclopedia</td>
53
+ <td></td>
54
+ </tr>
55
+
56
+ </tbody></table>
57
+ </body>
58
+ </html>
data/init.rb ADDED
@@ -0,0 +1,29 @@
1
+ def f(relpath)
2
+ root_path = File.dirname(__FILE__)
3
+ File.expand_path(File.join(root_path, relpath))
4
+ end
5
+
6
+ begin
7
+
8
+ # require f 'vendor/gems/environment'
9
+ # Bundler.require_env
10
+ # rescue LoadError
11
+ # puts "ack! run gem bundle"
12
+
13
+ require 'rubygems'
14
+ gem "rake", ">= 0.8.7"
15
+ gem "selenium-client", "= 1.2.7"
16
+ gem "nokogiri", ">= 1.4.0"
17
+ gem "rspec", "= 1.1.8"
18
+ gem "deep_test", "= 1.2.2"
19
+ gem "ruby-debug", "> 0"
20
+ require 'rake'
21
+ require 'nokogiri'
22
+ require 'spec'
23
+ require 'deep_test'
24
+ require 'ruby-debug'
25
+ require 'selenium/client'
26
+
27
+ require f 'lib/rubidium'
28
+ end
29
+
@@ -0,0 +1,9 @@
1
+ $: << File.dirname(__FILE__)
2
+
3
+ require 'rubidium/test_case'
4
+ require 'rubidium/test_suite'
5
+ require 'rubidium/translator'
6
+ require 'rubidium/spec_writer'
7
+ require 'rubidium/converter'
8
+
9
+
@@ -0,0 +1,25 @@
1
+ require 'fileutils'
2
+
3
+ module Rubidium
4
+ class Converter
5
+
6
+ attr_reader :test_suites
7
+
8
+ # given a source directory, find all test suites in it, and prepare ruby translations of them.
9
+ def initialize(source_folder)
10
+ raise ArgumentError.new("source folder expected") unless File.directory?(source_folder)
11
+
12
+ @test_suites = `grep -rnl suiteTable #{source_folder}`.split("\n").map do |fn|
13
+ TestSuite.new(fn)
14
+ end
15
+ end
16
+
17
+ # write the ruby tests to the given output folder
18
+ def write!(output_folder)
19
+ FileUtils.mkdir_p output_folder unless File.directory?(output_folder)
20
+ SpecWriter.new(output_folder).write!(@test_suites)
21
+ end
22
+
23
+
24
+ end
25
+ end
@@ -0,0 +1,75 @@
1
+ require 'fileutils'
2
+ require 'erb'
3
+
4
+ module Rubidium
5
+ class SpecWriter
6
+
7
+ def initialize(output_folder)
8
+ @output_folder = output_folder
9
+ end
10
+
11
+ def write!(*tests)
12
+ tests.flatten!
13
+ process_rakefile
14
+ process_helper
15
+ test_suites, test_cases = tests.partition { |t| t.is_a?(Rubidium::TestSuite) }
16
+ process_test_suites test_suites
17
+ process_test_cases test_cases
18
+ end
19
+
20
+ private
21
+
22
+ def process_rakefile
23
+ template_path = f 'templates/rakefile.rb.erb'
24
+ output_path = File.join(@output_folder, "rakefile.rb")
25
+ process_template(template_path, output_path)
26
+ end
27
+
28
+ def process_helper
29
+ template_path = f 'templates/spec_helper.rb.erb'
30
+ output_path = File.join(@output_folder, "spec_helper.rb")
31
+ process_template(template_path, output_path)
32
+ end
33
+
34
+ def process_test_suites(test_suites)
35
+ template_path = f 'templates/spec.rb.erb'
36
+ test_suites.each do |ts|
37
+ ts.test_cases.each do |tc|
38
+ output_folder = File.join(@output_folder, underscore(ts.name))
39
+ output_path = File.join(output_folder, "#{underscore tc.name}_spec.rb")
40
+ FileUtils.mkdir_p(output_folder)
41
+ process_template(template_path, output_path) do
42
+ @application_url = tc.base_url unless tc.base_url == ""
43
+ @test_case = tc
44
+ @test_suite = ts
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def underscore string
51
+ string.gsub(/ /,'_')
52
+ end
53
+
54
+ def process_test_cases(test_cases)
55
+ test_cases.each do |tc|
56
+ template_path = f 'templates/spec.erb'
57
+ output_path = File.join(@output_folder, "#{tc.name}_spec.rb")
58
+ process_template(template_path, output_path) do
59
+ @test_case = tc
60
+ end
61
+ end
62
+ end
63
+
64
+ def process_template(template_path, output_path, &block)
65
+ if File.exists?(output_path)
66
+ FileUtils.rm(output_path)
67
+ end
68
+ File.open(output_path, 'w') do |fh|
69
+ yield if block_given?
70
+ fh.write ERB.new(File.read(template_path)).result(binding)
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,26 @@
1
+ module Rubidium
2
+ class TestCase
3
+ attr_reader :title, :base_url, :selenese, :path
4
+ alias_method :table, :selenese
5
+ alias_method :name, :title
6
+
7
+ def initialize(path)
8
+ @path = path
9
+ x = Nokogiri::HTML(File.read(path))
10
+ @title = x.xpath('//title').first.text
11
+ @base_url = x.xpath('//link').attr('href').value
12
+ @selenese = x.xpath('//tbody/tr').map do |tr|
13
+ tr.search('td').map(&:text).reject { |txt| txt == "" }
14
+ end
15
+ end
16
+
17
+ def ruby
18
+ Translator.translate(selenese)
19
+ end
20
+
21
+ def commands
22
+ Translator.translate(selenese)
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ module Rubidium
2
+ class TestSuite
3
+ attr_reader :path, :title, :test_case_paths, :test_cases
4
+ alias_method :name, :title
5
+
6
+ def initialize(path)
7
+ @path = path
8
+ @test_cases = []
9
+ x = Nokogiri::HTML(File.read(path))
10
+ @title = x.xpath('//title').text
11
+ return false unless x.search('html').attribute 'xmlns' # filter out test reports
12
+ @test_case_paths = x.xpath('//table/tbody/tr/td/a').map {|a| test_case_path a.attributes['href'].text }
13
+ @test_cases = @test_case_paths.map { |p| Rubidium::TestCase.new(p) }
14
+ end
15
+
16
+ protected
17
+
18
+ def test_case_path relpath
19
+ dir = File.dirname(path)
20
+ File.expand_path(File.join(dir, relpath))
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,242 @@
1
+ module Rubidium
2
+
3
+ # these commands accept an assert | verify | waitFor prefix
4
+
5
+ VARIANTS = {
6
+ 'Alert' => [:pattern],
7
+ 'AlertNotPresent' => [],
8
+ 'AlertPresent' => [],
9
+ 'AllButtons' => [:pattern],
10
+ 'AllFields' => [:pattern],
11
+ 'AllLinks' => [:pattern],
12
+ 'AllWindowIds' => [:pattern],
13
+ 'AllWindowNames' => [:pattern],
14
+ 'AllWindowTitles' => [:pattern],
15
+ 'Attribute' => [:attributeLocator, :pattern],
16
+ 'AttributeFromAllWindows' => [:attributeName, :pattern],
17
+ 'BodyText' => [:pattern],
18
+ 'Checked' => [:locator],
19
+ 'Confirmation' => [:pattern],
20
+ 'ConfirmationNotPresent' => [],
21
+ 'ConfirmationPresent' => [],
22
+ 'Cookie' => [:pattern],
23
+ 'CookieByName' => [:name, :pattern],
24
+ 'CookieNotPresent' => [:name],
25
+ 'CookiePresent' => [:name],
26
+ 'CursorPosition' => [:locator, :pattern],
27
+ 'Editable' => [:locator],
28
+ 'ElementHeight' => [:locator, :pattern],
29
+ 'ElementIndex' => [:locator, :pattern],
30
+ 'ElementNotPresent' => [:locator],
31
+ 'ElementPositionLeft' => [:locator, :pattern],
32
+ 'ElementPositionTop' => [:locator, :pattern],
33
+ 'ElementPresent' => [:locator],
34
+ 'ElementWidth' => [:locator, :pattern],
35
+ 'Eval' => [:script, :pattern],
36
+ 'Expression' => [:expression, :pattern],
37
+ 'HtmlSource' => [:pattern],
38
+ 'Location' => [:pattern],
39
+ 'MouseSpeed' => [:pattern],
40
+ 'NotAlert' => [:pattern],
41
+ 'NotAllButtons' => [:pattern],
42
+ 'NotAllFields' => [:pattern],
43
+ 'NotAllLinks' => [:pattern],
44
+ 'NotAllWindowIds' => [:pattern],
45
+ 'NotAllWindowNames' => [:pattern],
46
+ 'NotAllWindowTitles' => [:pattern],
47
+ 'NotAttribute' => [:attributeLocator, :pattern],
48
+ 'NotAttributeFromAllWindows' => [:attributeName, :pattern],
49
+ 'NotBodyText' => [:pattern],
50
+ 'NotChecked' => [:locator],
51
+ 'NotConfirmation' => [:pattern],
52
+ 'NotCookie' => [:pattern],
53
+ 'NotCookieByName' => [:name, :pattern],
54
+ 'NotCursorPosition' => [:locator, :pattern],
55
+ 'NotEditable' => [:locator],
56
+ 'NotElementHeight' => [:locator, :pattern],
57
+ 'NotElementIndex' => [:locator, :pattern],
58
+ 'NotElementPositionLeft' => [:locator, :pattern],
59
+ 'NotElementPositionTop' => [:locator, :pattern],
60
+ 'NotElementWidth' => [:locator, :pattern],
61
+ 'NotErrorOnNext' => [:message],
62
+ 'NotEval' => [:script, :pattern],
63
+ 'NotExpression' => [:expression, :pattern],
64
+ 'NotFailureOnNext' => [:message],
65
+ 'NotHtmlSource' => [:pattern],
66
+ 'NotLocation' => [:pattern],
67
+ 'NotMouseSpeed' => [:pattern],
68
+ 'NotOrdered' => [:locator, :locator],
69
+ 'NotPrompt' => [:pattern],
70
+ 'NotSelectOptions' => [:selectLocator, :pattern],
71
+ 'NotSelected' => [:selectLocator, :optionLocator],
72
+ 'NotSelectedId' => [:selectLocator, :pattern],
73
+ 'NotSelectedIds' => [:selectLocator, :pattern],
74
+ 'NotSelectedIndex' => [:selectLocator, :pattern],
75
+ 'NotSelectedIndexes' => [:selectLocator, :pattern],
76
+ 'NotSelectedLabel' => [:selectLocator, :pattern],
77
+ 'NotSelectedLabels' => [:selectLocator, :pattern],
78
+ 'NotSelectedValue' => [:selectLocator, :pattern],
79
+ 'NotSelectedValues' => [:selectLocator, :pattern],
80
+ 'NotSomethingSelected' => [:selectLocator],
81
+ 'NotSpeed' => [:pattern],
82
+ 'NotTable' => [:tableCellAddress, :pattern],
83
+ 'NotText' => [:locator, :pattern],
84
+ 'NotTitle' => [:pattern],
85
+ 'NotValue' => [:locator, :pattern],
86
+ 'NotVisible' => [:locator],
87
+ 'NotWhetherThisFrameMatchFrameExpression' => [:currentFrameString, :target],
88
+ 'NotWhetherThisWindowMatchWindowExpression' => [:currentWindowString, :target],
89
+ 'NotXpathCount' => [:xpath, :pattern],
90
+ 'Ordered' => [:locator1, :locator2],
91
+ 'Prompt' => [:pattern],
92
+ 'PromptNotPresent' => [],
93
+ 'PromptPresent' => [],
94
+ 'SelectOptions' => [:selectLocator, :pattern],
95
+ 'SelectedId' => [:selectLocator, :pattern],
96
+ 'SelectedIds' => [:selectLocator, :pattern],
97
+ 'SelectedIndex' => [:selectLocator, :pattern],
98
+ 'SelectedIndexes' => [:selectLocator, :pattern],
99
+ 'SelectedLabel' => [:selectLocator, :pattern],
100
+ 'SelectedLabels' => [:selectLocator, :pattern],
101
+ 'SelectedValue' => [:selectLocator, :pattern],
102
+ 'SelectedValues' => [:selectLocator, :pattern],
103
+ 'SomethingSelected' => [:selectLocator],
104
+ 'Speed' => [:pattern],
105
+ 'Table' => [:tableCellAddress, :pattern],
106
+ 'Text' => [:locator, :pattern],
107
+ 'TextNotPresent' => [:pattern],
108
+ 'TextPresent' => [:pattern],
109
+ 'Title' => [:pattern],
110
+ 'Value' => [:locator, :pattern],
111
+ 'Visible' => [:locator],
112
+ 'WhetherThisFrameMatchFrameExpression' => [:currentFrameString, :target],
113
+ 'WhetherThisWindowMatchWindowExpression' => [:currentWindowString, :target],
114
+ 'XpathCount' => [:xpath, :pattern],
115
+ }
116
+
117
+ class Translator
118
+ COMPOSITE = /^(assert|verify|waitFor)([a-zA-Z]+)$/
119
+ PATTERN = /^(regexpi?|exact|glob):/
120
+ def self.translate(selenese)
121
+ selenese.map { |row| translate_command(*row) }
122
+ end
123
+
124
+ private
125
+
126
+ # A "Pattern" in selenium nomenclature is a string matcher.
127
+ # The default is a glob (? and * expansion).
128
+
129
+ def self.pattern(string)
130
+ # string =~ PATTERN
131
+ string.gsub! PATTERN, ''
132
+ type = $1 || 'glob'
133
+ send("#{type}_pattern", string)
134
+ end
135
+
136
+ def self.glob_pattern(string)
137
+ if string =~ /\?|\*/
138
+ string = Regexp.escape(string)
139
+ string.gsub! /\\\?/, '.'
140
+ string.gsub! /\\\*/, '.*'
141
+ Regexp.new(string)
142
+ else
143
+ string
144
+ end
145
+ end
146
+
147
+ def self.exact_pattern(string)
148
+ string
149
+ end
150
+
151
+ def self.regexp_pattern(string)
152
+ /#{string}/
153
+ end
154
+
155
+ def self.regexpi_pattern(string)
156
+ /#{string}/i
157
+ end
158
+
159
+ protected
160
+
161
+ def self.default_timeout
162
+ 10000
163
+ end
164
+
165
+ def self.build_composite_command(command, target=nil, value=nil)
166
+ # p [:build, command, target, value]
167
+ command =~ COMPOSITE
168
+ verb = $1
169
+ variant = $2
170
+ expectation = variant.gsub!(/Not/, '') ? 'should_not' : 'should'
171
+ ruby_command = ['', 'get_', 'is_'].map {|s| s + underscore(variant) }.detect { |s| client.respond_to?(s) }
172
+ ruby_args = []
173
+ args = [target, value].compact
174
+ client.method(ruby_command).arity.times do
175
+ ruby_args << args.shift
176
+ end
177
+ ruby_args = ruby_args.compact.map(&:inspect).join(", ")
178
+
179
+ result = args.first ? pattern(args.first) : true
180
+ comparison = result.is_a?(Regexp) ? '=~' : '=='
181
+ result = result.inspect
182
+ expression = "selenium.#{ruby_command}(#{ruby_args}).#{expectation} #{comparison} #{result}"
183
+
184
+ case verb
185
+ when 'assert'
186
+ expression
187
+ when 'verify'
188
+ "begin\n " +
189
+ "#{expression}\n " +
190
+ "rescue ::Test::Unit::AssertionFailedError, ::Spec::Expectations::ExpectationNotMetError => e\n " +
191
+ "@verification_errors << e\n " +
192
+ "end\n"
193
+ when 'waitFor'
194
+ "wait_for do\n #{expression}\n end\n"
195
+ end
196
+ end
197
+
198
+ def self.translate_command(command, target=nil, value=nil)
199
+ # p [:translate, command, target, value]
200
+
201
+ # TODO - custom treatment of patterns
202
+ # HACK / FIXME in the meantime
203
+ [target, value].compact.map(&:to_s).each { |s| s.gsub!(/^exact:/, '') }
204
+
205
+ if command.gsub!(/AndWait$/, '')
206
+ [translate_command(command, target, value), translate_command('waitForPageToLoad', default_timeout)].join("\n ")
207
+ elsif command =~ COMPOSITE && VARIANTS.has_key?($2)
208
+ build_composite_command(command, target, value)
209
+ else
210
+ case command
211
+ when 'pause'
212
+ "sleep #{target.to_i / 1000}"
213
+ when 'waitForPageToLoad'
214
+ "selenium.wait_for_page_to_load(\"#{default_timeout}\")"
215
+ else
216
+ ruby_command = underscore(command)
217
+ if client.respond_to?(ruby_command)
218
+ args = [target, value].compact
219
+ while args.length < client.method(ruby_command).arity
220
+ args << ""
221
+ end
222
+ "selenium.#{ruby_command} #{args.map(&:inspect).join(", ")}"
223
+ else
224
+ raise "unkown command error: #{command}"
225
+ end
226
+ end
227
+ end
228
+ end
229
+
230
+ def self.underscore(str)
231
+ str.split(/([A-Z])/).inject("") { |s, ch| s << (ch =~ /[A-Z]/ ? "_#{ch.downcase}" : ch) }.gsub(/^_/,'')
232
+ end
233
+
234
+ def self.client
235
+ @test_client ||= Selenium::Client::Driver.new(nil, nil, nil, nil)
236
+ end
237
+
238
+ end
239
+ end
240
+
241
+
242
+
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # require 'vendor/gems/environment'
4
+ require File.join(File.dirname(__FILE__),"init")
5
+ Bundler.require_env :runner rescue nil
6
+
7
+ # load rake tasks
8
+ require 'rake'
9
+ require "spec/rake/spectask"
10
+ require "selenium/rake/tasks"
11
+ require "deep_test/rake_tasks"
12
+
13
+ begin
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ gem.name = "rubidium"
17
+ gem.summary = %Q{convert Selenium tests to ruby/rspec for running against a Grid }
18
+ gem.description = %Q{convert Selenium tests to ruby/rspec for running against a Grid. Performs much better translation than the Selenium IDE, and a harness for running the resulting specs.}
19
+ gem.email = "david@davelee.com.au"
20
+ gem.homepage = "http://github.com/incite/rubidium"
21
+ gem.authors = ["davidlee"]
22
+ gem.add_development_dependency "jeweler", ">= 0"
23
+ gem.add_dependency "rake", ">= 0.8.7"
24
+ gem.add_dependency "selenium-client", "= 1.2.7"
25
+ gem.add_dependency "nokogiri", ">= 1.4.0"
26
+ gem.add_dependency "rspec", "= 1.1.8"
27
+ gem.add_dependency "deep_test", "= 1.2.2"
28
+ gem.add_dependency "ruby-debug", "> 0"
29
+ # gem.add_dependency "syntax"
30
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
31
+ end
32
+ Jeweler::GemcutterTasks.new
33
+ rescue LoadError
34
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
35
+ end
36
+
37
+
38
+ # Make sure we pick up the reporter from the appropriate selenium-client
39
+ # install as RSpec runner --require does not discriminate between multiple
40
+ # selenium-client gems.
41
+ gem_executable = Config::CONFIG["host_os"] =~ /mswin/ ? "gem.bat" : "gem"
42
+ report_formatter_path = `#{gem_executable} which -q "selenium/rspec/reporting/selenium_test_report_formatter"`.chomp
43
+ report_formatter_path.gsub!(/selenium-client-\d+\.\d+.\d+/, "selenium-client-1.2.7")
44
+
45
+ desc "Check whether you installed all dependencies and you environmnet is OK."
46
+ task :sanity_check do
47
+ require report_formatter_path
48
+ STDOUT.puts "yeah looks ok"
49
+ end
50
+
51
+ desc "Run all specs in spec directory (excluding plugin specs)"
52
+ Spec::Rake::SpecTask.new(:spec) do |t|
53
+ t.spec_files = FileList['spec/**/*/*_spec.rb']
54
+ end
55
+
56
+ desc 'generate test suites'
57
+ task :generate do
58
+ root = File.dirname(__FILE__)
59
+ Rubidium::Converter.new(File.join(root,'examples/')).write!(File.join(root,'tmp/tests'))
60
+ end
61
+
62
+ task :convert do
63
+ root = File.dirname(__FILE__)
64
+ src_dir = 1
65
+ Rubidium::Converter.new(File.join(root,'examples/')).write!(File.join(root,'tmp/tests'))
66
+ end
67
+
68
+ task :default => :spec
@@ -0,0 +1,90 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in rakefile.rb, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rubidium}
8
+ s.version = "0.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["davidlee"]
12
+ s.date = %q{2009-11-11}
13
+ s.description = %q{convert Selenium tests to ruby/rspec for running against a Grid. Performs much better translation than the Selenium IDE, and a harness for running the resulting specs.}
14
+ s.email = %q{david@davelee.com.au}
15
+ s.executables = ["bin/rubidium"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE",
18
+ "README",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".gitignore",
23
+ "Gemfile",
24
+ "LICENSE",
25
+ "README",
26
+ "README.rdoc",
27
+ "VERSION",
28
+ "examples/google.com/googleSuite.html",
29
+ "examples/google.com/sanityTest.html",
30
+ "init.rb",
31
+ "lib/rubidium.rb",
32
+ "lib/rubidium/converter.rb",
33
+ "lib/rubidium/spec_writer.rb",
34
+ "lib/rubidium/test_case.rb",
35
+ "lib/rubidium/test_suite.rb",
36
+ "lib/rubidium/translator.rb",
37
+ "rakefile.rb",
38
+ "rubidium.gemspec",
39
+ "script/rubidium",
40
+ "spec/rubidium/google.com/sanity_test_spec.rb",
41
+ "spec/rubidium_spec.rb",
42
+ "spec/spec_helper.rb",
43
+ "templates/rakefile.rb.erb",
44
+ "templates/spec.rb.erb",
45
+ "templates/spec_helper.rb.erb",
46
+ "todo.org"
47
+ ]
48
+ s.homepage = %q{http://github.com/incite/rubidium}
49
+ s.rdoc_options = ["--charset=UTF-8"]
50
+ s.require_paths = ["lib"]
51
+ s.rubygems_version = %q{1.3.5}
52
+ s.summary = %q{convert Selenium tests to ruby/rspec for running against a Grid}
53
+ s.test_files = [
54
+ "spec/rubidium/google.com/sanity_test_spec.rb",
55
+ "spec/rubidium_spec.rb",
56
+ "spec/spec_helper.rb"
57
+ ]
58
+
59
+ if s.respond_to? :specification_version then
60
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
61
+ s.specification_version = 3
62
+
63
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
64
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
65
+ s.add_runtime_dependency(%q<rake>, [">= 0.8.7"])
66
+ s.add_runtime_dependency(%q<selenium-client>, ["= 1.2.7"])
67
+ s.add_runtime_dependency(%q<nokogiri>, [">= 1.4.0"])
68
+ s.add_runtime_dependency(%q<rspec>, ["= 1.1.8"])
69
+ s.add_runtime_dependency(%q<deep_test>, ["= 1.2.2"])
70
+ s.add_runtime_dependency(%q<ruby-debug>, ["> 0"])
71
+ else
72
+ s.add_dependency(%q<jeweler>, [">= 0"])
73
+ s.add_dependency(%q<rake>, [">= 0.8.7"])
74
+ s.add_dependency(%q<selenium-client>, ["= 1.2.7"])
75
+ s.add_dependency(%q<nokogiri>, [">= 1.4.0"])
76
+ s.add_dependency(%q<rspec>, ["= 1.1.8"])
77
+ s.add_dependency(%q<deep_test>, ["= 1.2.2"])
78
+ s.add_dependency(%q<ruby-debug>, ["> 0"])
79
+ end
80
+ else
81
+ s.add_dependency(%q<jeweler>, [">= 0"])
82
+ s.add_dependency(%q<rake>, [">= 0.8.7"])
83
+ s.add_dependency(%q<selenium-client>, ["= 1.2.7"])
84
+ s.add_dependency(%q<nokogiri>, [">= 1.4.0"])
85
+ s.add_dependency(%q<rspec>, ["= 1.1.8"])
86
+ s.add_dependency(%q<deep_test>, ["= 1.2.2"])
87
+ s.add_dependency(%q<ruby-debug>, ["> 0"])
88
+ end
89
+ end
90
+
@@ -0,0 +1,29 @@
1
+ require File.join(File.dirname(__FILE__), '../../spec_helper.rb')
2
+
3
+ describe "sanity check w/ google" do
4
+ before do
5
+ @test = Rubidium::TestCase.new f 'examples/google.com/sanityTest.html'
6
+ end
7
+
8
+ it "is called sanityTest" do
9
+ @test.name.should == 'sanityTest'
10
+ end
11
+
12
+ it "operates on google.com.au" do
13
+ @test.base_url.should == "http://www.google.com.au/"
14
+ end
15
+
16
+ it "has a table of selenese commands" do
17
+ @test.table.should == [
18
+ ["open", "/"],
19
+ ["assertTextPresent", "Google"],
20
+ ["assertTextNotPresent", "Bing"],
21
+ ["type", "q", "wikipedia"],
22
+ ["keyPress", "q", "\\13"],
23
+ ["waitForElementPresent", "css=a.l"],
24
+ ["verifyTextPresent", "Wikipedia, the free encyclopedia"],
25
+ ["assertElementPresent", "link=Wikipedia, the free encyclopedia"]
26
+ ]
27
+ end
28
+
29
+ end
@@ -0,0 +1,22 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+
3
+ describe "spec writer" do
4
+ describe "convert a test case" do
5
+ before do
6
+ @test_case = Rubidium::TestCase.new(f('examples/google.com/sanityTest.html'))
7
+ @writer = Rubidium::SpecWriter.new(f('tmp/tests'))
8
+ end
9
+
10
+ it "generate a spec file" do
11
+ @test_case.should be_kind_of Rubidium::TestCase
12
+ @writer.write!(@test_case)
13
+ end
14
+ end
15
+
16
+ describe "convert a directory" do
17
+ it "convert test suites" do
18
+ converter = Rubidium::Converter.new f('examples/')
19
+ converter.write! f('tmp/suites')
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,8 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'init')
2
+
3
+ Spec::Runner.configure do |config|
4
+ # config.include CustomMatchers
5
+
6
+ # config.before(:all) do
7
+ # end
8
+ end
@@ -0,0 +1,56 @@
1
+
2
+ require <%= File.expand_path(f 'init').inspect %>
3
+
4
+ require "rake"
5
+ require "spec/rake/spectask"
6
+ require "selenium/rake/tasks"
7
+ require "deep_test/rake_tasks"
8
+
9
+ # Make sure we pick up the reporter from the appropriate selenium-client
10
+ # install as RSpec runner --require does not discriminate between multiple
11
+ # selenium-client gems.
12
+ gem_executable = Config::CONFIG["host_os"] =~ /mswin/ ? "gem.bat" : "gem"
13
+ report_formatter_path = `#{gem_executable} which -q "selenium/rspec/reporting/selenium_test_report_formatter"`.chomp
14
+ report_formatter_path.gsub! /selenium-client-\d+\.\d+.\d+/, "selenium-client-1.2.7"
15
+
16
+
17
+ #
18
+ # Recommended way to run tests in parallel and leverage Selenium Grid.
19
+ #
20
+
21
+ desc("Run all tests in parallel using DeepTest.")
22
+ Spec::Rake::SpecTask.new("tests:run_in_parallel") do |t|
23
+ t.spec_files = FileList['./**/*_spec.rb']
24
+ t.deep_test :number_of_workers => 6,
25
+ :timeout_in_seconds => 300
26
+ t.spec_opts << '--color'
27
+ t.spec_opts << "--require 'rubygems,#{report_formatter_path}'"
28
+ t.spec_opts << "--format=Selenium::RSpec::SeleniumTestReportFormatter:./tmp/test_report.html"
29
+ t.spec_opts << "--format=progress"
30
+ end
31
+ task :'tests:run_in_parallel' => :create_report_dir
32
+ #
33
+ # Running tests in sequence (without taking advantage of Selenium Grid),
34
+ # useful to troubleshoot problems with the parallel run.
35
+ #
36
+
37
+ desc "Run all behaviors in sequence"
38
+ Spec::Rake::SpecTask.new('tests:run_in_sequence') do |t|
39
+ t.pattern = "./**/*_spec.rb"
40
+ t.spec_opts << '--color'
41
+ t.spec_opts << "--require 'rubygems,#{report_formatter_path}'"
42
+ t.spec_opts << "--format=Selenium::RSpec::SeleniumTestReportFormatter:./tmp/test_report.html"
43
+ t.spec_opts << "--format=progress"
44
+ t.fail_on_error = true
45
+ end
46
+ task :'tests:run_in_sequence' => :create_report_dir
47
+
48
+ task :create_report_dir do
49
+ rm_f File.expand_path(File.dirname(__FILE__) + "/tmp/rspec_report")
50
+ mkdir_p File.expand_path(File.dirname(__FILE__) + "/tmp/rspec_report")
51
+ ENV['SELENIUM_TEST_REPORT_FILE'] = "./tmp/test_report.html" # Workaround for DeepTest reports
52
+ end
53
+
54
+ task :p => :'tests:run_in_parallel'
55
+ task :s => :'tests:run_in_sequence'
56
+ task :default => :s
@@ -0,0 +1,23 @@
1
+ # this is a selenium test case generated by Rubidium.
2
+ # do not edit this file directly.
3
+
4
+ require File.join(File.dirname(__FILE__), '../spec_helper')
5
+
6
+ describe "<%= @test_case && @test_suite.name || @test_case.name %>" do
7
+
8
+ before :each do
9
+ create_selenium_driver({ :application_url => <%= @application_url.inspect %> })
10
+ start_new_browser_session
11
+ @verification_errors = []
12
+ end
13
+
14
+ it "<%= @test_case.name %>" do
15
+ <%= @test_case.commands.join("\n ") %>
16
+ end
17
+
18
+ after :each do
19
+ @selenium_driver.stop
20
+ @verification_errors.should == []
21
+ end
22
+
23
+ end
@@ -0,0 +1,100 @@
1
+ # this is the helper
2
+
3
+ require <%= File.expand_path(f 'init').inspect %>
4
+
5
+ require "rake"
6
+ require 'spec/rake/spectask'
7
+ require "selenium/rake/tasks"
8
+ require "selenium/client"
9
+ require "selenium/rspec/spec_helper"
10
+ require "deep_test/rake_tasks"
11
+
12
+ module SeleniumTestHelper
13
+
14
+ def wait_for(params={})
15
+ timeout = params[:timeout] || 5
16
+ message = params[:message] || "Timeout exceeded"
17
+
18
+ begin_time = Time.now
19
+
20
+ while (Time.now - begin_time) < timeout
21
+ value = nil
22
+
23
+ begin
24
+ value = yield
25
+ rescue Exception => e
26
+ unless is_ignorable_wait_for_exception?(e)
27
+ raise e
28
+ end
29
+ end
30
+
31
+ return value if value
32
+
33
+ sleep 0.25
34
+ end
35
+
36
+ raise Webrat::TimeoutError.new(message + " (after #{timeout} sec)")
37
+ true
38
+ end
39
+
40
+ protected
41
+
42
+ def is_ignorable_wait_for_exception?(exception) #:nodoc:
43
+ if defined?(::Spec::Expectations::ExpectationNotMetError)
44
+ return true if exception.class == ::Spec::Expectations::ExpectationNotMetError
45
+ end
46
+ return [::Selenium::CommandError].include?(exception.class)
47
+ end
48
+
49
+ def start_new_browser_session
50
+ @selenium_driver.start_new_browser_session
51
+ @selenium_driver.set_context "Starting example '#{self.description}'"
52
+ end
53
+
54
+ def selenium_driver
55
+ @selenium_driver
56
+ end
57
+
58
+ def selenium
59
+ @selenium_driver
60
+ end
61
+
62
+ def create_selenium_driver(options={})
63
+ options = {
64
+ "grid_host" => ( ENV['SELENIUM_RC_HOST'] || 'localhost'),
65
+ "grid_port" => ( ENV['SELENIUM_RC_PORT'] || '4444'),
66
+ "browser" => ( ENV['SELENIUM_RC_BROWSER'] || '*firefox'),
67
+ "timeout" => ( ENV['SELENIUM_RC_TIMEOUT'] || '10000'),
68
+ "app_host" => ( ENV['SELENIUM_APPLICATION_HOST'] || 'localhost'),
69
+ "app_port" => ( ENV['SELENIUM_APPLICATION_PORT'] || '4000'),
70
+ }.merge(options)
71
+
72
+ options['application_url'] ||= "http://#{options['app_host']}:#{options['app_port']}"
73
+
74
+ @selenium_driver = Selenium::Client::Driver.new(
75
+ options['grid_host'],
76
+ options['grid_port'],
77
+ options['browser'],
78
+ options['application_url'],
79
+ options['timeout'].to_i
80
+ )
81
+ end
82
+
83
+ end
84
+
85
+ Spec::Runner.configure do |config|
86
+ config.include SeleniumTestHelper
87
+
88
+ config.before(:each) do
89
+ create_selenium_driver
90
+ start_new_browser_session
91
+ @verification_errors = []
92
+ end
93
+
94
+ # The system capture need to happen BEFORE the closing the Selenium session
95
+ config.append_after(:each) do
96
+ @selenium_driver.close_current_browser_session
97
+ end
98
+
99
+
100
+ end
File without changes
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubidium
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - davidlee
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-11 00:00:00 +11:00
13
+ default_executable: rubidium
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: jeweler
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.8.7
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: selenium-client
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.2.7
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: nokogiri
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.4.0
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ type: :runtime
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "="
62
+ - !ruby/object:Gem::Version
63
+ version: 1.1.8
64
+ version:
65
+ - !ruby/object:Gem::Dependency
66
+ name: deep_test
67
+ type: :runtime
68
+ version_requirement:
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "="
72
+ - !ruby/object:Gem::Version
73
+ version: 1.2.2
74
+ version:
75
+ - !ruby/object:Gem::Dependency
76
+ name: ruby-debug
77
+ type: :runtime
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">"
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ version:
85
+ description: convert Selenium tests to ruby/rspec for running against a Grid. Performs much better translation than the Selenium IDE, and a harness for running the resulting specs.
86
+ email: david@davelee.com.au
87
+ executables:
88
+ - rubidium
89
+ extensions: []
90
+
91
+ extra_rdoc_files:
92
+ - LICENSE
93
+ - README
94
+ - README.rdoc
95
+ files:
96
+ - .gitignore
97
+ - Gemfile
98
+ - LICENSE
99
+ - README
100
+ - README.rdoc
101
+ - VERSION
102
+ - bin/rubidium
103
+ - examples/google.com/googleSuite.html
104
+ - examples/google.com/sanityTest.html
105
+ - init.rb
106
+ - lib/rubidium.rb
107
+ - lib/rubidium/converter.rb
108
+ - lib/rubidium/spec_writer.rb
109
+ - lib/rubidium/test_case.rb
110
+ - lib/rubidium/test_suite.rb
111
+ - lib/rubidium/translator.rb
112
+ - rakefile.rb
113
+ - rubidium.gemspec
114
+ - spec/rubidium/google.com/sanity_test_spec.rb
115
+ - spec/rubidium_spec.rb
116
+ - spec/spec_helper.rb
117
+ - templates/rakefile.rb.erb
118
+ - templates/spec.rb.erb
119
+ - templates/spec_helper.rb.erb
120
+ - todo.org
121
+ has_rdoc: true
122
+ homepage: http://github.com/incite/rubidium
123
+ licenses: []
124
+
125
+ post_install_message:
126
+ rdoc_options:
127
+ - --charset=UTF-8
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: "0"
135
+ version:
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: "0"
141
+ version:
142
+ requirements: []
143
+
144
+ rubyforge_project:
145
+ rubygems_version: 1.3.5
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: convert Selenium tests to ruby/rspec for running against a Grid
149
+ test_files:
150
+ - spec/rubidium/google.com/sanity_test_spec.rb
151
+ - spec/rubidium_spec.rb
152
+ - spec/spec_helper.rb