diff --git a/.gitignore b/.gitignore index a4d53ae..11116ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,79 @@ -# git config --global core.excludesfile '~/.gitignore_global' -/vendor/bundle +# Created by https://www.gitignore.io/api/rails,sublimetext,osx + +### Rails ### +*.rbc +capybara-*.html +.rspec +/log /tmp -!/log/.keep +/db/*.sqlite3 +/db/*.sqlite3-journal +/public/system +/coverage/ +/spec/tmp +**.orig +rerun.txt +pickle-email-*.html + +## Environment normalisation: /.bundle -# -# Ignore bundler config. -/log -/log/* -# Ignore all logfiles and tempfiles. -# or operating system, you probably want to add a global ignore instead: -# See https://help.github.com/articles/ignoring-files for more about ignoring files. -Gemfile.lock -# If you find yourself ignoring temporary files generated by your text editor \ No newline at end of file +/vendor/bundle + +# these should all be checked in to normalise the environment: +# Gemfile.lock, .ruby-version, .ruby-gemset + +# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: +.rvmrc + +# if using bower-rails ignore default bower_components path bower.json files +/vendor/assets/bower_components +*.bowerrc +bower.json + +# Ignore pow environment settings +.powenv + + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + + +### OSX ### +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk \ No newline at end of file diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..43ae203 --- /dev/null +++ b/.rspec @@ -0,0 +1,3 @@ +--color +--require spec_helper +--format documentation diff --git a/Gemfile b/Gemfile index 00e10e3..024f1bd 100644 --- a/Gemfile +++ b/Gemfile @@ -15,4 +15,12 @@ group :development, :test do gem 'pry' gem 'pry-rails' gem 'spring' + # testing + gem 'airborne' + gem 'rspec-rails', '~> 3.0' + gem 'factory_girl_rails' +end + +group :test do + gem 'ffaker', git: "https://github.com/AsianTechInc/ffaker.git" end \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..d06e442 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,194 @@ +GIT + remote: https://github.com/AsianTechInc/ffaker.git + revision: 61dfb6075ed65ed7c0dad74d0c836203cf62528f + specs: + ffaker (2.1.0) + +GEM + remote: https://rubygems.org/ + specs: + actionmailer (4.2.4) + actionpack (= 4.2.4) + actionview (= 4.2.4) + activejob (= 4.2.4) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 1.0, >= 1.0.5) + actionpack (4.2.4) + actionview (= 4.2.4) + activesupport (= 4.2.4) + rack (~> 1.6) + rack-test (~> 0.6.2) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (4.2.4) + activesupport (= 4.2.4) + builder (~> 3.1) + erubis (~> 2.7.0) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + activejob (4.2.4) + activesupport (= 4.2.4) + globalid (>= 0.3.0) + activemodel (4.2.4) + activesupport (= 4.2.4) + builder (~> 3.1) + activerecord (4.2.4) + activemodel (= 4.2.4) + activesupport (= 4.2.4) + arel (~> 6.0) + activesupport (4.2.4) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + airborne (0.1.19) + activesupport (>= 3.0.0) + rack-test (~> 0.6, >= 0.6.2) + rest-client (~> 1.7, >= 1.7.3) + rspec (~> 3.1, >= 3.1.0) + arel (6.0.3) + bcrypt (3.1.10) + builder (3.2.2) + coderay (1.1.0) + devise (3.5.2) + bcrypt (~> 3.0) + orm_adapter (~> 0.1) + railties (>= 3.2.6, < 5) + responders + thread_safe (~> 0.1) + warden (~> 1.2.3) + diff-lcs (1.2.5) + domain_name (0.5.24) + unf (>= 0.0.5, < 1.0.0) + erubis (2.7.0) + factory_girl (4.5.0) + activesupport (>= 3.0.0) + factory_girl_rails (4.5.0) + factory_girl (~> 4.5.0) + railties (>= 3.0.0) + globalid (0.3.6) + activesupport (>= 4.1.0) + http-cookie (1.0.2) + domain_name (~> 0.5) + i18n (0.7.0) + json (1.8.3) + loofah (2.0.3) + nokogiri (>= 1.5.9) + mail (2.6.3) + mime-types (>= 1.16, < 3) + method_source (0.8.2) + mime-types (2.6.2) + mini_portile (0.6.2) + minitest (5.8.0) + mysql2 (0.3.20) + netrc (0.10.3) + nokogiri (1.6.6.2) + mini_portile (~> 0.6.0) + orm_adapter (0.5.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-rails (0.3.4) + pry (>= 0.9.10) + rack (1.6.4) + rack-test (0.6.3) + rack (>= 1.0) + rails (4.2.4) + actionmailer (= 4.2.4) + actionpack (= 4.2.4) + actionview (= 4.2.4) + activejob (= 4.2.4) + activemodel (= 4.2.4) + activerecord (= 4.2.4) + activesupport (= 4.2.4) + bundler (>= 1.3.0, < 2.0) + railties (= 4.2.4) + sprockets-rails + rails-api (0.4.0) + actionpack (>= 3.2.11) + railties (>= 3.2.11) + rails-deprecated_sanitizer (1.0.3) + activesupport (>= 4.2.0.alpha) + rails-dom-testing (1.0.7) + activesupport (>= 4.2.0.beta, < 5.0) + nokogiri (~> 1.6.0) + rails-deprecated_sanitizer (>= 1.0.1) + rails-html-sanitizer (1.0.2) + loofah (~> 2.0) + railties (4.2.4) + actionpack (= 4.2.4) + activesupport (= 4.2.4) + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rake (10.4.2) + responders (2.1.0) + railties (>= 4.2.0, < 5) + rest-client (1.8.0) + http-cookie (>= 1.0.2, < 2.0) + mime-types (>= 1.16, < 3.0) + netrc (~> 0.7) + rspec (3.3.0) + rspec-core (~> 3.3.0) + rspec-expectations (~> 3.3.0) + rspec-mocks (~> 3.3.0) + rspec-core (3.3.2) + rspec-support (~> 3.3.0) + rspec-expectations (3.3.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.3.0) + rspec-mocks (3.3.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.3.0) + rspec-rails (3.3.3) + actionpack (>= 3.0, < 4.3) + activesupport (>= 3.0, < 4.3) + railties (>= 3.0, < 4.3) + rspec-core (~> 3.3.0) + rspec-expectations (~> 3.3.0) + rspec-mocks (~> 3.3.0) + rspec-support (~> 3.3.0) + rspec-support (3.3.0) + slop (3.6.0) + spring (1.4.0) + sprockets (3.3.4) + rack (~> 1.0) + sprockets-rails (2.3.3) + actionpack (>= 3.0) + activesupport (>= 3.0) + sprockets (>= 2.8, < 4.0) + thor (0.19.1) + thread_safe (0.3.5) + tzinfo (1.2.2) + thread_safe (~> 0.1) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.1) + versionist (1.4.1) + activesupport (>= 3) + railties (>= 3) + yard (~> 0.7) + warden (1.2.3) + rack (>= 1.0) + yard (0.8.7.6) + +PLATFORMS + ruby + +DEPENDENCIES + airborne + devise + factory_girl_rails + ffaker! + mysql2 (= 0.3.20) + pry + pry-rails + rails (= 4.2.4) + rails-api + rspec-rails (~> 3.0) + spring + versionist + +BUNDLED WITH + 1.10.6 diff --git a/app/models/user.rb b/app/models/user.rb index 6324274..1cee11c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -8,6 +8,10 @@ class User < ActiveRecord::Base has_many :comments before_create :generate_token + VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i + validates :email, presence: true, length: { maximum: 255 }, + format: { with: VALID_EMAIL_REGEX }, + uniqueness: { case_sensitive: false } private def time_expire diff --git a/config/application.rb b/config/application.rb index a4ebd6d..fe642cd 100644 --- a/config/application.rb +++ b/config/application.rb @@ -29,5 +29,16 @@ class Application < Rails::Application # config.middleware.use ActionDispatch::Cookies config.middleware.use ActionDispatch::Session::CookieStore # config.middleware.use ActionDispatch::Flash + + config.generators do |g| + g.test_framework :rspec, + fixtures: true, + view_specs: false, + helper_specs: false, + routing_specs: false, + controller_specs: true, + request_specs: false + g.fixture_replacement :factory_girl, dir: "spec/factories" + end end end diff --git a/spec/factories/comment.rb b/spec/factories/comment.rb new file mode 100644 index 0000000..e45fa46 --- /dev/null +++ b/spec/factories/comment.rb @@ -0,0 +1,7 @@ +FactoryGirl.define do + factory :comment do + association :post + association :user + content { FFaker::Lorem.sentence(3) } + end +end \ No newline at end of file diff --git a/spec/factories/post.rb b/spec/factories/post.rb new file mode 100644 index 0000000..e969a56 --- /dev/null +++ b/spec/factories/post.rb @@ -0,0 +1,7 @@ +FactoryGirl.define do + factory :post do + association :user + title { FFaker::Food.vegetable } + content { FFaker::Lorem.sentence(3) } + end +end \ No newline at end of file diff --git a/spec/factories/user.rb b/spec/factories/user.rb new file mode 100644 index 0000000..c3ac1dc --- /dev/null +++ b/spec/factories/user.rb @@ -0,0 +1,10 @@ +FactoryGirl.define do + factory :user do + email { FFaker::Internet.email } + password { FFaker::Internet.password(8) } + + # after(:build) do |user| + # user.posts << FactoryGirl.build(:post, user: user) + # end + end +end \ No newline at end of file diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb new file mode 100644 index 0000000..e9c53ea --- /dev/null +++ b/spec/models/comment_spec.rb @@ -0,0 +1,59 @@ +require 'rails_helper' + +describe Comment do + before do + @error_blank_field = "can't be blank" + end + + it "is valid with content and associstion for post and user" do + expect(build(:comment)).to be_valid + end + + it "is invalid without content" do + comment = build(:comment, content: nil) + comment.valid? + expect(comment.errors[:content]).to include @error_blank_field + end + + it "is invalid with blank content" do + comment = build(:comment, content: "") + comment.valid? + expect(comment.errors[:content]).to include @error_blank_field + end + + it "is invalid without post" do + comment = build(:comment, post: nil) + comment.valid? + expect(comment.errors[:post]).to include @error_blank_field + end + + it "is invalid without post_id" do + comment = build(:comment, post_id: nil) + comment.valid? + expect(comment.errors[:post]).to include @error_blank_field + end + + it "is invalid with wrong post_id" do + comment = build(:comment, post_id: "this is wrong post_id") + comment.valid? + expect(comment.errors[:post]).to include @error_blank_field + end + + it "is invalid without user" do + comment = build(:comment, user: nil) + comment.valid? + expect(comment.errors[:user]).to include @error_blank_field + end + + it "is invalid without user_id" do + comment = build(:comment, user_id: nil) + comment.valid? + expect(comment.errors[:user]).to include @error_blank_field + end + + it "is invalid with wrong user_id" do + comment = build(:comment, user_id: "this is wrong user_id") + comment.valid? + expect(comment.errors[:user]).to include @error_blank_field + end +end diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb new file mode 100644 index 0000000..2caac4f --- /dev/null +++ b/spec/models/post_spec.rb @@ -0,0 +1,53 @@ +require 'rails_helper' + +describe Post do + before do + @error_blank_field = "can't be blank" + end + + it "is valid with title, content and associstion for user" do + expect(build(:post)).to be_valid + end + + it "is invalid without title" do + post = build(:post, title: nil) + post.valid? + expect(post.errors[:title]).to include @error_blank_field + end + + it "is invalid without content" do + post = build(:post, content: nil) + post.valid? + expect(post.errors[:content]).to include @error_blank_field + end + + it "is invalid without user" do + post = build(:post, user: nil) + post.valid? + expect(post.errors[:user]).to include @error_blank_field + end + + it "is invalid with blank title" do + post = build(:post, title: "") + post.valid? + expect(post.errors[:title]).to include @error_blank_field + end + + it "is invalid with blank content" do + post = build(:post, content: "") + post.valid? + expect(post.errors[:content]).to include @error_blank_field + end + + it "is invalid with blank user_id" do + post = build(:post, user_id: "") + post.valid? + expect(post.errors[:user]).to include @error_blank_field + end + + it "is invalid with wrong user_id" do + post = build(:post, user_id: "this is wrong user_id") + post.valid? + expect(post.errors[:user]).to include @error_blank_field + end +end \ No newline at end of file diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb new file mode 100644 index 0000000..fecc823 --- /dev/null +++ b/spec/models/user_spec.rb @@ -0,0 +1,92 @@ +require 'rails_helper' + +describe User do + before do + @error_blank_field = "can't be blank" + @error_invalid = "is invalid" + end + + it "is valid with email and password" do + user = build(:user) + expect(user).to be_valid + end + + it "is invalid without email" do + user = build(:user, email: nil) + user.valid? + expect(user.errors[:email]).to include @error_blank_field + end + + it "is invalid without password" do + user = build(:user, password: nil) + user.valid? + expect(user.errors[:password]).to include @error_blank_field + end + + it "is invalid without email and password" do + user = build(:user, email: nil, password: nil) + user.valid? + expect(user.errors[:email]).to include @error_blank_field + expect(user.errors[:password]).to include @error_blank_field + end + + it "is invalid with wrong email (foobar.com)" do + user = build(:user, email: "foobar.com") + user.valid? + expect(user.errors[:email]).to include @error_invalid + end + + it "is invalid with wrong email (foo@bar.)" do + user = build(:user, email: "foo@bar.") + user.valid? + expect(user.errors[:email]).to include @error_invalid + end + + it "is invalid with wrong email (foo@bar.1)" do + user = build(:user, email: "foo@bar.1") + user.valid? + expect(user.errors[:email]).to include @error_invalid + end + + it "is invalid with wrong email (foo@bar..com)" do + user = build(:user, email: "foo@bar..com") + user.valid? + expect(user.errors[:email]).to include @error_invalid + end + + it "is invalid with wrong email (more than 255 characters)" do + too_long_name = "a" * 256 + user = build(:user, email: "#{too_long_name}@bar..com") + user.valid? + expect(user.errors[:email]).to include @error_invalid + end + + it "is invalid with blank email" do + user = build(:user, email: "") + user.valid? + expect(user.errors[:email]).to include @error_invalid + end + + it "is invalid with a duplicate password" do + timestamp = Time.now.to_i + email = "foo.duplicate#{timestamp}@bar.com" + first_user = build(:user, email: email) + first_user.save! + + second_user = build(:user, email: email) + second_user.valid? + expect(second_user.errors[:email]).to include("has already been taken") + end + + it "is invalid with blank password" do + user = build(:user, password: "") + user.valid? + expect(user.errors[:password]).to include @error_blank_field + end + + it "is invalid with too short password" do + user = build(:user, password: "123") + user.valid? + expect(user.errors[:password]).to include("is too short (minimum is 8 characters)") + end +end \ No newline at end of file diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000..57ce076 --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,12 @@ +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../config/environment', __FILE__) +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'spec_helper' +require 'rspec/rails' +ActiveRecord::Migration.maintain_test_schema! + +RSpec.configure do |config| + config.include FactoryGirl::Syntax::Methods + config.use_transactional_fixtures = true + config.infer_spec_type_from_file_location! +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..3c862b9 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,9 @@ +RSpec.configure do |config| + config.expect_with :rspec do |expectations| + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + config.mock_with :rspec do |mocks| + mocks.verify_partial_doubles = true + end +end \ No newline at end of file