Bugfixing for windows API (primarily switch_to_window and within_window)

This commit is contained in:
Andrey Botalov 2014-04-09 11:22:17 +03:00
parent adda9b0acd
commit c157ef4e61
6 changed files with 67 additions and 28 deletions

View File

@ -363,14 +363,15 @@ module Capybara
##
# @overload switch_to_window(&block)
# Switches to the first window for which given block returns a value other than false or nil.
# If window that matches block can't be found, the window will be switched back and `WindowError` will be raised.
# @example
# window = switch_to_window { title == 'Page title' }
# @return [Capybara::Window] window that has been switched to
# @raise [Capybara::WindowError] if no window matches given block
# @overload switch_to_window(window)
# @param window [Capybara::Window] window that should be switched to
# @raise [Capybara::Driver::Base#no_such_window_error] if unexistent (e.g. closed) window was passed
#
# @return [Capybara::Window] window that has been switched to
# @raise [Capybara::ScopeError] if this method is invoked inside `within`,
# `within_frame` or `within_window` methods
# @raise [ArgumentError] if both or neither arguments were provided
@ -388,14 +389,23 @@ module Capybara
if window
driver.switch_to_window(window.handle)
window
else
driver.window_handles.each do |handle|
driver.switch_to_window handle
if yield
return Window.new(self, handle)
original_window_handle = driver.current_window_handle
begin
driver.window_handles.each do |handle|
driver.switch_to_window handle
if yield
return Window.new(self, handle)
end
end
rescue => e
driver.switch_to_window(original_window_handle)
raise e
else
driver.switch_to_window(original_window_handle)
raise Capybara::WindowError, "Could not find a window matching block/lambda"
end
raise Capybara::WindowError, "Could not find a window matching block/lambda"
end
end
@ -409,6 +419,7 @@ module Capybara
# @overload within_window(window) { do_something }
# @param [Capybara::Window] instance of Capybara::Window class
# that will be switched to
# @raise [driver#no_such_window_error] if unexistent (e.g. closed) window was passed
# @overload within_window(proc_or_lambda) { do_something }
# @param lambda [Proc] lambda. First window for which lambda
# returns a value other than false or nil will be switched to.
@ -421,7 +432,6 @@ module Capybara
#
# @raise [Capybara::ScopeError] if this method is invoked inside `within`,
# `within_frame` or `within_window` methods
# @raise [driver#no_such_window_error] if unexistent (e.g. closed) window was passed
# @return value returned by the block
#
def within_window(window_or_handle)
@ -429,20 +439,20 @@ module Capybara
original = current_window
begin
switch_to_window(window_or_handle) unless original == window_or_handle
scopes.push(nil)
scopes << nil
yield
ensure
scopes.pop if scopes.last.nil? # It will be not nil if closed window has been passed
@scopes = [nil]
switch_to_window(original) unless original == window_or_handle
end
elsif window_or_handle.is_a?(Proc)
original = current_window
switch_to_window { window_or_handle.call }
scopes << nil
begin
switch_to_window { window_or_handle.call }
scopes.push(nil)
yield
ensure
scopes.pop if scopes.last.nil?
@scopes = [nil]
switch_to_window(original)
end
else
@ -451,10 +461,10 @@ module Capybara
warn "DEPRECATION WARNING: Passing string argument to #within_window is deprecated. "\
"Pass window object or lambda. (called from #{file_line})"
begin
scopes.push(nil)
scopes << nil
driver.within_window(window_or_handle) { yield }
ensure
scopes.pop
@scopes = [nil]
end
end
end
@ -625,7 +635,7 @@ module Capybara
end
def scopes
@scopes ||= [document]
@scopes ||= [nil]
end
end
end

View File

@ -30,6 +30,17 @@ Capybara::SpecHelper.spec '#switch_to_window', requires: [:windows] do
@session.switch_to_window(window)
expect(['', 'about:blank']).to include(@session.title)
end
it "should raise error when closed window is passed" do
original_window = @session.current_window
new_window = @session.open_new_window
@session.switch_to_window(new_window)
new_window.close
@session.switch_to_window(original_window)
expect do
@session.switch_to_window(new_window)
end.to raise_error(@session.driver.no_such_window_error)
end
end
context "with block" do
@ -83,11 +94,21 @@ Capybara::SpecHelper.spec '#switch_to_window', requires: [:windows] do
end
end.to raise_error(Capybara::ScopeError, "`switch_to_window` is not supposed to be invoked from `within`'s, `within_frame`'s' or `within_window`'s' block.")
end
end
it "should raise error if window matching block wasn't found" do
expect do
@session.switch_to_window { @session.title == 'A title' }
end.to raise_error(Capybara::WindowError, "Could not find a window matching block/lambda")
it "should raise error if window matching block wasn't found" do
original = @session.current_window
expect do
@session.switch_to_window { @session.title == 'A title' }
end.to raise_error(Capybara::WindowError, "Could not find a window matching block/lambda")
expect(@session.current_window).to eq(original)
end
it "should switch to original window if error is raised inside block" do
original = @session.switch_to_window(@session.windows[1])
expect do
@session.switch_to_window { raise 'error' }
end.to raise_error(StandardError, 'error')
expect(@session.current_window).to eq(original)
end
end
end

View File

@ -18,7 +18,7 @@ Capybara::SpecHelper.spec '#window_opened_by', requires: [:windows] do
it 'should raise error if value of :wait is less than timeout' do
Capybara.using_wait_time 1 do
expect do
@session.window_opened_by(wait: 0.3) do
@session.window_opened_by(wait: 0.4) do
@session.find(:css, '#openWindowWithTimeout').click
end
end.to raise_error(Capybara::WindowError, zero_windows_message)
@ -27,7 +27,7 @@ Capybara::SpecHelper.spec '#window_opened_by', requires: [:windows] do
it 'should find window if value of :wait is more than timeout' do
Capybara.using_wait_time 0.1 do
window = @session.window_opened_by(wait: 0.9) do
window = @session.window_opened_by(wait: 1) do
@session.find(:css, '#openWindowWithTimeout').click
end
expect(window).to be_instance_of(Capybara::Window)
@ -37,7 +37,7 @@ Capybara::SpecHelper.spec '#window_opened_by', requires: [:windows] do
context 'without :wait option' do
it 'should raise error if default_wait_time is less than timeout' do
Capybara.using_wait_time 0.2 do
Capybara.using_wait_time 0.4 do
expect do
@session.window_opened_by do
@session.find(:css, '#openWindowWithTimeout').click
@ -47,7 +47,7 @@ Capybara::SpecHelper.spec '#window_opened_by', requires: [:windows] do
end
it 'should find window if default_wait_time is more than timeout' do
Capybara.using_wait_time 0.9 do
Capybara.using_wait_time 1 do
window = @session.window_opened_by do
@session.find(:css, '#openWindowWithTimeout').click
end

View File

@ -54,7 +54,7 @@ Capybara::SpecHelper.spec Capybara::Window, requires: [:windows] do
it 'should return false if window is closed' do
@session.switch_to_window(@other_window)
@other_window.close
expect(@other_window.current?).to be_false
expect(@other_window.current?).to eq(false)
end
end

View File

@ -42,11 +42,14 @@ Capybara::SpecHelper.spec '#within_window', requires: [:windows] do
window = (@session.windows - [@window]).first
expect do
@session.within_window(window) do
raise 'some error'
@session.within 'html' do
raise 'some error'
end
end
end.to raise_error(StandardError, 'some error')
expect(@session.current_window).to eq(@window)
expect(@session).to have_css('#doesNotOpenWindows')
expect(@session.send(:scopes)).to eq([nil])
end
it 'should raise error if closed window was passed' do
@ -59,7 +62,9 @@ Capybara::SpecHelper.spec '#within_window', requires: [:windows] do
raise 'should not be invoked'
end
end.to raise_error(@session.driver.no_such_window_error)
expect(@session.current_window).to eq(@window)
expect(@session).to have_css('#doesNotOpenWindows')
expect(@session.send(:scopes)).to eq([nil])
end
end
@ -86,7 +91,9 @@ Capybara::SpecHelper.spec '#within_window', requires: [:windows] do
expect(@session).to have_css('#divInPopupOne')
end
end.to raise_error(Capybara::WindowError, "Could not find a window matching block/lambda")
expect(@session.current_window).to eq(@window)
expect(@session).to have_css('#doesNotOpenWindows')
expect(@session.send(:scopes)).to eq([nil])
end
it "returns value from the block" do
@ -103,6 +110,7 @@ Capybara::SpecHelper.spec '#within_window', requires: [:windows] do
end
end.to raise_error(StandardError, 'some error')
expect(@session.current_window).to eq(@window)
expect(@session.send(:scopes)).to eq([nil])
end
end
@ -110,7 +118,7 @@ Capybara::SpecHelper.spec '#within_window', requires: [:windows] do
it "should warn" do
expect(@session).to receive(:warn).with("DEPRECATION WARNING: Passing string argument "\
"to #within_window is deprecated. Pass window object or lambda. "\
"(called from #{__FILE__}:114)").and_call_original
"(called from #{__FILE__}:122)").and_call_original
@session.within_window('firstPopup') {}
end

View File

@ -12,7 +12,7 @@
$('#openWindowWithTimeout').click(function(){
setTimeout(function(){
window.open('/popup_one', 'firstPopup');
}, 500);
}, 600);
return false;
});