From 0e047d2dfa6d0fe7fa1634aea88d61bd7bf52b6b Mon Sep 17 00:00:00 2001 From: Colby Endres <70925616+colbyendres@users.noreply.github.com> Date: Wed, 23 Oct 2024 18:20:25 -0500 Subject: [PATCH] Migrate home page and CSV parsing logic (#32) * Migrate homepage to schedule index * Fixed RSpec failures * Migrate CSV logic to separate service * Update Cucumber scenarios * Change class name to satisfy autoloader * Remove unused require --- app/controllers/csv_controller.rb | 41 -------- app/controllers/schedules_controller.rb | 98 +++---------------- app/controllers/welcome_controller.rb | 4 +- app/services/csv_handler.rb | 89 +++++++++++++++++ app/views/schedules/show.html.erb | 2 +- app/views/users/show.html.erb | 23 ----- config/routes.rb | 5 +- features/csv_upload.feature | 26 ----- features/schedules.feature | 20 +++- features/step_definitions/csv_upload_steps.rb | 19 ---- features/step_definitions/schedules_steps.rb | 16 +++ features/step_definitions/welcome.rb | 2 +- features/welcome.feature | 5 +- .../application_controller_spec.rb | 1 - spec/controllers/csv_controller_spec.rb | 37 ------- spec/controllers/schedules_controller_spec.rb | 5 +- spec/controllers/welcome_controller_spec.rb | 7 +- .../instructors_missing_headers.csv | 5 + spec/services/csv_handler_spec.rb | 72 ++++++++++++++ 19 files changed, 225 insertions(+), 252 deletions(-) delete mode 100644 app/controllers/csv_controller.rb create mode 100644 app/services/csv_handler.rb delete mode 100644 app/views/users/show.html.erb delete mode 100644 features/csv_upload.feature delete mode 100644 features/step_definitions/csv_upload_steps.rb delete mode 100644 spec/controllers/csv_controller_spec.rb create mode 100644 spec/fixtures/instructors/instructors_missing_headers.csv create mode 100644 spec/services/csv_handler_spec.rb diff --git a/app/controllers/csv_controller.rb b/app/controllers/csv_controller.rb deleted file mode 100644 index 73b3e6d..0000000 --- a/app/controllers/csv_controller.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -# app/controllers/csv_controller.rb -class CsvController < ApplicationController - require 'csv' - - def upload - if csv_file_present? - process_csv_file - else - flash[:error] = 'Please upload a CSV file.' - end - redirect_to user_path(@current_user) - end - - private - - def csv_file_present? - params[:csv_file].present? - end - - def process_csv_file - file = params[:csv_file].path - parse_and_handle_csv(file) - end - - def parse_and_handle_csv(file) - parse_csv(file) - flash[:notice] = 'CSV file uploaded successfully.' - rescue CSV::MalformedCSVError => e - flash[:error] = "Cannot parse CSV file: #{e.message}" - end - - def parse_csv(file) - csv = CSV.read(file, headers: true) - Rails.logger.debug { "CSV Headers: #{csv.headers}" } - csv.each do |row| - Rails.logger.debug row.to_hash - end - end -end diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb index 78dcde8..d6dfce7 100644 --- a/app/controllers/schedules_controller.rb +++ b/app/controllers/schedules_controller.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'csv' - # app/controllers/schedules_controller.rb class SchedulesController < ApplicationController before_action :set_schedule, only: %i[show destroy upload_rooms upload_instructors] @@ -46,96 +44,28 @@ def destroy def upload_rooms if params[:room_file].present? - begin - ActiveRecord::Base.transaction do - room_data = CSV.read(params[:room_file].path, headers: true) - - @schedule.rooms.destroy_all - - room_data.each do |row| - Room.create!( - schedule_id: @schedule.id, - campus: row['campus'], - building_code: row['building_code'], - room_number: row['room_number'], - capacity: row['capacity'], - is_lecture_hall: row['is_lecture_hall'] == 'True', - is_learning_studio: row['is_learning_studio'] == 'True', - is_lab: row['is_lab'] == 'True', - is_active: row['is_active'] == 'True', - comments: row['comments'] - ) - end - end - flash[:notice] = 'Rooms successfully uploaded.' - rescue StandardError => e - flash[:alert] = "There was an error uploading the CSV file: #{e.message}" - raise e - end + # FIXME: What if the input file is malformed? + # We've erased our past data with no way to restore it + # We probably need to create a back up and restore if parsing gives an alert + @schedule.rooms.destroy_all + csv_handler = CsvHandler.new + csv_handler.upload(params[:room_file]) + flash_result = csv_handler.parse_room_csv(@schedule.id) + flash[flash_result.keys.first] = flash_result.values.first else flash[:alert] = 'Please upload a CSV file.' end - redirect_to schedule_path(@schedule) end def upload_instructors if params[:instructor_file].present? - begin - ActiveRecord::Base.transaction do - instructor_data = CSV.read(params[:instructor_file].path) - - @schedule.instructors.destroy_all - actual_headers = instructor_data[1] - - required_headers = [ - 'anonimized ID', - 'First Name', - 'Last Name', - 'Email', - 'Teaching before 9:00 am.', - 'Teaching after 3:00 pm.', - 'Middle Name', - 'Is there anything else we should be aware of regarding your teaching load (special course reduction, ...)' # Optional: Include if needed - ] - - missing_headers = required_headers - actual_headers - unless missing_headers.empty? - flash[:alert] = "Missing required headers: #{missing_headers.join(', ')}" - redirect_to schedule_path(@schedule) and return - end - - instructor_data[2..].each do |row| - # Extracting values and checking for nulls - id_number = row[actual_headers.index('anonimized ID')] - first_name = row[actual_headers.index('First Name')] - last_name = row[actual_headers.index('Last Name')] - middle_name = row[actual_headers.index('Middle Name')] - email = row[actual_headers.index('Email')] - before_9 = row[actual_headers.index('Teaching before 9:00 am.')] - after_3 = row[actual_headers.index('Teaching after 3:00 pm.')] - beaware_of = row[actual_headers.index('Is there anything else we should be aware of regarding your teaching load (special course reduction, ...)')] - - instructor_data = { - schedule_id: @schedule.id, - id_number: id_number, - first_name: first_name, - last_name: last_name, - middle_name: middle_name, - email: email, - before_9: before_9, - after_3: after_3, - beaware_of: beaware_of - } - - Instructor.create(instructor_data) - end - end - flash[:notice] = 'Instructors successfully uploaded.' - rescue StandardError => e - flash[:alert] = "There was an error uploading the CSV file: #{e.message}" - raise e - end + # FIXME: See concern in upload_rooms + @schedule.instructors.destroy_all + csv_handler = CsvHandler.new + csv_handler.upload(params[:instructor_file]) + flash_result = csv_handler.parse_instructor_csv(@schedule.id) + flash[flash_result.keys.first] = flash_result.values.first else flash[:alert] = 'Please upload a CSV file.' end diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb index 9f7ffcf..7e1beda 100644 --- a/app/controllers/welcome_controller.rb +++ b/app/controllers/welcome_controller.rb @@ -9,8 +9,6 @@ class WelcomeController < ApplicationController def index return unless logged_in? - - flash[:notice] = "Welcome back, #{@current_user.first_name}!" unless flash[:notice] || flash[:error] - redirect_to user_path(@current_user) + redirect_to schedules_path end end diff --git a/app/services/csv_handler.rb b/app/services/csv_handler.rb new file mode 100644 index 0000000..a1f1cd2 --- /dev/null +++ b/app/services/csv_handler.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +class CsvHandler + require 'csv' + + def upload(file) + @file = file + end + + def parse_room_csv(schedule_id) + begin + ActiveRecord::Base.transaction do + room_data = CSV.parse(@file.read, headers: true) + room_data.each do |row| + Room.create!( + schedule_id: schedule_id, + campus: row['campus'], + building_code: row['building_code'], + room_number: row['room_number'], + capacity: row['capacity'].to_i, + is_lecture_hall: row['is_lecture_hall'] == 'True', + is_learning_studio: row['is_learning_studio'] == 'True', + is_lab: row['is_lab'] == 'True', + is_active: row['is_active'] == 'True', + comments: row['comments'] + ) + end + end + # Flash data to be received by controller + return { notice: 'Rooms successfully uploaded.' } + rescue StandardError => e + return { alert: "There was an error uploading the CSV file: #{e.message}" } + end + end + + def parse_instructor_csv(schedule_id) + begin + ActiveRecord::Base.transaction do + instructor_data = CSV.parse(@file.read) + actual_headers = instructor_data[1] + required_headers = [ + 'anonimized ID', + 'First Name', + 'Last Name', + 'Email', + 'Teaching before 9:00 am.', + 'Teaching after 3:00 pm.', + 'Middle Name', + 'Is there anything else we should be aware of regarding your teaching load (special course reduction, ...)' # Optional: Include if needed + ] + + missing_headers = required_headers - actual_headers + unless missing_headers.empty? + return {alert: "Missing required headers: #{missing_headers.join(', ')}"} + end + + instructor_data[2..].each do |row| + # Extracting values and checking for nulls + id_number = row[actual_headers.index('anonimized ID')] + first_name = row[actual_headers.index('First Name')] + last_name = row[actual_headers.index('Last Name')] + middle_name = row[actual_headers.index('Middle Name')] + email = row[actual_headers.index('Email')] + before_9 = row[actual_headers.index('Teaching before 9:00 am.')] + after_3 = row[actual_headers.index('Teaching after 3:00 pm.')] + beaware_of = row[actual_headers.index('Is there anything else we should be aware of regarding your teaching load (special course reduction, ...)')] + + instructor_data = { + schedule_id: schedule_id, + id_number: id_number, + first_name: first_name, + last_name: last_name, + middle_name: middle_name, + email: email, + before_9: before_9, + after_3: after_3, + beaware_of: beaware_of + } + + Instructor.create(instructor_data) + end + end + return {notice: 'Instructors successfully uploaded.'} + rescue StandardError => e + return {alert: "There was an error uploading the CSV file: #{e.message}"} + end + end + +end diff --git a/app/views/schedules/show.html.erb b/app/views/schedules/show.html.erb index b526559..34e83be 100644 --- a/app/views/schedules/show.html.erb +++ b/app/views/schedules/show.html.erb @@ -16,7 +16,7 @@ Semester:<%= @schedule.semester_name %> <%= form_with url: upload_instructors_schedule_path(@schedule), multipart: true, method: :post, local: true do |f| %>
- <%= f.label :instructor_file, "Select Instructors Data (CSV)", class: "form-label fw-bold" %> + <%= f.label :instructor_file, "Select Instructor Data (CSV)", class: "form-label fw-bold" %> <%= f.file_field :instructor_file, class: "form-control" %>
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb deleted file mode 100644 index b36bf8a..0000000 --- a/app/views/users/show.html.erb +++ /dev/null @@ -1,23 +0,0 @@ -

Howdy <%= @current_user.first_name %>!

-
-

- Email: - <%= @current_user.email %> -

- -

- First Name: - <%= @current_user.first_name %> -

- -

- Last Name: - <%= @current_user.last_name %> -

- -

Upload CSV File

- <%= form_with url: upload_csv_path, method: :post, local: true, data: { turbo: false } do |form| %> - <%= form.file_field :csv_file %> - <%= form.submit "Submit" %> - <% end %> -
diff --git a/config/routes.rb b/config/routes.rb index 7067725..9c6bf50 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -17,11 +17,8 @@ get 'manifest' => 'rails/pwa#manifest', as: :pwa_manifest # Defines the root path route ("/") - root 'welcome#index' get 'welcome/index', to: 'welcome#index', as: 'welcome' - - # Show user - get '/users/:id', to: 'users#show', as: 'user' + root 'welcome#index' # Login/logout get '/logout', to: 'sessions#logout', as: 'logout' diff --git a/features/csv_upload.feature b/features/csv_upload.feature deleted file mode 100644 index 446d15c..0000000 --- a/features/csv_upload.feature +++ /dev/null @@ -1,26 +0,0 @@ -# features/csv_upload.feature -Feature: CSV Upload - As a user - I want to upload a CSV file - So that I can process data from the file - - Background: - Given I am logged in as a user - - Scenario: Successfully upload a valid CSV file - Given I am on my profile page - When I attach a valid CSV file to the upload form - And I click the "Submit" button - Then I should see "CSV file uploaded successfully." - - Scenario: Upload an invalid CSV file - Given I am on my profile page - When I attach an invalid CSV file to the upload form - And I click the "Submit" button - Then I should see "Cannot parse CSV file" - - Scenario: Upload without selecting a file - Given I am on my profile page - When I do not attach any file to the upload form - And I click the "Submit" button - Then I should see "Please upload a CSV file." \ No newline at end of file diff --git a/features/schedules.feature b/features/schedules.feature index 77cc153..b4b9e39 100644 --- a/features/schedules.feature +++ b/features/schedules.feature @@ -37,4 +37,22 @@ Feature: Schedules page When I visit the schedules index page When I search for "ABCD" Then I should not see "Test Schedule 1" - And I should not see "Another Schedule" \ No newline at end of file + And I should not see "Another Schedule" + + Scenario: User can upload room CSV + Given I am logged in as a user with first name "Test" + When I visit the schedules index page + And I click on the card for "Test Schedule 1" + Then I should see "Select Room Data (CSV)" + When I upload a valid room file + And I click the "Upload Room Data" button + Then I should see "Rooms successfully uploaded" + + Scenario: User can upload instructor CSV + Given I am logged in as a user with first name "Test" + When I visit the schedules index page + And I click on the card for "Test Schedule 1" + Then I should see "Select Instructor Data (CSV)" + When I upload a valid instructor file + And I click the "Upload Instructor Data" button + Then I should see "Instructors successfully uploaded" \ No newline at end of file diff --git a/features/step_definitions/csv_upload_steps.rb b/features/step_definitions/csv_upload_steps.rb deleted file mode 100644 index 3952f82..0000000 --- a/features/step_definitions/csv_upload_steps.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -# features/step_definitions/csv_upload_steps.rb - -Given('I am on my profile page') do - visit user_path(User.first) -end - -When('I attach a valid CSV file to the upload form') do - attach_file('csv_file', Rails.root.join('spec/fixtures/files/test.csv')) -end - -When('I attach an invalid CSV file to the upload form') do - attach_file('csv_file', Rails.root.join('spec/fixtures/files/invalid.csv')) -end - -When('I do not attach any file to the upload form') do - # No file attached -end diff --git a/features/step_definitions/schedules_steps.rb b/features/step_definitions/schedules_steps.rb index f974aeb..1bc5066 100644 --- a/features/step_definitions/schedules_steps.rb +++ b/features/step_definitions/schedules_steps.rb @@ -38,3 +38,19 @@ fill_in 'search_by_name', with: search_term click_button 'Search' end + +When('I upload a valid instructor file') do + valid_instructor_csv = File.read(Rails.root.join('spec', 'fixtures', 'instructors', 'instructors_valid.csv')) + @instructor_file = Tempfile.new(['instructors_valid', '.csv']) + @instructor_file.write(valid_instructor_csv) + @instructor_file.rewind + attach_file('Select Instructor Data (CSV)', @instructor_file.path) +end + +When('I upload a valid room file') do + valid_room_csv = File.read(Rails.root.join('spec', 'fixtures', 'rooms', 'rooms_valid.csv')) + @room_file = Tempfile.new(['rooms_valid', '.csv']) + @room_file.write(valid_room_csv) + @room_file.rewind + attach_file('Select Room Data (CSV)', @room_file.path) +end diff --git a/features/step_definitions/welcome.rb b/features/step_definitions/welcome.rb index 777a0d0..e29a31b 100644 --- a/features/step_definitions/welcome.rb +++ b/features/step_definitions/welcome.rb @@ -8,4 +8,4 @@ When(/^I visit the welcome page$/) do visit welcome_path -end +end \ No newline at end of file diff --git a/features/welcome.feature b/features/welcome.feature index 7e74fec..b420b63 100644 --- a/features/welcome.feature +++ b/features/welcome.feature @@ -1,7 +1,6 @@ Feature: Welcome Page - Scenario: Logged-in user is redirected to their profile with a welcome notice + Scenario: Logged-in user is redirected to their schedules page Given I am logged in as a user with first name "Test" When I visit the welcome page - Then I should be on my profile page - And I should see "Welcome back, Test!" + Then I should be on my schedules page \ No newline at end of file diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 0ba9eae..bf4d466 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -10,7 +10,6 @@ @user = User.create!(uid: '12345', provider: 'google_oauth2', email: 'test@example.com', first_name: 'John', last_name: 'Doe') session[:user_id] = @user.id - puts "session[:user_id] = #{session[:user_id]}" end it 'returns the current user' do diff --git a/spec/controllers/csv_controller_spec.rb b/spec/controllers/csv_controller_spec.rb deleted file mode 100644 index c61644e..0000000 --- a/spec/controllers/csv_controller_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -# spec/controllers/csv_controller_spec.rb -require 'rails_helper' - -RSpec.describe CsvController, type: :controller do - before do - # Create a user and set session user_id as done in your application_controller_spec.rb - @user = User.create!(uid: '12345', provider: 'google_oauth2', email: 'test@example.com', first_name: 'John', - last_name: 'Doe') - session[:user_id] = @user.id - end - - let(:file) { fixture_file_upload(Rails.root.join('spec/fixtures/files/test.csv'), 'text/csv') } - - describe 'POST #upload' do - context 'with a valid CSV file' do - it "processes the CSV file, sets a success flash, and redirects to the user's page" do - post :upload, params: { csv_file: file } - - expect(response).to have_http_status(:redirect) - expect(response).to redirect_to(user_path(@user)) # Redirect to the current user's page - expect(flash[:notice]).to eq('CSV file uploaded successfully.') - end - end - - context 'when no CSV file is selected' do - it "sets an error flash and redirects to the user's page" do - post :upload, params: { csv_file: nil } - - expect(response).to have_http_status(:redirect) - expect(response).to redirect_to(user_path(@user)) # Redirect to the current user's page - expect(flash[:error]).to eq('Please upload a CSV file.') - end - end - end -end diff --git a/spec/controllers/schedules_controller_spec.rb b/spec/controllers/schedules_controller_spec.rb index 53b9eef..d0db2f9 100644 --- a/spec/controllers/schedules_controller_spec.rb +++ b/spec/controllers/schedules_controller_spec.rb @@ -115,10 +115,7 @@ context 'when invalid CSV file is selected' do it "sets an error flash and redirects to the user's page" do - expect do - post :upload_rooms, params: { id: schedule1.id, room_file: file_invalid } - end.to raise_error(ArgumentError, /'1' is not a valid campus/) - + post :upload_rooms, params: { id: schedule1.id, room_file: file_invalid } expect(flash[:alert]).to include('There was an error uploading the CSV file') end end diff --git a/spec/controllers/welcome_controller_spec.rb b/spec/controllers/welcome_controller_spec.rb index 6170480..55e4447 100644 --- a/spec/controllers/welcome_controller_spec.rb +++ b/spec/controllers/welcome_controller_spec.rb @@ -13,10 +13,9 @@ controller.instance_variable_set(:@current_user, @user) end - it 'redirects to the user path with a welcome notice' do + it 'redirects to the schedule path with a welcome notice' do get :index - expect(response).to redirect_to(user_path(@user)) - expect(flash[:notice]).to eq('Welcome back, John!') + expect(response).to redirect_to(schedules_path) end end @@ -25,7 +24,7 @@ allow(controller).to receive(:logged_in?).and_return(false) end - it 'renders the index template' do + it 'renders the welcome template' do get :index expect(response).to render_template(:index) end diff --git a/spec/fixtures/instructors/instructors_missing_headers.csv b/spec/fixtures/instructors/instructors_missing_headers.csv new file mode 100644 index 0000000..cdbeaac --- /dev/null +++ b/spec/fixtures/instructors/instructors_missing_headers.csv @@ -0,0 +1,5 @@ +Q20_1,Q20_2,Q20_3,Q20_4,Q20_5,Q20_6,Q20_7,Q20_8,Q20_9,Q20_10,Q20_11,Q20_12,Q20_13,Q20_14,Q20_15,Q20_16,Q20_17,Q20_18,Q20_19,Q20_20,Q20_21,Q20_22,Q20_23,Q20_24,Q20_25,Q20_26,Q20_27,Q20_28,Q20_29,Q20_30,Q20_31,Q20_32,Q20_33,Q20_34,Q20_35,Q20_36,Q20_37,Q20_38,Q20_39,Q20_40,Q20_41,Q20_42,Q20_43,Q20_44,Q20_45,Q20_46,Q20_47,Q20_48,Q20_49,Q20_50,Q20_51,Q20_52,Q20_53,Q20_54,Q20_55,Q20_56,Q20_57,Q20_58,Q5_1,Q5_2,Q5_3,Q5_4,Q5_5,Q5_6,Q5_7,Q5_8,Q5_9,Q5_10,Q5_11,Q5_12,Q5_65,Q5_13,Q5_14,Q5_15,Q5_16,Q5_17,Q5_18,Q5_19,Q5_20,Q5_21,Q5_22,Q5_23,Q5_24,Q5_25,Q5_90,Q5_26,Q5_27,Q5_28,Q5_29,Q5_30,Q5_66,Q5_32,Q5_33,Q5_87,Q5_34,Q5_35,Q5_36,Q5_37,Q5_38,Q5_39,Q5_40,Q5_67,Q5_67,Q5_41,Q5_42,Q5_43,Q5_44,Q5_45,Q5_46,Q5_47,Q5_48,Q5_49,Q5_50,Q5_51,Q5_52,Q5_53,Q5_54,Q5_55,Q5_56,Q5_57,Q5_58,Q5_59,Q5_67,Q5_61,Q5_68,Q5_69,Q5_72,Q5_62,Q5_63,Q5_88,Q5_77,Q5_71,Q5_70,Q5_79,Q5_75,Q5_81,Q5_74,Q5_80,Q5_76,Q5_82,Q5_83,Q5_84,Q5_85,Q5_86,Q5_89,Q7,Q21,Q12,Q13,Q17,Q18,,,,, +2755728,ABCD,Abcd,X,acb@gmail.com,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,1,2,2,2,2,1,2,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,2,2,2,5,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,2,1,1,1,2,1,2,1,1,2,2,2,1,2,2,2,2,2,2,1,2,2,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,2,2,1,2,2,1,1,1,1,1,2,2,1,1,2,2,2,2,2,2,1,1,2,1,2,1,1,1,2,1,1,2,,,,, +672598,EFGH,efgh,Y,hij@gmail.com,2,2,2,2,1,2,2,2,2,1,2,2,1,5,2,2,1,1,2,1,1,1,2,4,2,2,2,1,1,1,2,1,1,1,1,1,1,2,1,1,3,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,3,2,1,3,1,2,3,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,4,2,1,1,2,2,1,1,2,1,2,1,5,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,,,,,1 +670246,IJKL,Ijkl,Z,lmo@gmail.com,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,1,1,2,1,1,1,2,1,1,2,2,1,1,1,3,1,1,1,1,1,1,1,5,1,4,1,1,1,1,1,1,1,1,1,1,1,1,2,1,3,2,2,1,1,1,1,1,2,1,3,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,2,2,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,5,1,1,1,1,1,1,1,1,1,1,2,1,1,2,3,5,3,1,1,4,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,,1,,3,2 +2476413,MNOP,Mop,N,xyz@gmail.com,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,,3, \ No newline at end of file diff --git a/spec/services/csv_handler_spec.rb b/spec/services/csv_handler_spec.rb new file mode 100644 index 0000000..1a1b1fd --- /dev/null +++ b/spec/services/csv_handler_spec.rb @@ -0,0 +1,72 @@ +# spec/services/csv_handler_spec.rb +require 'rails_helper' + +RSpec.describe CsvHandler do + let(:schedule) { create(:schedule) } + let(:valid_room_csv) { File.read(Rails.root.join('spec', 'fixtures', 'rooms', 'rooms_valid.csv')) } + let(:invalid_room_csv) { File.read(Rails.root.join('spec', 'fixtures', 'rooms', 'rooms_invalid.csv')) } + let(:valid_instructor_csv) { File.read(Rails.root.join('spec', 'fixtures', 'instructors', 'instructors_valid.csv')) } + let(:invalid_instructor_csv) { File.read(Rails.root.join('spec', 'fixtures', 'instructors', 'instructors_missing_headers.csv')) } + + describe '#initialize' do + it 'initializes with a file' do + handler = CsvHandler.new + handler.upload(valid_room_csv) + expect(handler.instance_variable_get(:@file)).to eq(valid_room_csv) + end + end + + describe '#parse_room_csv' do + context 'with valid data' do + it 'creates room records' do + handler = CsvHandler.new + handler.upload(StringIO.new(valid_room_csv)) + handler.parse_room_csv(schedule.id) + expect(Room.count).to eq(10) + end + + it 'returns a success message' do + handler = CsvHandler.new + handler.upload(StringIO.new(valid_room_csv)) + result = handler.parse_room_csv(schedule.id) + expect(result[:notice]).to eq('Rooms successfully uploaded.') + end + end + + context 'with invalid data' do + it 'prints an alert' do + handler = CsvHandler.new + handler.upload(StringIO.new(invalid_room_csv)) + result = handler.parse_room_csv(schedule.id) + expect(result[:alert]).to include('There was an error uploading the CSV file') + end + end + end + + describe '#parse_instructor_csv' do + context 'with valid data' do + it 'creates instructor records' do + handler = CsvHandler.new + handler.upload(StringIO.new(valid_instructor_csv)) + handler.parse_instructor_csv(schedule.id) + expect(Instructor.count).to eq(4) + end + + it 'returns a success message' do + handler = CsvHandler.new + handler.upload(StringIO.new(valid_instructor_csv)) + result = handler.parse_instructor_csv(schedule.id) + expect(result[:notice]).to eq('Instructors successfully uploaded.') + end + end + + context 'with missing header data' do + it 'prints an alert' do + handler = CsvHandler.new + handler.upload(StringIO.new(invalid_instructor_csv)) + result = handler.parse_instructor_csv(schedule.id) + expect(result[:alert]).to include('Missing required headers') + end + end + end +end \ No newline at end of file