【问题标题】:Request in Capybara a GET, when it should be a POST在 Capybara 中请求一个 GET,而它应该是一个 POST
【发布时间】:2017-10-17 07:30:25
【问题描述】:

所以这是一个使用 Docker 的非常基本的 Rails 5 应用程序,其中包括一些我从头开始构建的用户身份验证(不使用 Devise 等)。现在,我想开始学习 Capybara 的请求规范,但我遇到了一个看起来很奇怪的问题。

这是我的登录表单 (sessions.new.erb):

<%= form_tag sessions_path do %>
          <form class="m-t" role="form" action="/">
              <div class="form-group">
                <%= text_field_tag :email, params[:email], class: 'form-control', placeholder: "Email Address", required: "" %>
              </div>
              <div class="form-group">
                <%= password_field_tag(:password, nil, class: 'form-control', placeholder: "Password", required: "") %>
              </div>
              <div class="form-group">
                        <%= check_box_tag :remember_me, 1, params[:remember_me] %>
                        <%= label_tag :remember_me %>
                      </div>
              <div class="actions"><%= submit_tag "Log In", class: "btn btn-primary block full-width m-b" %></div>
          </form>
        <% end %>

还有我的requests/sessions_spec.rb

require "rails_helper"

RSpec.feature "Login", :type => :feature do
  scenario "handles wrong email and password gracefully" do
    visit login_path
    fill_in "Email Address", :with => "something"
    fill_in "Password", :with => "something"
    click_button "Log In"

    expect(page).to have_text("Email or password incorrect")
  end
end

现在,如果您手动测试它就可以了,所以我认为 Capybara 会看到同样的东西。但它一直失败。我已经配置了应用程序,因此如果您尝试访问受保护的控制器并且您没有登录,它会将您重定向到/login 并闪烁一条消息说Please log in to see this page。 Rspec 测试返回了那个,这很奇怪 - 这表明 Capybara 正试图访问另一个页面。

所以我跟踪了测试日志 (docker-compose run web tail -f log/test.log)

而我的发现让我很困惑:

Started GET "/login" for 127.0.0.1 at 2017-10-17 06:59:26 +0000
Processing by SessionsController#new as HTML
  Rendering sessions/new.html.erb within layouts/empty
  Rendered sessions/new.html.erb within layouts/empty (1.1ms)
Completed 200 OK in 6ms (Views: 6.1ms | ActiveRecord: 0.0ms)
Started GET "/?email=something&password=[FILTERED]&commit=Log+In" for 127.0.0.1 at 2017-10-17 06:59:26 +0000
Started GET "/locations" for 127.0.0.1 at 2017-10-17 06:59:26 +0000
Processing by LocationsController#index as HTML
Redirected to http://www.example.com/login
Filter chain halted as :authenticate rendered or redirected
Completed 302 Found in 2ms (ActiveRecord: 0.0ms)
Started GET "/login" for 127.0.0.1 at 2017-10-17 06:59:26 +0000
Processing by SessionsController#new as HTML
  Rendering sessions/new.html.erb within layouts/empty
  Rendered sessions/new.html.erb within layouts/empty (1.1ms)
Completed 200 OK in 6ms (Views: 4.9ms | ActiveRecord: 0.0ms)
   (0.4ms)  ROLLBACK

第一点没问题,GET 登录由 SessionsController#new 处理。但是,(见第 6 行)由于某种原因 Capybara 试图获取根 URL,将电子邮件/密码参数传入。我的根 URL 被映射到 LocationsController#index,用户不允许访问,所以得到使用消息Please log in to see this page 重定向回/login。该按钮的实际作用是将 POST 发送到 SessionsController#create。如果您在手动操作时查看日志,就会发生这种情况:

web_1  | Started POST "/sessions" for 172.18.0.1 at 2017-10-17 07:02:19+0000
web_1  | Processing by SessionsController#create as HTML

我不明白为什么在 Capybara 中,当您按下按钮时,它会执行与您手动单击按钮时完全不同的请求。

帮助不胜感激!

【问题讨论】:

    标签: ruby-on-rails ruby rspec capybara integration-testing


    【解决方案1】:

    首先澄清一下。

    1. 您不是在编写请求规范,而是在编写功能规范(使用 RSpec.feature:type =&gt; :feature 可以证明这一点
    2. 使用RSpec.feature 时无需指定:type =&gt; :feature,因为它已经设置好了。

    现在谈谈你的问题。由于form_tag 创建了一个&lt;form&gt;element,然后您在其中直接有另一个&lt;form&gt; 元素,您的视图代码中有嵌套表单(注意:发布实际的HTML 而不是erb 总是更好,这样人们就可以看到什么实际的 HTML 是)。再加上您似乎正在使用rack-test 驱动程序(没有js: true 元数据)的事实,当HTML 无效(嵌套表单是)时,它的行为方式与真实浏览器不同,您最终会以你目前的行为。我猜当您将它与真正的浏览器一起使用时,内部表单元素将被忽略,而外部表单元素的方法属性等于“post”,因此它会被发布。当使用rack-test 时,它可能会提交没有method 属性的内部表单元素,因此默认为“get”。从您的视图中删除无关的 &lt;form class="m-t" role="form" action="/"&gt; 表单元素,一切都会正常。

    【讨论】:

    • 呃,完全错过了嵌套形式。很明显,现在你已经指出来了!非常感谢,还注意到您关于功能与请求规范的观点。
    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 2021-08-22
    • 1970-01-01
    相关资源
    最近更新 更多