Unzuverlässige / Flakey Capybara / AngularJS-Integrationstests mit Zeitproblemen

Wie bringe ich diese Tests zuverlässig zum Bestehen?

Derzeit sind diese Tests Flakey.
anchmal gehen sie vorbei. Manchmal scheitern sie.
Below ist das Setup, der Code und die Ausgabe, die dieses Problem demonstrieren.
Vorschläge zur Behebung dieses Problems werden sehr geschätzt, und ich bin mir sicher, dass ich vielen anderen helfen kann. Bitte kommentieren Sie dies!

Test Code EnvironmentRails 3.2RSpec 2.x CapybaraPoltergeis PhantomJS AngularJSGoogle Chrome Version 47.0.2526.106 (64-Bit)Testing Gems von Gemfile.lock
capybara (2.1.0)
database_cleaner (0.7.1)
debug_inspector (0.0.2)
guard-bundler (0.1.3)
guard-livereload (1.2.0)
guard-rspec (2.1.2)
jasminerice (0.0.10)
pg (0.17.1)
phantomjs (2.1.1.0)
poltergeist (1.4.1)
protractor-rails (0.0.17)
pry (0.9.12)
rack (1.4.7)
rack-test (0.6.3)
rails (3.2.21)
rails-assets-angular (1.3.20)
rspec-rails (2.11.4)
simplecov (0.8.2)
sprockets (2.2.3)
zeus (0.13.3)
zeus-parallel_tests (0.2.1)
Things habe ich versuchttellen Sie sicher, dass ich Capybaras wartende DSL-Matcher verwendStellen Sie sicher, dass mein Datenbankbereiniger korrekt eingerichtet istTesten Sie jedes Seitenelement, vorausgesetzt, es befindet sich möglicherweise nicht auf der Seite und wird noch geladen.Inkonsistente Tests eingrenzen Inkonsistenten Test alleine ausführen

Identifizieren Sie Code-Capybara-DSLs, die Auslöser für inkonsistente Testergebnisse sind.

d.h. Erstellen eines neuen Datensatzes und Annahme, dass die Seite umgeleitet wurde und sich der Datensatz auf der Seite befindet click_on

ode

.click funktioniert nicht durchgehendUpgrade Capybara auf die neueste Version (in einem separaten Zweig)Upgrade von Poltergeist und RSpec auf die neueste Version (in einem separaten Zweig, der noch daran arbeitet)Ressourcen, die ich verwendet habe

[1]Capybara Die DSL
[2]Capybara, PhantomJs, Poltergeist und Rspec Tips
Und viele mehr..

ie wurden Tests durchgeführ

rspec spec/integration/costings/show_costing_spec.rb --format documentation

Test Code show_costing_spec.rb
require "spec_helper"

RSpec.describe "Show a new costing in the listing," do

  before :each do
    admin_sign_in
    create_costing("test1")
  end

  it "shows the costing after creation" do
    within "#costings_table" do
      expect(page).to have_css("#name", text: "test1")
    end
  end

  it "shows the details of the new costing after creation" do
    expect(page).to have_content("Costings")
    within "#costings_table" do
      expect(page).to have_content("test1")
      all("#show").last.click
    end

    expect(page).to have_content("Costing Details")
    expect(page).to have_css("#name", text: "test1")
  end
end  
spec_helper.rb
# This file is copied to spec/ when you run 'rails generate r spec:install'  
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
# Add library functions here so we can test them.
require File.expand_path(File.dirname(__FILE__) + "/../lib/general")
require 'rspec/rails'
require 'rspec/autorun'

# Integration Testing
require 'capybara/poltergeist'
Capybara.register_driver :poltergeist_debug do |app|
 Capybara::Poltergeist::,Driver.new(app, :inspector => true)  
end
Capybara.javascript_driver = :poltergeist_debug
Capybara.default_driver = :poltergeist_debug

# Capybara Integration Test Helpers
def admin_sign_in
  visit "/login"
  #Create staff member in database
  Staff.make!(:admin)
  #Log In
  fill_in "staff_username", with: "adminstaff"
  fill_in "staff_password", with: "password"
  click_button "login"
