Wie wechsle ich mit Capybara zum neuen Fenster für Links zu "_blank" -Zielen?

77

Vielleicht ist dies nicht das eigentliche Problem, aber es scheint, dass die Sitzung den Fokus auf das aktuelle Fenster behält, wenn ich einen Link mit target = "_ blank" "click_link" mache.

Ich möchte entweder in der Lage sein, zum neuen Fenster zu wechseln oder das Attribut _blank zu ignorieren. Im Wesentlichen möchte ich nur, dass es tatsächlich zu der durch den Link angegebenen Seite wechselt, damit ich sicherstellen kann, dass es die richtige Seite ist.

Ich benutze das Webkit und Selentreiber.


Ich habe meine bisherigen Ergebnisse unten eingereicht. Eine gründlichere Antwort wird sehr geschätzt.

Dies funktioniert auch nur mit Selen - das Äquivalent für den Webkit-Treiber (oder das Aufzeigen, wo ich es selbst entdecken könnte) wäre sehr dankbar.

GlyphGryph
quelle

Antworten:

87

Capybara> = 2.3 enthält die neue Fensterverwaltungs-API. Es kann verwendet werden wie:

new_window = window_opened_by { click_link 'Something' }
within_window new_window do
  # code
end
Andrei Botalov
quelle
3
poltergeist 1.6 implementiert diese API, daher ist dies bei diesem Schreiben der richtige Weg für poltergeist.
Dave Schweisguth
54

Diese Lösung funktioniert nur für den Selenium-Treiber

Alle offenen Fenster sind Geschäfte in Selenium

response.driver.browser.window_handles

Welches scheint ein Array zu sein. Das letzte Element ist immer das Fenster, das zuletzt geöffnet wurde. Sie können also wie folgt vorgehen, um dorthin zu wechseln.

Innerhalb eines Blocks:

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

Konzentrieren Sie sich einfach auf die aktuelle Sitzung:

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

Auf der Seite mit den Capybara-Problemen wird darauf verwiesen: https://github.com/jnicklas/capybara/issues/173

Weitere Informationen zu den Fensterumschaltfunktionen von Selenium: http://qastuffs.blogspot.com/2010/10/testing-pop-up-windows-using-selenium.html

GlyphGryph
quelle
4
Das ist großartig, aber das zweite Beispiel ist etwas irreführend. Es gibt keinen Unterschied zwischen sessionund page, also session.driver.browserund page.driver.browserbeziehen sich tatsächlich auf dasselbe. Das hat mich durcheinander gebracht, als ich versucht habe, dies an einen anderen Kontext anzupassen, über eine andere Bibliothek auf Capybara zuzugreifen und kein DSL zu verwenden. Ich musste den Capybara-DSL-Code lesen, um herauszufinden, dass ich für den Zugriff auf "Seite" nur auf die Sitzung zugreifen muss.
Steve Jorgensen
@glyphgryph Junge Ich liebe es, wenn Lösungen nur mit Copy & Paste funktionieren, ohne all den zusätzlichen Abfall.
nfriend21
3
Es ist nicht nur für Selen: within_window(page.driver.window_handles.last)funktioniert für mich mit Capybara-Webkit .
Tony - Currentuser.io
2
Wie unten erwähnt, hat Capybara eine neue Syntax für den Umgang mit Fenstern: github.com/jnicklas/capybara#working-with-windows
Sarah
1
Diese Methode ist in CapybaraDEPRECATION WARNING: Passing string argument to #within_window is deprecated.
Aravin
11

Dies funktioniert jetzt mit Poltergeist. Obwohl window_handlesnoch nicht implementiert (Sie benötigen einen Fensternamen, dh über ein JavaScript-Popup):

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

Bearbeiten: Gemäß Kommentar unten implementiert Poltergeist jetzt window_handlesseit Version 1.4.0 .

Kridsada Thanabulpong
quelle
3
Ich habe es gerade versucht page.within_window page.driver.browser.window_handles.last do ... und es scheint in Poltergeist wie erwartet zu funktionieren. Sie müssen keinen Fensternamen angeben. Daher muss diese Antwort möglicherweise aktualisiert werden.
thom_nic
1
Capybara 2.3 lehnt das Aufrufen within_windowmit einem String ab: DEPRECATION WARNING: Passing string argument to #within_window is deprecated. Pass window object or lambda.Die von Andrey Botalov dokumentierte Methode behebt diese Ablehnung.
Dave Schweisguth
9

