terminus 0.2.0 → 0.3.0
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 +27 -89
- data/bin/terminus +7 -23
- data/lib/capybara/driver/terminus.rb +30 -11
- data/lib/terminus.rb +33 -22
- data/lib/terminus/application.rb +13 -7
- data/lib/terminus/browser.rb +110 -28
- data/lib/terminus/controller.rb +51 -20
- data/lib/terminus/host.rb +22 -0
- data/lib/terminus/node.rb +23 -4
- data/lib/terminus/proxy.rb +62 -0
- data/lib/terminus/proxy/driver_body.rb +63 -0
- data/lib/terminus/proxy/external.rb +25 -0
- data/lib/terminus/proxy/rewrite.rb +20 -0
- data/lib/terminus/public/icon.png +0 -0
- data/lib/terminus/public/loader.js +1 -0
- data/lib/terminus/public/style.css +43 -0
- data/lib/terminus/public/syn/browsers.js +150 -0
- data/lib/terminus/public/syn/drag/drag.js +322 -0
- data/lib/terminus/public/syn/key.js +905 -0
- data/lib/terminus/public/syn/mouse.js +284 -0
- data/lib/terminus/public/syn/synthetic.js +830 -0
- data/lib/{public → terminus/public}/terminus.js +109 -40
- data/lib/terminus/server.rb +5 -12
- data/lib/terminus/timeouts.rb +2 -2
- data/lib/{views/bookmarklet.erb → terminus/views/bootstrap.erb} +17 -12
- data/lib/terminus/views/index.erb +21 -0
- data/lib/terminus/views/infinite.html +16 -0
- data/spec/reports/chrome.txt +748 -0
- data/spec/reports/firefox.txt +748 -0
- data/spec/reports/opera.txt +748 -0
- data/spec/reports/safari.txt +748 -0
- data/spec/spec_helper.rb +18 -14
- data/spec/terminus_driver_spec.rb +7 -5
- data/spec/terminus_session_spec.rb +5 -18
- metadata +71 -57
- data/lib/public/loader.js +0 -1
- data/lib/public/style.css +0 -49
- data/lib/public/syn.js +0 -2355
- data/lib/views/index.erb +0 -32
data/README.rdoc
CHANGED
@@ -1,112 +1,50 @@
|
|
1
1
|
= Terminus
|
2
2
|
|
3
|
-
* http://
|
3
|
+
* http://terminus.jcoglan.com
|
4
4
|
|
5
5
|
Terminus is an experimental Capybara driver implemented in client-side
|
6
|
-
JavaScript. It lets you script your application in any browser on any
|
7
|
-
|
8
|
-
|
6
|
+
JavaScript. It lets you script your application in any browser on any device,
|
7
|
+
without needing browser plugins. This allows several types of testing to be
|
8
|
+
automated:
|
9
9
|
|
10
10
|
* Cross-browser testing
|
11
11
|
* Multi-browser interaction e.g. messaging apps
|
12
|
-
*
|
13
|
-
|
14
|
-
It is also a remote scripting tool, giving you a REPL that lets you
|
15
|
-
run JavaScript in any number of browsers at once.
|
16
|
-
|
17
|
-
|
18
|
-
== Usage
|
19
|
-
|
20
|
-
Terminus is a Capybara driver. For the most part, you will not use
|
21
|
-
it directly: you will use the Capybara API and it will send instructions
|
22
|
-
to Terminus for execution. To set Terminus as your driver:
|
23
|
-
|
24
|
-
require 'capybara'
|
25
|
-
require 'terminus'
|
26
|
-
|
27
|
-
Capybara.current_driver = :terminus
|
28
|
-
|
29
|
-
Terminus does require some extra setup before you can use it to control
|
30
|
-
your app. First up, you need to start the Terminus server on the machine
|
31
|
-
where your application will be running:
|
32
|
-
|
33
|
-
$ terminus
|
34
|
-
|
35
|
-
This starts the server on port 7004. Now open a browser at
|
36
|
-
http://127.0.0.1:7004/. (I recommend using the IP address of the Terminus
|
37
|
-
host; Chrome has bugs that can stop WebSockets working if you use the
|
38
|
-
hostname.) This is the 'holding page'. A browser is said to be 'docked'
|
39
|
-
while it is visiting this page, meaning it is ready and waiting to run
|
40
|
-
some tests for you.
|
41
|
-
|
42
|
-
To let Terminus control your app's pages, you need to include this
|
43
|
-
just before the closing +body+ tag when in testing mode:
|
44
|
-
|
45
|
-
<!-- For example if you're using Rails -->
|
46
|
-
|
47
|
-
<% if Rails.env.test? %>
|
48
|
-
<%= Terminus.driver_script '127.0.0.1' %>
|
49
|
-
<% end %>
|
50
|
-
|
51
|
-
If the browser you're using is on a different machine to the Terminus
|
52
|
-
server, replace <tt>127.0.0.1</tt> with the Terminus machine's IP as
|
53
|
-
seen by the browser. For example if I'm running the browser in VirtualBox
|
54
|
-
and the Terminus server on the host OS, then I set the IP to <tt>10.0.2.2</tt>.
|
55
|
-
You could also use <tt>request.host</tt> to get the right IP automatically
|
56
|
-
if you're running your app and your Terminus server on the same machine.
|
57
|
-
|
58
|
-
Finally, in your tests you need to make sure there's a docked browser
|
59
|
-
and select it. In a 'before' block, run the following:
|
60
|
-
|
61
|
-
Terminus.ensure_docked_browser
|
62
|
-
Terminus.browser = :docked
|
63
|
-
|
64
|
-
After each test is finished, you need to return the browser to the
|
65
|
-
holding page to make it ready to accept new work. In an 'after' block:
|
66
|
-
|
67
|
-
Terminus.return_to_dock
|
68
|
-
|
69
|
-
This returns all currently connected browsers to the holding page.
|
12
|
+
* Testing on remote machines, phones, iPads etc.
|
70
13
|
|
71
14
|
|
72
15
|
== Notes / to-do
|
73
16
|
|
74
|
-
* Support IE, which has no built-in XPath engine for querying the DOM.
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
* Allow <tt>Terminus.browser=</tt> to select browsers by name and
|
79
|
-
version so we can control multiple browsers at once.
|
17
|
+
* Support IE, which has no built-in XPath engine for querying the DOM. I'm
|
18
|
+
working on Pathology (see http://github.com/jcoglan/pathology) to try and fix
|
19
|
+
this but it's currently not fast enough.
|
80
20
|
|
81
|
-
* It's slow, especially at filling out forms. Use it to sanity-check
|
82
|
-
|
21
|
+
* It's slow, especially at filling out forms. Use it to sanity-check your
|
22
|
+
cross-browser code and JavaScript, not to test your whole app.
|
83
23
|
|
84
|
-
* It can be a little brittle, and occasionally there seem to be race
|
85
|
-
|
24
|
+
* It can be a little brittle, and occasionally there seem to be race conditions
|
25
|
+
when running the Capybara specs.
|
86
26
|
|
87
27
|
|
88
28
|
== License
|
89
29
|
|
90
30
|
(The MIT License)
|
91
31
|
|
92
|
-
Copyright (c) 2010 James Coglan
|
32
|
+
Copyright (c) 2010-2011 James Coglan
|
93
33
|
|
94
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
the following conditions:
|
34
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
35
|
+
this software and associated documentation files (the 'Software'), to deal in
|
36
|
+
the Software without restriction, including without limitation the rights to use,
|
37
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
38
|
+
Software, and to permit persons to whom the Software is furnished to do so,
|
39
|
+
subject to the following conditions:
|
101
40
|
|
102
|
-
The above copyright notice and this permission notice shall be
|
103
|
-
|
41
|
+
The above copyright notice and this permission notice shall be included in all
|
42
|
+
copies or substantial portions of the Software.
|
104
43
|
|
105
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
44
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
45
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
46
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
47
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
48
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
49
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
112
50
|
|
data/bin/terminus
CHANGED
@@ -5,7 +5,7 @@ require 'oyster'
|
|
5
5
|
require File.expand_path(File.dirname(__FILE__) + '/../lib/terminus')
|
6
6
|
|
7
7
|
spec = Oyster.spec do
|
8
|
-
name "terminus --
|
8
|
+
name "terminus -- Control web browsers with Ruby"
|
9
9
|
synopsis "terminus [--port PORT]"
|
10
10
|
|
11
11
|
integer :port, :default => Terminus::DEFAULT_PORT
|
@@ -15,30 +15,14 @@ begin
|
|
15
15
|
options = spec.parse
|
16
16
|
app = Terminus.create(options)
|
17
17
|
|
18
|
-
app.run!
|
19
|
-
puts "Terminus server running on port #{options[:port]}"
|
20
|
-
puts "Press CTRL-C to exit"
|
21
|
-
puts ""
|
22
|
-
|
23
18
|
trap("INT") { app.stop! ; exit }
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
loop {
|
33
|
-
script, result = Readline.readline('>> '), nil
|
34
|
-
Readline::HISTORY.push(script)
|
35
|
-
app.execute(script) { |r| result = r }
|
36
|
-
}
|
37
|
-
rescue LoadError
|
38
|
-
puts "If you install the readline library, you'll get a console"
|
39
|
-
puts "that lets you execute JavaScript in connected browsers."
|
40
|
-
puts ""
|
41
|
-
end
|
20
|
+
Terminus.port = options[:port]
|
21
|
+
|
22
|
+
puts "Terminus server running on port #{Terminus.port}"
|
23
|
+
puts "Press CTRL-C to exit"
|
24
|
+
puts ""
|
25
|
+
app.run!
|
42
26
|
|
43
27
|
rescue Oyster::HelpRendered
|
44
28
|
end
|
@@ -1,30 +1,49 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
1
|
class Capybara::Driver::Terminus < Capybara::Driver::Base
|
4
|
-
|
2
|
+
attr_reader :options
|
3
|
+
|
4
|
+
def initialize(app = nil, options = {})
|
5
5
|
raise ArgumentError.new if app.nil?
|
6
|
-
|
6
|
+
|
7
|
+
@app = Terminus::Proxy[app]
|
8
|
+
@options = options
|
7
9
|
@rack_server = Capybara::Server.new(@app)
|
8
|
-
|
10
|
+
|
11
|
+
@rack_server.boot
|
12
|
+
end
|
13
|
+
|
14
|
+
def find(xpath)
|
15
|
+
browser.find(xpath, self)
|
9
16
|
end
|
10
17
|
|
11
18
|
def visit(path)
|
12
|
-
browser.visit
|
19
|
+
browser.visit(@rack_server.url(path))
|
13
20
|
end
|
14
21
|
|
15
22
|
extend Forwardable
|
16
23
|
def_delegators :browser, :body,
|
17
|
-
:current_path,
|
18
24
|
:current_url,
|
19
25
|
:evaluate_script,
|
20
26
|
:execute_script,
|
21
|
-
:find,
|
22
27
|
:reset!,
|
23
|
-
:
|
28
|
+
:response_headers,
|
29
|
+
:source,
|
30
|
+
:status_code
|
24
31
|
|
25
32
|
def within_window(name)
|
26
33
|
current_browser = browser
|
27
|
-
Terminus.browser =
|
34
|
+
Terminus.browser = browser.id + '/' + name
|
35
|
+
yield
|
36
|
+
Terminus.browser = current_browser
|
37
|
+
end
|
38
|
+
|
39
|
+
def within_frame(name)
|
40
|
+
frame_src = browser.frame_src(name)
|
41
|
+
frame = browser.frames.find do |frame|
|
42
|
+
frame.current_url == frame_src or
|
43
|
+
frame.current_path == frame_src
|
44
|
+
end
|
45
|
+
current_browser = browser
|
46
|
+
Terminus.browser = frame
|
28
47
|
yield
|
29
48
|
Terminus.browser = current_browser
|
30
49
|
end
|
@@ -32,7 +51,7 @@ class Capybara::Driver::Terminus < Capybara::Driver::Base
|
|
32
51
|
private
|
33
52
|
|
34
53
|
def browser
|
35
|
-
Terminus.
|
54
|
+
Terminus.ensure_browsers
|
36
55
|
Terminus.browser
|
37
56
|
end
|
38
57
|
end
|
data/lib/terminus.rb
CHANGED
@@ -1,38 +1,39 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require 'uri'
|
3
|
-
require 'rubygems'
|
4
3
|
require 'rack'
|
5
4
|
require 'thin'
|
6
5
|
require 'eventmachine'
|
7
6
|
require 'faye'
|
8
|
-
require 'capybara'
|
9
7
|
require 'sinatra'
|
10
8
|
require 'packr'
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
%w[ application
|
15
|
-
server
|
16
|
-
timeouts
|
17
|
-
controller
|
18
|
-
browser
|
19
|
-
node
|
20
|
-
|
21
|
-
].each do |file|
|
22
|
-
require File.join(root, 'terminus', file)
|
23
|
-
end
|
24
|
-
|
25
|
-
require root + '/capybara/driver/terminus'
|
9
|
+
require 'capybara'
|
10
|
+
require 'rack-proxy'
|
11
|
+
require 'useragent'
|
26
12
|
|
27
13
|
Thin::Logging.silent = true
|
28
14
|
|
29
15
|
module Terminus
|
30
|
-
VERSION = '0.2.0'
|
31
16
|
FAYE_MOUNT = '/messaging'
|
32
17
|
DEFAULT_HOST = 'localhost'
|
33
18
|
DEFAULT_PORT = 7004
|
19
|
+
LOCALHOST = /^(localhost|0\.0\.0\.0|127\.0\.0\.1)$/
|
20
|
+
RETRY_LIMIT = 3
|
21
|
+
|
22
|
+
ROOT = File.expand_path(File.dirname(__FILE__))
|
23
|
+
autoload :Application, ROOT + '/terminus/application'
|
24
|
+
autoload :Browser, ROOT + '/terminus/browser'
|
25
|
+
autoload :Controller, ROOT + '/terminus/controller'
|
26
|
+
autoload :Host, ROOT + '/terminus/host'
|
27
|
+
autoload :Node, ROOT + '/terminus/node'
|
28
|
+
autoload :Proxy, ROOT + '/terminus/proxy'
|
29
|
+
autoload :Server, ROOT + '/terminus/server'
|
30
|
+
autoload :Timeouts, ROOT + '/terminus/timeouts'
|
31
|
+
|
32
|
+
require ROOT + '/capybara/driver/terminus'
|
34
33
|
|
35
34
|
class << self
|
35
|
+
attr_accessor :debug
|
36
|
+
|
36
37
|
def create(options = {})
|
37
38
|
Server.new(options)
|
38
39
|
end
|
@@ -42,7 +43,7 @@ module Terminus
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def endpoint(host = DEFAULT_HOST)
|
45
|
-
"http://#{host}:#{
|
46
|
+
"http://#{host}:#{port}#{FAYE_MOUNT}"
|
46
47
|
end
|
47
48
|
|
48
49
|
def ensure_reactor_running
|
@@ -50,12 +51,22 @@ module Terminus
|
|
50
51
|
while not EM.reactor_running?; end
|
51
52
|
end
|
52
53
|
|
54
|
+
def port
|
55
|
+
@port || DEFAULT_PORT
|
56
|
+
end
|
57
|
+
|
58
|
+
def port=(port)
|
59
|
+
@port = port.to_i
|
60
|
+
end
|
61
|
+
|
53
62
|
extend Forwardable
|
54
63
|
def_delegators :controller, :browser,
|
64
|
+
:browsers,
|
55
65
|
:browser=,
|
56
|
-
:
|
57
|
-
:
|
58
|
-
:
|
66
|
+
:ensure_browsers,
|
67
|
+
:return_to_dock,
|
68
|
+
:rewrite_local,
|
69
|
+
:rewrite_remote
|
59
70
|
|
60
71
|
private
|
61
72
|
|
data/lib/terminus/application.rb
CHANGED
@@ -4,16 +4,16 @@ module Terminus
|
|
4
4
|
ROOT = File.expand_path(File.dirname(__FILE__) + '/../')
|
5
5
|
|
6
6
|
set :static, true
|
7
|
-
set :public, ROOT + '/public'
|
8
|
-
set :views, ROOT + '/views'
|
7
|
+
set :public, ROOT + '/terminus/public'
|
8
|
+
set :views, ROOT + '/terminus/views'
|
9
9
|
|
10
10
|
def self.driver_script(host)
|
11
|
-
%Q{<script type="text/javascript" src="http://#{host}:#{
|
11
|
+
%Q{<script type="text/javascript" src="http://#{host}:#{Terminus.port}/bootstrap.js"></script>}
|
12
12
|
end
|
13
13
|
|
14
14
|
helpers do
|
15
|
-
def
|
16
|
-
Packr.pack(erb(:
|
15
|
+
def bootstrap
|
16
|
+
Packr.pack(erb(:bootstrap), :shrink_vars => true)
|
17
17
|
end
|
18
18
|
|
19
19
|
def host
|
@@ -21,8 +21,14 @@ module Terminus
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
get
|
25
|
-
|
24
|
+
get '/' do
|
25
|
+
erb :index
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/bootstrap.js' do
|
29
|
+
headers 'Content-Type' => 'text/javascript'
|
30
|
+
bootstrap
|
31
|
+
end
|
26
32
|
|
27
33
|
end
|
28
34
|
end
|
data/lib/terminus/browser.rb
CHANGED
@@ -3,19 +3,36 @@ module Terminus
|
|
3
3
|
|
4
4
|
include Timeouts
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
extend Forwardable
|
7
|
+
def_delegator :@user_agent, :browser, :name
|
8
|
+
def_delegators :@user_agent, :os, :version
|
8
9
|
|
9
10
|
def initialize(controller)
|
10
|
-
@controller
|
11
|
-
@attributes
|
12
|
-
@docked
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@results
|
11
|
+
@controller = controller
|
12
|
+
@attributes = {}
|
13
|
+
@docked = false
|
14
|
+
@frames = Set.new
|
15
|
+
@namespace = Faye::Namespace.new
|
16
|
+
@results = {}
|
17
|
+
|
16
18
|
add_timeout(:dead, Timeouts::TIMEOUT) { drop_dead! }
|
17
19
|
end
|
18
20
|
|
21
|
+
def ===(params)
|
22
|
+
return docked? if params == :docked
|
23
|
+
return params == id if String === params
|
24
|
+
return false if @parent
|
25
|
+
return false unless @user_agent
|
26
|
+
|
27
|
+
params.all? do |name, value|
|
28
|
+
property = __send__(name).to_s
|
29
|
+
case value
|
30
|
+
when Regexp then property =~ value
|
31
|
+
when String then property == value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
19
36
|
def ask(command, retries = RETRY_LIMIT)
|
20
37
|
id = tell(command)
|
21
38
|
result_hash = wait_with_timeout(:result) { result(id) }
|
@@ -29,17 +46,13 @@ module Terminus
|
|
29
46
|
ask([:body])
|
30
47
|
end
|
31
48
|
|
32
|
-
def source
|
33
|
-
ask([:source])
|
34
|
-
end
|
35
|
-
|
36
49
|
def current_path
|
37
50
|
return nil unless url = @attributes['url']
|
38
51
|
URI.parse(url).path
|
39
52
|
end
|
40
53
|
|
41
54
|
def current_url
|
42
|
-
@attributes['url']
|
55
|
+
@attributes['url'] || ''
|
43
56
|
end
|
44
57
|
|
45
58
|
def docked?
|
@@ -55,32 +68,67 @@ module Terminus
|
|
55
68
|
nil
|
56
69
|
end
|
57
70
|
|
58
|
-
def find(xpath)
|
59
|
-
ask([:find, xpath, false]).map { |id| Node.new(self, id) }
|
71
|
+
def find(xpath, driver = nil)
|
72
|
+
ask([:find, xpath, false]).map { |id| Node.new(self, id, driver) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def frame!(frame_browser)
|
76
|
+
@frames.add(frame_browser)
|
77
|
+
end
|
78
|
+
|
79
|
+
def frames
|
80
|
+
@frames.to_a
|
81
|
+
end
|
82
|
+
|
83
|
+
def frame_src(name)
|
84
|
+
ask([:frame_src, name])
|
60
85
|
end
|
61
86
|
|
62
87
|
def id
|
63
88
|
@attributes['id']
|
64
89
|
end
|
65
|
-
alias :name :id
|
66
90
|
|
67
91
|
def page_id
|
68
92
|
@attributes['page']
|
69
93
|
end
|
70
94
|
|
71
95
|
def ping!(message)
|
96
|
+
p message if Terminus.debug
|
72
97
|
remove_timeout(:dead)
|
73
98
|
add_timeout(:dead, Timeouts::TIMEOUT) { drop_dead! }
|
99
|
+
|
100
|
+
uri = @controller.rewrite_local(message['url'], @dock_host)
|
101
|
+
message['url'] = uri.to_s
|
102
|
+
|
74
103
|
@attributes = @attributes.merge(message)
|
104
|
+
@user_agent = UserAgent.parse(message['ua'])
|
75
105
|
detect_dock_host
|
106
|
+
|
107
|
+
@infinite_redirect = message['infinite']
|
108
|
+
|
109
|
+
if parent = message['parent']
|
110
|
+
@parent = Terminus.browser(parent)
|
111
|
+
@parent.frame!(self) unless @parent == self
|
112
|
+
end
|
113
|
+
|
76
114
|
@ping = true
|
77
115
|
end
|
78
116
|
|
79
117
|
def reset!
|
80
|
-
|
118
|
+
if url = @attributes['url']
|
119
|
+
uri = URI.parse(url)
|
120
|
+
visit("http://#{uri.host}:#{uri.port}")
|
121
|
+
end
|
122
|
+
ask([:clear_cookies])
|
123
|
+
@attributes.delete('url')
|
124
|
+
end
|
125
|
+
|
126
|
+
def response_headers
|
127
|
+
evaluate_script('TERMINUS_HEADERS')
|
81
128
|
end
|
82
129
|
|
83
130
|
def result!(message)
|
131
|
+
p message if Terminus.debug
|
84
132
|
@results[message['commandId']] = message['result']
|
85
133
|
end
|
86
134
|
|
@@ -90,19 +138,36 @@ module Terminus
|
|
90
138
|
end
|
91
139
|
|
92
140
|
def return_to_dock
|
93
|
-
visit "http://#{@
|
141
|
+
visit "http://#{@dock_host}:#{Terminus.port}/"
|
142
|
+
end
|
143
|
+
|
144
|
+
def source
|
145
|
+
evaluate_script('TERMINUS_SOURCE')
|
146
|
+
end
|
147
|
+
|
148
|
+
def status_code
|
149
|
+
evaluate_script('TERMINUS_STATUS')
|
94
150
|
end
|
95
151
|
|
96
152
|
def tell(command)
|
97
153
|
id = @namespace.generate
|
154
|
+
p [id, command] if Terminus.debug
|
98
155
|
messenger.publish(channel, 'command' => command, 'commandId' => id)
|
99
156
|
id
|
100
157
|
end
|
101
158
|
|
102
159
|
def visit(url, retries = RETRY_LIMIT)
|
103
|
-
|
104
|
-
|
160
|
+
close_frames!
|
161
|
+
uri = @controller.rewrite_remote(url, @dock_host)
|
162
|
+
uri.host = @dock_host if uri.host =~ LOCALHOST
|
163
|
+
tell([:visit, uri.to_s])
|
105
164
|
wait_for_ping
|
165
|
+
|
166
|
+
if @infinite_redirect
|
167
|
+
@infinite_redirect = nil
|
168
|
+
raise Capybara::InfiniteRedirectError
|
169
|
+
end
|
170
|
+
|
106
171
|
rescue Timeouts::TimeoutError => e
|
107
172
|
raise e if retries.zero?
|
108
173
|
visit(url, retries - 1)
|
@@ -113,22 +178,39 @@ module Terminus
|
|
113
178
|
wait_with_timeout(:ping) { @ping or @dead }
|
114
179
|
end
|
115
180
|
|
181
|
+
def to_s
|
182
|
+
"<#{self.class.name} #{name} #{version} (#{os})>"
|
183
|
+
end
|
184
|
+
alias :inspect :to_s
|
185
|
+
|
186
|
+
protected
|
187
|
+
|
188
|
+
def drop_dead!
|
189
|
+
remove_timeout(:dead)
|
190
|
+
close_frames!
|
191
|
+
@dead = true
|
192
|
+
@controller.drop_browser(self)
|
193
|
+
end
|
194
|
+
|
116
195
|
private
|
117
196
|
|
118
197
|
def channel
|
119
198
|
"/terminus/clients/#{id}"
|
120
199
|
end
|
121
200
|
|
122
|
-
def
|
123
|
-
|
124
|
-
|
125
|
-
@docked = true
|
126
|
-
@controller.dock_host = uri.host
|
201
|
+
def close_frames!
|
202
|
+
@frames.each { |frame| frame.drop_dead! }
|
203
|
+
@frames = Set.new
|
127
204
|
end
|
128
205
|
|
129
|
-
def
|
130
|
-
|
131
|
-
|
206
|
+
def detect_dock_host
|
207
|
+
uri = URI.parse(@attributes['url'])
|
208
|
+
if uri.port == Terminus.port
|
209
|
+
@docked = true
|
210
|
+
@dock_host = uri.host
|
211
|
+
else
|
212
|
+
@docked = false
|
213
|
+
end
|
132
214
|
end
|
133
215
|
|
134
216
|
def messenger
|