diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..83e16f8 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/Gemfile b/Gemfile index a72e420..7d44834 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,8 @@ source 'https://rubygems.org' gem 'rails', '4.2.3' # Use postgresql as the database for Active Record gem 'pg' +# Use bcrypt for password encryption +gem 'bcrypt' # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets @@ -41,5 +43,9 @@ group :development, :test do # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' + + # Use rpsec and Factory Girl for tests + gem 'rspec-rails' + gem 'factory_girl_rails' end diff --git a/Gemfile.lock b/Gemfile.lock index bd152e6..017d4a3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -37,6 +37,7 @@ GEM thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) arel (6.0.3) + bcrypt (3.1.10) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) builder (3.2.2) @@ -49,12 +50,18 @@ GEM execjs coffee-script-source (1.9.1.1) debug_inspector (0.0.2) + diff-lcs (1.2.5) erubis (2.7.0) execjs (2.6.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) i18n (0.7.0) - jbuilder (2.3.1) + jbuilder (2.3.2) activesupport (>= 3.0.0, < 5) multi_json (~> 1.2) jquery-rails (4.0.5) @@ -102,7 +109,23 @@ GEM thor (>= 0.18.1, < 2.0) rake (10.4.2) rdoc (4.2.0) - json (~> 1.4) + 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) sass (3.4.18) sass-rails (5.0.4) railties (>= 4.0.0, < 5.0) @@ -140,15 +163,21 @@ PLATFORMS ruby DEPENDENCIES + bcrypt byebug coffee-rails (~> 4.1.0) + factory_girl_rails jbuilder (~> 2.0) jquery-rails pg rails (= 4.2.3) + rspec-rails sass-rails (~> 5.0) sdoc (~> 0.4.0) spring turbolinks uglifier (>= 1.3.0) web-console (~> 2.0) + +BUNDLED WITH + 1.10.6 diff --git a/app/assets/javascripts/dashboards.coffee b/app/assets/javascripts/dashboards.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/dashboards.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/sessions.coffee b/app/assets/javascripts/sessions.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/sessions.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/users.coffee b/app/assets/javascripts/users.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/users.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/verifications.coffee b/app/assets/javascripts/verifications.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/verifications.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/dashboards.scss b/app/assets/stylesheets/dashboards.scss new file mode 100644 index 0000000..d82c52e --- /dev/null +++ b/app/assets/stylesheets/dashboards.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the dashboards controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/sessions.scss b/app/assets/stylesheets/sessions.scss new file mode 100644 index 0000000..7bef9cf --- /dev/null +++ b/app/assets/stylesheets/sessions.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the sessions controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss new file mode 100644 index 0000000..31a2eac --- /dev/null +++ b/app/assets/stylesheets/users.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Users controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/verifications.scss b/app/assets/stylesheets/verifications.scss new file mode 100644 index 0000000..67f0ff2 --- /dev/null +++ b/app/assets/stylesheets/verifications.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Verifications controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/dashboards_controller.rb b/app/controllers/dashboards_controller.rb new file mode 100644 index 0000000..1b8d57e --- /dev/null +++ b/app/controllers/dashboards_controller.rb @@ -0,0 +1,5 @@ +class DashboardsController < ApplicationController + def new + @user = User.find(session[:user_id]) + end +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000..0ae67f0 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,24 @@ +class SessionsController < ApplicationController + def new + @user = User.new + end + + def create + @user = User.where( + "email = ? AND verified_at IS NOT NULL", + params[:email] + ).first + if @user && @user.authenticate(params[:password]) + session[:user_id] = @user.id + redirect_to dashboard_path + else + flash.now[:alert] = "Email or password didn't match" + render :new + end + end + + def destroy + reset_session + redirect_to signin_path + end +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..1735dc6 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,21 @@ +class UsersController < ApplicationController + def new + @user = User.new + end + + def create + @user = User.new(user_params) + if @user && @user.password == @user.password_confirmation + @user.save! + redirect_to verify_path(user_id: @user.id) + else + redirect_to signup_path + end + end + + private + + def user_params + params.require(:user).permit(:email, :password, :password_confirmation) + end +end diff --git a/app/controllers/verifications_controller.rb b/app/controllers/verifications_controller.rb new file mode 100644 index 0000000..7ec834b --- /dev/null +++ b/app/controllers/verifications_controller.rb @@ -0,0 +1,18 @@ +require "securerandom" + +class VerificationsController < ApplicationController + def new + @user = User.find(params[:user_id]) + @user.verification_token = SecureRandom.hex(20) + @user.save! + UserMailer.verify(@user).deliver_now + end + + def create + @user = User.find_by(verification_token: params[:token]) + @user.verified_at = Time.now + @user.save! + flash[:notice] = "Email verified. Please sign in." + redirect_to signin_path + end +end diff --git a/app/helpers/dashboards_helper.rb b/app/helpers/dashboards_helper.rb new file mode 100644 index 0000000..28cd48d --- /dev/null +++ b/app/helpers/dashboards_helper.rb @@ -0,0 +1,2 @@ +module DashboardsHelper +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb new file mode 100644 index 0000000..309f8b2 --- /dev/null +++ b/app/helpers/sessions_helper.rb @@ -0,0 +1,2 @@ +module SessionsHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 0000000..2310a24 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/app/helpers/verifications_helper.rb b/app/helpers/verifications_helper.rb new file mode 100644 index 0000000..2571b95 --- /dev/null +++ b/app/helpers/verifications_helper.rb @@ -0,0 +1,2 @@ +module VerificationsHelper +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..d25d889 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout 'mailer' +end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb new file mode 100644 index 0000000..ca7d26e --- /dev/null +++ b/app/mailers/user_mailer.rb @@ -0,0 +1,13 @@ +class UserMailer < ApplicationMailer + default from: "donotreply@rubycommited.com" + + def verify(user) + @user = user + mail to: @user.email, subject: "[Ruby Committed] Verify Email" + end + + def reset_password(user) + @user = user + mail to: @user.email, subect: "[Ruby Committed] Reset Password" + end +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..5fca39b --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,8 @@ +class User < ActiveRecord::Base + has_secure_password + + validates :email, + presence: true, + format: /\A[^@\s]+@[^@\s]+\z/, + uniqueness: true +end diff --git a/app/views/dashboards/new.html.erb b/app/views/dashboards/new.html.erb new file mode 100644 index 0000000..4f7490f --- /dev/null +++ b/app/views/dashboards/new.html.erb @@ -0,0 +1,3 @@ +

