ReadyResponder/ReadyResponder

View on GitHub
spec/models/person_spec.rb

Summary

Maintainability
A
3 hrs
Test Coverage
require 'rails_helper'

RSpec.describe Person do
  describe 'validations' do
    subject { build :person }
    it { is_expected.to validate_length_of(:state).is_equal_to 2 }
    it { is_expected.to validate_uniqueness_of(:icsid).case_insensitive }
    it { is_expected.to have_many(:inspectors) }
    it { is_expected.to validate_presence_of(:department) }

    describe 'divisions' do
      context 'division 1 present' do
        it 'is invalid if division 2 is blank' do
          person = build :person, division2: ''
          expect(person).not_to be_valid
        end
      end

      context 'division 2 present' do
        it 'is invalid if division 1 is blank' do
          person = build :person, division1: ''
          expect(person).not_to be_valid
        end
      end
    end

    it "zipcode must be 5 digits" do
      person1 = build(:person, zipcode: "abcde")
      person2 = build(:person, zipcode: "1234")
      person3 = build(:person, zipcode: "#2827c")
      person4 = build(:person, zipcode: "12345")
      person5 = build(:person, zipcode: "12345-1234")
      expect(person1).not_to be_valid
      expect(person2).not_to be_valid
      expect(person3).not_to be_valid
      expect(person4).to be_valid
      expect(person5).to be_valid
    end

    it "requires end_date to be after start_date" do # chronology
      person = build(:person, start_date: 2.days.from_now, end_date: 2.days.ago)
      expect(person).not_to be_valid
    end

    describe "application_date_cannot_be_before_start_date" do
      let(:person) { build :person, start_date: start_date, application_date: application_date }

      context "when the start date is not present" do
        let!(:application_date) { Time.zone.today }
        let!(:start_date) { nil }

        it "is a valid person" do
          expect(person).to be_valid
        end
      end

      context "when the application date is not present" do
        let!(:application_date) { nil }
        let!(:start_date) { Time.zone.today }

        it "is a valid person" do
          expect(person).to be_valid
        end
      end

      context "when the application date and start date are the same" do
        let!(:application_date) { Time.zone.today }
        let!(:start_date) { Time.zone.today }

        it "is a valid person" do
          expect(person).to be_valid
        end
      end

      context "when the start date is before the application date" do
        let!(:application_date) { Time.zone.today }
        let!(:start_date) { Time.zone.yesterday }

        it "is not a valid person" do
          expect(person).to_not be_valid
        end
      end
    end
  end

  describe 'date_last for availability' do
    let!(:employee) {create :person}
    let!(:early_available) { create :availability, person: employee,
                             start_time: 300.hours.ago, end_time: 290.hours.ago,
                             status: 'Available' }
    let!(:recent_available) { create :availability, person: employee,
                            start_time: 48.hours.ago, end_time: 24.hours.ago,
                            status: 'Available' }
    let!(:recent_unavailable) { create :availability, person: employee,
                             start_time: 19.hours.ago, end_time: 16.hours.ago,
                             status: 'Unavailable' }
    it 'finds the correct date_last_responded' do
      expect(employee.date_last_responded).to be_within(1.second).of recent_unavailable.created_at
    end
    it 'finds the correct date_last_available' do
      expect(employee.date_last_available).to be_within(1.second).of recent_available.start_time
    end
  end

  describe 'date_last for timecards' do
    let!(:employee) {create :person}
    let!(:early_timecard) { create :timecard, person: employee,
                          start_time: 250.hours.ago, end_time: 225.hours.ago,
                          status: 'Verified'}
    let!(:recent_timecard) { create :timecard, person: employee,
                          start_time: 16.hours.ago, end_time: 8.hours.ago,
                          status: 'Verified'}
    let!(:unverified_timecard) { create :timecard, person: employee,
                          start_time: 2.hours.ago, end_time: 1.hours.ago,
                          status: 'Unverified'}
    it 'finds the correct date_last_worked' do
      expect(employee.date_last_worked).to be_within(1.second).of recent_timecard.start_time
    end
  end

  describe 'skills' do
    subject { create :person }
    let(:evoc_course) { create :course, skills: [skill] }
    let(:skill) { create :skill }
    let(:cert) { create(:cert, {person: subject, course: evoc_course}.merge(cert_options)) }
    let(:cert_options) { {} }

    context 'cert' do
      context 'does not exist' do
        before(:each) { Cert.destroy_all }

        it 'does not have the skill' do
          expect(subject).not_to be_skilled skill.name
        end
      end

      context 'expired' do
        let(:cert_options) { {status: 'Expired'} }

        it 'does not have the skill' do
          expect(cert.course.skills).to include skill
          expect(subject).not_to be_skilled skill.name
        end
      end

      context 'not expired' do
        it 'has the skill' do
          expect(cert.course.skills).to include skill
          expect(subject).to be_skilled skill.name
        end
      end
    end

    describe 'qualification' do
      let(:title) { create :title, skills: [skill] }

      before(:each) { cert }

      context 'has skill required by title' do
        it 'is qualified for the title' do
          expect(subject).to be_skilled skill.name
          expect(subject).to be_qualified title.name
        end
      end

      context 'does not have skill required by title' do
        let(:irrelevant_skill) { create :skill }
        let(:irrelevant_course) { create :course, skills: [irrelevant_skill] }
        let(:cert_options) { {course: irrelevant_course} }

        it 'is not qualified for the title' do
          expect(subject).to be_skilled irrelevant_skill.name
          expect(subject).not_to be_qualified title.name
        end
      end
    end
  end

  describe 'meeting requirement' do
    let(:title) { create :title }
    let(:requirement) { build :requirement, title: title }

    context 'has title of requirement' do
      let(:person) { create :person, titles: [title] }
      it 'meets the requirement' do
        expect(person.meets?(requirement)).to be true
      end
    end
  end
  describe 'associations' do
    it { is_expected.to have_many(:comments) }
  end

  describe 'sort' do
    it 'sorts based on first_name, last_name and middleinitial accordingly' do
      person1 = create(:person, firstname: 'Baily', lastname: 'joss') #6
      person2 = create(:person, firstname: 'AAA', lastname: 'Amose') #1
      person3 = create(:person, firstname: 'Alex', lastname: 'Bane', middleinitial: 'Andy') #4
      person4 = create(:person, firstname: 'Alex', lastname: 'Bane', middleinitial: 'Bndy') #5
      person5 = create(:person, firstname: 'Agon', lastname: 'Jane', middleinitial: 'Sndy') #3
      person6 = create(:person, firstname: 'aaon', lastname: 'Amose', middleinitial: 'Mndy') #2

      expect(Person.all.sort).to eq([person2, person6, person5, person3, person4, person1])
    end
  end

  context 'titled_equal_or_higher_than scope' do
    it 'returns a chainable relation' do
      expect(described_class.titled_equal_or_higher_than('a title'))
        .to be_a_kind_of(ActiveRecord::Relation)
    end

    context 'given 3 people with different titles' do
      let!(:person_1) { create(:person, title: 'Captain') }
      let!(:person_2) { create(:person, title: 'Recruit') }
      let!(:person_3) { create(:person, title: 'Director') }

      let(:title_order) { { 'Captain' => 7, 'Director' => 1,
                            'Recruit' => 23 } }
      let(:default_title_order) { 30 }

      it 'returns the ones titled higher than or equal to the given title' do
        stub_const('Person::TITLE_ORDER', title_order)
        expect(described_class.titled_equal_or_higher_than('Director'))
          .to contain_exactly(person_3)
        expect(described_class.titled_equal_or_higher_than('Captain'))
          .to contain_exactly(person_1, person_3)
      end

      it 'returns all people titled higher than the default title order '\
         'when an invalid title is given' do
        stub_const('Person::DEFAULT_TITLE_ORDER', default_title_order)
        expect(described_class.titled_equal_or_higher_than('no title'))
          .to contain_exactly(person_1, person_2, person_3)
      end
    end
  end

  describe 'calculate_title_order' do
    let!(:director) {create :person, title: 'Director'}
    let!(:chief) {create :person, title: 'Chief'}
    let!(:deputy) {create :person, title: 'Deputy'}
    let!(:captain) {create :person, title: 'Captain'}
    let!(:lieutenant) {create :person, title: 'Lieutenant'}
    let!(:sargeant) {create :person, title: 'Sargeant'}
    let!(:corporal) {create :person, title: 'Corporal'}
    let!(:senior_officer) {create :person, title: 'Senior Officer'}
    let!(:officer) {create :person, title: 'Officer'}
    let!(:cert_member) {create :person, title: 'CERT Member'}
    let!(:dispatcher) {create :person, title: 'Dispatcher'}
    let!(:student_officer) {create :person, title: 'Student Officer'}
    let!(:recruit) {create :person, title: 'Recruit'}
    let!(:applicant) {create :person, title: 'Applicant'}
    let!(:no_title) {create :person, title: 'no_title'}

    it 'sets title_order value to proper rank value or default which is 30' do
      expect(director.title_order).to eq 1
      expect(chief.title_order).to eq 3
      expect(deputy.title_order).to eq 5
      expect(captain.title_order).to eq 7
      expect(lieutenant.title_order).to eq 9
      expect(sargeant.title_order).to eq 11
      expect(corporal.title_order).to eq 13
      expect(senior_officer.title_order).to eq 15
      expect(officer.title_order).to eq 17
      expect(cert_member.title_order).to eq 19
      expect(dispatcher.title_order).to eq 19
      expect(student_officer.title_order).to eq 21
      expect(recruit.title_order).to eq 23
      expect(applicant.title_order).to eq 25
      expect(no_title.title_order).to eq 100
    end
  end

  describe 'fullname' do
    let!(:person_with_nickname) {create :person, nickname: 'tom', firstname: 'thomas', lastname: 'smith'}
    let!(:person) {create :person, nickname: '', firstname: 'roger', lastname: 'smith'}
    let!(:person_with_middleinitial) {create :person, nickname: nil, firstname: 'john', middleinitial: 'g', lastname: 'smith'}

    it 'will return nickname + lastname in camelcase' do
      expect(person_with_nickname.fullname).to eq 'Tom Smith'
    end

    it 'will return firstname + lastname in camelcase' do
      expect(person.fullname).to eq 'Roger Smith'
    end

    it 'will return firstname + middleinitial + lastname in camelcase' do
      expect(person_with_middleinitial.fullname).to eq 'John G Smith'
    end
  end

  describe 'upcoming_events' do
    let(:department) { create :department }
    let(:person) { create :person, department: department }
    let(:e1) { create :event, :upcoming, departments: [department] }
    let(:e2) { create :event, :upcoming, departments: [department] }
    let(:e3) { create :event, :upcoming, departments: [department] }
    let(:e4) { create :event, :upcoming, departments: [department] }
    let(:e5) { create :event, :upcoming, departments: [department] }
    let(:e6) { create :event, :upcoming, departments: [department] }
    let(:e7) { create :event, :upcoming, departments: [department] }
    let(:e8) { create :event, :upcoming, departments: [department] }
    let(:e9) { create :event, :upcoming, departments: [department] }
    let(:e10) { create :event, :upcoming, departments: [department] }
    Setting.where(:key => 'UPCOMING_EVENTS_COUNT').destroy_all
    let(:setting) { Setting.find_or_create_by(:key => 'UPCOMING_EVENTS_COUNT', :value => 5, :category => 'Person', :status => 'Active', :name => 'upcoming_events_count') }

    context 'with settings' do
      it 'returns count from setting' do
        expect(person.upcoming_events).to contain_exactly e6, e7, e8, e9, e10
      end

      it 'returns only the upcoming events' do
        e7.update!(status: 'Closed')
        e9.update!(start_time: 2.days.ago, end_time: 1.day.ago)

        expect(person.upcoming_events).to contain_exactly e6, e8, e10
      end
    end

    context 'without settings' do
      it 'uses fallback value when setting is not available' do
        setting.destroy
        expect(person.upcoming_events).to contain_exactly e1, e2, e3, e4, e5, e6, e7, e8, e9, e10
      end
      it 'returns fallback value when setting is inactive' do
        setting.update_attribute(:status, 'Inactive')
        expect(person.upcoming_events).to contain_exactly e1, e2, e3, e4, e5, e6, e7, e8, e9, e10
      end

      it 'returns only the upcoming events' do
        e1.update!(status: 'Cancelled')
        e3.update!(start_time: 2.hours.ago, end_time: 1.minute.ago)
        e7.update!(start_time: 24.hours.ago, end_time: 20.hours.ago)

        expect(person.upcoming_events).to contain_exactly e2, e4, e5, e6, e8, e9, e10
      end
    end
  end
end