Подтвердить что ты не робот

Rails - сеанс проигрывания с интеграционными тестами и Capybara - CSRF?

Я использую Rails 3.1.0.rc4, и я работаю над выполнением интеграционных тестов с помощью новых стильных DSL и Rspec (с использованием аутентификации) capybara

Проблема, с которой я столкнулась, заключается в том, что когда я запускаю интеграционный тест, драйвер стойки-драйвера из capybara, похоже, просто полностью потерял пользователя, зарегистрированного в сеансе, на самом деле сеанс, похоже, полностью очищается.

После нескольких дней отладки у меня есть полная потеря относительно того, почему. Идя по линии через стек промежуточного программного обеспечения, я считаю, что я решил проблему в том, что происходит в ActiveRecord::SessionStore, которая вызывает это. Я прочитал здесь, что Rails очистит сеанс, если он не сможет проверить токен CSRF, что оставляет мне поверить, что у меня что-то настроено неправильно, и по какой-то причине этот один тест не аутентифицирует маркер CSRF правильно.

Это то, что находится в моем session_store.rb в каталоге /initializers:

MyApp::Application.config.session_store :active_record_store

Кто-нибудь, кто знает о защите CSRF в рельсах, имеет какие-либо причины, почему это может произойти?

Также обратите внимание на некоторые вещи:

  • вещь, которую я пытаюсь протестировать, действительно работает в самом браузере, только этот один тест отбрасывает сеанс
  • сеанс, похоже, упадет после отправки формы, к которой URL-адрес действия относится к другому серверу. Я использую камень видеомагнитофона для захвата запросов/ответов на этот внешний сервер в тесте, и, хотя я считаю, что я нарушил внешний запрос как проблему, это может иметь что-то непосредственно с токеном CSRF, не аутентифицирующим, тем самым очистив сеанс.
  • другие тесты, связанные с входом в/сеанс сеанса, не выводят сеансы

Может ли кто-нибудь дать мне какие-либо указания относительно того, что здесь происходит, и почему один тест просто, кажется, произвольно отбрасывает сессию и терпит неудачу? Я сделал много отладки и попробовал все, о чем я могу думать.

4b9b3361

Ответ 1

Я тоже новичок в capybara, и у меня была аналогичная проблема.

Я пытался войти в систему, когда пользователь сделал что-то вроде этого:

post user_session_path, :user => {:email => user.email, :password => 'superpassword'}

И это работает нормально, пока я не попытался что-то сделать с capybara, например, посетив страницу и просто проверив, был ли пользователь вошел в систему. Этот простой тест не проходил:

visit root_path
page.should have_content("logout") #if the user is logged in then the logout link should be present

Сначала я думал, что капибара очищает сеансы, но я был неправ. Мне потребовалось некоторое время, чтобы понять, что драйвер capybara использует свои собственные сеансы, поэтому, с точки зрения capybara, мой пользователь никогда не регистрировался. Для этого вам нужно сделать это, как это.

page.driver.post user_session_path, :user => {:email => user.email, :password => 'superpassword'}

Не уверен, что это ваш случай, но надеюсь, что это поможет.

Ответ 2

Ручной способ сделать это очень просто:

it "does something after login" do
  password = "secretpass"
  user = Factory(:user, :password => password)
  visit login_path
  fill_in "Email", :with => user.email
  fill_in "Password", :with => password
  click_button "Log in"
  visit # somewhere else and do something
end

Затем вы можете разбить это на функцию в вашем spec_helper.rb:

# at the bottom of 'spec_helper.rb'
def make_user_and_login
  password = "secretpass"
  @user = Factory(:user, :password => password)
  visit login_path
  fill_in "Email", :with => @user.email
  fill_in "Password", :with => password
  click_button "Log in"
end

и использовать его в любом из ваших тестов (возможно, запрашивать спецификации):

it "does something after login" do
  make_user_and_login
  # now test something that requires a logged in user
  # you have access to the @user instance variable
end

Ответ 3

Я смог исправить эту ошибку, установив это значение в true в config/initializers/test.rb

# Disable request forgery protection in test environment
config.action_controller.allow_forgery_protection = true

Раньше теги CSRF <meta> не печатались на <head>. После изменения этого значения они, наконец, появляются.

Ответ 4

Это может быть длинный снимок, но я верю, что мы закончили плохое состояние после click_button 'Sign in' и сразу же вызвали visit elsewhere.

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

Из документации Capybara:

При выдаче инструкций DSL, например:

click_link('foo') click_link('bar') expect(page).to have_content('baz')

Если щелчок по ссылке foo запускает асинхронный процесс, такой как запрос Ajax, который, когда он будет добавлен, добавит ссылку на страницу на брандмауэр, нажатие на ссылку на панель будет терпеть неудачу, поскольку эта ссылка не есть еще. Однако Capybara достаточно умен, чтобы повторить поиск ссылки в течение короткого периода времени, прежде чем отказаться от и выбросить ошибку.

Если это так, решение прост: дайте Capybara что-то искать и дайте ему подождать, пока запрос не будет завершен. Это может быть так же просто, как добавление:

expect(page).to have_text('Signed in as [email protected]')