A flash test

前一節提到的 flash 錯誤顯示是個小 bug,根據之前提到的測試法則,我們應該寫個測試來捕捉錯誤然後防止不會再發生這種 bug。所以我們要為登入表單的提交處理,寫個簡短的整合測試:

$ rails generate integration_test users_login
      invoke  test_unit
      create    test/integration/users_login_test.rb

測試的步驟是:

  • 瀏覽登入頁面
  • 確認登入表單正確渲染
  • 使用無效的 params hash 對登入頁面發出 POST 請求
  • 確認登入頁面重新渲染,並且會出現 flash 的錯誤訊息
  • 瀏覽其他頁面(例如首頁)
  • 確認 flash 的訊息不會出現在其他頁面

完整程式碼如下:

test/integration/users_login_test.rb

require 'test_helper'

class UsersLoginTest < ActionDispatch::IntegrationTest

  test "login with invalid information" do
    get login_path
    assert_template 'sessions/new'
    post login_path, session: { email: "", password: "" }
    assert_template 'sessions/new'
    assert_not flash.empty?
    get root_path
    assert flash.empty?
  end
end

執行測試,會顯示失敗(Red):

$ bundle exec rake test TEST=test/integration/users_login_test.rb

TEST=test/integration/users_login_test.rb 這段是只測試指定的測試檔案。

為了要通過測試,必須把 flash 換成 flash.now,這是專門用在 render 頁面上的 flash 訊息。和 flash 不不的是,flash.now 的內容會在下一個請求時(get root_path)消失。

完整程式碼如下:

app/controllers/sessions_controller.rb

def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      # Log the user in and redirect to the user's show page.
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

執行測試,就會通過了(Green):

$ bundle exec rake test TEST=test/integration/users_login_test.rb
$ bundle exec rake test