Closed76

RSpec入門・演習3

なななななな

よし、実践に入る。まずはsystem specの準備。

  • Gemのインストール
  • formatの設定
  • webdriverの設定
なななななな

system specファイルの生成コードまちがってるな。rails g rspec:system ファイル名が正解っぽい。

なななななな

まずは一番ケース数の少ないUserSessionsからいこう。記載されてるのは以下の通り。

  • ログイン前
    • フォームの入力値が正常 => ログイン処理が成功する
    • フォームの値が未入力 => ログイン失敗
  • ログイン後
    • ログアウトボタンクリックする => ログアウトされる
なななななな

上を更に分解する。ログイン後はそのまんまでいいかな。

ログイン後

  • ログアウトボタンをクリックするとログアウトされるか

ログイン前

  • ログイン処理失敗
    • メールアドレス未入力でログインに失敗するか
    • パスワード未入力でログインに失敗するか
  • ログイン処理成功
    • メールアドレス・パスワード・パスワード確認が全て正しく入力されるとログインに成功するか
なななななな

続いてUserのテストケース。記載は以下の通り。

ログイン前

  • ユーザー新規登録
    • フォームの入力値が正常 => 登録成功
    • メールアドレスが未入力 => 登録失敗
    • 登録済みのメールアドレスを入力する => 登録失敗
  • マイページ遷移
    • ログイン前 => アクセス失敗

ログイン後

  • ユーザー編集
    • フォームの入力値が正常 => 編集成功
    • メールアドレスが未入力 => 編集失敗
    • 登録済みのメールアドレスを入力する => 編集失敗
    • 自分以外のユーザー編集ページに遷移する => アクセス失敗
  • マイページ遷移
    • タスクを作成 => 作成したタスクが表示される
なななななな

↑をさらに分解。

ログイン前

  • ユーザー新規登録
    • 失敗
      • メールアドレス未入力で登録失敗するか
      • 登録済のメールアドレス入力で登録失敗するか
    • 成功
      • フォームの値が正常で登録成功するか
  • マイページ遷移
    • 未ログイン状態でマイページにアクセスすると失敗するか

ログイン後

  • ユーザー編集
    • 編集失敗
      • メールアドレス未入力で編集失敗するか
      • 登録済のメールアドレス入力で編集失敗するか
    • 編集成功
      • フォームの入力値が正常で編集成功するか
    • 自分以外のユーザー編集ページにアクセスしようとすると失敗するか
  • マイページ遷移
    • タスクを作成するとそのタスクが表示されるか
なななななな

最後にTaskのケース。記載は次の通り。

ログイン前

  • ページ遷移確認
    • タスクの新規登録ページにアクセス => アクセス失敗
    • タスクの編集ページにアクセス => アクセス失敗
    • タスクの詳細ページにアクセス => タスク詳細情報が表示される
    • タスク一覧ページにアクセス => タスク一覧が表示される

ログイン後

  • タスクの新規登録
    • フォームの入力値が正常 => 登録成功
    • タイトルが未入力 => 登録失敗
    • 登録済みのタイトルを入力する => 登録失敗
  • タスクの編集
    • フォームの入力値が正常 => 編集成功
    • タイトルが未入力 => 編集失敗
    • 登録済みのタイトルを入力する => 編集失敗
  • タスクの削除
    • タスク削除する => 削除成功
なななななな

本日はここまで。明日はTaskのケース記載を続きからやっていく。

なななななな

2023.10.19

引き続きTaskのテストケースを記載していく。

なななななな

うーんなんかやっぱりdescribecontextの使い方を間違えている気がする…describeはあくまでテスト対象が何かを書いて、テストの分類はcontextに任せたほうがいいのかな。
ただそれだと階層が足りない…どうしようかな。

なななななな

Rails基礎のspecファイルを確認してみたら、describeの中に更にdescribeを入れ子にしていいんだ!というかcontextの中にdescribeが入ったりもしてる。
やっぱりdescribeは「テスト対象はなにか(このモデル、このメソッド、あるいはこの機能等)」、contextは「想定している状況、条件」、itは「成否の判定条件」を書くっていうルールっぽいな。
それに合わせてuserも直そう。

なななななな

OK。タスクのテストケース記載およびユーザーやユーザーセッションのテストケースの修正完了。
テストコードの記載を始める。
推奨されている、user_session→user→taskの順(難易度低い順)でいく。

なななななな

rails gで生成したspecファイルにデフォルトで記述されているdriven_byは使うブラウザを指定するもの。今回は設定ファイルで一括指定してあるので消してしまってOK。

なななななな

user_session

ログインするためにはユーザー登録必須なので、beforeでユーザーを生成しておく
... と思ったけど、Rails基礎のspecコード覗いた感じ、変数の宣言はわざわざbeforeの中に入れなくても普通にベタで書いていいっぽいな。そうしよう。

なななななな

とりあえず書けたのでテスト走らせてみる。

なななななな

