rook1202 / runteq_graduation_productio-

ランテック卒業制作
0 stars 0 forks source link

RSpecの実装とテストコードについて #62

Open rook1202 opened 1 week ago

rook1202 commented 1 week ago

申し訳ありません、解決いたしました!

ログインできなかった理由はテストコードではテスト用DBに、コントローラーからは開発環境用DBに接続しておりデータの照合、新規登録などがうまくいっておりませんでした。 念のためコメントに解決理由を残しておりますが、確認不要です。

解決したいこと・達成したいものについて

RSpecのテストコードで、ログインができない状態を解決したいです。

聞きたいこと・アドバイスが欲しいこと

ChatGPTでここまで確認しましたが、他にどこを確認していいのかわからなくなってしまいました。 ログインのできない原因、もしくは他に疑わしいところ、確認するべきところがあれば教えていただけないでしょうか?よろしくお願いいたします。

追記:下のコメントに検証を追加しておりますが、登録しようとしているDBが違うかもしれません。 テストコードのcreateではtest用のDBにデータを作成していますが、controllerから操作したときに別のDBを参照しているかもしれません。もしそうだった場合、どこで設定を確認するべきか教えていただきたいです。

実装の際に参考にした資料等

RUNTEQの課題で使用していたRSpecのコード

require 'rails_helper'

RSpec.describe 'ログイン・ログアウト', type: :system do
  let(:general_user) { create(:user, :general) }
  let(:admin_user) { create(:user, :admin) }

  describe '通常画面' do
    describe 'ログイン' do
      it '正しいタイトルが表示されていること' do
        visit '/login'
        expect(page).to have_title("ログイン | RUNTEQ BOARD APP"), '掲示板一覧ページのタイトルに「ログイン | RUNTEQ BOARD APP」が含まれていません。'
      end

      context '認証情報が正しい場合' do
        it 'ログインできること' do
          visit '/login'
          fill_in 'メールアドレス', with: general_user.email
          fill_in 'パスワード', with: '12345678'
          click_button 'ログイン'
          Capybara.assert_current_path("/boards", ignore_query: true)
          expect(current_path).to eq '/boards'
          expect(page).to have_content('ログインしました'), 'フラッシュメッセージ「ログインしました」が表示されていません'
        end
      end
FactoryBot.define do
  factory :user do
    email { Faker::Internet.unique.email }
    password { '12345678' }
    password_confirmation { '12345678' }
    first_name { Faker::Name.first_name }
    last_name { Faker::Name.last_name }
  end

  trait :general do
    role { :general }
  end

  trait :admin do
    role { :admin }
  end
end

Capybara.assert_current_pathとFakerは設定しておりません。

現状のコードの状態がわかるURL(プルリクエスト・リポジトリ等)

Rspec関係のプルリクエスト: https://github.com/rook1202/runteq_graduation_productio-/pull/63 リポジトリ: https://github.com/rook1202/runteq_graduation_productio-

現状のコードの状態がわかるURLのどこが関係していると考えているのか

RSpecの実行結果

Failures:

  1) ログイン・ログアウト機能 正常なログインが成功する
     Failure/Error: expect(page).to have_content('ログインしました'), 'フラッシュメッセージ「ログインしました」が表示さ れていません'
       フラッシュメッセージ「ログインしました」が表示されていません

     [Screenshot Image]: /runteq_graduation_productio-/tmp/capybara/failures_r_spec_example_groups_nested_正常なログインが成功する_239.png

     # ./spec/system/login/login_spec.rb:20:in `block (2 levels) in <top (required)>'

デバックコード

#login_spec.rb
RSpec.describe 'ログイン・ログアウト機能', type: :system do
  let(:user) { create(:user) }

  it '正常なログインが成功する' do
    visit root_path
    expect(current_path).to eq(login_path), '未ログイン時にroot_pathからlogin_pathにリダイレクトされていません'

    p user # ユーザーオブジェクトを出力
    puts User.all.inspect # データベース内のユーザーを確認

    fill_in 'email', with: user.email
    fill_in 'password', with: '12345678'
    # 入力内容をデバッグ出力
    p find('input[name="email"]').value
    p find('input[name="password"]').value
    click_button 'ログイン'

    expect(page).to have_content('ログインしました'), 'フラッシュメッセージ「ログインしました」が表示されていません'
    expect(current_path).to eq(root_path) # ペット一覧画面に遷移
  end
end

デバック結果

$ docker-compose exec web bundle exec rspec
#<User id: 31, name: "てすと", email: "test@example.com", crypted_password: "$2a$04$tEv4PsSN5kjB19PyE/8UBO4FBBe82mBxBvpaCi.pb4U...", salt: "_4zVgF9zmxSNubmC59hx", created_at: "2024-11-20 04:33:49.404843000 +0000", updated_at: "2024-11-20 04:33:49.404843000 +0000">
#<ActiveRecord::Relation [#<User id: 31, name: "てすと", email: "test@example.com", crypted_password: "$2a$04$tEv4PsSN5kjB19PyE/8UBO4FBBe82mBxBvpaCi.pb4U...", salt: "_4zVgF9zmxSNubmC59hx", created_at: "2024-11-20 04:33:49.404843000 +0000", updated_at: "2024-11-20 04:33:49.404843000 +0000">]>
"test@example.com"
"12345678"

こちらの結果から、ユーザーデータの作成と、入力内容は意図の通りできていると思います。 ただ以下のようにコントローラーで以下のようにテスト中のデバック行ったところ、

user_sessions_controller.rb
def create
    Rails.logger.debug "Params received: #{params.inspect}"

    user = User.find_by(email: params[:email])
  if user
    Rails.logger.debug "User found: #{user.inspect}"
    if user.authenticate(params[:password])
      Rails.logger.debug "Password authentication successful"
    else
      Rails.logger.debug "Password authentication failed"
    end
  else
    Rails.logger.debug "User not found"
  end

    @user = login(params[:email], params[:password])
    if @user
      flash[:success] = 'ログインしました'
      redirect_to root_path
    else
      flash.now[:danger] = 'ログインに失敗しました'
      render :new, status: :unprocessable_entity
    end
  end

デバック結果

