Compare commits
8 Commits
rspec-cucu
...
master
Author | SHA1 | Date |
---|---|---|
John Bintz | f698dc7bda | |
John Bintz | a83023b812 | |
John Bintz | b217fef4ee | |
John Bintz | 21a622ace0 | |
John Bintz | 2034c864f3 | |
John Bintz | ad5d5c5d05 | |
John Bintz | e738bab0f4 | |
John Bintz | f6bfa0cf29 |
42
README.md
42
README.md
|
@ -1,3 +1,5 @@
|
||||||
|
# Persistent Selenium
|
||||||
|
|
||||||
Now you can keep that precious browser window open when doing continuous integration testing.
|
Now you can keep that precious browser window open when doing continuous integration testing.
|
||||||
Save seconds, and sanity, with every test re-run!
|
Save seconds, and sanity, with every test re-run!
|
||||||
|
|
||||||
|
@ -7,7 +9,7 @@ fix your tests and/or code.
|
||||||
Start an instance:
|
Start an instance:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
persistent_selenium [ --port 9854 ] [ --browser firefox ]
|
persistent_selenium [ --port 9854 ] [ --browser firefox ] [ --chrome-extensions <file.crx> ... ]
|
||||||
```
|
```
|
||||||
|
|
||||||
Tell Capybara to use it:
|
Tell Capybara to use it:
|
||||||
|
@ -36,11 +38,45 @@ these two differences:
|
||||||
The browser's cache is disabled, and cookies are reset before the next test runs, so you still get the state
|
The browser's cache is disabled, and cookies are reset before the next test runs, so you still get the state
|
||||||
cleared out before your next set of tests.
|
cleared out before your next set of tests.
|
||||||
|
|
||||||
### Under the hood
|
### .persistent_selenium
|
||||||
|
|
||||||
|
Configure everything in your app with a `.persistent_selenium` file:
|
||||||
|
|
||||||
|
``` ruby
|
||||||
|
# .persistent_selenium
|
||||||
|
PersistentSelenium.configure do |c|
|
||||||
|
c.browser = :chrome
|
||||||
|
c.chrome_extensions = %w{AngularJS-Batarang.crx}
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Chrome Extensions
|
||||||
|
|
||||||
|
If, for example, you do a lot with AngularJS and want to use [Batarang](https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en),
|
||||||
|
download the extension, put it in your project's folder somewhere, and call `persistent_selenium` with the path
|
||||||
|
to the extension:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
persistent_selenium --browser chrome --chrome-extensions AngularJS-Batarang.crx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best practice
|
||||||
|
|
||||||
|
Use it with Foreman and Guard. Start up your test suite via Guard, configure your test suite to
|
||||||
|
use persistent_selenium, and run persistent_selenium alongside it:
|
||||||
|
|
||||||
|
``` yaml
|
||||||
|
guard: guard -g wip
|
||||||
|
ps: persistent_selenium
|
||||||
|
```
|
||||||
|
|
||||||
|
It's an integral part of my [integration testing setup](http://github.com/johnbintz/bintz-integration_testing_setup).
|
||||||
|
|
||||||
|
## Under the hood
|
||||||
|
|
||||||
It's DRb, which mostly Just Works (tm), and has a little reshuffling of the default Capybara Selenium driver's code.
|
It's DRb, which mostly Just Works (tm), and has a little reshuffling of the default Capybara Selenium driver's code.
|
||||||
|
|
||||||
#### When DRb doesn't Just Work (tm)
|
### When DRb doesn't Just Work (tm)
|
||||||
|
|
||||||
You're most likely using `all` and invoking an action on one of the nodes within, I'd wager. If you need to find a node
|
You're most likely using `all` and invoking an action on one of the nodes within, I'd wager. If you need to find a node
|
||||||
to perform an action on, it's best to stick with `find`, since it's less likely that node will go out of
|
to perform an action on, it's best to stick with `find`, since it's less likely that node will go out of
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
$: << File.expand_path('../../lib', __FILE__)
|
$: << File.expand_path('../../lib', __FILE__)
|
||||||
|
|
||||||
|
require 'persistent_selenium'
|
||||||
|
|
||||||
|
PersistentSelenium.load_dotfile
|
||||||
|
|
||||||
require 'persistent_selenium/cli'
|
require 'persistent_selenium/cli'
|
||||||
|
|
||||||
GC.disable
|
GC.disable
|
||||||
|
|
|
@ -3,7 +3,7 @@ require 'selenium-webdriver'
|
||||||
|
|
||||||
module PersistentSelenium
|
module PersistentSelenium
|
||||||
class << self
|
class << self
|
||||||
attr_writer :port, :browser
|
attr_writer :port, :browser, :timeout, :chrome_extensions
|
||||||
|
|
||||||
def port
|
def port
|
||||||
@port ||= 9854
|
@port ||= 9854
|
||||||
|
@ -13,6 +13,14 @@ module PersistentSelenium
|
||||||
@browser ||= :firefox
|
@browser ||= :firefox
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def timeout
|
||||||
|
@timeout ||= 120
|
||||||
|
end
|
||||||
|
|
||||||
|
def chrome_extensions
|
||||||
|
@chrome_extensions ||= []
|
||||||
|
end
|
||||||
|
|
||||||
def url
|
def url
|
||||||
"druby://localhost:#{port}"
|
"druby://localhost:#{port}"
|
||||||
end
|
end
|
||||||
|
@ -20,5 +28,11 @@ module PersistentSelenium
|
||||||
def configure
|
def configure
|
||||||
yield self
|
yield self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def load_dotfile(file = '.persistent_selenium')
|
||||||
|
if File.file?(file)
|
||||||
|
load file
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,8 @@ require 'base64'
|
||||||
module PersistentSelenium
|
module PersistentSelenium
|
||||||
class Browser < Capybara::Selenium::Driver
|
class Browser < Capybara::Selenium::Driver
|
||||||
def initialize(browser_type)
|
def initialize(browser_type)
|
||||||
@browser_type = browser_type
|
@browser_type = browser_type.to_s.to_sym
|
||||||
|
@frame_handles = {}
|
||||||
@__found_elements__ = []
|
@__found_elements__ = []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -20,7 +21,13 @@ module PersistentSelenium
|
||||||
|
|
||||||
options = { :profile => profile }
|
options = { :profile => profile }
|
||||||
when :chrome
|
when :chrome
|
||||||
options = { :switches => %w{--disk-cache-size=1 --media-cache-size=1} }
|
switches = %w{--disk-cache-size=1 --media-cache-size=1}
|
||||||
|
|
||||||
|
PersistentSelenium.chrome_extensions.each do |extension|
|
||||||
|
switches.push("--load-extension=#{extension}")
|
||||||
|
end
|
||||||
|
|
||||||
|
options = { switches: switches }
|
||||||
end
|
end
|
||||||
|
|
||||||
@browser ||= Selenium::WebDriver.for(@browser_type, options)
|
@browser ||= Selenium::WebDriver.for(@browser_type, options)
|
||||||
|
@ -30,6 +37,10 @@ module PersistentSelenium
|
||||||
{}
|
{}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def browser_initialized?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
def visit(path)
|
def visit(path)
|
||||||
if !path[/^http/]
|
if !path[/^http/]
|
||||||
path = @app_host + path
|
path = @app_host + path
|
||||||
|
|
|
@ -10,14 +10,19 @@ module PersistentSelenium
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "start", "Start the server"
|
desc "start", "Start the server"
|
||||||
method_options :port => PersistentSelenium.port, :browser => PersistentSelenium.browser
|
method_options :port => PersistentSelenium.port,
|
||||||
|
:browser => PersistentSelenium.browser,
|
||||||
|
:timeout => PersistentSelenium.timeout
|
||||||
|
method_option :chrome_extensions, :type => :array, :default => []
|
||||||
def start
|
def start
|
||||||
require 'persistent_selenium/browser'
|
require 'persistent_selenium/browser'
|
||||||
require 'drb'
|
require 'persistent_selenium/drb'
|
||||||
|
|
||||||
PersistentSelenium.configure do |c|
|
PersistentSelenium.configure do |c|
|
||||||
c.port = options[:port]
|
c.port = options[:port]
|
||||||
c.browser = options[:browser]
|
c.browser = options[:browser] if options[:browser]
|
||||||
|
c.timeout = options[:timeout]
|
||||||
|
c.chrome_extensions = options[:chrome_extensions] if !options[:chrome_extensions].empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
puts "Starting persistent_selenium on #{PersistentSelenium.port} with #{PersistentSelenium.browser}"
|
puts "Starting persistent_selenium on #{PersistentSelenium.port} with #{PersistentSelenium.browser}"
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
require_relative './driver'
|
||||||
|
|
||||||
|
Before do
|
||||||
|
if Capybara.current_driver == :persistent_selenium
|
||||||
|
Capybara.server_port ||= '3001'
|
||||||
|
Capybara.app_host ||= "http://localhost:#{Capybara.server_port}"
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,17 @@
|
||||||
|
require 'drb'
|
||||||
|
|
||||||
|
module DRb
|
||||||
|
class DRbTCPSocket
|
||||||
|
alias :_set_sockopt :set_sockopt
|
||||||
|
|
||||||
|
def set_sockopt(soc)
|
||||||
|
_set_sockopt(soc)
|
||||||
|
|
||||||
|
optval = [ PersistentSelenium.timeout, 0 ].pack("l_2")
|
||||||
|
|
||||||
|
soc.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
|
||||||
|
soc.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
require 'persistent_selenium'
|
require 'persistent_selenium'
|
||||||
|
require 'persistent_selenium/browser'
|
||||||
require 'capybara/selenium/driver'
|
require 'capybara/selenium/driver'
|
||||||
|
|
||||||
# make sure these classes exist on this end
|
# make sure these classes exist on this end
|
||||||
[ Selenium::WebDriver::Error::StaleElementReferenceError, Selenium::WebDriver::Error::UnhandledError, Selenium::WebDriver::Error::ElementNotVisibleError ]
|
[ Selenium::WebDriver::Error::StaleElementReferenceError, Selenium::WebDriver::Error::UnhandledError, Selenium::WebDriver::Error::ElementNotVisibleError ]
|
||||||
|
|
||||||
Before do
|
require 'persistent_selenium/drb'
|
||||||
if Capybara.current_driver == :persistent_selenium
|
|
||||||
Capybara.server_port ||= '3001'
|
|
||||||
Capybara.app_host ||= "http://localhost:#{Capybara.server_port}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Capybara.register_driver :persistent_selenium do |app|
|
Capybara.register_driver :persistent_selenium do |app|
|
||||||
require 'drb'
|
require 'drb'
|
||||||
|
|
||||||
|
module DRb
|
||||||
|
class DRbObject
|
||||||
|
def method(name)
|
||||||
|
method_missing(:method, name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
DRb.start_service
|
DRb.start_service
|
||||||
|
|
||||||
browser = DRbObject.new nil, PersistentSelenium.url
|
browser = DRbObject.new nil, PersistentSelenium.url
|
||||||
|
|
||||||
server = Capybara::Server.new(app)
|
server = Capybara::Server.new(app)
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
require_relative './driver'
|
||||||
|
|
||||||
|
RSpec.configure do |c|
|
||||||
|
c.before :each do
|
||||||
|
if Capybara.current_driver == :persistent_selenium
|
||||||
|
Capybara.server_port ||= '3001'
|
||||||
|
Capybara.app_host ||= "http://localhost:#{Capybara.server_port}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,3 +1,3 @@
|
||||||
module PersistentSelenium
|
module PersistentSelenium
|
||||||
VERSION = "0.0.2"
|
VERSION = "0.1.1"
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue