rubidium 0.0.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.
@@ -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