end

def create_costing(item)
  visit "/api#/costings"
  click_on "new_btn"
  within "#form_costing" do
    find("#name", match: :first).set("#{item}")
    find("#description", match: :first).set("test description")    
    find("#from_date", match: :first).set("15/02/2016")
    find("#cost_hourly_cents", match: :first).set("1.00")
    click_on "create_btn"
  end
end

RSpec.configure do |config|
  config.before(:suite) do
    # Requires supporting ruby files with custom matchers and macros, etc,
    # in spec/support/ and its subdirectories.
    require File.expand_path(File.dirname(__FILE__) + "/support/blueprints")
    Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
  end

  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  # Allow a 'focus' tag so that we can run just a few tests which we are currently working on
  config.treat_symbols_as_metadata_keys_with_true_values = true
  config.filter_run focus: true
  config.run_all_when_everything_filtered = true
  config.filter_run_excluding :slow unless ENV["SLOW_SPECS"]

  # Defer Garbage Collection
  config.before(:all) { DeferredGarbageCollection.start }
  config.after(:all)  { DeferredGarbageCollection.reconsider }

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = false
  # config.infer_spec_type_from_file_location!

  # Configure Database Cleaner
  config.include Capybara::DSL
  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, :js => true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end
end
Testergebniss

Test Run 1: Failing

Run-Optionen: {: focus => true} einschließen {: slow => true} ausschließen

Alle Beispiele wurden herausgefiltert; ignoriert {: focus => true}

Eine neue Kalkulation in der Auflistung anzeigen, zeigt die Kalkulation nach dem Anlegen an, zeigt die Details der neuen Kalkulation nach dem Anlegen an (FAILED - 1)

Failures:

1) Zeige eine neue Kalkulation in der Auflistung,
zeigt die Details der neuen Kalkulation nach dem Anlegen an
Fehler / Fehler: Erwarte (Seite) .to have_content ("test1")
expected #has_content? ("test1") um true zurückzugeben, got false
# ./spec/integration/costings/show_costing_spec.rb:20:in Block (3 Ebenen) in
# ./spec/integration/costings/show_costing_spec.rb:19:in Block (2 Ebenen) in

Finished in 5.46 Sekunden 2 Beispiele, 1 Fehler

Test Run 2: Passing

Run-Optionen: {: focus => true} einschließen {: slow => true} ausschließen

Alle Beispiele wurden herausgefiltert; ignoriert {: focus => true}

Eine neue Kalkulation in der Auflistung anzeigen,
zeigt die Kosten nach der Erstellung
zeigt die Details der neuen Kalkulation nach dem Anlegen an

In 3,57 Sekunden fertig 2 Beispiele, 0 Fehler

Update 1

Test-Edelsteine wurden auf die folgenden Versionen aktualisiert:
capybara (2.6.2) von (2.1.0)
database_cleaner (1.5.1) von (0.7.1)
debug_inspector (0.0.2)
guard-bundler (0.1.3)
guard-livereload (1.2.0)
guard-spec (2.1.2)
jasminerice (0.0.10)
pg (0.17.1)
phantomjs (2.1.1.0)
poltergeist (1.9.0) von (1.4.1)
Winkelmesserschienen (0.0.17)
pry (0.10.3) from (0.9.12)
rack (1.4.7)
rack-test (0.6.3)
rails (3.2.21)
Rails-Assets-Angular (1.4.9) von (1.3.20)
rspec-Rails (3.4.2) von (2.11.4)
simplecov (0.8.2)
sprockets (2.2.3)
zeus (0.13.3)
zeus-parallel_tests (0.2.1)

Result 1

eider schien die Aufrüstung dieser Edelsteine keinen Unterschied zu bewirken, und meine Tests waren immer noch unauffälli

Update 2

Ich habe die Vorschläge von Tom Walpole umgesetzt. Es wurde sichergestellt, dass mein admin_sign_in auf den Abschluss von sign_in wartet.

Auch mein database_cleaner-Setup wurde aktualisiert, wie von Tom vorgeschlagen.

Result 2

