Arhn - архитектура программирования

RSpec, Capybara: redirect_to не работает в спецификациях создания/публикации

Я настроил простой контроллер с соответствующим ему feature_spec:

stamps_controller.rb

class StampsController < ApplicationController
  def new
    @stamp = Stamp.new
  end

  def create
    @stamp = Stamp.new(stamp_params)

    if @stamp.save
      redirect_to(stamp_url(@stamp.id), status: 201)
    else
      render 'new'
    end
  end

  def show
    @stamp = Stamp.find(params[:id])
  end

  private

  def stamp_params
    params.require(:stamp).permit(::percentage)
  end
end

specs/requests/stamps_request_spec.rb

RSpec.describe 'stamp requests', type: :request do
  describe 'stamp creation', js: true do
    before do
      FactoryBot.create_list(:domain, 2)
      FactoryBot.create_list(:label, 2)
    end

    it 'allows users to create new stamps' do
      visit new_stamp_path
      expect(page).to have_content('Percentage')

      find('#stamp_percentage').set('20')

      click_button 'Create'

      expect(current_path).to eq(stamp_path(Stamp.first.id))
    end
  end
end

Согласно документам капибары:

Capybara автоматически выполняет любые перенаправления и отправляет формы, связанные с кнопками.

Но в тесте этого не происходит, вместо этого выдает ошибку:

ожидается: /штампы/1

получил: /штампы

Результаты очевидны: он успешно создает штамп, но не может перенаправить на новый штамп. Я также подтвердил это, используя binding.pry.

Почему капибара не следует перенаправлению, как описано в документах?


Примечания:

  1. это даже не работает, если я использую обычный драйвер вместо js
  2. Я просмотрел множество вопросов и документов SO, но не нашел ничего полезного. Одной потенциальной попыткой, которую я не смог понять, был ответ с никаких подробностей о том, как это реализовать.
  3. мои конфиги:

support/capybara.rb

require 'capybara/rails'
require 'capybara/rspec'

Capybara.server = :puma
Capybara.register_driver :selenium do |app|
  Capybara::Selenium::Driver.new(app, browser: :firefox, marionette: true)
end

Capybara.javascript_driver = :selenium

RSpec.configure do |config|
  config.include Capybara::DSL
end

spec_helper.rb

ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
require 'rspec/rails'
require 'factory_bot_rails'
require 'pundit/matchers'

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

RSpec.configure do |config|
  # .
  # unrelated stuff
  # .
end

  • Вы пробовали expect(page).to have_current_path(stamp_path(Stamp.first.id))? 21.08.2018

Ответы:


1

У вас есть ряд проблем в вашем тесте.

Во-первых, Capybara не предназначена для использования в request спецификациях — https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec, но вместо этого его следует использовать с тестами функций/системы. После того, как вы исправите это, вам больше не нужно включать Capybara в каждый тест RSpec, и вам следует удалить config.include Capybara::DSL из вашей конфигурации (когда вам требуется capybara/rspec, он включает Capybara в типы тестов, в которые он должен быть включен - https://github.com/teamcapybara/capybara/blob/master/lib/capybara/rspec.rb#L10)

Во-вторых, click_button не гарантирует, что какое-либо действие будет завершено. Из-за этого вам нужно дождаться визуального изменения страницы, прежде чем пытаться получить доступ к любым объектам базы данных, которые будут созданы этим действием (технически вы действительно не должны делать прямой доступ к БД в спецификациях функций вообще, но если вы собираетесь ...)

  click_button 'Create' 
  expect(page).to have_text('Stamp created!') # Whatever message is shown after creation
  # Now you can safely access the DB for the created stamp

В-третьих, как указал @chumakoff, вы не должны использовать статические сопоставители с Capybara, а вместо этого должны использовать сопоставители, предоставленные Capybara.

  click_button 'Create' 
  expect(page).to have_text('Stamp created!') # Whatever message is shown after creation
  expect(page).to have_path(stamp_path(Stamp.first.id))

Наконец, вы должны посмотреть на свой test.log и использовать save_and_open_screenshot, чтобы увидеть, что на самом деле сделали ваши контроллеры. На самом деле при создании возникает ошибка, из-за которой ваше приложение перенаправляется на /stamps и отображает сообщение об ошибке (также подразумевается, что ваш тест БД на самом деле не сбрасывается между тестами, или показанные вами фабрики создают вложенные записи и т. д.).

Обновление: после повторного чтения кода вашего контроллера я заметил, что вы передаете код состояния 201 в redirect_to. 201 на самом деле не будет выполнять перенаправление - Из документов redirect_to - https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_to

Обратите внимание, что код состояния должен быть HTTP-кодом 3xx, иначе перенаправление не произойдет.

21.08.2018
  • Спасибо за ваш обширный ответ. Что касается 1., я с радостью поверю на слово эксперту, а не сообщению в блоге. Но если спецификации функций реализованы, разве они не охватывают все, что могут делать спецификации запросов? Не могли бы вы сослаться на источники, чтобы увидеть ценность обоих? Или хотя бы ссылку на отличный проект, в котором реализованы оба типа тестов? - 2. Значит, достаточно ожидания страницы и ждать визуального изменения? - 2.5 я постараюсь избегать вызовов БД ;) - и 3., я с удовольствием покопаюсь во всех подходящих сопоставлениях 22.08.2018
  • К сожалению, проблема все еще возникает с правильным матчером (ради этого я добавил sleep(2) перед ожиданием). Мой браузер зависает на imgur.com/a/XoWhP0R - улучшения структуры еще не сделаны, но я сомневаюсь, что многое изменится 22.08.2018
  • Спецификации запросов @TheCha͢mp полезны для тестирования API (и я понятия не имею, о чем говорится в этом сообщении в блоге, поскольку они на самом деле пишут спецификации функций, как указано в заключительном разделе). Спецификации функций больше ориентированы на пользователя и основаны на браузере — relishapp. com/rspec/rspec-rails/docs/feature-specs/feature-spec. Я добавил обновление, которое, вероятно, является причиной того, что ваше перенаправление не происходит, однако остальные проблемы, которые я перечислил, по-прежнему актуальны для вашего кода. 22.08.2018
  • ???????? хороший улов! Это действительно было проблемой. И я с удовольствием исправлю все остальные проблемы. Я переключу все текущие спецификации запросов на спецификации функций, поскольку они таковы. Я новичок в капибаре, но со временем обязательно выучу условности. 22.08.2018

  • 2

    Проблема может заключаться в том, что для изменения current_path требуется некоторое время после отправки формы. Ваш код будет работать, если вы поместите sleep(x) перед expect(current_path).

    Вместо этого вы должны использовать методы с так называемым «поведением ожидания», такие как has_current_path?, have_current_path, assert_current_path:

    expect(page).to have_current_path(stamp_path(Stamp.first.id))
    

    or

    expect(page.has_current_path?(stamp_path(Stamp.first.id))).to eq true
    
    21.08.2018
  • К сожалению, проблема все еще возникает с правильным матчером (ради этого я добавил sleep(2) перед ожиданием). Мой браузер зависает на imgur.com/a/XoWhP0R 22.08.2018
  • Томас Уолпол нашел основную проблему, но все равно спасибо за помощь! 22.08.2018

  • 3

    Для всех, кто приходит сюда, еще одно возможное решение — увеличить время ожидания. Либо глобально, либо по клику

    # Globally
    Capybara.default_max_wait_time = 5
    
    # Per Click
    find("#my-button").click(wait: 5)
    
    
    
    05.03.2021
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..