Dashboard

+ +<%= link_to "Sign Out", signout_path, method: "DELETE" %> diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..991cf0f --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,5 @@ + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb new file mode 100644 index 0000000..13c8f60 --- /dev/null +++ b/app/views/sessions/new.html.erb @@ -0,0 +1,13 @@ +Sign In + +<%= form_tag do %> + <%= label_tag :email, "Email" %> + <%= email_field_tag :email %> +
+ <%= label_tag :password, "Password" %> + <%= password_field_tag :password %> +
+ <%= submit_tag "Sign In" %> +<% end %> +
+
diff --git a/app/views/user_mailer/verify.text.erb b/app/views/user_mailer/verify.text.erb new file mode 100644 index 0000000..1212010 --- /dev/null +++ b/app/views/user_mailer/verify.text.erb @@ -0,0 +1,3 @@ +Please click the following link to verify your email: + +<%= confirm_url(token: @user.verification_token) %> diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb new file mode 100644 index 0000000..423dc5d --- /dev/null +++ b/app/views/users/new.html.erb @@ -0,0 +1,14 @@ +Sign Up! + +<%= form_for @user, url: signup_path do |f| %> + <%= f.label :email, "Email" %> + <%= f.email_field :email %> +
+ <%= f.label :password, "Password" %> + <%= f.password_field :password %> +
+ <%= f.label :password_confirmation, "Confirm Password" %> + <%= f.password_field :password_confirmation %> +
+ <%= f.submit %> +<% end %> diff --git a/app/views/verifications/new.html.erb b/app/views/verifications/new.html.erb new file mode 100644 index 0000000..e44df3c --- /dev/null +++ b/app/views/verifications/new.html.erb @@ -0,0 +1,2 @@ +

Please Verify Your Email

+

An email has been sent to <%= @user.email %>. Please click on the link in that message to verify your email address.

