sauce_ruby 3.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/sauce +103 -0
- data/lib/childprocess/process.rb +34 -0
- data/lib/generators/sauce/install/install_generator.rb +54 -0
- data/lib/parallel_tests/cli_patch.rb +23 -0
- data/lib/parallel_tests/saucecucumber/runner.rb +43 -0
- data/lib/parallel_tests/saucerspec/runner.rb +40 -0
- data/lib/sauce.rb +33 -0
- data/lib/sauce/capybara.rb +189 -0
- data/lib/sauce/client.rb +40 -0
- data/lib/sauce/config.rb +434 -0
- data/lib/sauce/driver_pool.rb +5 -0
- data/lib/sauce/heroku.rb +18 -0
- data/lib/sauce/job.rb +159 -0
- data/lib/sauce/parallel.rb +16 -0
- data/lib/sauce/parallel/test_broker.rb +110 -0
- data/lib/sauce/parallel/test_group.rb +24 -0
- data/lib/sauce/railtie.rb +11 -0
- data/lib/sauce/raketasks.rb +83 -0
- data/lib/sauce/rspec/rspec.rb +186 -0
- data/lib/sauce/rspec/rspec_formatter.rb +20 -0
- data/lib/sauce/rspec/rspec_one_support.rb +66 -0
- data/lib/sauce/selenium.rb +95 -0
- data/lib/sauce/test_base.rb +21 -0
- data/lib/sauce/test_unit.rb +111 -0
- data/lib/sauce/utilities.rb +80 -0
- data/lib/sauce/utilities/connect.rb +45 -0
- data/lib/sauce/utilities/rails_server.rb +95 -0
- data/lib/sauce/utilities/rake.rb +32 -0
- data/lib/sauce/version.rb +9 -0
- data/lib/sauce/webmock.rb +16 -0
- data/lib/tasks/parallel_testing.rb +148 -0
- data/spec/cucumber_helper.rb +42 -0
- data/spec/integration/connect/spec/spec_helper.rb +21 -0
- data/spec/integration/connect/spec/start_tunnel_spec.rb +9 -0
- data/spec/integration/connect/spec/with_capybara_spec.rb +10 -0
- data/spec/integration/connect_integration_spec.rb +99 -0
- data/spec/integration/rspec-capybara/spec/capybara_required_last_spec.rb +18 -0
- data/spec/integration/rspec-capybara/spec/integration_spec.rb +17 -0
- data/spec/integration/rspec-capybara/spec/sauce_config_spec.rb +13 -0
- data/spec/integration/rspec-capybara/spec/sauce_required_last_spec.rb +21 -0
- data/spec/integration/rspec-capybara/spec/selenium/selenium_with_capybara.rb +12 -0
- data/spec/integration/rspec-capybara/spec/spec_helper.rb +37 -0
- data/spec/integration/rspec/spec/integration_spec.rb +13 -0
- data/spec/integration/rspec/spec/selenium/selenium_directory_spec.rb +20 -0
- data/spec/integration/rspec/spec/spec_helper.rb +52 -0
- data/spec/integration/rspec/spec/tagging/selenium_tagging_spec.rb +29 -0
- data/spec/integration/testunit/test/capybara_integration_test.rb +37 -0
- data/spec/integration/testunit/test/integration_test.rb +21 -0
- data/spec/integration/testunit/test/test_helper.rb +13 -0
- data/spec/parallel_tests/sauce_rspec_runner_spec.rb +23 -0
- data/spec/sauce/capybara_spec.rb +386 -0
- data/spec/sauce/config/browser_spec.rb +73 -0
- data/spec/sauce/config/config_spec.rb +400 -0
- data/spec/sauce/config/default_browsers_spec.rb +46 -0
- data/spec/sauce/config/environment_config_spec.rb +106 -0
- data/spec/sauce/config/load_defaults_spec.rb +50 -0
- data/spec/sauce/config/perfile_browser_spec.rb +105 -0
- data/spec/sauce/connect_spec.rb +21 -0
- data/spec/sauce/cucumber_spec.rb +212 -0
- data/spec/sauce/driver_pool_spec.rb +8 -0
- data/spec/sauce/file_detector_spec.rb +15 -0
- data/spec/sauce/jasmine_spec.rb +30 -0
- data/spec/sauce/parallel/test_broker_spec.rb +77 -0
- data/spec/sauce/selenium_spec.rb +60 -0
- data/spec/sauce/tasks_spec.rb +180 -0
- data/spec/sauce/utilities/rails_server_spec.rb +109 -0
- data/spec/sauce/utilities/rake_spec.rb +46 -0
- data/spec/sauce/utilities/utilities_spec.rb +137 -0
- data/spec/sauce_helper.rb +8 -0
- data/spec/spec_helper.rb +27 -0
- metadata +390 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
begin
|
2
|
+
require 'rspec/core/formatters/base_text_formatter'
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
module Formatters
|
6
|
+
class BaseTextFormatter
|
7
|
+
def dump_failure(example, index)
|
8
|
+
output.puts "#{short_padding}#{index.next}) #{example.full_description}"
|
9
|
+
puts "#{short_padding}Sauce public job link: #{example.metadata[:sauce_public_link]}"
|
10
|
+
dump_failure_info(example)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
rescue LoadError
|
17
|
+
# User isn't using RSpec
|
18
|
+
rescue NameError
|
19
|
+
# User is using RSpec 3
|
20
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'sauce/utilities'
|
2
|
+
require "sauce_whisk"
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'spec'
|
6
|
+
module Sauce
|
7
|
+
module RSpec
|
8
|
+
class SeleniumExampleGroup < Spec::Example::ExampleGroup
|
9
|
+
attr_reader :selenium
|
10
|
+
@@need_tunnel = false
|
11
|
+
|
12
|
+
def self.inherited(subclass)
|
13
|
+
# only setup tunnel if somebody needs it
|
14
|
+
@@need_tunnel = true
|
15
|
+
super(subclass)
|
16
|
+
end
|
17
|
+
|
18
|
+
before :suite do
|
19
|
+
config = Sauce::Config.new
|
20
|
+
if @@need_tunnel
|
21
|
+
if config[:application_host]
|
22
|
+
Sauce::Utilities::Connect.start(:host => config[:application_host], :port => config[:application_port])
|
23
|
+
end
|
24
|
+
if config[:start_local_application] &&
|
25
|
+
Sauce::Utilities::RailsServer.is_rails_app?
|
26
|
+
@@server = Sauce::Utilities::RailsServer.new
|
27
|
+
@@server.start
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
after :suite do
|
33
|
+
Sauce::Utilities::Connect.close
|
34
|
+
@@server.stop if defined? @@server
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute(*args)
|
38
|
+
config = Sauce::Config.new
|
39
|
+
description = [self.class.description, self.description].join(" ")
|
40
|
+
config[:browsers].each do |os, browser, version|
|
41
|
+
@selenium = Sauce::Selenium2.new({:os => os, :browser => browser,
|
42
|
+
:browser_version => version,
|
43
|
+
:job_name => description})
|
44
|
+
|
45
|
+
begin
|
46
|
+
success = super(*args)
|
47
|
+
SauceWhisk::Jobs.change_status @selenium.session_id, success
|
48
|
+
ensure
|
49
|
+
@selenium.stop
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
alias_method :page, :selenium
|
55
|
+
alias_method :s, :selenium
|
56
|
+
|
57
|
+
Spec::Example::ExampleGroupFactory.register(:selenium, self)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
rescue LoadError
|
62
|
+
# User doesn't have RSpec 1.x installed
|
63
|
+
rescue => e
|
64
|
+
STDERR.puts "Exception occured: #{e.to_s}"
|
65
|
+
exit 1
|
66
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "sauce/driver_pool"
|
3
|
+
|
4
|
+
require "selenium/client"
|
5
|
+
require "selenium/webdriver"
|
6
|
+
|
7
|
+
require 'selenium/webdriver/remote/http/persistent'
|
8
|
+
|
9
|
+
module Selenium
|
10
|
+
module WebDriver
|
11
|
+
class Proxy
|
12
|
+
class << self
|
13
|
+
alias :existing_json_create :json_create
|
14
|
+
|
15
|
+
def json_create(data)
|
16
|
+
# Some platforms derp up JSON encoding proxy details,
|
17
|
+
# notably Appium.
|
18
|
+
if (data.class == String)
|
19
|
+
data = JSON.parse data if data.start_with? "{\"proxy"
|
20
|
+
end
|
21
|
+
|
22
|
+
dup = data.dup.delete_if {|k,v| v.nil?}
|
23
|
+
dup.delete_if {|k,v| k == "autodetect" && v == false}
|
24
|
+
existing_json_create(dup)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module Sauce
|
32
|
+
class << self
|
33
|
+
attr_accessor :webdriver_method
|
34
|
+
end
|
35
|
+
@webdriver_method = lambda { |*args| ::Selenium::WebDriver.for *args }
|
36
|
+
end
|
37
|
+
|
38
|
+
module Sauce
|
39
|
+
class Selenium2
|
40
|
+
extend Forwardable
|
41
|
+
|
42
|
+
attr_reader :config, :driver, :watir
|
43
|
+
|
44
|
+
def_delegator :@driver, :execute_script
|
45
|
+
|
46
|
+
def self.used_at_least_once?
|
47
|
+
@used_at_least_once || false
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.used_at_least_once
|
51
|
+
@used_at_least_once = true
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(opts={})
|
55
|
+
@config = Sauce::Config.new(opts)
|
56
|
+
http_client = ::Selenium::WebDriver::Remote::Http::Persistent.new
|
57
|
+
http_client.timeout = 300 # Browser launch can take a while
|
58
|
+
|
59
|
+
@driver = Sauce.webdriver_method.call(:remote,
|
60
|
+
:url => "http://#{@config.username}:#{@config.access_key}@#{@config.host}:#{@config.port}/wd/hub",
|
61
|
+
:desired_capabilities => @config.to_desired_capabilities,
|
62
|
+
:http_client => http_client)
|
63
|
+
http_client.timeout = 90 # Once the browser is up, commands should time out reasonably
|
64
|
+
|
65
|
+
@watir = defined?(Watir::Browser) && @driver.is_a?(Watir::Browser)
|
66
|
+
|
67
|
+
raw_driver.file_detector = lambda do |args|
|
68
|
+
file_path = args.first.to_s
|
69
|
+
File.exist?(file_path) ? file_path : false
|
70
|
+
end
|
71
|
+
|
72
|
+
Sauce::Selenium2.used_at_least_once
|
73
|
+
end
|
74
|
+
|
75
|
+
def raw_driver
|
76
|
+
watir ? @driver.driver : @driver
|
77
|
+
end
|
78
|
+
|
79
|
+
def method_missing(meth, *args)
|
80
|
+
@driver.send(meth, *args)
|
81
|
+
end
|
82
|
+
|
83
|
+
def session_id
|
84
|
+
raw_driver.send(:bridge).session_id
|
85
|
+
end
|
86
|
+
|
87
|
+
def current_url
|
88
|
+
raw_driver.current_url
|
89
|
+
end
|
90
|
+
|
91
|
+
def stop
|
92
|
+
@driver.quit
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sauce
|
2
|
+
module TestBase
|
3
|
+
|
4
|
+
# Run a block with every platform
|
5
|
+
def test_each(platforms, description)
|
6
|
+
platforms.each do |platform|
|
7
|
+
capabilities = {
|
8
|
+
:os => platform[0],
|
9
|
+
:browser => platform[1],
|
10
|
+
:browser_version => platform[2],
|
11
|
+
:job_name => description
|
12
|
+
}
|
13
|
+
|
14
|
+
capabilities.merge! platform[3] if platform[3]
|
15
|
+
selenium = Sauce::Selenium2.new(capabilities)
|
16
|
+
|
17
|
+
yield selenium, capabilities
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'sauce/utilities'
|
2
|
+
require "sauce_whisk"
|
3
|
+
|
4
|
+
module Sauce
|
5
|
+
module SeleniumForTestUnit
|
6
|
+
attr_reader :browser
|
7
|
+
|
8
|
+
alias_method :page, :browser
|
9
|
+
alias_method :s, :browser
|
10
|
+
alias_method :selenium, :browser
|
11
|
+
|
12
|
+
def run(*args, &blk)
|
13
|
+
if self.respond_to? :name
|
14
|
+
my_name = self.name
|
15
|
+
else
|
16
|
+
my_name = self.__name__
|
17
|
+
end
|
18
|
+
unless my_name =~ /^default_test/
|
19
|
+
config = Sauce::Config.new
|
20
|
+
if config[:application_host]
|
21
|
+
unless ENV['TEST_ENV_NUMBER'].to_i > 1
|
22
|
+
Sauce::Connect.ensure_connected(:host => config[:application_host], :port => config[:application_port] || 80)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
unless defined?(@@server)
|
27
|
+
unless ENV['TEST_ENV_NUMBER'].to_i > 1
|
28
|
+
if config[:start_local_application] &&
|
29
|
+
Sauce::Utilities::RailsServer.is_rails_app?
|
30
|
+
@@server = Sauce::Utilities::RailsServer.new
|
31
|
+
@@server.start
|
32
|
+
at_exit do
|
33
|
+
@@server.stop
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
config[:browsers].each do |os, browser, version|
|
40
|
+
options = self.class.sauce_config
|
41
|
+
options.merge!({:os => os, :browser => browser,
|
42
|
+
:browser_version => version,
|
43
|
+
:job_name => my_name.to_s})
|
44
|
+
@browser = Sauce::Selenium2.new(options)
|
45
|
+
Sauce.driver_pool[Thread.current.object_id] = @browser
|
46
|
+
|
47
|
+
super(*args, &blk)
|
48
|
+
|
49
|
+
SauceWhisk::Jobs.change_status @browser.session_id, passed?
|
50
|
+
@browser.stop
|
51
|
+
Sauce.driver_pool.delete Thread.current.object_id
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module Sauce
|
59
|
+
module SeleniumForTestUnitClassMethods
|
60
|
+
def selenium_flags=(options)
|
61
|
+
@selenium_flags = options
|
62
|
+
end
|
63
|
+
|
64
|
+
def selenium_flags
|
65
|
+
return @selenium_flags
|
66
|
+
end
|
67
|
+
|
68
|
+
def sauce_config=(config)
|
69
|
+
@sauce_config = config
|
70
|
+
end
|
71
|
+
|
72
|
+
def sauce_config
|
73
|
+
@sauce_config || {}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
if defined?(ActiveSupport::TestCase)
|
79
|
+
module Sauce
|
80
|
+
class RailsTestCase < ::ActiveSupport::TestCase
|
81
|
+
include SeleniumForTestUnit
|
82
|
+
extend SeleniumForTestUnitClassMethods
|
83
|
+
|
84
|
+
# Placeholder so test/unit ignores test cases without any tests.
|
85
|
+
def default_test
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
begin
|
92
|
+
if Object.const_defined? :Test
|
93
|
+
if Test.const_defined? :Unit
|
94
|
+
require 'test/unit/testcase'
|
95
|
+
module Sauce
|
96
|
+
class TestCase < Test::Unit::TestCase
|
97
|
+
include SeleniumForTestUnit
|
98
|
+
extend SeleniumForTestUnitClassMethods
|
99
|
+
|
100
|
+
# Placeholder so test/unit ignores test cases without any tests.
|
101
|
+
def default_test
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
rescue LoadError
|
108
|
+
# User doesn't have Test::Unit installed
|
109
|
+
rescue => e
|
110
|
+
STDERR.puts "Exception caught: #{e.to_s}"
|
111
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'socket'
|
3
|
+
require 'net/http'
|
4
|
+
require 'sauce/parallel'
|
5
|
+
require 'sauce/utilities/rails_server'
|
6
|
+
require 'sauce/utilities/connect'
|
7
|
+
|
8
|
+
module Sauce
|
9
|
+
module Utilities
|
10
|
+
def silence_stream(stream)
|
11
|
+
old_stream = stream.dup
|
12
|
+
stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
|
13
|
+
stream.sync = true
|
14
|
+
yield
|
15
|
+
ensure
|
16
|
+
stream.reopen(old_stream)
|
17
|
+
end
|
18
|
+
|
19
|
+
def wait_for_server_on_port(port)
|
20
|
+
while true
|
21
|
+
begin
|
22
|
+
Timeout::timeout(2) do
|
23
|
+
socket = TCPSocket.new('127.0.0.1', port)
|
24
|
+
socket.close unless socket.nil?
|
25
|
+
return
|
26
|
+
end
|
27
|
+
rescue Errno::ECONNREFUSED,
|
28
|
+
Errno::EBADF, # Windows
|
29
|
+
Timeout::Error
|
30
|
+
end
|
31
|
+
sleep 2
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.warn_if_suspect_misconfiguration(style = :rspec)
|
36
|
+
if Sauce::Selenium2.used_at_least_once?
|
37
|
+
integrated = Sauce::Config.called_from_integrations?
|
38
|
+
warnings_on = Sauce::Config.new[:warn_on_skipped_integration]
|
39
|
+
unless (integrated && warnings_on)
|
40
|
+
STDERR.puts Sauce::Utilities.incorrectly_integrated_warning(style)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.page_deprecation_message
|
46
|
+
return <<-MESSAGE
|
47
|
+
[DEPRECATED] Using the #page method is deprecated for RSpec tests without Capybara. Please use the #s or #selenium method instead.
|
48
|
+
If you are using Capybara and are seeing this message, check the Capybara README for information on how to include the Capybara DSL in your tests.
|
49
|
+
MESSAGE
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.incorrectly_integrated_warning(style = :rspec)
|
53
|
+
case style
|
54
|
+
when :cuke
|
55
|
+
tests = 'features'
|
56
|
+
runner = 'Cucumber'
|
57
|
+
tag = '@selenium'
|
58
|
+
else :rspec
|
59
|
+
tests = 'specs'
|
60
|
+
runner = 'RSpec'
|
61
|
+
tag = ':sauce => true'
|
62
|
+
end
|
63
|
+
|
64
|
+
return <<-stringend
|
65
|
+
|
66
|
+
===============================================================================
|
67
|
+
Your #{tests} used the Sauce Selenium driver, but not the #{runner} integration.
|
68
|
+
This may result in undesired behaviour, such as configured platforms being
|
69
|
+
skipped.
|
70
|
+
|
71
|
+
You can correct this by tagging #{tests} intended for Sauce with
|
72
|
+
'#{tag}'.
|
73
|
+
|
74
|
+
You can disable this message by setting the 'warn_on_skipped_integration'
|
75
|
+
config option to false.
|
76
|
+
===============================================================================
|
77
|
+
stringend
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Sauce
|
2
|
+
module Utilities
|
3
|
+
class Connect
|
4
|
+
def self.start_from_config(config)
|
5
|
+
self.start(:host => config[:application_host], :port => config[:application_port], :quiet => true)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.start(options={})
|
9
|
+
begin
|
10
|
+
require "sauce/connect"
|
11
|
+
rescue LoadError => e
|
12
|
+
STDERR.puts 'Please install the `sauce-connect` gem if you intend on using Sauce Connect with your tests!'
|
13
|
+
exit(1)
|
14
|
+
end
|
15
|
+
|
16
|
+
if ParallelTests.first_process?
|
17
|
+
unless @tunnel
|
18
|
+
@tunnel = Sauce::Connect.new options
|
19
|
+
@tunnel.connect
|
20
|
+
@tunnel.wait_until_ready
|
21
|
+
end
|
22
|
+
@tunnel
|
23
|
+
else
|
24
|
+
while not File.exist? "sauce_connect.ready"
|
25
|
+
sleep 0.5
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.close
|
31
|
+
if @tunnel
|
32
|
+
if ParallelTests.first_process?
|
33
|
+
ParallelTests.wait_for_other_processes_to_finish
|
34
|
+
@tunnel.disconnect
|
35
|
+
@tunnel = nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
attr_reader :tunnel
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|