Ненадежные / Flakey Capybara / AngularJS Интеграционные тесты с проблемами синхронизации
В настоящее время эти тесты являются ненадежными.
Иногда они проходят. Иногда они терпят неудачу.
Ниже приведены настройки, код и выходные данные, демонстрирующие эту проблему.
Предложения по преодолению этой проблемы будут высоко оценены, и я уверен, что поможет многим другим, поэтому, пожалуйста, прокомментируйте!
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)
Вещи, которые я пробовалУбедитесь, что я использую ожидающие DSL соответствия CapybaraУбедитесь, что мой очиститель базы данных правильно настроенПротестируйте каждый элемент страницы, предполагая, что он может отсутствовать на странице и все еще может загружатьсяУзкие противоречивые тестыВыполнить только непоследовательный тестОпределите код DSL Capybara, которые являются причиной несовместимых результатов испытаний.
то есть создание новой записи и предполагая, что страница перенаправлена и что запись находится на странице click_onили же
.click не всегда «работает»Обновите Capybara до последней версии (в отдельной ветке)Обновлен Poltergeist и RSpec до последней версии (в отдельной ветке, все еще работаем над этим)Ресурсы, которые я использовал[1]Капибара DSL
[2]Советы Capybara, PhantomJs, Poltergeist и Rspec
И многое другое ...
rspec spec/integration/costings/show_costing_spec.rb --format documentation
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
Результаты тестаTest Run 1: Failing
Параметры запуска: include {: focus => true} exclude {: slow => true}
Все примеры были отфильтрованы; игнорируя {: focus => true}
Показать новую калькуляцию в списке, показывает калькуляцию после создания, показывает детали новой калькуляции после создания (СБОЙ - 1)
Неудачи:
1) Показать новую калькуляцию в листинге,
показывает детали новой калькуляции после создания
Ошибка / Ошибка: ожидаемо (страница) .to have_content ("test1")
ожидал, что #has_content? ("test1") вернет true, получил false
# ./spec/integration/costings/show_costing_spec.rb:20:in блок (3 уровня) в
# ./spec/integration/costings/show_costing_spec.rb:19:in блок (2 уровня) в
Закончено за 5,46 секунд 2 примера, 1 неудача
Test Run 2: Passing
Параметры запуска: include {: focus => true} exclude {: slow => true}
Все примеры были отфильтрованы; игнорируя {: focus => true}
Показать новую калькуляцию в листинге,
показывает стоимость после создания
показывает детали новой калькуляции после создания
Закончено за 3,57 секунды 2 примера, 0 сбоев
Обновление 1Обновлены гемы тестирования до следующих версий:
капибара (2.6.2) из (2.1.0)
database_cleaner (1.5.1) из (0.7.1)
debug_inspector (0.0.2)
охранник (0.1.3)
guard-livereload (1.2.0)
Guard-Spec (2.1.2)
Жасминерис (0.0.10)
пг (0.17.1)
фантомы (2.1.1.0)
полтергейст (1.9.0) из (1.4.1)
транспортир-рельсы (0.0.17)
pry (0.10.3) из (0.9.12)
стойка (1.4.7)
рейк-тест (0.6.3)
рельсы (3.2.21)
рельсы-активы-угловые (1.4.9) из (1.3.20)
рельсы rspec (3.4.2) из (2.11.4)
simplecov (0.8.2)
звездочки (2.2.3)
Зевс (0.13.3)
zeus-parallel_tests (0.2.1)
Result 1
К сожалению, модернизация этих драгоценных камней, казалось, не имела никакого значения, и мои тесты все еще были ненадежными.
Обновление 2Я реализовал предложения Тома Уолпола. Убедитесь, что мой admin_sign_in ожидает завершения входа в систему.
Также обновил мои настройки database_cleaner, как предложил Том.
Result 2
На мой стек эти изменения, похоже, не повлияли.
Замечания: Если кто-то не использует AngularJS, я чувствую, что эти изменения имели бы значение. Так что спасибо Тому за твои предложения.
Обновление 3Мне нужно было получить больше информации о том, что происходило во время моих тестовых прогонов. В сети есть предложения для входа в систему, использования скриншотов, сохранения драгоценных камней и тому подобного, но я не чувствовал, что они будут наиболее эффективными по времени. Я хотел указать, где я хочу, чтобы тест останавливался и просматривал содержимое переменных и полей формы. В браузере было бы идеально.
Что я использовал
Я использовал "save_and_open_page" и "print page.html" для отладки.
К чему я переехал
Когда я работал с RSpec 3.4.2, я добавил вспомогательный метод отладки:
rails_helper.rb
def debugit
puts current_url
require 'pry'
binding.pry
end
Result 3
URL будет напечатан в консоли, и тест будет приостановлен. На этом этапе я смогу перейти к URL-адресу, войти в систему, перейти на тестовую страницу и посмотреть, что сделал тест Capybara.
Это позволило мне определить, что источник моих проблем возник, когда в тесте использовался DSL capybara fill_in. В некоторых тестовых прогонах поля будут заполнены правильно, и форма будет отправлена. В другом случае форма будет заполнена правильно, но кнопка отправки будет нажата слишком быстро. В результате мы создали запись, но поля ввода имени и описания не были сохранены.
Обновление 4Я обнаружил, что, поскольку я использовал формы и таблицы ввода AngularJS, AngularJS требовалось совсем немного времени для привязки к полям ввода. Если это не было разрешено, на этот раз входные данные не будут сохранены.
Capybara предоставляет методы ожидания, такие как "inside" и "find". Я использовал их, но они не помогли с проблемой времени привязки AngularJS. Я обнаружил, что ng-if можно использовать для создания оператора if для ожидания конкретного элемента, который будет означать привязки AngularJS к полям формы.
Поэтому я использовал методы ожидания Capybara для ожидания полей, которые я хотел заполнить, и использовал AngularJS 'ng-if, чтобы не показывать поля, пока они не будут готовы.
Реализация
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
Тесты наконец проходят! Однако у меня есть все эти методы find с xpath, гарантирующие, что конкретные и трудные для цели объекты ожидаются ...
Обновление 5Несмотря на то, что в моем gemfile я использовал gem phantomJS версии 2.1.1, моя версия командной строки была только 1.X. Это оказалось значительным.
Я обновил версию phantomJS для командной строки до 2.1.1. В то же время я обеспечил, чтобы все мои поля ввода, кнопки, таблицы, заголовки имели уникальные идентификаторы. Затем я смог удалить все вхождения find (: xpath), не нарушая тесты.
Result 5
Этот набор тестов теперь надежно проходит все время! Именно то, что я хотел! Да!