web-1     | Started POST "/login" for 172.18.0.2 at 2024-11-20 13:34:10 +0900
web-1     | Cannot render console from 172.18.0.2! Allowed networks: 127.0.0.0/127.255.255.255, ::1
web-1     | Processing by UserSessionsController#create as TURBO_STREAM
web-1     |   Parameters: {"authenticity_token"=>"[FILTERED]", "email"=>"test@example.com", "password"=>"[FILTERED]", "commit"=>"ログイン"}
web-1     | Params received: #<ActionController::Parameters {"authenticity_token"=>"j2L9ET6E7bwQAGEhIv7L-2LKu5xT_wrfvg9j6yQ1AtPjPZsyZ60kADyI9ivgvek6gQIqJv7yarCaMVcKyq8LFg", "email"=>"test@example.com", "password"=>"12345678", "commit"=>"ロ グイン", "controller"=>"user_sessions", "action"=>"create"} permitted: false>
web-1     |   User Load (0.4ms)  SELECT `users`.* FROM `users` WHERE `users`.`email` = 'test@example.com' LIMIT 1
web-1     |   ↳ app/controllers/user_sessions_controller.rb:14:in `create'
web-1     | User not found
web-1     |   User Load (0.4ms)  SELECT `users`.* FROM `users` WHERE `users`.`email` = 'test@example.com' ORDER BY `users`.`id` ASC LIMIT 1

permitted: falseとなってしまうことと User not foundが出ています。 ちなみにパスワード認証にはSorceryを使用しています。

検証した結果から分かったこと・考えたこと

controllerのデバック結果からDBに該当のデータが見つからず、認証が失敗していると考えられます。 ただlogin_spec.rbではユーザーデータの作成はできており、入力内容も合っていると出ていますので、どこを確認するべきなのかわからなくなってしまいました。

rook1202 commented 1 week ago

検証した結果から分かったこと・考えたこと追記:

新規登録についてのテストコードを2つ追加してみたところ、登録はできませんでしたが、下のフラッシュメッセージはきちんと表示されていることがわかりました。 以下他にも検証した結果、登録しようとしているDBが違うかもしれません。もしそうだった場合、どこで設定を間違えているのか教えていただきたいです。

RSpec.describe 'ユーザー登録', type: :system do

    it 'ユーザーが新規作成できること' do
      visit '/users/new'
      expect {
        fill_in 'user_name', with: 'てすと'
        fill_in 'user_email', with: 'example@example.com'
        fill_in 'user_password', with: '12345678'
        fill_in 'user_password_confirmation', with: '12345678'
        click_button '登録'
      }.to change { User.count }.by(1)
      expect(page).to have_content('ユーザー登録が完了しました'), 'フラッシュメッセージ「ユーザー登録が完了しました」が表示されていません'
    end

    it 'ユーザーが新規作成できない' do
      visit '/users/new'
      expect {
        fill_in 'user_email', with: 'example@example.com'
        click_button '登録'
      }.to change { User.count }.by(0)
      expect(page).to have_content('ユーザー登録に失敗しました'), 'フラッシュメッセージ「ユーザー登録に失敗しました」が表示されていません'
      expect(page).to have_content('ユーザー名 を入力してください'), 'エラーメッセージ「姓を入力してください」が表示されていません'
      expect(page).to have_content('パスワード は6文字以上で入力してください'), 'フラッシュメッセージ「パスワード6文字以上で入力してください」が表示されていません'
    end
end

ユーザー新規登録の前後に puts User.all.inspect # データベース内のユーザーを確認 を入れたところ相変わらずDBには何も登録されていないのですが、

$ docker-compose exec -e RAILS_ENV=test web bundle exec rspec
F.FF#<ActiveRecord::Relation []>
#<ActiveRecord::Relation []>
F.

controllerの登録失敗に Rails.logger.debug "User save failed: #{@user.errors.full_messages}" こちらを挿入してログを確認したところ

User save failed: ["メールアドレス はすでに登録されています"]

このようにメッセージが出ていました。

$ docker-compose exec -e RAILS_ENV=test web rails c
Loading test environment (Rails 7.0.8.4)
irb(main):001> User.all
  User Load (0.8ms)  SELECT `users`.* FROM `users`
=> []

DBを確認してもテストが終わると毎回削除されています。 datebase.yml

test:
  <<: *default
  database: runteq_graduation_test

rails_helper.rb

# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'

ちなみにFactoryBotで作成するemailはtest@example.comなので違います。

rook1202 commented 1 week ago

rails_helper.rb

# Capybaraがサーバーを起動しないように設定
Capybara.run_server = false 
Capybara.app_host = "http://web:3000" # Docker Composeの`web`サービスに直接接続

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :remote_chrome
  end
end

この設定にしたのはCapybara.run_serverとポート設定の競合したためで Capybara.server_port = 0 を指定しても、Capybara.app_hostで動的に割り当てられたポートを正しく参照できていない状態で、 Capybara.current_session.server.port を使用したコードが適切に動作せず、通信エラーや遅延を引き起こしていたためです。ただこのせいで開発環境のDBを使用してしまったので結局うまく動きませんでした。

修正版:

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :remote_chrome

    # Docker内の`web`サービスのIPアドレスを取得
    ip = Socket.ip_address_list.detect(&:ipv4_private?).ip_address
    Capybara.server_host = ip
    Capybara.app_host = "http://#{ip}:#{Capybara.current_session.server.port}"

    Capybara.run_server = true
    Capybara.server = :puma, { Silent: true }
  end
end