んん〜??謎のエラーが出た。

  1) ログイン・ログアウト ログイン前 フォームの入力値が正常の場合 ログインに成功するか
     Got 0 failures and 2 other errors:

     1.1) Failure/Error: options = Selenium::Webdriver::Chrome::Options.new

          NameError:
            uninitialized constant Selenium::Webdriver

              options = Selenium::Webdriver::Chrome::Options.new
                                ^^^^^^^^^^^
            Did you mean?  Webdrivers
                           Selenium::WebDriver
なななななな

あ、タイポかな?ウェブドライバーの表記を間違えてる疑惑。

なななななな

当たり。WebDriverWebdriverになってた。再度テスト。

なななななな

お、無事テストが走った。エラーが以下の通り出た。

  1) ログイン・ログアウト ログイン前 フォームの入力値が正常の場合 ログインに成功するか
     Failure/Error: Capybara.assert_current_path(root_path, ignore_query: true)

     Capybara::ExpectationNotMet:
       expected "/login" to equal "/"

(中略)

  2) ログイン・ログアウト ログイン後 ログアウトボタンをクリックするとログアウトされるか
     Failure/Error: click_button 'Logout'

     Capybara::ElementNotFound:
       Unable to find button "Logout" that is not disabled
なななななな

1はおそらくフォームのラベル名が違ってるんじゃないかな。だから入力するべきフォームが見つからずにログイン失敗して/loginが再表示されてる。
2はひょっとするとLogoutがボタンじゃないのかも。
それぞれ確認する。まずは1のスクリーンショット見てみよう。そうすればラベル名がわかる。

なななななな

2は当たりっぽい。ボタンじゃなくてリンクだった。
1は予想が外れた。ラベル名あってそう。う〜んなんでだろう。
とりあえず2を直して再テストしてみる。

なななななな

あれー?"Logout"っていうリンクもボタンもないよって言われた。なんで??
…と思ったけどわかった。そもそもログインの処理書いてない!書く。

なななななな

ついでによく使いそうなのでモジュール化しておくことにする。

なななななな

ん〜〜やっぱりだめだ。ということはログイン処理がうまくできてないってことだな。どこがまずいんだろう。

なななななな

let(:user)じゃなくてlet!(:user)にしないといけないとか?やってみよう。

なななななな

違うっぽい…。
今日はここまでにして明日ログイン失敗の謎を解明する。

なななななな

ダメだった。
DBスキーマファイルでusersテーブルの確認をしてみて思ったのが、passwordっていうカラムがないからでは?ということ。sorceryを使っているため、crypted_passwordになってる。
あとRails基礎の/spec/rails_helper.rbを見てたらconfig.include Sorcery::TestHelpers::Rails::Request, type: :requestという記述があったので、それを追記してみる。

なななななな

関係なかった。
どこがうまく行ってないのか探るため、わざとclick_button 'Login'を消してみた。そしたらスクリーンショットによりどうもパスワードが入力されていないことが判明。なんで??

なななななな

あ、ひょっとしてさっきのが当たってる?user.passwordだとpasswordっていうカラムがないからダメで、文字列としてパスワードを入力しないといけないのでは??

なななななな

当たり〜〜〜〜!!
うわ〜盲点だった!でも気づいてみれば確かにそうだ!パスワードは通常暗号化された状態で保存されてて、ユーザーが入力したまんまの文字列はDB上にはないから、DB参照しないで直接文字列として指定しなきゃダメなんだ。あ〜〜なんて簡単なことに時間を費やしたんだ〜〜〜〜😭
これから気をつけよう…

なななななな

ともあれこれでテスト通ったので、userの方に移る。

なななななな

user

今気づいたけど、「マイページ」ってどのページのことを指してるんだ??コードとかファイル構成見てもいまいちはっきりしないので、とりあえず/users/index.html.erbということにしておこう。

なななななな

へー、redirect_to @userで自動的にredirect_to user_path(@user)と同じだと解釈してくれるんだ。知らなかった。

なななななな

う〜ん、今度はこんなエラーが出ている。

An error occurred while loading ./spec/system/users_spec.rb.
Failure/Error: __send__(method, file)

