simulacrum-browserstack 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6d33c5ed98259b24be10580a2e31b397eb97551d
4
+ data.tar.gz: c80c8ea8b9ec5656acaaa6d10cfac461007ce05f
5
+ SHA512:
6
+ metadata.gz: 90d4e359d4504ae1a354a2f9cbc9694b37c89895c780364d99b38f4ac36210be7455ce179f5b69182f8544926402adf016e6e9d006d558e65a18c102ed59da09
7
+ data.tar.gz: cd99c323cee573b9a63e5a4cc4e740fdd4e69d4180374f4a80101b17e1015ae63523b283b84aa9a4fcc278c3652318c6b1b006906b0ad34ebf1f73092f00dc6d
data/.gitignore ADDED
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in simulacrum-browserstack.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Justin Morris
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ simulacrum-browserstack
2
+ =======================
3
+
4
+ A BrowserStack runner for Simulacrum
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,7 @@
1
+ require 'simulacrum/browserstack/version'
2
+
3
+ module Simulacrum
4
+ module Browserstack
5
+ # Your code goes here...
6
+ end
7
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: UTF-8
2
+ require 'uri'
3
+ require 'net/https'
4
+
5
+ module Simulacrum
6
+ module Browserstack
7
+ # The Browserstack API class wraps up functionality for talking to the
8
+ # Browserstack REST API.
9
+ class API
10
+ def initialize(username, apikey)
11
+ @username = username
12
+ @apikey = apikey
13
+ end
14
+
15
+ def account_details
16
+ request = request('https://www.browserstack.com/automate/plan.json')
17
+ account_details = OpenStruct.new
18
+ account_details.sessions_running = request['parallel_sessions_running'].to_i
19
+ account_details.sessions_allowed = request['parallel_sessions_max_allowed'].to_i
20
+ account_details
21
+ end
22
+
23
+ private
24
+
25
+ def request(url)
26
+ response = make_request(url)
27
+ JSON.parse(response.body)
28
+ end
29
+
30
+ def parse_url(url)
31
+ URI.parse(url)
32
+ end
33
+
34
+ def prepare_http(uri)
35
+ http = Net::HTTP.new(uri.host, uri.port)
36
+ http.read_timeout = 30
37
+ http.use_ssl = true
38
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
39
+ http
40
+ end
41
+
42
+ def make_request(url)
43
+ uri = parse_url(url)
44
+ http = prepare_http(uri)
45
+ request = Net::HTTP::Get.new(uri.request_uri)
46
+ request.basic_auth(@username, @apikey)
47
+ http.request(request)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+
3
+ module Capybara
4
+ module Selenium
5
+ # Monkey patch the Capybara Driver class to ensure that we can call `quit`
6
+ # at the end of a parallel process run and not generate errors if capybara
7
+ # then attempts to quit.
8
+ #
9
+ # We need to do this so that sessions are terminated as early as possible
10
+ # at the remote end.
11
+ class Driver < Capybara::Driver::Base
12
+ def quit
13
+ @browser.quit if @browser
14
+ rescue Errno::ECONNREFUSED,
15
+ ::Selenium::WebDriver::Error::UnknownError
16
+ # Browser must have already gone
17
+ ensure
18
+ @browser = nil
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,93 @@
1
+ # encoding: UTF-8
2
+ require 'simulacrum/driver'
3
+ require 'capybara'
4
+ require 'selenium-webdriver'
5
+ require 'selenium/webdriver/remote/http/persistent'
6
+
7
+ module Simulacrum
8
+ module Browserstack
9
+ # Responsible for registering a custom Capybara driver for use with
10
+ # Selenium grid endpoints (Browserstack, SauceLabs, etc.). Configures
11
+ # selenium options via ENV vars so that they can be passed into
12
+ class Driver < Simulacrum::Driver
13
+ private
14
+
15
+ def configuration
16
+ {
17
+ browser: :remote,
18
+ url: selenium_remote_url,
19
+ desired_capabilities: capabilities,
20
+ http_client: persistent_http_client
21
+ }
22
+ end
23
+
24
+ def persistent_http_client
25
+ Selenium::WebDriver::Remote::Http::Persistent.new
26
+ end
27
+
28
+ def capabilities
29
+ caps = Selenium::WebDriver::Remote::Capabilities.new
30
+ caps['project'] = Simulacrum.configuration.project_name
31
+ caps['build'] = Simulacrum.configuration.build_name
32
+ caps['browserstack.local'] = true
33
+ caps['browserstack.debug'] = false
34
+ caps['browser'] = browser
35
+ caps['browserName'] = browser_name
36
+ caps['browser_version'] = browser_version
37
+ caps['os'] = os
38
+ caps['os_version'] = os_version
39
+ caps['device'] = device
40
+ caps['deviceOrientation'] = device_orientation
41
+ caps['platform'] = platform
42
+ caps['resolution'] = resolution
43
+ caps['requireWindowFocus'] = require_window_focus
44
+ caps['realMobile'] = real_mobile
45
+ caps
46
+ end
47
+
48
+ def browser
49
+ ENV['SELENIUM_BROWSER']
50
+ end
51
+
52
+ def browser_name
53
+ ENV['BS_BROWSERNAME'] || ''
54
+ end
55
+
56
+ def real_mobile
57
+ ENV['BS_REALMOBILE'] || false
58
+ end
59
+
60
+ def browser_version
61
+ ENV['SELENIUM_VERSION'] || ''
62
+ end
63
+
64
+ def os
65
+ ENV['BS_AUTOMATE_OS'] || ''
66
+ end
67
+
68
+ def os_version
69
+ ENV['BS_AUTOMATE_OS_VERSION'] || ''
70
+ end
71
+
72
+ def device
73
+ ENV['BS_AUTOMATE_DEVICE'] || ''
74
+ end
75
+
76
+ def device_orientation
77
+ ENV['BS_AUTOMATE_DEVICEORIENTATION'] || ''
78
+ end
79
+
80
+ def platform
81
+ ENV['BS_AUTOMATE_PLATFORM'] || ''
82
+ end
83
+
84
+ def resolution
85
+ ENV['BS_AUTOMATE_RESOLUTION'] || ''
86
+ end
87
+
88
+ def require_window_focus
89
+ ENV['BS_AUTOMATE_REQUIREWINDOWFOCUS'] || ''
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,42 @@
1
+ # # encoding: UTF-8
2
+
3
+ # module Simulacrum
4
+ # module Browserstack
5
+ # # Class for ensuring BrowserStackLocal is available
6
+ # class LocalWrapper
7
+ # Simulacrum.logger.debug('BrowserStack') { 'Downloading BrowserStackLocal binary for ' }
8
+
9
+ # def download_binary
10
+
11
+ # end
12
+
13
+ # "https://www.browserstack.com/browserstack-local/BrowserStackLocal-"
14
+
15
+ # private
16
+
17
+ # def platform
18
+
19
+ # end
20
+
21
+ # def windows?
22
+ # (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
23
+ # end
24
+
25
+ # def mac?
26
+ # (/darwin/ =~ RUBY_PLATFORM) != nil
27
+ # end
28
+
29
+ # def linux?
30
+ # (/linux/ =~ RUBY_PLATFORM) != nil
31
+ # end
32
+
33
+ # def x64?
34
+ # (/x86_64/ =~ RUBY_PLATFORM) != nil
35
+ # end
36
+
37
+ # def i386?
38
+ # (/i386/ =~ RUBY_PLATFORM) != nil
39
+ # end
40
+ # end
41
+ # end
42
+ # end
@@ -0,0 +1,193 @@
1
+ # encoding: UTF-8
2
+ require_relative './capybara_patch'
3
+ require_relative './tunnel'
4
+ require_relative './summary'
5
+ require_relative './api'
6
+ require_relative './driver'
7
+ require 'simulacrum/runner'
8
+ require 'parallel'
9
+ require 'yaml'
10
+ require 'retries'
11
+ require 'pry'
12
+
13
+ module Simulacrum
14
+ module Browserstack
15
+ # A Runner Class for Browserstack that handles creating a Browserstack
16
+ # tunnel, closing it when done. Also handles running the suite in parallel.
17
+ class Runner < Simulacrum::Runner
18
+ # Exception to indicate that Browserstack has no available sessions
19
+ # to start a new test run, this is used inside a retries loop but will
20
+ # be raised if maximum retries is exceeded
21
+ class NoRemoteSessionsAvailable < RuntimeError; end
22
+
23
+ attr_reader :app_ports
24
+
25
+ def initialize
26
+ start_timer
27
+
28
+ @username = Simulacrum.runner_options.username
29
+ @apikey = Simulacrum.runner_options.apikey
30
+ @app_ports = app_ports
31
+ @api = Simulacrum::Browserstack::API.new(@username, @apikey)
32
+ @tunnel = Simulacrum::Browserstack::Tunnel.new(@username, @apikey, @app_ports)
33
+
34
+ set_global_env
35
+ execute
36
+ summarize_results
37
+ summarize_exit_codes
38
+ ensure
39
+ @tunnel.close if @tunnel
40
+ end
41
+
42
+ def execute
43
+ Simulacrum.logger.info('BrowserStack') { "Using runner with #{processes} remote workers" }
44
+ @process_exit_codes, @process_results = Parallel.map_with_index(browsers, in_processes: processes) do |(name, caps), index|
45
+ begin
46
+ ensure_available_remote_runner
47
+ configure_app_port(index)
48
+ configure_environment(name, caps)
49
+ configure_browser_setting(name)
50
+ exit_code = run
51
+ [exit_code, { results: dump_results }]
52
+ rescue SystemExit
53
+ exit 1
54
+ ensure
55
+ quit_browser
56
+ end
57
+ end.transpose
58
+ ensure
59
+ stop_timer
60
+ end
61
+
62
+ private
63
+
64
+ def quit_browser
65
+ Capybara.current_session.driver.browser.quit
66
+ end
67
+
68
+ def configure_browser_setting(name)
69
+ RSpec.configuration.around do |example|
70
+ example.metadata[:browser] = name
71
+ begin
72
+ example.run
73
+ end
74
+ end
75
+ end
76
+
77
+ def configure_rspec
78
+ super
79
+ RSpec.configuration.instance_variable_set(:@reporter, reporter)
80
+ end
81
+
82
+ def configure_driver
83
+ Simulacrum::Browserstack::Driver.use
84
+ end
85
+
86
+ def reporter
87
+ @reporter ||= RSpec::Core::Reporter.new(formatter)
88
+ end
89
+
90
+ def formatter
91
+ @formatter ||= Simulacrum::Formatters::SimulacrumFormatter.new($stdout)
92
+ end
93
+
94
+ def dump_results
95
+ Marshal.dump(formatter.output_hash)
96
+ end
97
+
98
+ def ensure_available_remote_runner
99
+ with_retries(max_tries: 20, base_sleep_seconds: 0.5, max_sleep_seconds: 15) do
100
+ remote_worker_available?
101
+ end
102
+ end
103
+
104
+ def remote_worker_available?
105
+ account_details = @api.account_details
106
+ unless account_details.sessions_running < account_details.sessions_allowed
107
+ fail NoRemoteSessionsAvailable
108
+ end
109
+ end
110
+
111
+ def start_timer
112
+ @start_time = Time.now
113
+ end
114
+
115
+ def stop_timer
116
+ @end_time = Time.now
117
+ end
118
+
119
+ def summarize_results
120
+ summary = Simulacrum::Browserstack::Summary.new(@process_results, @start_time, @end_time)
121
+ summary.dump_summary
122
+ summary.dump_failures
123
+ summary.dump_pending
124
+ end
125
+
126
+ def summarize_exit_codes
127
+ @exit_code = (@process_exit_codes.inject(&:+) == 0) ? 0 : 1
128
+ end
129
+
130
+ def configure_app_port(index)
131
+ ENV['APP_SERVER_PORT'] = app_ports[index].to_s
132
+ end
133
+
134
+ # rubocop:disable MethodLength
135
+ def configure_environment(name, caps)
136
+ ENV['SELENIUM_REMOTE_URL'] = @tunnel.selenium_remote_url
137
+ ENV['BS_DRIVER_NAME'] = name
138
+ ENV['SELENIUM_BROWSER'] = caps['browser']
139
+ ENV['SELENIUM_VERSION'] = caps['browser_version'].to_s
140
+ ENV['BS_AUTOMATE_OS'] = caps['os']
141
+ ENV['BS_AUTOMATE_OS_VERSION'] = caps['os_version'].to_s
142
+ ENV['BS_AUTOMATE_RESOLUTION'] = caps['resolution']
143
+ ENV['BS_AUTOMATE_REQUIREWINDOWFOCUS'] = caps['requireWindowFocus'].to_s
144
+ ENV['BS_AUTOMATE_PLATFORM'] = caps['platform']
145
+ ENV['BS_AUTOMATE_DEVICE'] = caps['device']
146
+ ENV['BS_AUTOMATE_DEVICEORIENTATION'] = caps['deviceOrientation']
147
+ ENV['BS_BROWSERNAME'] = caps['browserName']
148
+ ENV['BS_REALMOBILE'] = caps['realMobile'].to_s
149
+ end
150
+ # rubocop:enable MethodLength
151
+
152
+ def processes
153
+ Simulacrum.runner_options.max_processes || @api.account_details.sessions_allowed
154
+ end
155
+
156
+ def set_global_env
157
+ ENV['SELENIUM_REMOTE_URL'] = @tunnel.selenium_remote_url
158
+ end
159
+
160
+ def app_ports
161
+ @app_ports ||= begin
162
+ if browsers.any?
163
+ browsers.length.times.map { find_available_port }
164
+ else
165
+ [find_available_port]
166
+ end
167
+ end
168
+ end
169
+
170
+ def find_available_port
171
+ server = TCPServer.new('127.0.0.1', 0)
172
+ server.addr[1]
173
+ ensure
174
+ server.close if server
175
+ end
176
+
177
+ def browsers
178
+ @browsers ||= begin
179
+ if Simulacrum.config_file?
180
+ browsers = Simulacrum.config_file['browsers']
181
+ browsers = browsers.select do |name, value|
182
+ name == Simulacrum.runner_options.browser
183
+ end if Simulacrum.runner_options.browser
184
+ browsers
185
+ else
186
+ # TODO: Raise a better error...
187
+ fail 'DERP!'
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,89 @@
1
+ # encoding: UTF-8
2
+ require 'rspec/core/formatters/helpers'
3
+ require 'rspec/core/formatters/base_text_formatter'
4
+
5
+ module Simulacrum
6
+ module Browserstack
7
+ # The Summary Class is responsible for combining dumped examlpes from one
8
+ # or more other RSpec runs.
9
+ class Summary < RSpec::Core::Formatters::BaseTextFormatter
10
+ # TODO: Rename me, I'm really just a formatter anyway
11
+ # TODO: Also, should this just be an external gem...? Prolly not?
12
+ def initialize(results_set, start_time, end_time)
13
+ super($stdout)
14
+ @results_set = results_set
15
+ @start_time = start_time
16
+ @end_time = end_time
17
+ end
18
+
19
+ def dump_commands_to_rerun_failed_examples
20
+ return if failed_examples.empty?
21
+ output.puts
22
+ output.puts('Failed examples:')
23
+ output.puts
24
+
25
+ failed_examples.each do |example|
26
+ output.puts(failure_color("simulacrum --browser=#{example.metadata[:browser]} #{RSpec::Core::Metadata::relative_path(example.location)}") + ' ' + detail_color("# #{example.full_description}"))
27
+ end
28
+ end
29
+
30
+ def dump_summary
31
+ super(duration, example_count, failure_count, pending_count)
32
+ end
33
+
34
+ def failed_examples
35
+ examples.select do |example|
36
+ example.execution_result[:status] == 'failed'
37
+ end
38
+ end
39
+
40
+ def pending_examples
41
+ examples.select do |example|
42
+ example.execution_result[:status] == 'pending'
43
+ end
44
+ end
45
+
46
+ def duration
47
+ @end_time - @start_time
48
+ end
49
+
50
+ def example_count
51
+ summaries.map { |x| x[:example_count] }.reduce(:+)
52
+ end
53
+
54
+ def failure_count
55
+ summaries.map { |x| x[:failure_count] }.reduce(:+)
56
+ end
57
+
58
+ def pending_count
59
+ summaries.map { |x| x[:pending_count] }.reduce(:+)
60
+ end
61
+
62
+ def find_shared_group(example)
63
+ end
64
+
65
+ def group_and_parent_groups(example)
66
+ end
67
+
68
+ private
69
+
70
+ def color_enabled?
71
+ Simulacrum.runner_options.color
72
+ end
73
+
74
+ def examples
75
+ dumped_results.map { |result| result[:examples] }.flatten
76
+ end
77
+
78
+ def summaries
79
+ dumped_results.map { |result| result[:summary] }.flatten
80
+ end
81
+
82
+ def dumped_results
83
+ @dumped_results ||= @results_set.map do |result|
84
+ Marshal.load(result[:results])
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,105 @@
1
+ # encoding: UTF-8
2
+ require 'timeout'
3
+ require 'fileutils'
4
+ require 'English'
5
+
6
+ module Simulacrum
7
+ module Browserstack
8
+ # Class for handling Browserstack tunnel opening/closing/management
9
+ class Tunnel
10
+ attr_reader :selenium_remote_url, :pid, :ports, :open
11
+ alias_method :open?, :open
12
+
13
+ DEFAULT_OPTIONS = {
14
+ skip_check: true,
15
+ only_automate: false,
16
+ verbose: false,
17
+ force: true
18
+ }
19
+
20
+ def initialize(username, apikey, ports, options = {})
21
+ @pid = nil
22
+ @open = false
23
+ @username = username
24
+ @apikey = apikey
25
+ @ports = ports
26
+ @options = OpenStruct.new(DEFAULT_OPTIONS.clone.merge!(options))
27
+
28
+ create_tunnel
29
+ ensure_open
30
+ end
31
+
32
+ def selenium_remote_url
33
+ "http://#{@username}:#{@apikey}@hub.browserstack.com/wd/hub"
34
+ end
35
+
36
+ def close
37
+ kill
38
+ end
39
+
40
+ private
41
+
42
+ def binary_path
43
+ binary_path = `which BrowserStackLocal`.strip
44
+ if $CHILD_STATUS.success? && File.executable?(binary_path)
45
+ binary_path
46
+ else
47
+ Simulacrum.logger.fail('BrowserStack') { 'BrowserStackLocal binary not found or not executable' }
48
+ fail
49
+ end
50
+ end
51
+
52
+ def create_tunnel
53
+ @process = IO.popen(command)
54
+ @pid = @process.pid
55
+ Simulacrum.logger.debug('BrowserStack') { "Openning tunnel (pid #{@pid})" }
56
+ end
57
+
58
+ def command
59
+ cmd = [binary_path]
60
+ cmd << '-skipCheck' if @options.skip_check == true
61
+ cmd << '-onlyAutomate' if @options.only_automate == true
62
+ cmd << '-force' if @options.force == true
63
+ cmd << '-v' if @options.verbose == true
64
+ cmd << @apikey
65
+ cmd << formatted_ports
66
+ cmd.join(' ')
67
+ end
68
+
69
+ def formatted_ports
70
+ ports.map { |port| "localhost,#{port},0" }.join(',')
71
+ end
72
+
73
+ def kill
74
+ Process.kill('TERM', @pid) if running?
75
+ end
76
+
77
+ def ensure_open
78
+ Simulacrum.logger.debug('BrowserStack') { 'Waiting for tunnel to open' }
79
+ Timeout.timeout(240) do
80
+ sleep 1 until tunnel_open?
81
+ end
82
+ @open = true
83
+ Simulacrum.logger.debug('BrowserStack') { 'Tunnel open' }
84
+ rescue Timeout::Error
85
+ Simulacrum.logger.debug('BrowserStack') { 'Tunnel failed to open, exiting.' }
86
+ exit(1)
87
+ end
88
+
89
+ def tunnel_open?
90
+ `curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:45691`.to_i == 200
91
+ end
92
+
93
+ def running?
94
+ if @pid.nil?
95
+ false
96
+ else
97
+ Process.getpgid(@pid)
98
+ true
99
+ end
100
+ rescue Errno::ESRCH
101
+ false
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,5 @@
1
+ module Simulacrum
2
+ module Browserstack
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'simulacrum/browserstack/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = 'simulacrum-browserstack'
8
+ gem.version = Simulacrum::Browserstack::VERSION
9
+ gem.authors = ['Justin Morris']
10
+ gem.email = ['desk@pixelbloom.com']
11
+ gem.summary = %q{BrowserStack runner for Simulacrum}
12
+ gem.description = %q{BrowserStack runner for Simulacrum}
13
+ gem.homepage = ''
14
+ gem.license = 'MIT'
15
+
16
+ gem.files = `git ls-files -z`.split("\x0")
17
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ['lib']
20
+
21
+ gem.add_dependency 'parallel', ['~> 1.2.0']
22
+ gem.add_dependency 'net-http-persistent'
23
+
24
+ gem.add_development_dependency 'bundler', '~> 1.6'
25
+ gem.add_development_dependency 'rake'
26
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simulacrum-browserstack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Justin Morris
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: parallel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: net-http-persistent
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: BrowserStack runner for Simulacrum
70
+ email:
71
+ - desk@pixelbloom.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - lib/simulacrum/browserstack.rb
82
+ - lib/simulacrum/browserstack/api.rb
83
+ - lib/simulacrum/browserstack/capybara_patch.rb
84
+ - lib/simulacrum/browserstack/driver.rb
85
+ - lib/simulacrum/browserstack/local_wrapper.rb
86
+ - lib/simulacrum/browserstack/runner.rb
87
+ - lib/simulacrum/browserstack/summary.rb
88
+ - lib/simulacrum/browserstack/tunnel.rb
89
+ - lib/simulacrum/browserstack/version.rb
90
+ - simulacrum-browserstack.gemspec
91
+ homepage: ''
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.0.14
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: BrowserStack runner for Simulacrum
115
+ test_files: []
116
+ has_rdoc: