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.

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

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


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 .


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('a@example.com')
  find('#login_password').set('qwerty')
  click_button 'Submit'
end

Weitere Details hier: Capybara-Dokumentation


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

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.


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



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)


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


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


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

Ü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.


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"]

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.