SyntaxError:
  /sample_app_for_rspec/spec/system/users_spec.rb:98: syntax error, unexpected end-of-input, expecting `end'

本来あるべきendがないよって言われてるっぽいけど、該当箇所見ても問題ないように見える…。
こういう人間だと見つけづらい凡ミス系(だと思う、たぶん。)こそロボらんてくんに助けてほしいんだけど、字数制限でエラーになっちゃうんだよね〜。
今日はもう時間なのでおしまいにして、あした改めてどこがまずいのか探そう。

なななななな

と思ったら見つけちゃった〜!直したのでこれでもう一回テスト走らせてみよう。

なななななな

結局いろんなタイポが見つかって直した。今度こそほんとのほんとにこれでおしまい!続きは明日!

なななななな

あれ?いつの間にかユーザ登録失敗パターンがうまく通らなくなってるな。登録ページ(new_user_path)が再表示されずにユーザー一覧(users_path)に行っちゃってるっぽい。

なななななな

仮説1:ユーザーオブジェクトを引数として渡してないのが問題
user_without_emailuser_duplicated_emailというユーザーオブジェクトを作ってそれを呼び出す形にしてみる。

なななななな

特に変わらず。
なのでブラウザからユーザー登録して確かめてみた。すると確かに失敗した場合のパスが/usersになってる。でも表示されてるページはあってる。
ここでrails routesでルーティングを確認し、そういえばusers#createがPOSTの/usersだったことを思い出す。
つまり、これで合ってる。ユーザー一覧に飛んでるんじゃなく、usersコントローラのcreateアクションが呼び出されてるだけ。
SignUpボタンを押してusers#create=POSTメソッドの/usersに飛ぶ。登録失敗なのでページの中身だけがusers#newに置き換わる。renderなのでnew_user_pathに飛ぶわけじゃなく、パスはusers_pathusers#create)のまま変わらない。

なななななな

めっちゃ初歩的なことだった今回も…情けない。
とにかく進めよう…ユーザー編集失敗パターンからだな。

なななななな

Rails基礎のテストコード見てると、どうも失敗時はパスのチェックしてないっぽいな、エラーメッセージのチェックだけで。やっぱりrender使うことが多いからかな。
同じ感じにしよう。

なななななな

今更ながらMyPage発見。ユーザー詳細(自分の)みたいだ。直しておこう。

なななななな

よし、ユーザー編集関連終わり!あとはタスク作成だけだ。

なななななな

2023.10.22

引き続きtaskのテストコードを書いていく。できれば今日中に終わらせたい。

なななななな

???
なんで新規登録のときはTime.new(...)だと通るのにTime.new(...).strftime(...)だと通らないんだ??

なななななな

いや、↑のはデータベースのデータ型じゃなくてRubyのクラスの話か。データ型としてのdatetimeはやっぱり日時であってそう。ん〜〜直接文字列で指定してみるか。

なななななな

お、編集の方を直指定にしたらいけた。新規登録の方も試してみよう。

なななななな

ええ…ダメじゃん…コピペしたのにどうしてこっちだけダメなの……
スクショよく見るとyearの値がおかしなことになってるな。なんで??

なななななな

タイムゾーンの問題とかそういうことある??

なななななな

ちがうっぽい…。
今度は全部1.week.from_nowで統一してみたけどそうするとやっぱり編集の方だけ失敗する。いやマジでなにこれ??同じフォームレンダリングして使ってるんだけど???

なななななな

やっぱり編集の方だけ引っかかる。何が違うんだ?新規登録と編集で同じフォームをつかってるはずなのに明らかに何かが違ってる。

なななななな

ロボらんてくんにも相談してみたけどダメだ…もういいやDeadlineは入力必須じゃないから入力しないことにする。あとで解答例みて答え合わせする。めっちゃ悔しいけどここで詰まっててもしょうがないわ…進むことにする。

なななななな

全部書けて全部通ったーーー。
まあ加筆修正山程必要だろうけど、いつまでもやっててもしょうがないしここまでとする。解答例を見て正しいやり方を学ぼう。

なななななな

ここから解答例見て修正

include LoginMacrosはrails_helperに書いちゃうのか。

なななななな

せっかくだから修正内容をIssueにしよ〜

というか最初からIssue立てて進めればよかったな

あれ?Issueのタブがない

どうやらforkしたリポジトリはデフォルトでIssueが無効になっていて、設定から有効にできるらしい
https://rcmdnk.com/blog/2017/08/29/computer-github/

というわけで今更ながらIssue有効にした。修正内容をここに放り込んでいく。

なななななな

Capybara.assert_current_pathは要らなかった感じかな全体的に。

なななななな

登録済メールアドレス云々のケースでわざわざexisted_userを作るのは、そのほうがコード読んだときにわかりやすいからかな。user.emailでも普通にいけちゃうけど。

なななななな

have_fieldなんていうマッチャーがあるんだな。fill_inと同じく'フィールド名', with: 値で書ける。
登録・編集失敗した際に入力した値が再表示される場合はこれも書いたほうがいいな。

なななななな

create_listなんてのもあるのか。
create_list(:ファクトリー名, 数)でまとめてオブジェクトを生成できるんだな。

なななななな

あーやっぱりというか、新規登録以外Deadlineの入力してないね…。ロボらんてくんもブラウザによってはうまく行かないことがあるって言ってたし、Capybaraのテストだとうまくいかないことがあるって最初からわかってるやつなのかもなあ。
こんなことならもっと早く諦めちゃえばよかったなあ……

なななななな

「他のユーザーのタスク編集ページにアクセスすると失敗する」は課題のリストにないな。漏れてるのか。

なななななな

よーーやく完成!コミットしてプルリクする。

なななななな

OK、ひとまず終了。TILに少しまとめようかな。

このスクラップは2023/10/22にクローズされました