From 91d6198523532e3e151d8c4278dc1d720c29e896 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 25 Feb 2012 12:47:18 +0000 Subject: [PATCH] Experimental remote debugger support. --- lib/capybara/poltergeist.rb | 1 + lib/capybara/poltergeist/browser.rb | 2 +- lib/capybara/poltergeist/client.rb | 55 ++++++++++++++++--- .../poltergeist/client/compiled/main.js | 1 + lib/capybara/poltergeist/client/main.coffee | 5 ++ lib/capybara/poltergeist/driver.rb | 3 +- lib/capybara/poltergeist/server.rb | 11 +--- lib/capybara/poltergeist/util.rb | 12 ++++ spec/spec_helper.rb | 6 +- 9 files changed, 75 insertions(+), 21 deletions(-) create mode 100644 lib/capybara/poltergeist/util.rb diff --git a/lib/capybara/poltergeist.rb b/lib/capybara/poltergeist.rb index ad2c054..7da9b31 100644 --- a/lib/capybara/poltergeist.rb +++ b/lib/capybara/poltergeist.rb @@ -9,6 +9,7 @@ module Capybara autoload :Server, 'capybara/poltergeist/server' autoload :WebSocketServer, 'capybara/poltergeist/web_socket_server' autoload :Client, 'capybara/poltergeist/client' + autoload :Util, 'capybara/poltergeist/util' require 'capybara/poltergeist/errors' end diff --git a/lib/capybara/poltergeist/browser.rb b/lib/capybara/poltergeist/browser.rb index cca65dd..7d9fa6c 100644 --- a/lib/capybara/poltergeist/browser.rb +++ b/lib/capybara/poltergeist/browser.rb @@ -9,7 +9,7 @@ module Capybara::Poltergeist def initialize(options = {}) @options = options @server = Server.new(options.fetch(:timeout, DEFAULT_TIMEOUT)) - @client = Client.start(server.port, options[:phantomjs]) + @client = Client.start(server.port, options[:inspector], options[:phantomjs]) end def timeout diff --git a/lib/capybara/poltergeist/client.rb b/lib/capybara/poltergeist/client.rb index 91ec8e6..1cd1944 100644 --- a/lib/capybara/poltergeist/client.rb +++ b/lib/capybara/poltergeist/client.rb @@ -2,11 +2,16 @@ require 'sfl' module Capybara::Poltergeist class Client - PHANTOMJS_SCRIPT = File.expand_path('../client/compiled/main.js', __FILE__) - PHANTOMJS_VERSION = '1.4.1' - PHANTOMJS_NAME = 'phantomjs' + INSPECTOR_BROWSERS = %w(chromium chromium-browser google-chrome safari) + PHANTOMJS_SCRIPT = File.expand_path('../client/compiled/main.js', __FILE__) + PHANTOMJS_VERSION = '1.4.1' + PHANTOMJS_NAME = 'phantomjs' - attr_reader :pid, :port, :path + def self.inspector_browser + @inspector_browser ||= INSPECTOR_BROWSERS.find do |name| + system "which #{name} &>/dev/null" + end + end def self.start(*args) client = new(*args) @@ -14,15 +19,23 @@ module Capybara::Poltergeist client end - def initialize(port, path = nil) - @port = port - @path = path || PHANTOMJS_NAME + attr_reader :pid, :port, :path, :inspector + + def initialize(port, inspector = false, path = nil) + @port = port + @inspector = inspector + @path = path || PHANTOMJS_NAME at_exit { stop } end def start check_phantomjs_version - @pid = Kernel.spawn("#{path} #{PHANTOMJS_SCRIPT} #{port}") + @pid = Kernel.spawn(command) + + # Opens a remote debugger for the phantomjs session. This feature + # is unfinished / experimental. When the debugger opens, you have + # to type __run() into the console to get it going. + Kernel.spawn(inspector_command) if inspector end def stop @@ -34,6 +47,32 @@ module Capybara::Poltergeist start end + def command + @command ||= begin + parts = [path] + parts << "--remote-debugger-port=#{inspector_port}" if inspector + parts << PHANTOMJS_SCRIPT + parts << port + parts.join(" ") + end + end + + def inspector_port + @inspector_port ||= Util.find_available_port + end + + def inspector_command + "#{inspector_browser} http://localhost:#{inspector_port}/webkit/inspector/inspector.html?page=1" + end + + def inspector_browser + if inspector == true + self.class.inspector_browser or raise "webkit browser not found; please specify it explicitly" + else + inspector + end + end + private def check_phantomjs_version diff --git a/lib/capybara/poltergeist/client/compiled/main.js b/lib/capybara/poltergeist/client/compiled/main.js index 43198bc..b9f3e3d 100644 --- a/lib/capybara/poltergeist/client/compiled/main.js +++ b/lib/capybara/poltergeist/client/compiled/main.js @@ -23,6 +23,7 @@ Poltergeist = (function() { }; return Poltergeist; })(); +window.Poltergeist = Poltergeist; Poltergeist.ObsoleteNode = (function() { function ObsoleteNode() {} ObsoleteNode.prototype.name = function() { diff --git a/lib/capybara/poltergeist/client/main.coffee b/lib/capybara/poltergeist/client/main.coffee index 3494293..41306bc 100644 --- a/lib/capybara/poltergeist/client/main.coffee +++ b/lib/capybara/poltergeist/client/main.coffee @@ -16,6 +16,11 @@ class Poltergeist sendResponse: (response) -> @connection.send(response: response) +# This is necessary because the remote debugger will wrap the +# script in a function, causing the Poltergeist variable to +# become local. +window.Poltergeist = Poltergeist + class Poltergeist.ObsoleteNode name: -> "Poltergeist.ObsoleteNode" args: -> [] diff --git a/lib/capybara/poltergeist/driver.rb b/lib/capybara/poltergeist/driver.rb index 41e17e3..f4fe496 100644 --- a/lib/capybara/poltergeist/driver.rb +++ b/lib/capybara/poltergeist/driver.rb @@ -14,7 +14,8 @@ module Capybara::Poltergeist def browser @browser ||= Browser.new( :logger => logger, - :phantomjs => options[:phantomjs] + :phantomjs => options[:phantomjs], + :inspector => options[:inspector] ) end diff --git a/lib/capybara/poltergeist/server.rb b/lib/capybara/poltergeist/server.rb index 3f9151a..c7c6aed 100644 --- a/lib/capybara/poltergeist/server.rb +++ b/lib/capybara/poltergeist/server.rb @@ -3,7 +3,7 @@ module Capybara::Poltergeist attr_reader :port, :socket, :timeout def initialize(timeout = nil) - @port = find_available_port + @port = Util.find_available_port @timeout = timeout start end @@ -24,14 +24,5 @@ module Capybara::Poltergeist def send(message) @socket.send(message) or raise DeadClient.new(message) end - - private - - def find_available_port - server = TCPServer.new('127.0.0.1', 0) - server.addr[1] - ensure - server.close if server - end end end diff --git a/lib/capybara/poltergeist/util.rb b/lib/capybara/poltergeist/util.rb new file mode 100644 index 0000000..737a8ed --- /dev/null +++ b/lib/capybara/poltergeist/util.rb @@ -0,0 +1,12 @@ +require 'socket' + +module Capybara::Poltergeist + module Util + def self.find_available_port + server = TCPServer.new('127.0.0.1', 0) + server.addr[1] + ensure + server.close if server + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4fdf61e..44ffd2e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -16,7 +16,11 @@ alias :running :lambda logger = SpecLogger.new Capybara.register_driver :poltergeist do |app| - Capybara::Poltergeist::Driver.new(app, :logger => logger) + Capybara::Poltergeist::Driver.new( + app, + :logger => logger, + :inspector => (ENV['DEBUG'] != nil) + ) end module TestSessions