<repo_name>ShvedAction/RailsTimeTraker<file_sep>/test/integration/time_flow_test.rb
require 'test_helper'

class TimeFlowTest < ActionDispatch::IntegrationTest
  # test "the truth" do
  #   assert true
  # end
  
  setup do
    @track_hash_example = { 
      start_time: "2016-11-18T14:56:08+03:00",
      total_time: 3000,
      tag: "some tage",
      work_type: 'developing', #link to type work
    }
  end
  
  test "create temp user when try add track" do
    assert_difference ->{User.count}, 1, "user count should increase" do
      assert_difference ->{Track.count}, 1, "track count should increase" do
        open_session do |sess|
          sess.extend(UserSessionHelper)
          
          sess.add_track @track_hash_example
          
          assert sess.current_user.temporary?, "user should be temp"
        end
      end
    end
  end
  
  test "in one session a track should create for current user" do
  
    user_session = build_some_user
    
    #get model from this session
    user = user_session.current_user
    assert_difference ->{user.tracks.count}, 1, "tracks count of user should increase by 1" do
      user_session.add_track @track_hash_example
    end
  end
  
  test "after sign up, user should be auth" do
    login = "new_login"
    password = "<PASSWORD>"
    
    #Given:
    user_with_login_should_not_exist login, "Given error:"
    
    user_session = build_session_for_user login, password
    user_session.sign_up
    
    #Verify that user is auth, passes inside next method. See defenition
    user_session.should_success_sign_up
    
    user_session.should_out_login_in_tag 'span'
  end
  
  private 

    def build_some_user login="some_login", password="<PASSWORD>"
      #Given:
      user_with_login_should_not_exist login, "Given error:"
      
      user = build_session_for_user login, password
      user.sign_up
      
      #follow redirect in this method
      user.should_success_sign_up
      
      return user
    end
end
<file_sep>/test/user_session_helper.rb
module UserSessionHelper
  def set_login_password login, password
    @login = login
    @password = <PASSWORD>
  end
  
  def sign_up
    post "/users", params: {user: {login: @login, password: <PASSWORD>, password_confirmation: <PASSWORD>}}
  end
  
  def log_in
    post '/user/log_in', params: {user: {login: @login, password: <PASSWORD>}}
  end
  
  def add_track track_hash
    post "/tracks", params: {track: track_hash}
  end
  
  def should_success_logining message=""
    assert !!User.find_by(login: @login), "#{message} For success logining, user should be in database."
    assert_equal current_user.id, controller.session[:current_user_id], "#{message} For success logining, session should have user_id."
  end
  
  def should_success_sign_up message=""
    follow_redirect!
    should_success_logining message
  end
  
  def should_out_login_in_tag tag_name, message=""
    assert_select tag_name, @login, message
  end
  
  def current_user
    @current_user ||= User.find session[:current_user_id]
  end
end

<file_sep>/test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'user_session_helper'

class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
  fixtures :all

  # Add more helper methods to be used by all tests here...
  
  def user_with_login_should_exist login, message = ""
    assert !!User.find_by(login: login), "#{message} User with login: #{login} should exist."
  end
  
  def user_with_login_should_not_exist login, message = ""
    assert_nil User.find_by(login: login), "#{message} User with login: #{login} should not exist."
  end
  
  def build_session_for_user login, password, description_case = ""
    open_session do |sess|
      sess.extend(UserSessionHelper)
      sess.set_login_password login, password
    end
  end
  
