persistent_selenium 0.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/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +50 -0
- data/Rakefile +2 -0
- data/bin/persistent_selenium +8 -0
- data/lib/persistent_selenium/browser.rb +102 -0
- data/lib/persistent_selenium/cli.rb +44 -0
- data/lib/persistent_selenium/driver.rb +26 -0
- data/lib/persistent_selenium/version.rb +3 -0
- data/lib/persistent_selenium.rb +23 -0
- data/persistent_selenium.gemspec +17 -0
- data/skel/features/support/persistent_selenium.rb +11 -0
- metadata +61 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 John Bintz
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
Now you can keep that precious browser window open when doing continuous integration testing.
|
2
|
+
Save seconds, and sanity, with every test re-run!
|
3
|
+
|
4
|
+
Also, the browser stays open at its last state so you can inspect it and more easily
|
5
|
+
fix your tests and/or code.
|
6
|
+
|
7
|
+
Start an instance:
|
8
|
+
|
9
|
+
``` bash
|
10
|
+
persistent_selenium [ --port 9854 ] [ --browser firefox ]
|
11
|
+
```
|
12
|
+
|
13
|
+
Tell Capybara to use it:
|
14
|
+
|
15
|
+
```
|
16
|
+
# features/support/env.rb
|
17
|
+
|
18
|
+
require 'persistent_selenium/driver'
|
19
|
+
Capybara.default_driver = :persistent_selenium
|
20
|
+
```
|
21
|
+
|
22
|
+
If you're using Cucumber, you can also install that hook:
|
23
|
+
|
24
|
+
``` bash
|
25
|
+
persistent_selenium install
|
26
|
+
```
|
27
|
+
|
28
|
+
Should work just the same as if you used the standard Capybara Selenium driver, except for
|
29
|
+
these two differences:
|
30
|
+
|
31
|
+
* The browser starts up first thing and sticks around, so you don't pay the startup/shutdown
|
32
|
+
penalty with each test run.
|
33
|
+
* The last page you were on before your tests passed/failed stays there, so you can inspect it
|
34
|
+
and adjust your tests.
|
35
|
+
|
36
|
+
The browser's cache is disabled, and cookies are reset before the next test runs, so you still get the state
|
37
|
+
cleared out before your next set of tests.
|
38
|
+
|
39
|
+
### Under the hood
|
40
|
+
|
41
|
+
It's DRb, which mostly Just Works (tm), and has a little reshuffling of the default Capybara Selenium driver's code.
|
42
|
+
|
43
|
+
#### When DRb doesn't Just Work (tm)
|
44
|
+
|
45
|
+
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
|
46
|
+
to perform an action on, it's best to stick with `find`, since it's less likely that node will go out of
|
47
|
+
ObjectSpace that quickly. If you need to examine the document for particular properties, and `all` seems like
|
48
|
+
the best way to do it, instead try parsing the document body with Nokogiri and using its finders.
|
49
|
+
That way, all your node searching will be done on the client end.
|
50
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
require 'capybara/selenium/driver'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module PersistentSelenium
|
6
|
+
class Browser < Capybara::Selenium::Driver
|
7
|
+
def initialize(browser_type)
|
8
|
+
@browser_type = browser_type
|
9
|
+
@__found_elements__ = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def browser
|
13
|
+
case @browser_type
|
14
|
+
when :firefox
|
15
|
+
profile = Selenium::WebDriver::Firefox::Profile.new
|
16
|
+
profile['browser.cache.disk.enable'] = false
|
17
|
+
profile['browser.cache.memory.enable'] = false
|
18
|
+
profile['browser.cache.offline.enable'] = false
|
19
|
+
profile['network.http.use-cache'] = false
|
20
|
+
|
21
|
+
options = { :profile => profile }
|
22
|
+
when :chrome
|
23
|
+
options = { :switches => %w{--disk-cache-size=1 --media-cache-size=1} }
|
24
|
+
end
|
25
|
+
|
26
|
+
@browser ||= Selenium::WebDriver.for(@browser_type, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def options
|
30
|
+
{}
|
31
|
+
end
|
32
|
+
|
33
|
+
def visit(path)
|
34
|
+
if !path[/^http/]
|
35
|
+
path = @app_host + path
|
36
|
+
end
|
37
|
+
|
38
|
+
browser.navigate.to(path)
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_app_host(host)
|
42
|
+
@app_host = host.dup
|
43
|
+
load_splash_page
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_splash_page
|
47
|
+
browser.navigate.to("data:text/html;base64,#{Base64.encode64(starting_page)}")
|
48
|
+
end
|
49
|
+
|
50
|
+
def reset!
|
51
|
+
if @browser
|
52
|
+
begin
|
53
|
+
@browser.manage.delete_all_cookies
|
54
|
+
rescue Selenium::WebDriver::Error::UnhandledError => e
|
55
|
+
# delete_all_cookies fails when we've previously gone
|
56
|
+
# to about:blank, so we rescue this error and do nothing
|
57
|
+
# instead.
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def starting_page
|
63
|
+
<<-HTML
|
64
|
+
<html>
|
65
|
+
<head>
|
66
|
+
<title>Persistent Selenium -- Starting up...</title>
|
67
|
+
<style>
|
68
|
+
body {
|
69
|
+
background: #444;
|
70
|
+
}
|
71
|
+
|
72
|
+
* {
|
73
|
+
font-family: Verdana, Helvetica, sans-serif;
|
74
|
+
}
|
75
|
+
|
76
|
+
td {
|
77
|
+
background: #ccc;
|
78
|
+
width: 50%;
|
79
|
+
text-align: center;
|
80
|
+
|
81
|
+
border: solid #333 1px;
|
82
|
+
border-radius: 5px;
|
83
|
+
padding: 10px;
|
84
|
+
}
|
85
|
+
</style>
|
86
|
+
</head>
|
87
|
+
<body>
|
88
|
+
<table width="100%" height="100%" cellpadding="0" cellspacing="0">
|
89
|
+
<tr>
|
90
|
+
<td>
|
91
|
+
<h1>Persistent Selenium</h1>
|
92
|
+
<h2>Starting up...</h2>
|
93
|
+
</td>
|
94
|
+
</tr>
|
95
|
+
</table>
|
96
|
+
</body>
|
97
|
+
</html>
|
98
|
+
HTML
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'persistent_selenium'
|
3
|
+
|
4
|
+
module PersistentSelenium
|
5
|
+
class CLI < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.expand_path('../../../skel', __FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "start", "Start the server"
|
13
|
+
method_options :port => PersistentSelenium.port, :browser => PersistentSelenium.browser
|
14
|
+
def start
|
15
|
+
require 'persistent_selenium/browser'
|
16
|
+
require 'drb'
|
17
|
+
|
18
|
+
PersistentSelenium.configure do |c|
|
19
|
+
c.port = options[:port]
|
20
|
+
c.browser = options[:browser]
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "Starting persistent_selenium on #{PersistentSelenium.port} with #{PersistentSelenium.browser}"
|
24
|
+
|
25
|
+
@browser = Browser.new(PersistentSelenium.browser)
|
26
|
+
@browser.browser
|
27
|
+
|
28
|
+
DRb.start_service PersistentSelenium.url, @browser
|
29
|
+
|
30
|
+
trap('TERM') { exit }
|
31
|
+
trap('INT') { exit }
|
32
|
+
|
33
|
+
DRb.thread.join
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "install", "Install Cucumber hook for using persistent selenium"
|
37
|
+
def install
|
38
|
+
directory '.', '.'
|
39
|
+
end
|
40
|
+
|
41
|
+
default_task :start
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'persistent_selenium'
|
2
|
+
require 'capybara/selenium/driver'
|
3
|
+
|
4
|
+
# make sure these classes exist on this end
|
5
|
+
[ Selenium::WebDriver::Error::StaleElementReferenceError, Selenium::WebDriver::Error::UnhandledError, Selenium::WebDriver::Error::ElementNotVisibleError ]
|
6
|
+
|
7
|
+
Before do
|
8
|
+
if Capybara.current_driver == :persistent_selenium
|
9
|
+
Capybara.server_port ||= '3001'
|
10
|
+
Capybara.app_host ||= "http://localhost:#{Capybara.server_port}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Capybara.register_driver :persistent_selenium do |app|
|
15
|
+
require 'drb'
|
16
|
+
|
17
|
+
DRb.start_service
|
18
|
+
browser = DRbObject.new nil, PersistentSelenium.url
|
19
|
+
|
20
|
+
server = Capybara::Server.new(app)
|
21
|
+
server.boot
|
22
|
+
|
23
|
+
browser.set_app_host(Capybara.app_host)
|
24
|
+
browser
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "persistent_selenium/version"
|
2
|
+
|
3
|
+
module PersistentSelenium
|
4
|
+
class << self
|
5
|
+
attr_writer :port, :browser
|
6
|
+
|
7
|
+
def port
|
8
|
+
@port ||= 9854
|
9
|
+
end
|
10
|
+
|
11
|
+
def browser
|
12
|
+
@browser ||= :firefox
|
13
|
+
end
|
14
|
+
|
15
|
+
def url
|
16
|
+
"druby://localhost:#{port}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure
|
20
|
+
yield self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/persistent_selenium/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["John Bintz"]
|
6
|
+
gem.email = ["john@coswellproductions.com"]
|
7
|
+
gem.description = %q{Keep your Selenium browser open while you use Capybara to talk to it. Save seconds and sanity.}
|
8
|
+
gem.summary = %q{Keep your Selenium browser open while you use Capybara to talk to it. Save seconds and sanity.}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "persistent_selenium"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = PersistentSelenium::VERSION
|
17
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# get the driver ready for use
|
2
|
+
require 'persistent_selenium/driver'
|
3
|
+
|
4
|
+
# set it for all tests
|
5
|
+
# Capybara.default_driver = Capybara.javascript_driver = :persistent_selenium
|
6
|
+
#
|
7
|
+
# or, set it via the ENV, with it being the default
|
8
|
+
# Before do
|
9
|
+
# Capybara.default_driver = Capybara.javascript_driver = (ENV['DRIVER'] || 'persistent_selenium').to_sym
|
10
|
+
# end
|
11
|
+
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: persistent_selenium
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- John Bintz
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-09 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Keep your Selenium browser open while you use Capybara to talk to it.
|
15
|
+
Save seconds and sanity.
|
16
|
+
email:
|
17
|
+
- john@coswellproductions.com
|
18
|
+
executables:
|
19
|
+
- persistent_selenium
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- .gitignore
|
24
|
+
- Gemfile
|
25
|
+
- LICENSE
|
26
|
+
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- bin/persistent_selenium
|
29
|
+
- lib/persistent_selenium.rb
|
30
|
+
- lib/persistent_selenium/browser.rb
|
31
|
+
- lib/persistent_selenium/cli.rb
|
32
|
+
- lib/persistent_selenium/driver.rb
|
33
|
+
- lib/persistent_selenium/version.rb
|
34
|
+
- persistent_selenium.gemspec
|
35
|
+
- skel/features/support/persistent_selenium.rb
|
36
|
+
homepage: ''
|
37
|
+
licenses: []
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.8.25
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: Keep your Selenium browser open while you use Capybara to talk to it. Save
|
60
|
+
seconds and sanity.
|
61
|
+
test_files: []
|