Perhaps this isn't actually the issue I'm experiencing, but it seems that when I "click_link" a link with target="_blank", the session keeps the focus on the current window.

So I either want to be able to switch to the new window, or to ignore the _blank attribute - essentially, I just want it to actually go to the page indicated by the link so I can make sure it's the right page.

I use the webkit and selenium drivers.


I submitted my findings thus far below. A more thorough answer is much appreciated.

Also, this only works with selenium - the equivalent for the webkit driver (or pointing out where I could discover it myself) would be much appreciated.

share|improve this question

13 Answers 13

up vote 53 down vote accepted

Capybara >= 2.3 includes the new window management API. It can be used like:

new_window = window_opened_by { click_link 'Something' }
within_window new_window do
  # code
end
share|improve this answer
3  
poltergeist 1.6 implements this API, so at this writing this is the way to go with poltergeist. – Dave Schweisguth Jun 30 '15 at 12:01

This solution only works for the Selenium driver

All open windows are stores in Selenium's

response.driver.browser.window_handles

Which seems to be an array. The last item is always the window that was most recently opened, meaning you can do the following to switch to it.

Within a block:

new_window=page.driver.browser.window_handles.last 
page.within_window new_window do
  #code
end

Simply refocus for current session:

session.driver.browser.switch_to.window(page.driver.browser.window_handles.last)

Referenced on the capybara issues page: https://github.com/jnicklas/capybara/issues/173

More details on Selenium's window switching capabilities: http://qastuffs.blogspot.com/2010/10/testing-pop-up-windows-using-selenium.html

share|improve this answer
4  
This is great, but the second example is a bit misleading. There is no difference between session and page, so session.driver.browser and page.driver.browser actually refer to the same thing. That messed me up while trying to adapt this to a different context, accessing Capybara through a different library, and not using the DSL. I had to read the Capybara DSL code to figure out that to access 'page`, I just need to access the session. – Steve Jorgensen Jul 9 '12 at 8:05
    
@glyphgryph boy I love when solutions just work with a copy & paste, sans all the extra waste. – nfriend21 Oct 29 '13 at 11:30
3  
It's not only for Selenium: within_window(page.driver.window_handles.last) works for me with capybara-webkit. – Tony - Currentuser.io May 2 '14 at 14:54
2  
As mentioned below, Capybara has a new syntax for dealing with windows: github.com/jnicklas/capybara#working-with-windows – Sarah Apr 1 '15 at 23:21
1  
This method is deprecated in capybara DEPRECATION WARNING: Passing string argument to #within_window is deprecated. – Aravin Nov 24 '15 at 11:31

This is now working with Poltergeist. Although window_handles is still not implemented (you need a window name, i.e. via a JavaScript popup):

within_window 'other_window' do
  current_url.should match /example.com/
end

Edit: Per comment below, Poltergeist now implements window_handles since version 1.4.0.

share|improve this answer
3  
I just tried page.within_window page.driver.browser.window_handles.last do ... and it appears to work as expected in Poltergeist. No need to give a window name. So this answer might need to be updated. – thom_nic Oct 27 '14 at 20:11
1  
Capybara 2.3 deprecates calling within_window with a String: DEPRECATION WARNING: Passing string argument to #within_window is deprecated. Pass window object or lambda. The method documented by Andrey Botalov fixes this deprecation. – Dave Schweisguth Jun 30 '15 at 12:12

Capybara provides some methods to ease finding and switching windows:

facebook_window = window_opened_by do
  click_button 'Like'
end
within_window facebook_window do
  find('#login_email').set('a@example.com')
  find('#login_password').set('qwerty')
  click_button 'Submit'
end

More details here: Capybara documentation

share|improve this answer

Seems like it is not possible with capybara-webkit right now: https://github.com/thoughtbot/capybara-webkit/issues/271

:-(

At the same time https://github.com/thoughtbot/capybara-webkit/issues/129 claims it is possible to switch windows with within_window.

Also https://github.com/thoughtbot/capybara-webkit/issues/47 suggests that page.driver.browser.switch_to().window(page.driver.browser.window_handles.last) works. Ah well, on to code reading.

The code at https://github.com/thoughtbot/capybara-webkit/blob/master/lib/capybara/webkit/browser.rb at least has some references that suggest that the API that works for webdriver / firefox is also working for webkit.

share|improve this answer
    
It's not working at all on capybara-webkit. – Chamnap Sep 30 '12 at 6:10
1  
See my comment on accepted answer: within_window(page.driver.window_handles.last) works for me with capybara-webkit. – Tony - Currentuser.io May 2 '14 at 14:56

Now within_window implemented for capybara-webkit http://github.com/thoughtbot/capybara-webkit/pull/314 and here you can see how to use it http://github.com/mhoran/capybara-webkit-demo

share|improve this answer

As of May 2014 the following code works on capybara-webkit

 within_window(page.driver.browser.window_handles.last) do
   expect(current_url).to eq('http://www.example.com/')
 end
share|improve this answer
    
page.driver.brower.window_handles.las is now deprecated. Use windows.last. See github.com/thoughtbot/capybara-webkit/issues/650 – smcgregor May 2 '16 at 1:43

I know this is old post, but for what its worth in capybara 2.4.4

within_window(switch_to_window(windows.last)) do 
    # in my case assert redirected url from a prior click action
    expect(current_url).to eq(redirect['url'])
end
share|improve this answer
1  
thanks for posting this anyways, stuff like this helps alot! – NickEckhart Mar 9 '15 at 15:27

This works for me in capybara-webkit:

within_window(windows.last) do
  # code here
end

(I'm using capybara 2.4.1 and capybara-webkit 1.3.0)

share|improve this answer

I had this issue when opening links in an gmail window: I fixed it like this:

Given /^(?:|I )click the "([^"]*)" link in email message$/ do |field|

  # var alllinks = document.getElementsByTagName("a");
  # for (alllinksi=0; alllinksi<alllinks.length; alllinksi++) {
  #   alllinks[alllinksi].removeAttribute("target");
  # }

  page.execute_script('var alllinks = document.getElementsByTagName("a"); for (alllinksi=0; alllinksi<alllinks.length; alllinksi++) { alllinks[alllinksi].removeAttribute("target"); }')

  within(:css, "div.msg") do
    click_link link_text
  end

end
share|improve this answer
    
BTW, instead of comments you could use heredoc syntax: page.execute_script <<-JS var alllinks = document.getElementsByTagName("a"); for (alllinksi=0; alllinksi<alllinks.length; alllinksi++) { alllinks[alllinksi].removeAttribute("target"); } JS Comments would only allow inline code, so make sure there are line breaks before and after "JS", but you get the idea. this way you don't have to manage code in two places and most editors will highlight them anyway. – David Feb 4 '16 at 18:05

You can pass a name, url or title of the window also (But now its dipricated)

  let(:product) { create :product }

  it 'tests' do
    visit products_path
    click_link(product.id)

    within_window(product_path(product)) do
      expect(page).to have_content(product.title)
    end
  end

You can pass a labda or a proc also

within_window(->{ page.title == 'Page title' }) do
  click_button 'Submit'
end

wish it stretches the method usage to more clearly understaing

share|improve this answer

The best idea is to update capybara to the latests version (2.4.1) and just use windows.last because page.driver.browser.window_handles is deprecated.

share|improve this answer

To explicitly change window, you use switch_to_window

  def terms_of_use
    terms_window = window_opened_by do
      click_link(@terms_link)
    end
    switch_to_window(terms_window)
  end

An after that method browser will work in the new page, instead of wrap everything in a within_window block

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.