Capybara bietet einige Methoden, um das Auffinden und Wechseln von Fenstern zu vereinfachen:

facebook_window = window_opened_by do
  click_button 'Like'
end
within_window facebook_window do
  find('#login_email').set('[email protected]')
  find('#login_password').set('qwerty')
  click_button 'Submit'
end

Weitere Details hier: Capybara-Dokumentation

Aravin
quelle
8

Ich weiß, dass dies ein alter Beitrag ist, aber wofür ist er in Capybara 2.4.4 wert?

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
bcar
quelle
7

Mit dem Capybara-Webkit scheint dies derzeit nicht möglich zu sein: https://github.com/thoughtbot/capybara-webkit/issues/271

:-(

Gleichzeitig behauptet https://github.com/thoughtbot/capybara-webkit/issues/129 , es sei möglich, mit Windows zu wechseln within_window.

Auch https://github.com/thoughtbot/capybara-webkit/issues/47 schlägt vor, dass dies page.driver.browser.switch_to().window(page.driver.browser.window_handles.last)funktioniert. Na ja, weiter zum Codelesen.

Der Code unter https://github.com/thoughtbot/capybara-webkit/blob/master/lib/capybara/webkit/browser.rb enthält zumindest einige Referenzen, die darauf hindeuten, dass die API, die für Webdriver / Firefox funktioniert, auch funktioniert Webkit.

user132837
quelle
1
Siehe meinen Kommentar zur akzeptierten Antwort: Funktioniert within_window(page.driver.window_handles.last)für mich mit Capybara-Webkit.
Tony - Currentuser.io
6

Ab Mai 2014 funktioniert der folgende Code auf dem Capybara-Webkit

 within_window(page.driver.browser.window_handles.last) do
   expect(current_url).to eq('http://www.example.com/')
 end
thekindofme
quelle
page.driver.brower.window_handles.lasist jetzt veraltet. Verwenden Sie windows.last. Siehe github.com/thoughtbot/capybara-webkit/issues/650
smcgregor
4

Das funktioniert bei mir im Capybara-Webkit:

within_window(windows.last) do
  # code here
end

(Ich benutze Capybara 2.4.1 und Capybara-Webkit 1.3.0)

lavaturtle
quelle
4

Sie können auch einen Namen , eine URL oder einen Titel des Fensters übergeben (aber jetzt ist es dipriciert).

  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

Sie können einen Pass labda oder eine proc auch

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

Ich wünschte, es würde die Methodenanwendung deutlicher verstehen

itsnikolay
quelle
4

Um das Fenster explizit zu ändern, verwenden Sie switch_to_window

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

Ein Browser nach dieser Methode funktioniert auf der neuen Seite, anstatt alles in einen Block inside_window zu packen

GI Joe
quelle
3

Ich hatte dieses Problem beim Öffnen von Links in einem Google Mail-Fenster: Ich habe es folgendermaßen behoben:

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
komplistisch
quelle
Übrigens könnten Sie anstelle von Kommentaren die Heredoc-Syntax verwenden: page.execute_script <<-JS var alllinks = document.getElementsByTagName("a"); for (alllinksi=0; alllinksi<alllinks.length; alllinksi++) { alllinks[alllinksi].removeAttribute("target"); } JS Kommentare erlauben nur Inline-Code. Stellen Sie daher sicher, dass vor und nach "JS" Zeilenumbrüche vorhanden sind, aber Sie haben die Idee. Auf diese Weise müssen Sie den Code nicht an zwei Stellen verwalten, und die meisten Editoren markieren ihn trotzdem.
David
3

Die beste Idee ist, Capybara auf die neueste Version (2.4.1) zu aktualisieren und nur zu verwenden, windows.last weil page.driver.browser.window_handleses veraltet ist.

Adam Piotrowski
quelle
0

Die Hauptimplementierung ( window_opened_by) löst für mich einen Fehler aus:

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

Also löse ich es mit dieser Lösung:

new_window = open_new_window

within_window new_window do
  visit(click_link 'Something')
end

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

Ich persönlich mag den folgenden Ansatz, da er korrekt funktioniert, unabhängig davon, ob JS aktiviert ist oder nicht.

Meine Spezifikation:

  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 

Testhelfer:

  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
Andres Leon
quelle