From 9a818fd84e75935d07890b3055f8f3b70e0ec080 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Sat, 27 Jul 2024 13:36:02 +0200 Subject: [PATCH] Add spec for creating visits with points --- .github/workflows/ci.yml | 6 +- app/services/areas/visits/create.rb | 4 +- spec/services/areas/visits/create_spec.rb | 93 +++++++++++++++++++++++ 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 741c63e3..328bab92 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,9 +29,12 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: .ruby-version + ruby-version: '3.2.3' bundler-cache: true + - name: Install dependencies + run: bundle install + - name: Run tests env: RAILS_ENV: test @@ -45,6 +48,7 @@ jobs: name: screenshots path: ${{ github.workspace }}/tmp/capybara if-no-files-found: ignore + - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4.0.1 with: diff --git a/app/services/areas/visits/create.rb b/app/services/areas/visits/create.rb index 6a3f21fb..6d429957 100644 --- a/app/services/areas/visits/create.rb +++ b/app/services/areas/visits/create.rb @@ -58,7 +58,7 @@ class Areas::Visits::Create Rails.logger.info("Visit from #{time_range}, Points: #{visit_points.size}") ActiveRecord::Base.transaction do - visit = find_visit(area.id, visit_points.first.timestamp) + visit = find_or_initialize_visit(area.id, visit_points.first.timestamp) visit.tap do |v| v.name = "#{area.name}, #{time_range}" @@ -73,7 +73,7 @@ class Areas::Visits::Create end end - def find_visit(area_id, timestamp) + def find_or_initialize_visit(area_id, timestamp) Visit.find_or_initialize_by( area_id:, user_id: user.id, diff --git a/spec/services/areas/visits/create_spec.rb b/spec/services/areas/visits/create_spec.rb index a6581558..655993c6 100644 --- a/spec/services/areas/visits/create_spec.rb +++ b/spec/services/areas/visits/create_spec.rb @@ -4,5 +4,98 @@ require 'rails_helper' RSpec.describe Areas::Visits::Create do describe '#call' do + let(:user) { create(:user) } + let(:home_area) { create(:area, user:, latitude: 0, longitude: 0, radius: 100) } + let(:work_area) { create(:area, user:, latitude: 1, longitude: 1, radius: 100) } + + subject(:create_visits) { described_class.new(user, [home_area, work_area]).call } + + context 'when there are no points' do + it 'does not create visits' do + expect { create_visits }.not_to(change { Visit.count }) + end + + it 'does not log any visits' do + expect(Rails.logger).not_to receive(:info) + create_visits + end + end + + context 'when there are points' do + let(:home_visit_date) { DateTime.new(2021, 1, 1, 10, 0, 0, Time.zone.formatted_offset) } + let!(:home_point1) { create(:point, user:, latitude: 0, longitude: 0, timestamp: home_visit_date) } + let!(:home_point2) { create(:point, user:, latitude: 0, longitude: 0, timestamp: home_visit_date + 10.minutes) } + let!(:home_point3) { create(:point, user:, latitude: 0, longitude: 0, timestamp: home_visit_date + 20.minutes) } + + let(:work_visit_date) { DateTime.new(2021, 1, 1, 12, 0, 0, Time.zone.formatted_offset) } + let!(:work_point1) { create(:point, user:, latitude: 1, longitude: 1, timestamp: work_visit_date) } + let!(:work_point2) { create(:point, user:, latitude: 1, longitude: 1, timestamp: work_visit_date + 10.minutes) } + let!(:work_point3) { create(:point, user:, latitude: 1, longitude: 1, timestamp: work_visit_date + 20.minutes) } + + it 'creates visits' do + expect { create_visits }.to change { Visit.count }.by(2) + end + + it 'creates visits with correct points' do + create_visits + + home_visit = Visit.find_by(area_id: home_area.id) + work_visit = Visit.find_by(area_id: work_area.id) + + expect(home_visit.points).to match_array([home_point1, home_point2, home_point3]) + expect(work_visit.points).to match_array([work_point1, work_point2, work_point3]) + end + + context 'when there are points outside the time threshold' do + let(:home_point4) { create(:point, user:, latitude: 0, longitude: 0, timestamp: home_visit_date + 40.minutes) } + + it 'does not create visits' do + expect { create_visits }.to change { Visit.count }.by(2) + end + + it 'does not include points outside the time threshold' do + create_visits + + home_visit = Visit.find_by(area_id: home_area.id) + work_visit = Visit.find_by(area_id: work_area.id) + + expect(home_visit.points).to match_array([home_point1, home_point2, home_point3]) + expect(work_visit.points).to match_array([work_point1, work_point2, work_point3]) + end + end + + context 'when there are visits already' do + let!(:home_visit) do + create(:visit, + user:, + started_at: Time.zone.at(home_point1.timestamp), + name: 'Home', + area: home_area, + points: [home_point1, home_point2]) + end + let!(:work_visit) do + create(:visit, + user:, + started_at: Time.zone.at(work_point1.timestamp), + name: 'Work', + area: work_area, + points: [work_point1, work_point2]) + end + + it 'does not create new visits' do + expect { create_visits }.not_to(change { Visit.count }) + end + + it 'updates existing visits' do + create_visits + + home_visit = Visit.find_by(area_id: home_area.id) + work_visit = Visit.find_by(area_id: work_area.id) + + expect(home_visit.points).to match_array([home_point1, home_point2, home_point3]) + expect(work_visit.points).to match_array([work_point1, work_point2, work_point3]) + end + end + end end end