diff --git a/bin/rspec b/bin/rspec new file mode 100755 index 0000000..0c86b5c --- /dev/null +++ b/bin/rspec @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# +# This file was generated by Bundler. +# +# The application 'rspec' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('rspec-core', 'rspec') diff --git a/config/database.yml.sample b/config/database.yml.sample index d43355b..0cf7198 100644 --- a/config/database.yml.sample +++ b/config/database.yml.sample @@ -57,7 +57,7 @@ development: # Do not set this db to the same as development or production. test: <<: *default - database: committed_test + database: committed_development # As with config/secrets.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is diff --git a/config/environments/development.rb b/config/environments/development.rb index b55e214..ca361a6 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -38,4 +38,6 @@ # Raises error for missing translations # config.action_view.raise_on_missing_translations = true + + config.action_mailer.default_url_options = { :host => "localhost:3000" } end diff --git a/config/routes.rb b/config/routes.rb index 3f66539..ff5d781 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,21 @@ Rails.application.routes.draw do + + get "signup" => "users#new", as: :signup + post "signup" => "users#create" + get "signin" => "sessions#new", as: :signin + post "signin" => "sessions#create" + delete "signout" => "sessions#destroy" + get "verify/:user_id" => "verifications#new", as: :verify + get "verify/confirm/:token" => "verifications#create", as: :confirm + get "reset_password" => "password_resets#new", as: :reset_password + post "reset_password" => "password_resets#create" + get "reset_password/:token/edit" => "password_resets#edit", as: :edit_reset_password + post "reset_password/:token/edit" => "password_resets#update" + get "dashboard" => "dashboards#new", as: :dashboard + + + + # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". diff --git a/db/migrate/20151004184620_create_users.rb b/db/migrate/20151004184620_create_users.rb new file mode 100644 index 0000000..048c182 --- /dev/null +++ b/db/migrate/20151004184620_create_users.rb @@ -0,0 +1,12 @@ +class CreateUsers < ActiveRecord::Migration + def change + create_table :users do |t| + t.string :email, null: false, index: :unique + t.string :password_digest, null: false + t.string :verification_token + t.datetime :verified_at + t.string :password_reset_token + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..f3e9ef4 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,31 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 20151004184620) do + + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + + create_table "users", force: :cascade do |t| + t.string "email", null: false + t.string "password_digest", null: false + t.string "verification_token" + t.datetime "verified_at" + t.string "password_reset_token" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "users", ["email"], name: "index_users_on_email", using: :btree + +end diff --git a/spec/controllers/dashboards_controller_spec.rb b/spec/controllers/dashboards_controller_spec.rb new file mode 100644 index 0000000..c9e7cbc --- /dev/null +++ b/spec/controllers/dashboards_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe DashboardsController, type: :controller do + +end diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb new file mode 100644 index 0000000..9d02c1e --- /dev/null +++ b/spec/controllers/sessions_controller_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +RSpec.describe SessionsController, type: :controller do + it "prevents invalid users from signing in" do + user = FactoryGirl.create(:user) + post :create, email: user.email, password: "" + assert_response(:success) + expect(session[:user_id]).not_to eq(user.id) + end + + it "signs in valid users" do + user = FactoryGirl.create(:user) + post :create, email: user.email, password: user.password + assert_response(:redirect) + expect(session[:user_id]).to eq(user.id) + end +end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb new file mode 100644 index 0000000..300064c --- /dev/null +++ b/spec/controllers/users_controller_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe UsersController, type: :controller do + it "creates new users" do + attributes = {user: FactoryGirl.attributes_for(:user) } + expect(User.find_by(email: attributes[:user][:email])).to be_nil + post :create, attributes + assert_response(:redirect) + expect(User.find_by(email: attributes[:user][:email])).not_to be_nil + end + + it "returns the form if there are errors" do + attributes = {user: FactoryGirl.attributes_for(:user) } + attributes[:user][:password] = "" + expect(User.find_by(email: attributes[:user][:email])).to be_nil + post :create, attributes + assert_response(:redirect) + user = assigns[:user] + expect(user.email).to eq(attributes[:user][:email]) + expect(User.find_by(email: attributes[:user][:email])).to be_nil + end +end diff --git a/spec/controllers/verifications_controller_spec.rb b/spec/controllers/verifications_controller_spec.rb new file mode 100644 index 0000000..4a4ec7b --- /dev/null +++ b/spec/controllers/verifications_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe VerificationsController, type: :controller do + +end diff --git a/spec/factories/users.rb b/spec/factories/users.rb new file mode 100644 index 0000000..cd2d6c8 --- /dev/null +++ b/spec/factories/users.rb @@ -0,0 +1,8 @@ +FactoryGirl.define do + factory :user do + sequence(:email) { |n| "user#{n}@website.com" } + password "password" + password_confirmation "password" + verified_at Time.now + end +end diff --git a/spec/helpers/dashboards_helper_spec.rb b/spec/helpers/dashboards_helper_spec.rb new file mode 100644 index 0000000..d68481c --- /dev/null +++ b/spec/helpers/dashboards_helper_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the DashboardsHelper. For example: +# +# describe DashboardsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe DashboardsHelper, type: :helper do +end diff --git a/spec/helpers/sessions_helper_spec.rb b/spec/helpers/sessions_helper_spec.rb new file mode 100644 index 0000000..38c13fc --- /dev/null +++ b/spec/helpers/sessions_helper_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the SessionsHelper. For example: +# +# describe SessionsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe SessionsHelper, type: :helper do +end diff --git a/spec/helpers/verifications_helper_spec.rb b/spec/helpers/verifications_helper_spec.rb new file mode 100644 index 0000000..ec425a9 --- /dev/null +++ b/spec/helpers/verifications_helper_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the VerificationsHelper. For example: +# +# describe VerificationsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe VerificationsHelper, type: :helper do +end diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb new file mode 100644 index 0000000..957e12b --- /dev/null +++ b/spec/mailers/previews/user_mailer_preview.rb @@ -0,0 +1,4 @@ +# Preview all emails at http://localhost:3000/rails/mailers/user_mailer +class UserMailerPreview < ActionMailer::Preview + +end diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb new file mode 100644 index 0000000..4ad85dc --- /dev/null +++ b/spec/mailers/user_mailer_spec.rb @@ -0,0 +1,4 @@ +require "rails_helper" + +RSpec.describe UserMailer, type: :mailer do +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb new file mode 100644 index 0000000..5ff2ca8 --- /dev/null +++ b/spec/models/user_spec.rb @@ -0,0 +1,55 @@ +require 'rails_helper' + +RSpec.describe User, type: :model do + it "makes sure the email is present" do + user = FactoryGirl.build(:user, email: nil) + expect(user).not_to be_valid + expect(user.errors[:email]).not_to be_empty + end + + it "ensures the email is well-formed" do + user = FactoryGirl.build(:user, email: "bad fake email") + expect(user).not_to be_valid + expect(user.errors[:email]).not_to be_empty + end + + it "ensures the email is unique" do + user1 = FactoryGirl.create(:user) + user2 = FactoryGirl.build(:user, email: user1.email) + expect(user1).to be_valid + expect(user2).not_to be_valid + expect(user2.errors[:email]).not_to be_empty + end + + it "ensures the password is present when user created" do + user = FactoryGirl.build(:user, password: nil) + expect(user).not_to be_valid + expect(user.errors[:password]).not_to be_empty + end + + it "ensures password confirmation is present on change" do + user = FactoryGirl.build( + :user, + password: "password", + password_confirmation: "" + ) + expect(user).not_to be_valid + expect(user.errors[:password_confirmation]).not_to be_empty + end + + it "ensures password is confirmed on change" do + user = FactoryGirl.build( + :user, + password: "password", + password_confirmation: "123" + ) + expect(user).not_to be_valid + expect(user.errors[:password_confirmation]).not_to be_empty + end + + it "allows user authentication" do + user = FactoryGirl.build(:user) + expect(user.authenticate("password")).to be_truthy + expect(user.authenticate("123")).to be_falsey + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000..88ff2d0 --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,52 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../config/environment', __FILE__) +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'spec_helper' +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } + +# Checks for pending migrations before tests are run. +# If you are not using ActiveRecord, you can remove this line. +ActiveRecord::Migration.maintain_test_schema! + +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, :type => :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + 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..913e28a --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,92 @@ +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # These two settings work together to allow you to limit a spec run + # to individual examples or groups you care about by tagging them with + # `:focus` metadata. When nothing is tagged with `:focus`, all examples + # get run. + config.filter_run :focus + config.run_all_when_everything_filtered = true + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching + config.disable_monkey_patching! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end