Für meinen Stack schienen diese Änderungen keine Auswirkungen zu haben.

Hinweis Wenn man AngularJS nicht benutzt, haben diese Änderungen meiner Meinung nach einen Unterschied gemacht. Also danke Tom für deine Vorschläge.

Update 3

Ich musste mehr Informationen darüber erhalten, was während meiner Testläufe passierte. Es gibt Vorschläge im Internet, wie man sich anmeldet, Edelsteine zum Speichern von Screenshots verwendet und dergleichen, aber ich hatte nicht das Gefühl, dass diese die effizienteste Zeit sind. Ich wollte angeben, wo der Test anhalten und den Inhalt von Variablen und Formularfeldern anzeigen soll. In einem Browser wäre das ideal.

Was ich benutzt habe
Ich habe "save_and_open_page" und "print page.html" zum Debuggen verwendet.

Was ich umgezogen bin
Als ich RSpec 3.4.2 ausführte, fügte ich eine Debug-Hilfsmethode hinzu:

rails_helper.rb

def debugit
  puts current_url
  require 'pry'
  binding.pry
end

Result 3

Eine URL würde in der Konsole gedruckt und der Test unterbrochen. Zu diesem Zeitpunkt könnte ich zur URL navigieren, mich anmelden, zur Testseite navigieren und anzeigen, was der Capybara-Test getan hat.

Auf diese Weise konnte ich feststellen, dass die Ursache meiner Probleme bei der Verwendung von capybaras fill_in DSL lag. In einigen Testläufen wurden die Felder korrekt ausgefüllt und das Formular gesendet. In dem anderen Szenario würde das Formular korrekt ausgefüllt, aber die Senden-Schaltfläche würde zu schnell gedrückt. Dies hat zur Folge, dass ein Datensatz erstellt wurde, die Eingabefelder Name und Beschreibung jedoch nicht beibehalten wurden.

Update 4

Ich habe festgestellt, dass AngularJS aufgrund der Verwendung von AngularJS-Eingabeformularen und -Tabellen nur wenig Zeit für die Bindung an die Eingabefelder benötigt. Wenn diesmal nicht erlaubt, werden die Eingabedaten nicht gespeichert.

Capybara bietet Wartemethoden wie "inside" und "find". Ich habe diese verwendet, aber sie haben bei der Ausgabe der AngularJS-Bindungszeit nicht geholfen. Ich fand, dass ng-if verwendet werden könnte, um eine if-Anweisung zu erstellen, die auf ein bestimmtes Element wartet, das angibt, dass die AngularJS-Bindungen zu den Formularfeldern vollständig sind.

So habe ich Capybara-Wartemethoden verwendet, um auf die Felder zu warten, die ich ausfüllen wollte, und ich habe AngularJS 'ng-if verwendet, um die Felder nicht anzuzeigen, bis sie fertig sind.

Implementierun
index.html.erb

<div  ng-if="tableParams.data">
  <table id="costings_table ng-table="tableParams" class="table">
    <td id="field1">{{table.field1}}</td>
    <td id="field2">{{table.field2}}</td>
  </table>
</div>

Result 4

Tests endlich bestanden! Ich habe jedoch alle diese Find-Methoden mit xpath, die sicherstellen, dass auf bestimmte und schwer zu zielende Elemente gewartet wird ...

Update 5

Obwohl ich in meiner Gemdatei die Gem-PhantomJS-Version 2.1.1 ausgeführt habe, war meine Befehlszeilenversion nur 1.X. Dies hat sich als bedeutsam erwiesen.

Ich habe meine Kommandozeilen-PhantomJS-Version auf 2.1.1 aktualisiert. Gleichzeitig stellte ich sicher, dass alle meine Eingabefelder, Schaltflächen, Tabellen und Überschriften eindeutige IDs hatten. Ich konnte dann alle Fundstellen (: xpath) entfernen, ohne die Tests zu unterbrechen.

Result 5

Diese Testsuite besteht jetzt zuverlässig die ganze Zeit! Genau das was ich wollte! Ja

Antworten auf die Frage(4)

Ihre Antwort auf die Frage