require "capybara" require "capybara/webkit/version" require "capybara/webkit/node" require "capybara/webkit/connection" require "capybara/webkit/browser" require "capybara/webkit/cookie_jar" require "capybara/webkit/errors" require "capybara/webkit/server" module Capybara::Webkit class Driver < Capybara::Driver::Base def initialize(app, options={}) @app = app @options = options.dup @options[:server] ||= Server.new(options) @browser = options[:browser] || Browser.new(Connection.new(@options)) apply_options end def enable_logging deprecate_and_replace_with_config "enable_logging", "debug = true" @browser.enable_logging end def allow_url(url) deprecate_and_replace_with_config "allow_url", "allow_url(#{url.inspect})" @browser.allow_url(url) end def block_url(url) deprecate_and_replace_with_config "block_url", "block_url(#{url.inspect})" @browser.block_url(url) end def block_unknown_urls deprecate_and_replace_with_config "block_unknown_urls" @browser.block_unknown_urls end def allow_unknown_urls deprecate_and_replace_with_config "allow_unknown_urls" @browser.allow_url("*") end def current_url @browser.current_url end def visit(path) @browser.visit(path) end def find_xpath(xpath) @browser. find_xpath(xpath). map { |native| Node.new(self, native, @browser) } end alias_method :find, :find_xpath def find_css(selector) @browser. find_css(selector). map { |native| Node.new(self, native, @browser) } end def html @browser.body end def header(key, value) @browser.header(key, value) end def title @browser.title end def execute_script(script, *args) value = @browser.execute_script(script, *encode_args(args)) if value.empty? nil else value end end def evaluate_script(script, *args) result = @browser.evaluate_script(script, *encode_args(args)) decode_result(result) end def console_messages @browser.console_messages end def error_messages @browser.error_messages end def alert_messages warn '[DEPRECATION] Capybara::Webkit::Driver#alert_messages ' \ 'is deprecated. Please use Capybara::Session#accept_alert instead.' @browser.alert_messages end def confirm_messages warn '[DEPRECATION] Capybara::Webkit::Driver#confirm_messages ' \ 'is deprecated. Please use Capybara::Session#accept_confirm ' \ 'or Capybara::Session#dismiss_confirm instead.' @browser.confirm_messages end def prompt_messages warn '[DEPRECATION] Capybara::Webkit::Driver#prompt_messages ' \ 'is deprecated. Please use Capybara::Session#accept_prompt ' \ 'or Capybara::Session#dismiss_prompt instead.' @browser.prompt_messages end def response_headers @browser.response_headers end def status_code @browser.status_code end def resize_window(width, height) warn '[DEPRECATION] Capybara::Webkit::Driver#resize_window ' \ 'is deprecated. Please use Capybara::Window#resize_to instead.' resize_window_to(current_window_handle, width, height) end def resize_window_to(handle, width, height) @browser.window_resize(handle, width, height) end def window_size(handle) @browser.window_size(handle) end def within_frame(selector) @browser.frame_focus(selector) begin yield ensure @browser.frame_focus end end def switch_to_frame(frame) case frame when :top begin loop { @browser.frame_focus } rescue Capybara::Webkit::InvalidResponseError => e raise unless e.message =~ /Already at parent frame/ end when :parent @browser.frame_focus else @browser.frame_focus(frame) end end def within_window(selector) current_window = current_window_handle switch_to_window(selector) begin yield ensure @browser.window_focus(current_window) end end def switch_to_window(selector) @browser.window_focus(selector) end def window_handles @browser.get_window_handles end def current_window_handle @browser.get_window_handle end def open_new_window @browser.window_open end def close_window(selector) @browser.window_close(selector) end def maximize_window(selector) @browser.window_maximize(selector) end def accept_js_confirms! warn '[DEPRECATION] Capybara::Webkit::Driver#accept_js_confirms! ' \ 'is deprecated. Please use Capybara::Session#accept_confirm instead.' @browser.accept_js_confirms end def dismiss_js_confirms! warn '[DEPRECATION] Capybara::Webkit::Driver#dismiss_js_confirms! ' \ 'is deprecated. Please use Capybara::Session#dismiss_confirm instead.' @browser.reject_js_confirms end def accept_js_prompts! warn '[DEPRECATION] Capybara::Webkit::Driver#accept_js_prompts! ' \ 'is deprecated. Please use Capybara::Session#accept_prompt instead.' @browser.accept_js_prompts end def dismiss_js_prompts! warn '[DEPRECATION] Capybara::Webkit::Driver#dismiss_js_prompts! ' \ 'is deprecated. Please use Capybara::Session#dismiss_prompt instead.' @browser.reject_js_prompts end def js_prompt_input=(value) warn '[DEPRECATION] Capybara::Webkit::Driver#js_prompt_input= ' \ 'is deprecated. Please use Capybara::Session#accept_prompt instead.' if value.nil? @browser.clear_prompt_text else @browser.set_prompt_text_to(value) end end def go_back @browser.go_back end def go_forward @browser.go_forward end def accept_modal(type, options={}) options = modal_action_options_for_browser(options) case type when :confirm id = @browser.accept_confirm(options) when :prompt id = @browser.accept_prompt(options) else id = @browser.accept_alert(options) end yield find_modal(type, id, options) end def dismiss_modal(type, options={}) options = modal_action_options_for_browser(options) case type when :confirm id = @browser.reject_confirm(options) else id = @browser.reject_prompt(options) end yield find_modal(type, id, options) end def wait? true end def needs_server? true end def reset! @browser.reset! apply_options end def has_shortcircuit_timeout? false end def save_screenshot(path, options={}) options[:width] ||= 1000 options[:height] ||= 10 @browser.render path, options[:width], options[:height] end def cookies @cookie_jar ||= CookieJar.new(@browser) end def set_cookie(cookie) @browser.set_cookie(cookie) end def clear_cookies @browser.clear_cookies end def invalid_element_errors [Capybara::Webkit::ClickFailed, Capybara::Webkit::NodeNotAttachedError] end def no_such_window_error Capybara::Webkit::NoSuchWindowError end def version [ "Capybara: #{Capybara::VERSION}", "capybara-webkit: #{Capybara::Driver::Webkit::VERSION}", @browser.version ].join("\n") end def authenticate(username, password) @browser.authenticate(username, password) end def timeout deprecate_and_replace_with_config "timeout" @browser.timeout end def timeout=(timeout) deprecate_and_replace_with_config( "timeout=", "timeout = #{timeout.inspect}" ) @browser.timeout = timeout end def browser warn "[DEPRECATION] Capybara::Webkit::Driver#browser is deprecated." @browser end private def modal_action_options_for_browser(options) if options[:text].is_a?(Regexp) options.merge(text: options[:text].source) else options.merge(text: Regexp.escape(options[:text].to_s)) end.merge(original_text: options[:text]) end def default_wait_time Capybara.respond_to?(:default_max_wait_time) ? Capybara.default_max_wait_time : Capybara.default_wait_time end def find_modal(type, id, options) Timeout::timeout(options[:wait] || default_wait_time) do @browser.find_modal(id) end rescue ModalNotFound raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{options[:original_text]}" if options[:original_text]}" rescue Timeout::Error raise Capybara::ModalNotFound, "Timed out waiting for modal dialog#{" with #{options[:original_text]}" if options[:original_text]}" end def apply_options if @options[:debug] @browser.enable_logging end if @options[:block_unknown_urls] @browser.block_unknown_urls end if @options[:ignore_ssl_errors] @browser.ignore_ssl_errors end if @options[:skip_image_loading] @browser.set_skip_image_loading(true) end if @options[:proxy] @browser.set_proxy(@options[:proxy]) end if @options[:timeout] @browser.timeout = @options[:timeout] end if @options.has_key? :raise_javascript_errors @browser.set_raise_javascript_errors(@options[:raise_javascript_errors]) end Array(@options[:allowed_urls]).each { |url| @browser.allow_url(url) } Array(@options[:blocked_urls]).each { |url| @browser.block_url(url) } end def deprecate_and_replace_with_config(deprecated_method, config_syntax = deprecated_method) warn "[DEPRECATION] #{deprecated_method} is deprecated. " \ "Please use Capybara::Webkit.configure instead:\n\n" \ " Capybara::Webkit.configure do |config|\n" \ " config.#{config_syntax}\n" \ " end\n\n" \ "This option is global and can be configured once" \ " (not in a `before` or `setup` block)." end def encode_args(args) args.map do |arg| if arg.is_a?(Capybara::Webkit::Node) { 'element-581e-422e-8be1-884c4e116226' => arg.native }.to_json else arg.to_json end end end def decode_result(result) case result when Array result.map { |r| decode_result(r) } when Hash if element_ref = result['element-581e-422e-8be1-884c4e116226'] Capybara::Webkit::Node.new(self, element_ref, @browser) else result.each { |k,v| result[k] = decode_result(v) } end else result end end end end