使用Capybara,如何切换到具有“ _blank”目标链接的新窗口?


77

也许这实际上并不是我遇到的问题,但是似乎当我“ click_link”与target =“ _ blank”的链接时,会话会将焦点集中在当前窗口上。

因此,我要么希望能够切换到新窗口,要么就忽略_blank属性-本质上,我只是希望它实际转到链接所指示的页面,因此我可以确保它是正确的页面。

我使用webkit和硒驱动程序。


到目前为止,我已经提交了我的发现。一个更彻底的答案是极大的赞赏。

同样,这仅适用于硒-非常感谢webkit驱动程序的等效功能(或指出我自己可以在哪里发现它)。

Answers:



54

此解决方案仅适用于Selenium驱动程序

所有打开的窗口都在Selenium's

response.driver.browser.window_handles

这似乎是一个数组。最后一项始终是最近打开的窗口,这意味着您可以执行以下操作来切换到该窗口。

在一个块内:

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

只需重新调整当前会话的焦点即可:

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

在水豚问题页面上引用:https : //github.com/jnicklas/capybara/issues/173

有关Selenium的窗口切换功能的更多详细信息:http : //qastuffs.blogspot.com/2010/10/testing-pop-up-windows-using-selenium.html


4
这很好,但是第二个示例有点误导。session和之间没有区别page,因此session.driver.browserpage.driver.browser实际上是指同一件事。试图将其适应于不同的上下文,通过不同的库而不是使用DSL访问Capybara时,这使我感到困惑。我必须阅读Capybara DSL代码才能弄清楚要访问“页面”,我只需要访问会话即可。
史蒂夫·乔根森

@glyphgryph男孩,我爱,当解决方案仅适用于复制和粘贴时,不会产生所有额外的浪费。
nfriend21

3
它不仅适用于Selenium:within_window(page.driver.window_handles.last)还可以通过capybara-webkit与我一起使用。
Tony-Currentuser.io 2014年

2
如下所述,Capybara具有处理Windows的新语法:github.com/jnicklas/capybara#working-with-windows
Sarah

1
在水豚中不推荐使用此方法DEPRECATION WARNING: Passing string argument to #within_window is deprecated.
Aravin

11

现在正在与Poltergeist合作。尽管window_handles仍未实现(您需要一个窗口名称,即通过JavaScript弹出窗口):

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

编辑:根据下面的注释,Poltergeist现在window_handles1.4.0版本开始实施。


3
我刚刚尝试过page.within_window page.driver.browser.window_handles.last do ... ,它似乎在Poltergeist中按预期工作。无需提供窗口名称。因此,此答案可能需要更新。
thom_nic 2014年

1
Capybara 2.3不赞成使用within_windowString进行调用:DEPRECATION WARNING: Passing string argument to #within_window is deprecated. Pass window object or lambda.Andrey Botalov记录的方法解决了此不赞成使用的问题。
Dave Schweisguth,2015年

9

水豚提供了一些简化查找和切换窗口的方法:

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

此处有更多详细信息:Capybara文档


8

我知道这是旧帖子,但是在水豚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

7

似乎现在用capybara-webkit无法实现:https//github.com/thoughtbot/capybara-webkit/issues/271

:-(

同时https://github.com/thoughtbot/capybara-webkit/issues/129声称可以使用切换窗口within_window

同样https://github.com/thoughtbot/capybara-webkit/issues/47表示page.driver.browser.switch_to().window(page.driver.browser.window_handles.last)可行。嗯,继续阅读代码。

https://github.com/thoughtbot/capybara-webkit/blob/master/lib/capybara/webkit/browser.rb上的代码至少具有一些参考,这些建议表明适用于webdriver / firefox的API也适用于Webkit。


1
请参阅我对已接受答案的评论:within_window(page.driver.window_handles.last)与capybara-webkit一起适用于我。
Tony-Currentuser.io 2014年



4

这在capybara-webkit中对我有用:

within_window(windows.last) do
  # code here
end

(我正在使用capybara 2.4.1和capybara-webkit 1.3.0)


4

您还可以传递窗口的名称URL标题(但现在是其标题)

  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

您可以通过一个labdaPROC

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

希望它可以将方法的使用范围扩展到更清晰的基础


4

要显式更改窗口,请使用switch_to_window

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

之后的方法浏览器将在新页面中运行,而不是将所有内容包装在一个inner_window块中


3

在gmail窗口中打开链接时遇到了这个问题:我像这样修复它:

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

顺便说一句,您可以使用heredoc语法代替注释:page.execute_script <<-JS var alllinks = document.getElementsByTagName("a"); for (alllinksi=0; alllinksi<alllinks.length; alllinksi++) { alllinks[alllinksi].removeAttribute("target"); } JS 注释仅允许内联代码,因此请确保在“ JS”之前和之后都有换行符,但是您可以理解。这样,您就不必在两个地方管理代码,并且大多数编辑器仍然会突出显示它们。
大卫,


0

主要实现(window_opened_by)对我提出了一个错误:

*** Capybara::WindowError Exception: block passed to #window_opened_by opened 0 windows instead of 1

因此,我通过以下解决方案来解决它:

new_window = open_new_window

within_window new_window do
  visit(click_link 'Something')
end

page.driver.browser.window_handles
# => ["CDwindow-F7EF6D3C12B68D6B6A3DFC69C2790718", "CDwindow-9A026DEC65C3C031AF7D2BA12F28ADC7"]

0

我个人喜欢以下方法,因为无论是否启用JS,它都能正常工作。

我的规格:

  it "shows as expected" do
    visit my_path

    # ...test my non-JS stuff in the current tab

    switch_to_new_tab

    # ...test my non-JS stuff in the new tab
    
    # ...keep switching to new tabs as much as necessary
  end 

  # OR

  it "shows as expected", js: true do
    visit my_path

    # ...test my non-JS stuff in the current tab
    # ...also test my JS stuff in the current tab

    switch_to_new_tab

    # ...test my non-JS stuff in the new tab
    # ...also test my JS stuff in the new tab

    # ...keep switching to new tabs as much as necessary
  end 

测试助手:

  def switch_to_new_tab
    current_browser = page.driver.browser

    if js_enabled?
      current_browser.switch_to.window(current_browser.window_handles.last)
    else
      visit current_browser.last_request.fullpath
    end
  end

  def js_enabled?
    Capybara.current_driver == Capybara.javascript_driver
  end
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.