sauce-test 0.1
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.
- data/README.rdoc +57 -0
- data/TODO.rdoc +3 -0
- data/bin/sauce_test +4 -0
- data/examples/google_search/Rakefile +9 -0
- data/examples/google_search/config/sauce.yml +3 -0
- data/examples/google_search/helpers/google_test_helper.rb +21 -0
- data/examples/google_search/spec/selenium/google_spec.rb +37 -0
- data/examples/google_search/spec/selenium/r.html +97 -0
- data/examples/google_search/spec/spec_helper.rb +4 -0
- data/lib/sauce-test/collection.rb +104 -0
- data/lib/sauce-test/helpers/sauce_test_options.rb +77 -0
- data/lib/sauce-test/rake/tasks.rb +35 -0
- data/lib/sauce-test/rspec/rake_tasks.rb +14 -0
- data/lib/sauce-test/rspec/runner.rb +49 -0
- data/lib/sauce-test/rspec/sauce_formatter.rb +76 -0
- data/lib/sauce-test/runner.rb +32 -0
- data/lib/sauce-test/runner/options.rb +116 -0
- data/lib/sauce-test/runner/report.rb +65 -0
- data/lib/sauce-test/selenium/client_driver_extension.rb +35 -0
- data/lib/sauce-test/templates/collection_report.erb +57 -0
- data/lib/sauce-test/templates/img/saucelabs.jpg +0 -0
- data/lib/sauce-test/templates/test_report.erb +81 -0
- data/lib/sauce-test/testunit/rake_tasks.rb +14 -0
- data/lib/sauce-test/testunit/runner.rb +15 -0
- data/lib/sauce-test/version.rb +13 -0
- metadata +110 -0
data/README.rdoc
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
= RSpec
|
2
|
+
|
3
|
+
* http://rspec.info
|
4
|
+
* http://rubyforge.org/projects/rspec
|
5
|
+
* http://github.com/dchelimsky/rspec/wikis
|
6
|
+
* mailto:rspec-users@rubyforge.org
|
7
|
+
* mailto:rspec-devel@rubyforge.org
|
8
|
+
|
9
|
+
== DESCRIPTION:
|
10
|
+
|
11
|
+
SauceTest lets you run your Selenium tests on Sauce Labs cloud unchanged.
|
12
|
+
|
13
|
+
sauce_test is command line utility you can use
|
14
|
+
or create rake task and run your tests in parallel
|
15
|
+
|
16
|
+
== SYNOPSIS:
|
17
|
+
|
18
|
+
1. create new rake task, should look like that:
|
19
|
+
|
20
|
+
only 'files' field is mandatory
|
21
|
+
|
22
|
+
require 'rubygems'
|
23
|
+
require 'rake'
|
24
|
+
require 'sauce-test/rake/tasks'
|
25
|
+
|
26
|
+
SauceTest::Rake::RSpecTask.new do |t|
|
27
|
+
t.files = 'spec/**/*_spec.rb' # Dir.glob pattern
|
28
|
+
|
29
|
+
t.browsers = [{'os' => "Linux", 'name' => "firefox", 'version' => 3},
|
30
|
+
{'os' => "Windows 2003", 'name' => "iexplore", 'version' => 7}]
|
31
|
+
|
32
|
+
t.workers = 4 #workers per browser
|
33
|
+
|
34
|
+
t.report = 'path_to/report'
|
35
|
+
t.config = 'config/sauce.yml'
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
2. create sauce.yml file in config dir.
|
43
|
+
if you like to use different dir/file make sure that SAUCE_CONFIG env variable contains path to config file. .
|
44
|
+
example sauce.yml
|
45
|
+
|
46
|
+
login: user
|
47
|
+
key: ff487724-2sfe-4a50-8365-sc750f2d875f
|
48
|
+
timeout: 180 #optional but advised to be at least 90 sec
|
49
|
+
|
50
|
+
|
51
|
+
3. rake sauce:spec
|
52
|
+
|
53
|
+
== INSTALL:
|
54
|
+
|
55
|
+
[sudo] gem install rspec
|
56
|
+
|
57
|
+
|
data/TODO.rdoc
ADDED
data/bin/sauce_test
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
class GooglePage < Selenium::Client::Driver
|
2
|
+
|
3
|
+
def initialize()
|
4
|
+
super( :host => "localhost",
|
5
|
+
:port => 4444,
|
6
|
+
:browser => '*chrome',
|
7
|
+
:url => "http://www.google.com",
|
8
|
+
:timeout_in_second => 60 )
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def search_for(search_str)
|
13
|
+
self.type "q", search_str
|
14
|
+
self.click "btnG", :wait_for => :page
|
15
|
+
end
|
16
|
+
|
17
|
+
def query_str
|
18
|
+
self.value("q")
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe "Google Search" do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@page = GooglePage.new
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
@page.start
|
11
|
+
end
|
12
|
+
|
13
|
+
append_after(:each) do
|
14
|
+
@page.stop
|
15
|
+
end
|
16
|
+
|
17
|
+
it "can find Selenium" do
|
18
|
+
@page.open "/"
|
19
|
+
@page.title.should eql("Google")
|
20
|
+
@page.search_for "Selenium"
|
21
|
+
@page.query_str.should eql("Selenium")
|
22
|
+
@page.title.should eql("Selenium - Google Search")
|
23
|
+
@page.text?("seniumhq.org").should be_true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return Sauce Labs website as top result" do
|
27
|
+
@page.open "/"
|
28
|
+
@page.title.should eql("Google")
|
29
|
+
@page.search_for "Sauce Labs"
|
30
|
+
@page.query_str.should eql("Sauce Labs")
|
31
|
+
@page.title.should eql("Sauce Labs - Google Search")
|
32
|
+
@page.text?("saucelabs.com").should be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
<!DOCTYPE html
|
2
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
5
|
+
<head>
|
6
|
+
<title>SauceTest Report</title>
|
7
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
8
|
+
<meta http-equiv="Expires" content="-1" />
|
9
|
+
<meta http-equiv="Pragma" content="no-cache" />
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
<div class="sauce-report">
|
16
|
+
|
17
|
+
<div id="sauce-header">
|
18
|
+
<div id="summary">
|
19
|
+
<p id="file">/home/bart/Projects/sauce-test/examples/google_search/spec/selenium/google_spec.rb</p>
|
20
|
+
<p id="browser">
|
21
|
+
googlechrome 1 on Windows 2003
|
22
|
+
</p>
|
23
|
+
<p id="totals">
|
24
|
+
3 examples
|
25
|
+
, 1 FAILED
|
26
|
+
, 1 pending
|
27
|
+
</p>
|
28
|
+
<p id="duration">Duration: 42.071908 sec</p>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
|
32
|
+
<div class="results">
|
33
|
+
<div class=example_group">
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
<dl>
|
38
|
+
<dt>Google Search</dt>
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
<dd class="failed">
|
44
|
+
<span class="failed_name">can find Selenium
|
45
|
+
<a class="job_link" href="http://saucelabs.com/jobs/dcd89827c758495ca782bcf1c66a1e05">(Sauce Labs Job)</a></span>
|
46
|
+
<div class="failure">
|
47
|
+
<div class="message"><pre>
|
48
|
+
expected true, got false
|
49
|
+
</pre></div>
|
50
|
+
<div class="backtrace"><pre>
|
51
|
+
/home/bart/Projects/sauce-test/examples/google_search/spec/selenium/google_spec.rb:23
|
52
|
+
</pre></div>
|
53
|
+
</div>
|
54
|
+
</dd>
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
<dd class="passed">
|
67
|
+
<span class="passed_name">should return Sauce Labs website as top result
|
68
|
+
<a class="job_link" href="http://saucelabs.com/jobs/d7e4b4e1f0ce6fe4985a4896ac70d025">(Sauce Labs Job)</a></span>
|
69
|
+
</dd>
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
<dd class="pending">
|
82
|
+
<span class="pending_name">is pend PENDING: blabla</span>
|
83
|
+
</dd>
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
</dl>
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
</div>
|
93
|
+
</div>
|
94
|
+
|
95
|
+
|
96
|
+
</body>
|
97
|
+
</html>
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'stringio'
|
3
|
+
require 'thread'
|
4
|
+
require 'erb'
|
5
|
+
|
6
|
+
require 'sauce-test/runner'
|
7
|
+
|
8
|
+
module SauceTest
|
9
|
+
module Collection
|
10
|
+
|
11
|
+
class << self
|
12
|
+
include ERB::Util
|
13
|
+
|
14
|
+
def run(files, browsers, workers, config, report, type)
|
15
|
+
bin_path = File.expand_path(File.dirname(__FILE__) + '/../../bin')
|
16
|
+
ENV['PATH'] = bin_path + ':' + ENV['PATH']
|
17
|
+
test_array = []
|
18
|
+
test_array_mutex = Mutex.new
|
19
|
+
@test_result = []
|
20
|
+
test_result_mutex = Mutex.new
|
21
|
+
|
22
|
+
Dir.glob(files) do |file|
|
23
|
+
sauce_test = 'sauce_test -l -t ' + type.to_s + ' ' + file
|
24
|
+
result = `#{sauce_test}`
|
25
|
+
|
26
|
+
groups = YAML::load(StringIO.new result)['groups']
|
27
|
+
|
28
|
+
groups.each do |group|
|
29
|
+
group['examples'].each do |example|
|
30
|
+
test_array << [file,
|
31
|
+
group['name'],
|
32
|
+
example['name'],
|
33
|
+
example['full_name']]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
browser_threads = []
|
39
|
+
worker_threads = []
|
40
|
+
|
41
|
+
browsers.each do |b|
|
42
|
+
browser_threads << Thread.new(b) do |browser|
|
43
|
+
test_count = 0
|
44
|
+
test_count_mutex = Mutex.new
|
45
|
+
(1..workers).each do
|
46
|
+
worker_threads << Thread.new do
|
47
|
+
loop do
|
48
|
+
test = nil
|
49
|
+
test_count_mutex.synchronize do
|
50
|
+
test_array_mutex.synchronize{test = test_array[test_count]}
|
51
|
+
test_count += 1
|
52
|
+
end
|
53
|
+
break unless test
|
54
|
+
|
55
|
+
file = test[0]
|
56
|
+
group = test[1]
|
57
|
+
example = test[3]
|
58
|
+
report_file = '/' + file + '/' + example + '/' + browser['name'] +
|
59
|
+
'/' + browser['version'].to_s + '/' + browser['os'] + '/report.html'
|
60
|
+
|
61
|
+
sauce_test = 'sauce_test -t ' + type.to_s + ' ' +
|
62
|
+
'-c ' + config + ' ' +
|
63
|
+
'-r "' + report + report_file + '" ' +
|
64
|
+
'-b ' + browser['name'] + ' ' +
|
65
|
+
'-v ' + browser['version'].to_s + ' ' +
|
66
|
+
'-o "' + browser['os'] + '" ' +
|
67
|
+
'-e "' + example + '" ' + file
|
68
|
+
|
69
|
+
result = `#{sauce_test}`
|
70
|
+
|
71
|
+
test_result_mutex.synchronize do
|
72
|
+
example = test[2]
|
73
|
+
status = YAML::load(StringIO.new result)['status']
|
74
|
+
duration = YAML::load(StringIO.new result)['duration']
|
75
|
+
job_id = YAML::load(StringIO.new result)['groups'][0]['examples'][0]['job_id']
|
76
|
+
@test_result << [file,
|
77
|
+
group,
|
78
|
+
example,
|
79
|
+
browser,
|
80
|
+
status,
|
81
|
+
duration,
|
82
|
+
job_id,
|
83
|
+
report_file]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
worker_threads.each{|t| t.join}
|
92
|
+
browser_threads.each{|t| t.join}
|
93
|
+
|
94
|
+
template_file = File.dirname(__FILE__) + '/templates/collection_report.erb'
|
95
|
+
template_str = IO.readlines(template_file).join
|
96
|
+
template = ERB.new(template_str)
|
97
|
+
File.new(report + '/report.html', 'w') << template.result(binding)
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module SauceTest
|
4
|
+
module Helpers
|
5
|
+
|
6
|
+
class SauceTestOptions
|
7
|
+
|
8
|
+
attr_reader :user,
|
9
|
+
:key,
|
10
|
+
:timeout,
|
11
|
+
:browser
|
12
|
+
|
13
|
+
attr_accessor :job_name
|
14
|
+
|
15
|
+
def initialize(browser = nil)
|
16
|
+
set_browser(browser || "firefox")
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_config(config_file)
|
20
|
+
config = YAML::load_file config_file
|
21
|
+
@user = config['login']
|
22
|
+
@key = config['key']
|
23
|
+
@timeout = config['timeout'] || 180
|
24
|
+
|
25
|
+
if(@user and @key) then true
|
26
|
+
else false end
|
27
|
+
end
|
28
|
+
|
29
|
+
def browser_json
|
30
|
+
%W({ "username": "#{@user}",) +
|
31
|
+
%W("access-key": "#{@key}",) +
|
32
|
+
%W("job-name": "#{@job_name}",) +
|
33
|
+
%W("os": "#{@browser['os']}",) +
|
34
|
+
%W("browser": "#{@browser['name']}",) +
|
35
|
+
%W("browser-major-version": "#{@browser['version']}" })
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_browser_version(version)
|
39
|
+
@browser['version'] = version
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_os(os)
|
43
|
+
@browser['os'] = os
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def set_browser(name)
|
49
|
+
@browser = {}
|
50
|
+
case name
|
51
|
+
when "firefox", "chrome"
|
52
|
+
@browser['name'] = "firefox"
|
53
|
+
@browser['version'] = 3
|
54
|
+
@browser['os'] = "Linux"
|
55
|
+
when "iehta", "iexplore"
|
56
|
+
@browser['name'] = "iexplore"
|
57
|
+
@browser['version'] = 7
|
58
|
+
@browser['os'] = "Windows 2003"
|
59
|
+
when "safari"
|
60
|
+
@browser['name'] = name
|
61
|
+
@browser['version'] = 4
|
62
|
+
@browser['os'] = "Windows 2003"
|
63
|
+
when "opera"
|
64
|
+
@browser['name'] = name
|
65
|
+
@browser['version'] = 9
|
66
|
+
@browser['os'] = "Windows 2003"
|
67
|
+
when "googlechrome"
|
68
|
+
@browser['name'] = name
|
69
|
+
@browser['version'] = 1
|
70
|
+
@browser['os'] = "Windows 2003"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'sauce-test/collection'
|
2
|
+
|
3
|
+
module SauceTest
|
4
|
+
module Rake
|
5
|
+
|
6
|
+
class BaseTask
|
7
|
+
|
8
|
+
attr_accessor :files, :browsers, :report, :workers, :config
|
9
|
+
|
10
|
+
def initialize(name)
|
11
|
+
@name = name
|
12
|
+
@browsers = [{'os' => "Linux", 'name' => "firefox", 'version' => 3},
|
13
|
+
{'os' => "Windows 2003", 'name' => "iexplore", 'version' => 7}]
|
14
|
+
@workers = 1
|
15
|
+
@config = 'config/sauce.yml'
|
16
|
+
@report = 'reports/sauce_test'
|
17
|
+
|
18
|
+
yield self if block_given?
|
19
|
+
|
20
|
+
define_task
|
21
|
+
end
|
22
|
+
|
23
|
+
def define_task
|
24
|
+
task @name do
|
25
|
+
SauceTest::Collection.run(@files, @browsers, @workers, @config, @report, @type)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'sauce-test/rspec/rake_tasks'
|
35
|
+
require 'sauce-test/testunit/rake_tasks'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'spec'
|
5
|
+
|
6
|
+
require 'sauce-test/rspec/sauce_formatter'
|
7
|
+
require 'sauce-test/selenium/client_driver_extension'
|
8
|
+
|
9
|
+
module SauceTest
|
10
|
+
module RSpec
|
11
|
+
|
12
|
+
module Runner
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def run(options)
|
16
|
+
@options = options
|
17
|
+
rspec_init
|
18
|
+
Spec::Runner.run
|
19
|
+
report = SauceTest::RSpec::Runner::SauceFormatter.report
|
20
|
+
report.test_file = @options.test_file
|
21
|
+
report
|
22
|
+
end
|
23
|
+
|
24
|
+
def rspec_init
|
25
|
+
out_str = StringIO.new
|
26
|
+
err_str = StringIO.new
|
27
|
+
spec_opt = Spec::Runner::Options.new(@err_str, @out_str)
|
28
|
+
|
29
|
+
if @options.list
|
30
|
+
spec_opt.dry_run = true
|
31
|
+
else
|
32
|
+
SauceTest::RSpec::Runner::SauceFormatter.set_sauce_test_options @options.sauce_options
|
33
|
+
end
|
34
|
+
|
35
|
+
if @options.example
|
36
|
+
spec_opt.parse_example @options.example
|
37
|
+
end
|
38
|
+
|
39
|
+
spec_opt.parse_format SauceTest::RSpec::Runner::SauceFormatter.to_s
|
40
|
+
spec_opt.files << @options.test_file
|
41
|
+
|
42
|
+
Spec::Runner.use spec_opt
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec/runner/formatter/base_formatter'
|
2
|
+
|
3
|
+
module SauceTest
|
4
|
+
module RSpec
|
5
|
+
module Runner
|
6
|
+
|
7
|
+
class SauceFormatter < Spec::Runner::Formatter::BaseFormatter
|
8
|
+
|
9
|
+
def initialize(options, output)
|
10
|
+
@dry_run = !!options.dry_run
|
11
|
+
@selenium = Selenium::Client::Driver
|
12
|
+
@selenium.set_sauce_options(@@sauce_options) unless @dry_run
|
13
|
+
@@report = SauceTest::Runner::Report.new
|
14
|
+
@@report.browser = @@sauce_options.browser unless @dry_run
|
15
|
+
end
|
16
|
+
|
17
|
+
def example_group_started(group_proxy)
|
18
|
+
@group = group_proxy.description
|
19
|
+
end
|
20
|
+
|
21
|
+
def example_started(example_proxy)
|
22
|
+
example = example_proxy.description
|
23
|
+
if @dry_run
|
24
|
+
@@report.add_example(@group,
|
25
|
+
{'name' => example,
|
26
|
+
'status' => 'passed'})
|
27
|
+
else
|
28
|
+
@@sauce_options.job_name = @group + ' ' + example unless @dry_run
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def example_pending(example_proxy, message)
|
33
|
+
@@report.add_example(@group,
|
34
|
+
{'name' => example_proxy.description,
|
35
|
+
'status' => 'pending',
|
36
|
+
'message' => message})
|
37
|
+
end
|
38
|
+
|
39
|
+
def example_passed(example_proxy)
|
40
|
+
@@report.add_example(@group,
|
41
|
+
{'name' => example_proxy.description,
|
42
|
+
'status' => 'passed',
|
43
|
+
'job_id' => @selenium.last_session_id }
|
44
|
+
) unless @dry_run
|
45
|
+
end
|
46
|
+
|
47
|
+
def example_failed(example_proxy, counter, failure)
|
48
|
+
failure.exception.backtrace[0] =~ /(.*):(\d+)/
|
49
|
+
file = $1
|
50
|
+
line = $2.to_i
|
51
|
+
@@report.add_example(@group,
|
52
|
+
{'name' => example_proxy.description,
|
53
|
+
'status' => 'failed',
|
54
|
+
'job_id' => @selenium.last_session_id,
|
55
|
+
'message' => failure.exception.message,
|
56
|
+
'file' => file,
|
57
|
+
'line' => line})
|
58
|
+
end
|
59
|
+
|
60
|
+
def dump_summary(duration, example_count, failure_count, pending_count)
|
61
|
+
@@report.duration = duration
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.report
|
65
|
+
@@report
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.set_sauce_test_options(options)
|
69
|
+
@@sauce_options = options.clone
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
require 'sauce-test/runner/options'
|
5
|
+
require 'sauce-test/runner/report'
|
6
|
+
require 'sauce-test/rspec/runner'
|
7
|
+
require 'sauce-test/testunit/runner'
|
8
|
+
|
9
|
+
module SauceTest
|
10
|
+
module Runner
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def run(opts = nil)
|
14
|
+
options = opts || SauceTest::Runner::Options.new
|
15
|
+
|
16
|
+
case options.test_type
|
17
|
+
when :unit then runner = SauceTest::TestUnit::Runner
|
18
|
+
when :spec then runner = SauceTest::RSpec::Runner
|
19
|
+
end
|
20
|
+
|
21
|
+
report = runner.run(options)
|
22
|
+
YAML.dump(report.to_hash, $stdout)
|
23
|
+
|
24
|
+
if report_name = options.report_file and !options.list
|
25
|
+
FileUtils.mkdir_p File.dirname(report_name)
|
26
|
+
File.new(report_name, 'w') << report.to_html
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
require 'sauce-test/version'
|
4
|
+
require 'sauce-test/helpers/sauce_test_options'
|
5
|
+
|
6
|
+
module SauceTest
|
7
|
+
module Runner
|
8
|
+
|
9
|
+
class Options
|
10
|
+
|
11
|
+
attr_reader :list,
|
12
|
+
:test_type,
|
13
|
+
:example,
|
14
|
+
:report_file,
|
15
|
+
:test_file,
|
16
|
+
:sauce_options
|
17
|
+
|
18
|
+
def initialize(opt_array = ARGV)
|
19
|
+
@browser = {}
|
20
|
+
|
21
|
+
@opt_parser = OptionParser.new
|
22
|
+
|
23
|
+
@opt_parser.banner = "Usage: sauce_test [options] FILE"
|
24
|
+
|
25
|
+
@opt_parser.on(*OPTIONS[:list]) {|list| @list = true}
|
26
|
+
@opt_parser.on(*OPTIONS[:type]) {|type| parse_type type}
|
27
|
+
@opt_parser.on(*OPTIONS[:example]) {|example| @example = example}
|
28
|
+
@opt_parser.on(*OPTIONS[:report]) {|report| @report_file = File.expand_path report}
|
29
|
+
@opt_parser.on(*OPTIONS[:browser]) {|browser| @browser['name'] = browser}
|
30
|
+
@opt_parser.on(*OPTIONS[:version]) {|version| @browser['version'] = version}
|
31
|
+
@opt_parser.on(*OPTIONS[:os]) {|os| @browser['os'] = os}
|
32
|
+
@opt_parser.on(*OPTIONS[:config]) {|config| parse_config(config)}
|
33
|
+
@opt_parser.on(*OPTIONS[:help]) {show_help}
|
34
|
+
|
35
|
+
@opt_parser.separator EXAMPLES
|
36
|
+
|
37
|
+
opt_rest = @opt_parser.parse(opt_array)
|
38
|
+
|
39
|
+
create_sauce_options unless list
|
40
|
+
|
41
|
+
parse_test_file(opt_rest[0])
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def create_sauce_options
|
47
|
+
@sauce_options = SauceTest::Helpers::SauceTestOptions.new(@browser['name'])
|
48
|
+
parse_config(DEFAULT_CFG) unless @config_file
|
49
|
+
show_help unless @sauce_options.parse_config(@config_file)
|
50
|
+
@sauce_options.set_os @browser['os'] if @browser['os']
|
51
|
+
@sauce_options.set_browser_version @browser['version'] if @browser['version']
|
52
|
+
end
|
53
|
+
|
54
|
+
def show_help
|
55
|
+
puts SauceTest::VERSION::SUMMARY
|
56
|
+
puts @opt_parser
|
57
|
+
exit
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_config(path)
|
61
|
+
@config_file = File.expand_path path
|
62
|
+
show_help unless File.file?(@config_file)
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_test_file(path)
|
66
|
+
if path and File.file?(path)
|
67
|
+
then @test_file = File.expand_path path
|
68
|
+
else show_help end
|
69
|
+
|
70
|
+
unless @test_type
|
71
|
+
case File.basename @test_file
|
72
|
+
when /_test\.rb/ then @test_type = :unit
|
73
|
+
when /_spec\.rb/ then @test_type = :spec
|
74
|
+
else show_help
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_type(type_str)
|
80
|
+
case type_str
|
81
|
+
when 'unit', 'u' then @test_type = :unit
|
82
|
+
when 'spec', 's'then @test_type = :spec
|
83
|
+
else show_help
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
DEFAULT_CFG = './config/sauce.yml'
|
88
|
+
|
89
|
+
OPTIONS = {
|
90
|
+
:example => ["-e", "--example NAME", "Run single test case. Use -l to list NAMEs"],
|
91
|
+
:list => ["-l", "--list", "List all tests"],
|
92
|
+
:type => ["-t", "--type TYPE", "Specify type of test file(optional)",
|
93
|
+
"spec|s :RSpec",
|
94
|
+
"unit|u :Test::Unit"],
|
95
|
+
:report => ["-r", "--report PATH", "HTML report directory path"],
|
96
|
+
:config => ["-c", "--config PATH", "config file path(#{DEFAULT_CFG} by default)"],
|
97
|
+
:browser => ["-b", "--browser STRING", "Sauce Labs JSON web browser string(firefox by default)"],
|
98
|
+
:os => ["-o", "--os STRING", "Sauce Labs JSON operating system string(optional)"],
|
99
|
+
:version => ["-v", "--version NUM", "Sauce Labs JSON browser version number(optional)"],
|
100
|
+
:help => ["-h", "--help", "You're looking at it"]
|
101
|
+
}
|
102
|
+
|
103
|
+
EXAMPLES = [ "\nUsage Examples:\n",
|
104
|
+
" sauce_test example_test.rb",
|
105
|
+
' sauce_test -r "./reports/" example_spec.rb',
|
106
|
+
" sauce_test -l example_test.rb",
|
107
|
+
' sauce_test -b "iexplore" example_test.rb',
|
108
|
+
' sauce_test -b "firefox" -v 2 -o "Windows 2003" example_spec.rb',
|
109
|
+
' sauce_test -t unit -e "test_something(ExampleTest)" example_test.rb',
|
110
|
+
' sauce_test -t s -e "ExampleTest can do something" example_spec.rb']
|
111
|
+
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module SauceTest
|
4
|
+
module Runner
|
5
|
+
|
6
|
+
class Report
|
7
|
+
|
8
|
+
include ERB::Util
|
9
|
+
|
10
|
+
attr_accessor :test_file, :browser, :duration
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@groups = []
|
14
|
+
@status = 'passed'
|
15
|
+
@count = {'total' => 0,
|
16
|
+
'pending' => 0,
|
17
|
+
'failed' => 0}
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_example(group_name, descripton)
|
21
|
+
descripton['full_name'] = group_name + ' ' + descripton['name']
|
22
|
+
@count['total'] += 1
|
23
|
+
status = descripton['status']
|
24
|
+
@count['pending'] += 1 if status == 'pending'
|
25
|
+
@count['failed'] += 1 if status == 'failed'
|
26
|
+
|
27
|
+
group = nil
|
28
|
+
@groups.each do |g|
|
29
|
+
if g['name'] == group_name
|
30
|
+
group = g
|
31
|
+
g['examples'] << descripton
|
32
|
+
g['status'] = status if status != 'passed' and g['status'] != 'failed'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
unless group
|
37
|
+
group = {'name' => group_name,
|
38
|
+
'status' => status,
|
39
|
+
'examples' => [descripton]}
|
40
|
+
@groups << group
|
41
|
+
end
|
42
|
+
|
43
|
+
@status = status if status != 'passed' and @status != 'failed'
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_hash
|
47
|
+
{'file' => test_file,
|
48
|
+
'browser' => browser,
|
49
|
+
'duration' => duration,
|
50
|
+
'status' => @status,
|
51
|
+
'count' => @count,
|
52
|
+
'groups' => @groups}
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_html
|
56
|
+
template_file = File.dirname(__FILE__) + '/../templates/test_report.erb'
|
57
|
+
template_str = IO.readlines(template_file).join
|
58
|
+
template = ERB.new(template_str)
|
59
|
+
template.result(binding)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "selenium/client"
|
3
|
+
|
4
|
+
module Selenium
|
5
|
+
module Client
|
6
|
+
|
7
|
+
class Driver
|
8
|
+
|
9
|
+
def start_new_browser_session(options={})
|
10
|
+
sauce_init
|
11
|
+
super(options)
|
12
|
+
@@last_session_id = @session_id
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.set_sauce_options(sauce_options)
|
16
|
+
@@sauce_options = sauce_options
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.last_session_id
|
20
|
+
@@last_session_id
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def sauce_init
|
26
|
+
@host = "saucelabs.com"
|
27
|
+
@port = 4444
|
28
|
+
@browser_string = @@sauce_options.browser_json
|
29
|
+
@default_timeout_in_seconds = @@sauce_options.timeout
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
<!DOCTYPE html
|
2
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
5
|
+
<head>
|
6
|
+
<title>SauceTest Report</title>
|
7
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
8
|
+
<meta http-equiv="Expires" content="-1" />
|
9
|
+
<meta http-equiv="Pragma" content="no-cache" />
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
<div class="sauce-report">
|
16
|
+
|
17
|
+
<div class="results">
|
18
|
+
|
19
|
+
|
20
|
+
<% @test_result.each do |result| %>
|
21
|
+
|
22
|
+
<div>
|
23
|
+
<div>
|
24
|
+
File: <a href="<%=u(result[7])%>"><%=result[0]%></a>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<div>
|
28
|
+
Test: <%=result[1] + ' ' + result[2]%>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<div>
|
32
|
+
Browser: <%=result[3]['name'] + ' ' + result[3]['version'].to_s + ' on ' + result[3]['os']%>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div>
|
36
|
+
Status: <%=result[4]%>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
|
40
|
+
<div>
|
41
|
+
Duration: <%=result[5]%> sec
|
42
|
+
</div>
|
43
|
+
|
44
|
+
<div>
|
45
|
+
<a href="http://saucelabs.com/jobs/<%=result[6]%>">Sauce Labs Report</a>
|
46
|
+
</div>
|
47
|
+
|
48
|
+
</br>
|
49
|
+
</div>
|
50
|
+
|
51
|
+
<% end %>
|
52
|
+
|
53
|
+
</div>
|
54
|
+
|
55
|
+
|
56
|
+
</body>
|
57
|
+
</html>
|
Binary file
|
@@ -0,0 +1,81 @@
|
|
1
|
+
<!DOCTYPE html
|
2
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
5
|
+
<head>
|
6
|
+
<title>SauceTest Report</title>
|
7
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
8
|
+
<meta http-equiv="Expires" content="-1" />
|
9
|
+
<meta http-equiv="Pragma" content="no-cache" />
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
<div class="sauce-report">
|
16
|
+
|
17
|
+
<div id="sauce-header">
|
18
|
+
<div id="summary">
|
19
|
+
<p id="file"><%= test_file %></p>
|
20
|
+
<p id="browser">
|
21
|
+
<%= browser['name'] + ' ' + browser['version'].to_s + ' on ' + browser['os'] %>
|
22
|
+
</p>
|
23
|
+
<p id="totals">
|
24
|
+
<%= @count['total'].to_s + ' examples' %>
|
25
|
+
<%= ', ' + @count['failed'].to_s + ' FAILED' %>
|
26
|
+
<%= ', ' + @count['pending'].to_s + ' pending' %>
|
27
|
+
</p>
|
28
|
+
<p id="duration">Duration: <%= duration %> sec</p>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
|
32
|
+
<div class="results">
|
33
|
+
<div class=example_group">
|
34
|
+
|
35
|
+
<% @groups.each do |g| %>
|
36
|
+
|
37
|
+
<dl>
|
38
|
+
<dt><%= h(g['name']) %></dt>
|
39
|
+
|
40
|
+
<% g['examples'].each do |e| %>
|
41
|
+
|
42
|
+
<% if e['status'] == 'failed' %>
|
43
|
+
<dd class="failed">
|
44
|
+
<span class="failed_name"><%= h(e['name']) %>
|
45
|
+
<a class="job_link" href="<%= 'http://saucelabs.com/jobs/' + e['job_id'] %>">(Sauce Labs Job)</a></span>
|
46
|
+
<div class="failure">
|
47
|
+
<div class="message"><pre>
|
48
|
+
<%= h(e['message']) %>
|
49
|
+
</pre></div>
|
50
|
+
<div class="backtrace"><pre>
|
51
|
+
<%= e['file'] + ':' + e['line'].to_s %>
|
52
|
+
</pre></div>
|
53
|
+
</div>
|
54
|
+
</dd>
|
55
|
+
<% end %>
|
56
|
+
|
57
|
+
<% if e['status'] == 'passed' %>
|
58
|
+
<dd class="passed">
|
59
|
+
<span class="passed_name"><%= h(e['name']) %>
|
60
|
+
<a class="job_link" href="<%= 'http://saucelabs.com/jobs/' + e['job_id'] %>">(Sauce Labs Job)</a></span>
|
61
|
+
</dd>
|
62
|
+
<% end %>
|
63
|
+
|
64
|
+
<% if e['status'] == 'pending' %>
|
65
|
+
<dd class="pending">
|
66
|
+
<span class="pending_name"><%= h(e['name'] + ' PENDING: ' + e['message']) %></span>
|
67
|
+
</dd>
|
68
|
+
<% end %>
|
69
|
+
|
70
|
+
<% end %>
|
71
|
+
|
72
|
+
</dl>
|
73
|
+
|
74
|
+
<% end %>
|
75
|
+
|
76
|
+
</div>
|
77
|
+
</div>
|
78
|
+
|
79
|
+
|
80
|
+
</body>
|
81
|
+
</html>
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sauce-test
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bart Wadolowski
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-25 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :runtime
|
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: selenium-client
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description:
|
36
|
+
email: bart@saucelabs.com
|
37
|
+
executables:
|
38
|
+
- sauce_test
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- bin/sauce_test
|
45
|
+
- lib/sauce-test
|
46
|
+
- lib/sauce-test/rake
|
47
|
+
- lib/sauce-test/rake/tasks.rb
|
48
|
+
- lib/sauce-test/runner.rb
|
49
|
+
- lib/sauce-test/rspec
|
50
|
+
- lib/sauce-test/rspec/runner.rb
|
51
|
+
- lib/sauce-test/rspec/sauce_formatter.rb
|
52
|
+
- lib/sauce-test/rspec/rake_tasks.rb
|
53
|
+
- lib/sauce-test/templates
|
54
|
+
- lib/sauce-test/templates/test_report.erb
|
55
|
+
- lib/sauce-test/templates/collection_report.erb
|
56
|
+
- lib/sauce-test/templates/img
|
57
|
+
- lib/sauce-test/templates/img/saucelabs.jpg
|
58
|
+
- lib/sauce-test/collection.rb
|
59
|
+
- lib/sauce-test/selenium
|
60
|
+
- lib/sauce-test/selenium/client_driver_extension.rb
|
61
|
+
- lib/sauce-test/version.rb
|
62
|
+
- lib/sauce-test/runner
|
63
|
+
- lib/sauce-test/runner/report.rb
|
64
|
+
- lib/sauce-test/runner/options.rb
|
65
|
+
- lib/sauce-test/testunit
|
66
|
+
- lib/sauce-test/testunit/runner.rb
|
67
|
+
- lib/sauce-test/testunit/rake_tasks.rb
|
68
|
+
- lib/sauce-test/helpers
|
69
|
+
- lib/sauce-test/helpers/sauce_test_options.rb
|
70
|
+
- examples/google_search
|
71
|
+
- examples/google_search/spec
|
72
|
+
- examples/google_search/spec/selenium
|
73
|
+
- examples/google_search/spec/selenium/google_spec.rb
|
74
|
+
- examples/google_search/spec/selenium/r.html
|
75
|
+
- examples/google_search/spec/spec_helper.rb
|
76
|
+
- examples/google_search/Rakefile
|
77
|
+
- examples/google_search/config
|
78
|
+
- examples/google_search/config/sauce.yml
|
79
|
+
- examples/google_search/helpers
|
80
|
+
- examples/google_search/helpers/google_test_helper.rb
|
81
|
+
- README.rdoc
|
82
|
+
- TODO.rdoc
|
83
|
+
has_rdoc: true
|
84
|
+
homepage: http://www.saucelabs.com
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
95
|
+
version:
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: "0"
|
101
|
+
version:
|
102
|
+
requirements: []
|
103
|
+
|
104
|
+
rubyforge_project: sauce-test
|
105
|
+
rubygems_version: 1.3.1
|
106
|
+
signing_key:
|
107
|
+
specification_version: 2
|
108
|
+
summary: Run your Selenium tests on Sauce Labs cloud
|
109
|
+
test_files: []
|
110
|
+
|