Testes de integração não confiáveis / Flakey Capybara / AngularJS com problemas de tempo

Como faço para que esses testes sejam aprovados com segurança?

Atualmente esses testes são flakey.
Às vezes eles passam. Às vezes eles falham.
Abaixo está a configuração, o código e a saída que demonstram esse problema.
As sugestões para superar esse problema serão muito apreciadas e tenho certeza de que ajudarão muitos outros, por isso, comente!

Ambiente do código de testeTrilhos 3.2RSpec 2.xCapivaraPoltergeistPhantomJSAngularJSGoogle Chrome versão 47.0.2526.106 (64 bits)Testando gemas do 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)
Coisas que tenteiCertifique-se de que eu uso os correspondentes DSL em espera da CapivaraVerifique se meu limpador de banco de dados está configurado corretamenteTeste todos os itens da página, supondo que ele possa não estar na página e ainda estar carregandoReduzir testes inconsistentesExecutar teste inconsistente sozinho

Identifique os DSLs de Capivara de código que são o gatilho para resultados de teste inconsistentes.

ou seja, criando um novo registro e assumindo que a página foi redirecionada e que o registro está na página click_on

ou

.click não 'constantemente' trabalhandoAtualize a Capivara para a versão mais recente (em uma ramificação separada)Poltergeist atualizado e RSpec para a versão mais recente (em uma ramificação separada, ainda trabalhando nisso)Recursos que eu usei

[1]Capivara O DSL
[2]Dicas de Capivara, PhantomJs, Poltergeist e Rspec
E muitos mais...

Como os testes foram executados

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

Código de testeshow_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
Resultado dos testes

Test Run 1: Failing

Opções de execução: inclua {: focus => true} exclua {: slow => true}

Todos os exemplos foram filtrados; ignorando {: focus => true}

Mostrar um novo custeio na lista, mostra o custeio após a criação mostra os detalhes do novo custeio após a criação (FAILED - 1)

Falhas:

1) Mostre um novo custo na listagem,
mostra os detalhes do novo custo após a criação
Falha / Erro: expect (page) .to have_content ("test1")
espera que #has_content? ("test1") retorne verdadeiro, ficou falso
# ./spec/integration/costings/show_costing_spec.rb:20:in block (3 levels) in
# ./spec/integration/costings/show_costing_spec.rb:19:in block (2 levels) in

Concluído em 5,46 segundos 2 exemplos, 1 falha

Test Run 2: Passing

Opções de execução: inclua {: focus => true} exclua {: slow => true}

Todos os exemplos foram filtrados; ignorando {: focus => true}

Mostrar um novo custo na listagem,
mostra o custo após a criação
mostra os detalhes do novo custo após a criação

Concluído em 3,57 segundos 2 exemplos, 0 falhas

Atualização 1

Gems de teste atualizados para as seguintes versões:
capivara (2.6.2) a partir de (2.1.0)
database_cleaner (1.5.1) de (0.7.1)
debug_inspector (0.0.2)
empacotador de guarda (0.1.3)
carga de fígado de guarda (1.2.0)
especificação de proteção (2.1.2)
jasminerice (0.0.10)
pág (0.17.1)
phantomjs (2.1.1.0)
poltergeist (1.9.0) de (1.4.1)
trilhos-transferidor (0.0.17)
alavanca (0.10.3) de (0.9.12)
rack (1.4.7)
teste de rack (0.6.3)
trilhos (3.2.21)
rails-assets-angular (1.4.9) de (1.3.20)
rspec-trilhos (3.4.2) de (2.11.4)
simplecov (0.8.2)
rodas dentadas (2.2.3)
zeus (0.13.3)
zeus-parallel_tests (0.2.1)

Result 1

Infelizmente, atualizar essas gemas não pareceu fazer diferença e meus testes ainda estavam em perfeitas condições.

Atualização 2

Eu implementei as sugestões de Tom Walpole. Garante que meu admin_sign_in aguarde a conclusão de login.

Também atualizei minha configuração do database_cleaner, como sugeriu Tom.

Result 2

Para minha pilha, essas mudanças não pareciam ter efeito.

Nota: Se alguém não estiver usando o AngularJS, sinto que essas alterações teriam feito diferença. Então, obrigado Tom por suas sugestões.

Atualização 3

Eu precisava obter mais informações sobre o que estava acontecendo durante minhas execuções de teste. Existem sugestões na rede para registrar, usar gemas de economia de captura de tela e coisas do tipo, mas eu não achava que essas seriam as mais eficientes em termos de tempo. Eu queria especificar onde queria que o teste fosse pausado e exibir o conteúdo de variáveis e campos de formulário. Em um navegador seria o ideal.

O que eu usei
Eu estava usando "save_and_open_page" e "print page.html" para depurar.

O que eu mudei para
Como eu estava executando o RSpec 3.4.2, adicionei um método auxiliar de depuração:

rails_helper.rb

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

Result 3

Um URL seria impresso no console e o teste seria pausado. Nesta fase, eu seria capaz de navegar para a URL, fazer login, navegar até a página de teste e ver o que o teste da Capybara havia feito.

Isso me permitiu identificar que a origem dos meus problemas surgiu quando o teste estava usando o DSL fill_in da capivara. Em algumas execuções de teste, os campos seriam preenchidos corretamente e o formulário seria enviado. No outro cenário, o formulário seria preenchido corretamente, mas o botão enviar seria pressionado muito rapidamente. O resultado aqui é que um registro foi criado, mas os campos de entrada de nome e descrição não foram mantidos.

Atualização 4

Descobri que, porque estava usando formulários e tabelas de entrada AngularJS, o AngularJS exigia um pouco de tempo para vincular aos campos de entrada. Se não fosse permitido desta vez, os dados de entrada não seriam salvos.

A Capivara fornece métodos de espera como "dentro" e "encontrar". Usei-os, mas eles não ajudaram no problema do tempo de ligação do AngularJS. Eu achei ng-if poderia ser usado para criar uma instrução if para aguardar um item específico que significaria as ligações do AngularJS aos campos do formulário completos.

Então, usei os métodos de espera da Capybara para aguardar os campos que queria preencher e usei o ng-if do AngularJS para não mostrar os campos até que estejam prontos.

Implementação
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

Os testes finalmente passam! No entanto, tenho todos esses métodos de localização com o xpath, garantindo que itens específicos e difíceis de segmentar sejam esperados em ...

Atualização 5

Embora no meu gemfile eu estivesse executando o gem phantomJS versão 2.1.1, minha versão da linha de comando era apenas 1.X. Isto provou ser significativo.

Atualizei minha versão do phantomJS da linha de comando para 2.1.1. Ao mesmo tempo, assegurei que todas as minhas caixas de entrada, botões, tabelas e títulos tivessem IDs únicos. Pude remover todas as ocorrências de localização (: xpath) sem interromper os testes.

Result 5

Agora, esse conjunto de testes passa com confiabilidade o tempo todo! Exatamente o que eu queria! Sim!

questionAnswers(2)

yourAnswerToTheQuestion