end
<file_sep>/app/controllers/tracks_controller.rb
class TracksController < ApplicationController
  before_action :set_track, only: [:show, :edit, :update, :destroy]
  before_action :set_user, except: :create
  before_action :set_current_user, only: [:update, :destroy, :create]
  before_action :chenge_only_my_tracks, only: [:update, :destroy]

  # GET /users/1/tracks
  # GET /users/1/tracks.json
  def index
    @tracks = @user.tracks.all
  end

  # GET /users/1/tracks/1
  # GET /users/1/tracks/1.json
  def show
  end

  # GET /users/1/tracks/new
  def new
    @track = Track.new
  end

  # GET /users/1/tracks/1/edit
  def edit
  end

  # POST /users/1/tracks
  # POST /users/1/tracks.json
  def create
    @track = @current_user.tracks.new(track_params)

    respond_to do |format|
      if @track.save
        format.html { redirect_to @track, notice: 'Track was successfully created.' }
        format.json { render :show, status: :created, location: @track }
      else
        format.html { render :new }
        format.json { render json: @track.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /users/1/tracks/1
  # PATCH/PUT /users/1/tracks/1.json
  def update
    respond_to do |format|
      if @track.update(track_params)
        format.html { redirect_to @track, notice: 'Track was successfully updated.' }
        format.json { render :show, status: :ok, location: @track }
      else
        format.html { render :edit }
        format.json { render json: @track.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1/tracks/1
  # DELETE /users/1/tracks/1.json
  def destroy
    @track.destroy
    respond_to do |format|
      format.html { redirect_to user_tracks_url @user, notice: 'Track was successfully destroyed.' }
      format.json { head :no_content }
    end
  end
  
  def track_url track
    user_tracks_url track.user
  end
  
  private
    # Use callbacks to share common setup or constraints between actions.
    def set_track
      @track = Track.find(params[:id])
    end
    
    def set_user
      @user = User.find params[:user_id]
    end
    
    def set_current_user
      if session[:current_user_id]
        @current_user = User.find session[:current_user_id]
      else
        @current_user = User.create_temp
        session[:current_user_id] = @current_user.id
      end
    end
    
    def chenge_only_my_tracks
      redirect_to user_tracks_url @user if !@current_user && @current_user.id != @user.id
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def track_params
      params.require(:track).permit(:start_time, :end_time, :total_time, :tag, :work_type, :user_id)
    end
end
<file_sep>/test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  # test "the truth" do
  #   assert true
  # end
  
  test "should not save if confirmation_password does not mach password" do
    login = "login_for_incorrect_password"
    
    #Given:
    assert_nil User.find_by(login: login), "Given error: User with login #{login} should not exist."
    
    new_user = User.new login: login, password: "<PASSWORD>", password_confirmation:"<PASSWORD>"
    
    #When:
    assert_raises ActiveRecord::RecordInvalid, "User with incorrect confirmation password have saved." do
      new_user.registration!
    end
    
    #Then:
    assert_nil User.find_by(login: login), "User with incorrect confirmation password have found."
  end
  
  test "should save if confirmation_password mach password" do
    login = "no_exist_login"
    password = "<PASSWORD>"
    
    #Given:
    assert_nil User.find_by(login: login), "Given error: User with login #{login} should not exist."
    
    new_user = User.new login: login, password: <PASSWORD>, password_confirmation: <PASSWORD>
    
    #When:
    assert_difference 'User.count', 1, "User with correct confirmation password should saved." do
      new_user.registration!
    end
    
    #Then:
    assert !!User.find_by(login: login), "User with correct confirmation password should found."
  end
  
  test "should save without password if his auth_type is temp_user" do
  
    temp_user = User.new auth_type: 'temporary'
    
    #When:
    assert_difference 'User.count', 1, "Temp user should saved." do
      temp_user.save
    end
    
    #Then:
    refute_empty temp_user.login, "Temp user should have unic login"
  end
  
  test "on new User should auth_type init with deffault auth_type is registred" do
    new_user = User.new
    
    assert new_user.registred?, "default auth_type should be registred"
  end
  
  test "after registration new user, class method 'log_in' should return user if hash of password and login match record in DB" do
    login = "model_try_login"
    password = "<PASSWORD> <PASSWORD>"
    
    #Given:
    assert_nil User.find_by(login: login), "Given error: User with login #{login} should not exist."
    
    user = User.new login: login, password: <PASSWORD>, password_confirmation: <PASSWORD>
    user.registration!
    
    #When:
    logining_user = User.log_in({login: login, password: <PASSWORD>})
    
    #Then:
    assert !!logining_user, "retunred value from method log_in should not be nil"
    assert !!logining_user.id, "id user should not be nil"
    assert_equal login, logining_user.login
  end
  
  test "class method log_in shoul return nil if wrong password" do
    login = "model_try_login"
    true_password = "<PASSWORD>"
    wron_password = "<PASSWORD>"
    
    #Given:
    assert_nil User.find_by(login: login), "Given error: User with login #{login} should not exist."
    
    user = User.new login: login, password: <PASSWORD>, password_confirmation: <PASSWORD>
    user.registration!
    
    #When:
    logining_user = User.log_in({login: login, password: <PASSWORD>})
    
    #Then:
    assert_nil logining_user
  end
  
  
  test "class method create_temp should save user with no empty login" do  
  
    assert_difference -> {User.count}, 1, "user count should increase" do
      temp_user = User.create_temp
      refute_empty temp_user.login, "login of temp user should not be empty"
    end
    
  end
end
<file_sep>/config/routes.rb
Rails.application.routes.draw do

  resources :users do
    resources :tracks, except: :create
  end
  resources :tracks, only: :create
  
  post "user/log_in" => "users#log_in", as: :user_log_in, defaults: {login: nil, password: nil}
end
<file_sep>/app/views/tracks/_track.json.jbuilder
json.extract! track, :id, :start_time, :end_time, :total_time, :tag, :work_type, :user_id, :created_at, :updated_at
json.url track_url(track, format: :json)<file_sep>/test/controllers/tracks_controller_test.rb
require 'test_helper'

class TracksControllerTest < ActionDispatch::IntegrationTest
  setup do
    @track = tracks(:one)
    @user = users(:one)
  end

  test "should get index" do
    get user_tracks_url(@track.user, @track)
    assert_response :success
  end

  test "should get new for current user" do
    get new_user_track_url(@user)
    assert_response :success
  end
  
  test "should get edit" do
    get edit_user_track_url(@track.user, @track)
    assert_response :success
  end

  test "should update track" do
    patch user_track_url(@track.user, @track), params: { track: { end_time: @track.end_time, start_time: @track.start_time, tag: @track.tag, total_time: @track.total_time, user_id: @track.user_id, work_type: @track.work_type } }
    assert_redirected_to user_tracks_url(@user)
  end

  test "should destroy track" do
    assert_difference('Track.count', -1) do
      delete user_track_url(@track.user, @track)
    end

    follow_redirect!
  end
end
<file_sep>/app/models/user.rb
require 'securerandom'

class User < ApplicationRecord
  has_many :tracks
  enum auth_type: [:registred, :temporary]
  validates :password, confirmation: true, if: :registred?
  after_initialize :set_default_values
  before_save :genrate_unic_login, if: :temporary?
  
  def set_default_values
    self.auth_type ||= 'registred'
  end
  
  def genrate_unic_login 
    self.login ||= SecureRandom.uuid.gsub('-','')
  end
  
  def registration!
    self.password = <PASSWORD>(password)
    self.password_confirmation = <PASSWORD>.password_encrypt_method(password_confirmation)
    
    #save
    self.registred!
  end
  
  def self.log_in params
    return User.find_by login: params[:login], password: <PASSWORD>(params[:password])
  end
  
  def self.create_temp
    return User.create auth_type: 'temporary'
  end
  
  protected
  def self.password_encrypt_method password
    return Digest::MD5.hexdigest password
  end
end
<file_sep>/test/controllers/users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionDispatch::IntegrationTest

  USER_LOGIN_ALLREADY_USED = 'allready_used_login'
  PASSWORD_OF_ALLREADY_USED_USER = '<PASSWORD>'
  

  setup do
    @user = User.create login: USER_LOGIN_ALLREADY_USED, password: password_encrypt_method(PASSWORD_OF_ALLREADY_USED_USER)
  end
  
  def password_encrypt_method pass
    return Digest::MD5.hexdigest pass
  end

  #общий сценрий при котором пользователь не создаётся
  def user_should_not_create_with login, pass, confirm_pass
    assert_no_difference('User.count')do
      post users_url, params: { 
        user: { 
          login: login, 
          password: <PASSWORD>, 
          password_confirmation: <PASSWORD> 
        } 
      }
    end
  end

  #Для демонстрации
  test "should get index" do
    get users_url
    assert_response :success
  end

  test "should get new" do
    get new_user_url
    assert_response :success
  end

  test "should create user if confirmation match with password" do
  
    login = 'login_for_new_user'
    password = '<PASSWORD>'
    
    #Given:
    assert_nil User.find_by(login: login), "Given error: User with login:#{login} should not exist."
    
    #When:
    assert_difference('User.count') do
      post users_url, params: { 
        user: { 
          login: login, 
          password: <PASSWORD>, 
          password_confirmation: <PASSWORD> 
        } 
      }
    end

    #Then:
    created_user = User.last
    assert_redirected_to user_url(created_user)
    assert_equal login, created_user.login
  end

  test "should not create user if confirmation does not match with password" do
  
    login = 'login_for_new_user_bad_confirm'
    password = '<PASSWORD>'
    pass_confirmation = '<PASSWORD>'
    
    #Given:
    assert_nil User.find_by(login: login), "Given error: User with login:#{login} should not exist."
  
    #When:
    user_should_not_create_with login, password, pass_confirmation
  end


  test "should not create user if login allready exist" do
  
    login = USER_LOGIN_ALLREADY_USED
    password = '<PASSWORD>'
    pass_confirmation = '<PASSWORD>'
  
    #Given:
    assert !!User.find_by(login: login), "Given error: User with login:#{login} should exist."
    
    #When:
    user_should_not_create_with login, password, pass_confirmation
    
  end

  test "should show user" do
  
    #Given:
    assert !!@user, "Given error: User with login:#{@user.login} should exist."
  
    get user_url(@user)
    assert_response :success
  end
  
  test "after log in session should had user_id" do
    login = USER_LOGIN_ALLREADY_USED
    password = <PASSWORD>
    password_hash = <PASSWORD>
    
    #Given:
    user = User.find_by(login: login)
    assert !!user, "Given error: User with login:#{login} should exist."
    assert_equal password_hash, user.password, "Given error: User with login:#{login} should have correct hash of password."
    
    #When:
    post user_log_in_url, params: {user: {login: login, password: <PASSWORD>}}
    
    #Then:
    assert_response :success
    assert_equal user.id, session[:current_user_id]
  end
end
<file_sep>/app/models/track.rb
class Track < ApplicationRecord
  belongs_to :user
  enum :work_type => [:designing, :developing, :analis, :testing, :training]
end
