diff --git a/Gemfile b/Gemfile index 29fcdeef..6d400acd 100644 --- a/Gemfile +++ b/Gemfile @@ -16,6 +16,7 @@ gem 'jbuilder', '~> 2.5' group :development, :test do gem 'rspec-rails', '~> 3.6.0' + gem "factory_bot_rails", "~> 4.10.0" gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem 'capybara', '~> 2.13.0' gem 'selenium-webdriver' diff --git a/Gemfile.lock b/Gemfile.lock index 45f1595d..af8982c5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -80,6 +80,11 @@ GEM diff-lcs (1.3) erubi (1.7.1) execjs (2.7.0) + factory_bot (4.10.0) + activesupport (>= 3.0.0) + factory_bot_rails (4.10.0) + factory_bot (~> 4.10.0) + railties (>= 3.0.0) faker (1.7.3) i18n (~> 0.5) ffi (1.9.18) @@ -235,6 +240,7 @@ DEPENDENCIES capybara (~> 2.13.0) coffee-rails (~> 4.2) devise + factory_bot_rails (~> 4.10.0) faker geocoder jbuilder (~> 2.5) @@ -256,4 +262,4 @@ DEPENDENCIES web-console (>= 3.3.0) BUNDLED WITH - 1.14.6 + 1.16.4 diff --git a/config/application.rb b/config/application.rb index 6ea74494..12c65af0 100644 --- a/config/application.rb +++ b/config/application.rb @@ -17,10 +17,10 @@ class Application < Rails::Application config.generators do |g| g.test_framework :rspec, - fixtures: false, view_specs: false, helper_specs: false, - routing_specs: false + routing_specs: false, + request_specs: false end end end diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb new file mode 100644 index 00000000..4cd81a69 --- /dev/null +++ b/spec/factories/notes.rb @@ -0,0 +1,8 @@ +FactoryBot.define do + factory :note do + message "My important note." + association :project + # association :user + user { project.owner } + end +end diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb new file mode 100644 index 00000000..9930114c --- /dev/null +++ b/spec/factories/projects.rb @@ -0,0 +1,72 @@ +FactoryBot.define do + factory :project do + sequence(:name) { |n| "Project #{n}" } + description "A test project." + due_on 1.week.from_now + association :owner + + # メモ付きのプロジェクト + trait :with_notes do + after(:create) { |project| create_list(:note, 5, project: project) } + end + + # 締め切りが昨日 + trait :due_yesterday do + due_on 1.day.ago + end + + # 締め切りが今日 + trait :due_today do + due_on Date.current.in_time_zone + end + + # 締め切りが明日 + trait :due_tomorrow do + due_on 1.day.from_now + end + +=begin + # 昨日が締め切りのプロジェクト + factory :project_due_yesterday do + due_on 1.day.ago + end + + # 今日が締め切りのプロジェクト + factory :project_due_today do + due_on Date.current.in_time_zone + end + + # 明日が締め切りのプロジェクト + factory :project_due_tomorrow do + due_on 1.day.from_now + end +=end + + end + +=begin + # 昨日が締め切りのプロジェクト + factory :project_due_yesterday, class: Project do + sequence(:name) { |n| "Test Project #{n}" } + description "Sample project for testing purposes" + due_on 1.day.ago + association :owner + end + + # 今日が締め切りのプロジェクト + factory :project_due_today, class: Project do + sequence(:name) { |n| "Test Project #{n}" } + description "Sample project for testing purposes" + due_on Date.current.in_time_zone + association :owner + end + + # 明日が締め切りのプロジェクト + factory :project_due_tomorrow, class: Project do + sequence(:name) { |n| "Test Project #{n}" } + description "Sample project for testing purposes" + due_on 1.day.from_now + association :owner + end +=end +end diff --git a/spec/factories/users.rb b/spec/factories/users.rb new file mode 100644 index 00000000..a2a94ba9 --- /dev/null +++ b/spec/factories/users.rb @@ -0,0 +1,19 @@ +FactoryBot.define do + factory :user, aliases: [:owner] do + first_name "Aaron" + last_name "Sumner" + sequence(:email) { |n| "tester#{n}@example.com" } + password "dottle-nouveau-pavilion-tights-furze" + end +end + +=begin +FactoryBot.define do + factory :user do + first_name "Aaron" + last_name "Sumner" + email "tester@example.com" + password "dottle-nouveau-pavilion-tights-furze" + end +end +=end diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb new file mode 100644 index 00000000..911c0002 --- /dev/null +++ b/spec/models/note_spec.rb @@ -0,0 +1,150 @@ +require 'rails_helper' + +RSpec.describe Note, type: :model do + + # ファクトリで関連するデータを生成する + it "generates associated data from a factory" do + note = FactoryBot.create(:note) + puts "This note's project is #{note.project.inspect}" + puts "This note's user is #{note.user.inspect}" + end + + + before do + # このファイルの全テストで使用するテストデータをセットアップする + @user = User.create( + first_name: "Joe", + last_name: "Tester", + email: "joetester@example.com", + password: "dottle-nouveau-pavilion-tights-furze", + ) + @project = @user.projects.create( + name: "Test Project", + ) + end + + # バリデーションのテストが並ぶ + + # ユーザ、プロジェクト、メッセージがあれば有効な状態であること + it "is valid with a user, project, and message" do + note = Note.new( + message: "This is a sample note.", + user: @user, + project: @project, + ) + + expect(note).to be_valid + end + + # メッセージがなければ無効な状態であること + it "is invalid without a message" do + note = Note.new(message: nil) + note.valid? + expect(note.errors[:message]).to include("can't be blank") + end + + # 文字列に一致するメッセージを検索する + describe "search message for a term" do + + before do + # 検索機能の全テストに関連する追加のテストデータをセットアップする + @note1 = @project.notes.create( + message: "This is the first note.", + user: @user, + ) + + @note2 = @project.notes.create( + message: "This is the second note.", + user: @user, + ) + + @note3 = @project.notes.create( + message: "First, preheat the oven.", + user: @user, + ) + end + + # 一致するデータが見つかるとき + context "when a match is found" do + # 検索文字列に一致するメモを返すこと + it "returns notes that match the search term" do + expect(Note.search("first")).to include(@note1, @note3) + end + end + + # 一致するデータが1件も見つからないとき + context "when no match is found" do + # 空のコレクションを返すこと + it "returns an empty collection" do + expect(Note.search("message")).to be_empty + end + end + end + +=begin + # 検索文字列に一致するメモを返すこと + it "returns notes that match the search term" do + user = User.create( + first_name: "Joe", + last_name: "Tester", + email: "joetester@example.com", + password: "dottle-nouveau-pavilion-tights-furze", + ) + + project = user.projects.create( + name: "Test Project", + ) + + note1 = project.notes.create( + message: "This is the first note.", + user: user, + ) + + note2 = project.notes.create( + message: "This is the second note.", + user: user, + ) + + note3 = project.notes.create( + message: "First, preheat the oven.", + user: user, + ) + + expect(Note.search("first")).to include(note1, note3) + expect(Note.search("first")).to_not include(note2) + end + + # 検索結果を検証するスペック... + + # 検索結果が1件も見つからなければ空のコレクションを返すこと + it "returns an empty collection when no results are found" do + user = User.create( + first_name: "Joe", + last_name: "Tester", + email: "joetester@example.com", + password: "dottle-nouveau-pavilion-tights-furze", + ) + + project = user.projects.create( + name: "Test Project", + ) + + note1 = project.notes.create( + message: "This is the first note.", + user: user, + ) + + note2 = project.notes.create( + message: "This is the second note.", + user: user, + ) + + note3 = project.notes.create( + message: "First, preheat the oven.", + user: user, + ) + + expect(Note.search("message")).to be_empty + end +=end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb new file mode 100644 index 00000000..67b4b8b7 --- /dev/null +++ b/spec/models/project_spec.rb @@ -0,0 +1,100 @@ +require 'rails_helper' + +# 遅延ステータス +describe "late status" do + + # たくさんのメモが付いていること + it "can have many notes" do + # project = FactoryBot.create(:project) + project = FactoryBot.create(:project, :with_notes) + expect(project.notes.length).to eq 5 + end + + # 締切日が過ぎていれば遅延していること + it "is late when the due date is past today" do + project = FactoryBot.create(:project, :due_yesterday) + expect(project).to be_late + end + + # 締切日が今日ならスケジュールどおりであること + it "is on time when the due date is today" do + project = FactoryBot.create(:project, :due_today) + expect(project).to_not be_late + end + + # 締切日が未来ならスケジュールどおりであること + it "is on time when the due date is in the future" do + project = FactoryBot.create(:project, :due_tomorrow) + expect(project).to_not be_late + end + +=begin + # 締切日が過ぎていれば遅延していること + it "is late when the due date is past today" do + project = FactoryBot.create(:project_due_yesterday) + expect(project).to be_late + end + + # 締切日が今日ならスケジュールどおりであること + it "is on time when the due date is today" do + project = FactoryBot.create(:project_due_today) + expect(project).to_not be_late + end + + # 締切日が未来ならスケジュールどおりであること + it "is on time when the due date is in the future" do + project = FactoryBot.create(:project_due_tomorrow) + expect(project).to_not be_late + end +=end +end + +RSpec.describe Project, type: :model do + # ユーザー単位では重複したプロジェクト名を許可しないこと + it "does not allow duplicate project names per user" do + user = User.create( + first_name: "Joe", + last_name: "Tester", + email: "joetester@example.com", + password: "dottle-nouveau-pavilion-tights-furze", + ) + + user.projects.create( + name: "Test Project", + ) + + new_project = user.projects.build( + name: "Test Project", + ) + + new_project.valid? + expect(new_project.errors[:name]).to include("has already been taken") + end + + # 二人のユーザーが同じ名前を使うことは許可すること + it "allows two users to share a project name" do + user = User.create( + first_name: "Joe", + last_name: "Tester", + email: "joetester@example.com", + password: "dottle-nouveau-pavilion-tights-furze", + ) + + user.projects.create( + name: "Test Project", + ) + + other_user = User.create( + first_name: "Jane", + last_name: "Tester", + email: "janetester@example.com", + password: "dottle-nouveau-pavilion-tights-furze", + ) + + other_project = other_user.projects.build( + name: "Test Project", + ) + + expect(other_project).to be_valid + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb new file mode 100644 index 00000000..ee3222a9 --- /dev/null +++ b/spec/models/user_spec.rb @@ -0,0 +1,109 @@ +require 'rails_helper' + +RSpec.describe User, type: :model do + # 有効なファクトリを持つこと + it "has a valid factory" do + expect(FactoryBot.build(:user)).to be_valid + end + + # 名がなければ無効な状態であること + it "is invalid without a first name" do + user = FactoryBot.build(:user, first_name: nil) + user.valid? + expect(user.errors[:first_name]).to include("can't be blank") + end + + # 姓がなければ無効な状態であること + it "is invalid without a last name" do + user = FactoryBot.build(:user, last_name: nil) + user.valid? + expect(user.errors[:last_name]).to include("can't be blank") + end + + # メールアドレスがなければ無効な状態であること + it "is invalid without an email address" do + user = FactoryBot.build(:user, email: nil) + user.valid? + expect(user.errors[:email]).to include("can't be blank") + end + + # ユーザーのフルネームを文字列として返すこと + it "returns a user's full name as a string" do + user = FactoryBot.build(:user, first_name: "John", last_name: "Doe") + expect(user.name).to eq "John Doe" + end + + # 重複したメールアドレスなら無効な状態であること + it "is invalid with a duplicate email address" do + FactoryBot.create(:user, email: "aaron@example.com") + user = FactoryBot.build(:user, email: "aaron@example.com") + user.valid? + expect(user.errors[:email]).to include("has already been taken") + end + + # 複数のユーザーで何かする + it "does something with multiple users" do + user1 = FactoryBot.create(:user) + user2 = FactoryBot.create(:user) + expect(true).to be_truthy + end + + + # 姓、名、メール、パスワードがあれば有効な状態であること + it "is valid with a first name, last name, email, and password" do + user = User.new( + first_name: "Aaron", + last_name: "Summer", + email: "tester@example.com", + password: "dottle-nouveau-tights-furze", + ) + expect(user).to be_valid + end + + # 名がなければ無効な状態であること + it "is invalid without a first name" do + user = User.new(first_name: nil) + user.valid? + expect(user.errors[:first_name]).to include("can't be blank") + # expect(user.errors[:first_name]).to_not include("can't be blank") + end + + # 姓がなければ無効な状態であること + it "is invalid without a last name" do + user = User.new(last_name: nil) + user.valid? + expect(user.errors[:last_name]).to include("can't be blank") + end + + # メールアドレスがなければ無効な状態であること + it "is invalid without an email address" + + # 重複したメールアドレスなら無効な状態であること + it "is invalid with a duplicate email address" do + User.create( + first_name: "Joe", + last_name: "Tester", + email: "tester@example.com", + password: "dottle-nouveau-pavilion-tights-furze", + ) + user = User.new( + first_name: "Jane", + last_name: "Tester", + email: "tester@example.com", + password: "dottle-nouveau-pavilion-tights-furze", + ) + user.valid? + expect(user.errors[:email]).to include("has already been taken") + end + + # ユーザーのフルネームを文字列として返すこと + it "returns a user's full name as a string" do + user = User.new( + first_name: "John", + last_name: "Doe", + email: "johndoe@example.com", + ) + expect(user.name).to eq "John Doe" + end +end +