Как я могу сделать тесты DRY в Rails и при этом использовать Capybara и Warden? (используя минитест)

Я намерен создать несколько тестов для одной и той же формы, и в этих тестах мне нужно, чтобы Capybara полностью заполнила форму. Тем не менее, я хотел избежать переписывания кода для заполнения формы.

Я не использую RSPEC! Я использую минитест.

Проблема, с которой я столкнулся, заключается в том, что метод Capybara visit и вспомогательный метод Warden login_as недоступны из моего модуля CapybaraHelper.

Я видел этот вопрос, поэтому я создал свой модуль в папке test/support, но методы, которые я упомянул, по-прежнему недоступны. Как повторно использовать код в Capybara

Я видел этот вопрос, но код, который я хочу повторно использовать, похоже, не подходит ни для метода setup, ни для метода teardown. Rails: предварительно создайте экземпляр модели для вашего модульные тесты (для целей DRY)?

Я также видел сообщения о том, что этот модуль должен быть внутри test_helper.rb, но по мере того, как я добавляю в этот файл больше модулей, он становится беспорядочным.

Так что теперь мне интересно, что я делаю неправильно. Я пытался добавить следующие строки в CapybaraHelper, но это не помогло. На самом деле это вызвало ошибку NoMethodError: undefined methodsetup для CapybaraHelper:Module`.

include Devise::Test::ControllerHelpers
include Warden::Test::Helpers

Правильно ли повторно использовать код в тестах? Я пропустил что-то, что должно быть включено в мой вспомогательный модуль? Все эти методы отлично работают в тестовом контроллере, который использует CapybaraHelper:Module.

Вот сообщение об ошибке:

NoMethodError: undefined method `login_as' for CapybaraHelper:Module

А вот сообщение об ошибке из другого теста с использованием CapybaraHelper:Module.

NoMethodError: undefined method `visit' for CapybaraHelper:Module

Вот мой тест:

require 'test_helper'

class TravelsControllerTest < ActionController::TestCase
  include Devise::Test::ControllerHelpers
  include Warden::Test::Helpers
  Warden.test_mode!

  test 'should accept correct fields' do
    CapybaraHelper.login
    result = CapybaraHelper.access_and_fill_travel_page
    assert_equal "/travels/success/#{Travel.last.uuid}", result[:final_path]
  end

end

А вот помощник, который я создал в test/support/capybara/capybara_helper.rb, чтобы избежать дублирования кода:

require 'test_helper'
require 'capybara/rails'
require 'capybara/poltergeist'

module CapybaraHelper
  def self.access_and_fill_travel_page options = {}
    options.symbolize_keys!
    set_js_driver
    visit(Rails.application.routes.url_helpers.root_path)
    initial_path = current_path
    #Fields
    fill_in('origin', with: options[:origin] || 'Guarulhos')
    fill_autocomplete('origin', with: options[:origin] || 'Guarulhos')
    fill_in('destination', with: options[:destination] || 'Seul')
    fill_autocomplete('destination', with: options[:destination] || 'Seul')
    fill_in('date_from', with: options[:date_from] || Date.today+10)
    fill_in('date_to', with: options[:date_to] || Date.today+26)
    fill_in('adults', with: options[:adults] || 1)
    fill_in('children', with: options[:children] || 0)
    fill_in('babies', with: options[:babies] || 0)
    find('#travel-submit').click()
    final_path = current_path
    return {initial_path: initial_path, final_path: final_path}
  end

  def self.fill_autocomplete(field, options = {})
    page.execute_script %Q{ el = $('input[name=#{field}]').get(0) }
    page.execute_script %Q{ $(el).trigger('focus') }
    page.execute_script %Q{ $(el).trigger('keydown') }
    page.all('.ui-menu-item', minimum: 1)
    page.execute_script %Q{ item = $('.ui-menu-item').get(0) }
    page.execute_script %Q{ $(item).trigger('mouseenter').click() }
  end

  def self.set_js_driver
    Capybara.javascript_driver = :poltergeist
    Capybara.current_driver = Capybara.javascript_driver
  end

  def self.login
    user = FactoryGirl.create(:user)
    login_as(user, :scope => :user)
  end

end

person Samir Haddad    schedule 07.04.2017    source источник


Ответы (1)


Вы должны использовать ActionDispatch::IntegrationTest, а не ActionController::TestCase в качестве родительского класса для тестов с использованием капибары. ActionController::TestCase имитирует фазу запроса и большие части Rails. Он устарел в Rails 5.

Вместо того, чтобы вызывать методы в вашем тестовом вспомогательном модуле, вы должны смешивать их с вашими тестовыми классами.

class TravelsIntegrationTest < ActionDispatch::IntegrationTest
  include Devise::Test::ControllerHelpers
  include Warden::Test::Helpers
  include CapybaraHelper 
  Warden.test_mode!

  test 'should accept correct fields' do
    login
    # ...
  end
end

module CapybaraHelper
  def login(user = FactoryGirl.create(:user))
    login_as(user, scope: :user)
  end
end

Кроме того, вам не хватает организации кода - такие шаги настройки, как настройка Warden.test_mode!, должны выполняться в вашем test_helper.rb, а не повторяться в ваших тестах. Также не сбрасывайте все свои определения шагов в один файл. Вы можете разместить их, например, в /test/support/.

module SessionHelper
  def login(user = FactoryGirl.create(:user))
    login_as(user, :scope => :user)
  end
end

module TravelHelper
  def access_and_fill_travel_page
    # ...
  end
end

И если вы действительно хотите сохранить его сухим, используйте наследование для настройки своих тестовых классов:

class BaseIntegrationTest < ActionDispatch::IntegrationTest
  include Devise::Test::ControllerHelpers
  include Warden::Test::Helpers
  include SessionHelper 
end

class TravelsIntegrationTest < BaseIntegrationTest
  test 'should accept correct fields' do
    login
    # ...
  end
end
person max    schedule 07.04.2017
comment
Следуя вашему ответу, я нашел причину, по которой некоторые методы были недоступны в моем модуле, и это было связано с тем, что я использовал методы класса вместо методов экземпляра. Простое удаление self из объявления метода и CapybaraHelper, где я их вызывал, решило проблему. Я использовал ActionController::TestCase из-за этой проблемы github.com/plataformatec/devise/issues/3913 но я не заметил, что простое добавление include Devise::Test::IntegrationHelpers решит эту проблему. Спасибо, я также создал новые модули, как вы предложили, и они работают нормально. - person Samir Haddad; 10.04.2017
comment
И добавление include SessionHelper к TravelsControllerTest в одиночку не сработало. Мне также пришлось добавить require 'support/session_helper'. - person Samir Haddad; 10.04.2017