From 51ee84f383de06767db1d5b62eaddeda374169c9 Mon Sep 17 00:00:00 2001 From: 61315 Date: Sun, 14 Apr 2024 15:59:49 -0500 Subject: [PATCH 1/5] chore: bounty hunt (non-autocorrectable offenses) --- rails_root/app/models/survey_response.rb | 52 ++- .../requests/survey_responses/create_spec.rb | 90 +++++ .../requests/survey_responses/destroy_spec.rb | 28 ++ .../requests/survey_responses/edit_spec.rb | 58 ++++ .../requests/survey_responses/index_spec.rb | 21 ++ .../requests/survey_responses/new_spec.rb | 51 +++ .../requests/survey_responses/show_spec.rb | 51 +++ .../requests/survey_responses/update_spec.rb | 79 +++++ .../spec/requests/survey_responses_spec.rb | 326 ------------------ 9 files changed, 403 insertions(+), 353 deletions(-) create mode 100644 rails_root/spec/requests/survey_responses/create_spec.rb create mode 100644 rails_root/spec/requests/survey_responses/destroy_spec.rb create mode 100644 rails_root/spec/requests/survey_responses/edit_spec.rb create mode 100644 rails_root/spec/requests/survey_responses/index_spec.rb create mode 100644 rails_root/spec/requests/survey_responses/new_spec.rb create mode 100644 rails_root/spec/requests/survey_responses/show_spec.rb create mode 100644 rails_root/spec/requests/survey_responses/update_spec.rb delete mode 100644 rails_root/spec/requests/survey_responses_spec.rb diff --git a/rails_root/app/models/survey_response.rb b/rails_root/app/models/survey_response.rb index 8336602..4812924 100644 --- a/rails_root/app/models/survey_response.rb +++ b/rails_root/app/models/survey_response.rb @@ -20,46 +20,44 @@ class SurveyResponse < ApplicationRecord def self.create_from_params(user_id, params) # FIXME: When we look up things and fail, we should use more descriptive exceptions instead of ActiveRecord::RecordNotFound - - profile = SurveyProfile.where(user_id:).first! + profile = find_profile(user_id) # Use provided share_code if exists, else generate a new one - share_code = if params.nil? - SecureRandom.hex(3) - else - params[:share_code] || SecureRandom.hex(3) - end + share_code = generate_share_code(params) # FIXME: Handle share code already existing - survey_response = SurveyResponse.create(profile:, share_code:) + survey_response = create_survey_response(profile, share_code) return survey_response if params.nil? - params&.each do |key, choice| + create_survey_answers(params, survey_response) + survey_response + rescue ActiveRecord::RecordNotFound + logger.info 'Survey profile not found!' + nil + end + + def self.find_profile(user_id) + SurveyProfile.where(user_id:).first! + end + + def self.generate_share_code(params) + params.nil? ? SecureRandom.hex(3) : params[:share_code] || SecureRandom.hex(3) + end + + def self.create_survey_response(profile, share_code) + SurveyResponse.create(profile:, share_code:) + end + + def self.create_survey_answers(params, survey_response) + params.each do |key, choice| begin question = SurveyQuestion.find key rescue ActiveRecord::RecordNotFound next end - SurveyAnswer.create choice:, question:, response: survey_response + SurveyAnswer.create(choice:, question:, response: survey_response) end - survey_response - rescue ActiveRecord::RecordNotFound - logger.info 'Survey profile not found!' - nil - - # 96.times do |i| - # begin - # index = (i+1).to_s - # question = SurveyQuestion.find index - # if params[index].nil? - # choice = "5" - # else - # choice = params[index] - # end - # SurveyAnswer.create choice:, question:, response: survey_response - # end - # end end def update_from_params(user_id, params) diff --git a/rails_root/spec/requests/survey_responses/create_spec.rb b/rails_root/spec/requests/survey_responses/create_spec.rb new file mode 100644 index 0000000..560e204 --- /dev/null +++ b/rails_root/spec/requests/survey_responses/create_spec.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +# spec/requests/survey_responses/create_spec.rb +require 'rails_helper' + +RSpec.describe 'GET /create/:id', type: :request do # rubocop:disable Metrics/BlockLength + let(:survey_profile) { FactoryBot.create(:survey_profile) } + let(:survey_response) { FactoryBot.create(:survey_response) } + let(:survey_answer) { FactoryBot.create(:survey_answer) } + let(:survey_question) { FactoryBot.create(:survey_question) } + let(:create_response_attr) do + { + survey_question.id => 2 + } + end + + context 'with valid parameters' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(survey_profile.user_id) + end + + %w[Next Save Previous Submit].each do |action| + it "creates a new SurveyResponse when click #{action}" do + expect do + post survey_responses_path, params: { survey_response: create_response_attr, commit: action } + end.to change(SurveyResponse, :count).by(1) + end + + it "redirects to the appropriate page when click #{action}" do + post survey_responses_path, params: { survey_response: create_response_attr, commit: action } + redirect_path = action == 'Submit' ? survey_response_path(SurveyResponse.last) : edit_survey_response_path(SurveyResponse.last) + expect(response).to redirect_to(redirect_path) + end + end + + it 'updates the requested survey_response answers' do + my_question = survey_question + post survey_responses_path, params: { survey_response: { my_question.id => 2 } } + answer = SurveyAnswer.where(question: my_question, response: SurveyResponse.last).first + expect(answer.choice).to eq(2) + end + end + + context 'without user id' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } + end + it 'returns to root' do + post survey_responses_path + expect(response).to redirect_to(root_url) + end + end + + context 'user profile not exist' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) + end + it 'redirects to the root page' do + post survey_responses_path + expect(response).to redirect_to(root_url) + end + end + + context 'with invalid parameters' do + let(:invalid_attributes) do + # any value in form is null + { + profile_id: nil, + share_code: 1 + } + end + before do + allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(survey_profile.user_id) + end + + it 'does not create a new SurveyResponse - bad attributes' do + expect do + post survey_responses_path, params: { survey_response: invalid_attributes } + end.to_not change(SurveyResponse, :count) + end + + it 'returns a failure response (i.e., to display the "new" template)' do + post survey_responses_url, params: { survey_response: invalid_attributes } + expect(response).to have_http_status(:unprocessable_entity) + end + end +end diff --git a/rails_root/spec/requests/survey_responses/destroy_spec.rb b/rails_root/spec/requests/survey_responses/destroy_spec.rb new file mode 100644 index 0000000..4bbcdcb --- /dev/null +++ b/rails_root/spec/requests/survey_responses/destroy_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +# spec/requests/survey_responses/destroy_spec.rb +require 'rails_helper' + +RSpec.describe 'GET /destroy/:id', type: :request do + let(:survey_profile) { FactoryBot.create(:survey_profile) } + let(:survey_response) { FactoryBot.create(:survey_response) } + let(:survey_answer) { FactoryBot.create(:survey_answer) } + let(:survey_question) { FactoryBot.create(:survey_question) } + let(:create_response_attr) do + { + survey_question.id => 2 + } + end + + it 'destroys the requested survey_response' do + my_response = survey_response + expect do + delete survey_response_url(my_response) + end.to change(SurveyResponse, :count).by(-1) + end + + it 'redirects to the survey_responses list' do + delete survey_response_url(survey_response) + expect(response).to redirect_to(survey_responses_url) + end +end diff --git a/rails_root/spec/requests/survey_responses/edit_spec.rb b/rails_root/spec/requests/survey_responses/edit_spec.rb new file mode 100644 index 0000000..97699a5 --- /dev/null +++ b/rails_root/spec/requests/survey_responses/edit_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +# spec/requests/survey_responses/edit_spec.rb +require 'rails_helper' + +RSpec.describe 'GET /edit/:id', type: :request do # rubocop:disable Metrics/BlockLength + let(:survey_profile) { FactoryBot.create(:survey_profile) } + let(:survey_response) { FactoryBot.create(:survey_response) } + let(:survey_answer) { FactoryBot.create(:survey_answer) } + let(:survey_question) { FactoryBot.create(:survey_question) } + let(:create_response_attr) do + { + survey_question.id => 2 + } + end + + context 'valid response and profile exist' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return('1') + end + + it 'renders a successful response' do + profile = FactoryBot.create(:survey_profile, user_id: 1) + my_response = FactoryBot.create(:survey_response, profile:) + get edit_survey_response_path(my_response) + expect(response).to have_http_status(:success) + end + + it 'renders the edit template' do + profile = FactoryBot.create(:survey_profile, user_id: 1) + my_response = FactoryBot.create(:survey_response, profile:) + get edit_survey_response_path(my_response) + expect(response).to render_template(:edit) + end + end + + context 'user does not log in' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(nil) + end + it 'redirects to the root page' do + get edit_survey_response_path(survey_response) + expect(response).to redirect_to(root_url) + end + end + + context 'responses with different profile' do + before do + survey_response + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) + end + + it 'redirects to the root page' do + get edit_survey_response_path(survey_response) + expect(response).to redirect_to(root_url) + end + end +end diff --git a/rails_root/spec/requests/survey_responses/index_spec.rb b/rails_root/spec/requests/survey_responses/index_spec.rb new file mode 100644 index 0000000..4cdf1e6 --- /dev/null +++ b/rails_root/spec/requests/survey_responses/index_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# spec/requests/survey_responses/index_spec.rb +require 'rails_helper' + +RSpec.describe 'GET /index/:id', type: :request do + let(:survey_profile) { FactoryBot.create(:survey_profile) } + let(:survey_response) { FactoryBot.create(:survey_response) } + let(:survey_answer) { FactoryBot.create(:survey_answer) } + let(:survey_question) { FactoryBot.create(:survey_question) } + let(:create_response_attr) do + { + survey_question.id => 2 + } + end + + it 'renders a successful response' do + get survey_responses_url + expect(response).to be_successful + end +end diff --git a/rails_root/spec/requests/survey_responses/new_spec.rb b/rails_root/spec/requests/survey_responses/new_spec.rb new file mode 100644 index 0000000..ef73006 --- /dev/null +++ b/rails_root/spec/requests/survey_responses/new_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# spec/requests/survey_responses/new_spec.rb +require 'rails_helper' + +RSpec.describe 'GET /new/:id', type: :request do + let(:survey_profile) { FactoryBot.create(:survey_profile) } + let(:survey_response) { FactoryBot.create(:survey_response) } + let(:survey_answer) { FactoryBot.create(:survey_answer) } + let(:survey_question) { FactoryBot.create(:survey_question) } + let(:create_response_attr) do + { + survey_question.id => 2 + } + end + + context 'user profile exist' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(survey_profile.user_id) + end + it 'returns a successful response' do + get new_survey_response_path + expect(response).to have_http_status(:success) + end + + it 'renders the new template' do + get new_survey_response_path + expect(response).to render_template(:new) + end + end + + context 'user does not log in' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(nil) + end + it 'redirects to the root page' do + get new_survey_response_path + expect(response).to redirect_to(root_url) + end + + context 'user profile not exist' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) + end + it 'redirects to the root page' do + get new_survey_response_path + expect(response).to redirect_to(root_url) + end + end + end +end diff --git a/rails_root/spec/requests/survey_responses/show_spec.rb b/rails_root/spec/requests/survey_responses/show_spec.rb new file mode 100644 index 0000000..48b88f4 --- /dev/null +++ b/rails_root/spec/requests/survey_responses/show_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# spec/requests/survey_responses/show_spec.rb +require 'rails_helper' + +RSpec.describe 'GET /show/:id', type: :request do + let(:survey_profile) { FactoryBot.create(:survey_profile) } + let(:survey_response) { FactoryBot.create(:survey_response) } + let(:survey_answer) { FactoryBot.create(:survey_answer) } + let(:survey_question) { FactoryBot.create(:survey_question) } + let(:create_response_attr) do + { + survey_question.id => 2 + } + end + + context 'valid response and profile exist' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return('1') + end + it 'renders a successful response' do + profile = FactoryBot.create(:survey_profile, user_id: 1) + my_response = FactoryBot.create(:survey_response, profile:) + get survey_response_url(my_response) + expect(response).to have_http_status(:success) + end + end + + context 'user not logged in' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(nil) + end + + it 'redirects to the root page' do + get survey_response_url(survey_response) + expect(response).to redirect_to(root_url) + end + end + + context 'responses with different profile' do + before do + survey_response + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) + end + + it 'redirects to the root page' do + get survey_response_url(survey_response) + expect(response).to redirect_to(root_url) + end + end +end diff --git a/rails_root/spec/requests/survey_responses/update_spec.rb b/rails_root/spec/requests/survey_responses/update_spec.rb new file mode 100644 index 0000000..26790aa --- /dev/null +++ b/rails_root/spec/requests/survey_responses/update_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +# spec/requests/survey_responses/update_spec.rb +require 'rails_helper' + +RSpec.describe 'GET /update/:id', type: :request do # rubocop:disable Metrics/BlockLength + let(:survey_profile) { FactoryBot.create(:survey_profile) } + let(:survey_response) { FactoryBot.create(:survey_response) } + let(:survey_answer) { FactoryBot.create(:survey_answer) } + let(:survey_question) { FactoryBot.create(:survey_question) } + let(:create_response_attr) do + { + survey_question.id => 2 + } + end + + context 'with valid parameters' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(survey_answer.response.profile.user_id) + end + + it 'updates the requested survey_response answers' do + patch survey_response_url(survey_answer.response), params: { survey_response: { survey_answer.question.id => 2 } } + survey_answer.reload + expect(survey_answer.choice).to eq(2) + end + + it 'redirects to the survey_response' do + patch survey_response_url(survey_answer.response), params: { survey_response: { survey_answer.question.id => 2 } } + expect(response).to redirect_to(survey_answer.response) + end + end + + context 'without user id' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } + end + it 'returns to root' do + my_answer = survey_answer + patch survey_response_url(my_answer.response), params: { survey_response: { my_answer.question.id => 2 } } + expect(response).to redirect_to(root_url) + end + end + + context 'user profile not exist' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:session) { { user_id: 99, page_number: 2 } } + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) + end + it 'redirects to the root page' do + my_answer = survey_answer + patch survey_response_url(my_answer.response), params: { survey_response: { my_answer.question.id => 2 } } + expect(response).to redirect_to(root_url) + end + end + + context 'responses with different profile' do + before do + allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) + end + + it 'redirects to the root page' do + patch survey_response_url(survey_answer.response), params: { survey_response: { survey_answer.question.id => 2 } } + expect(response).to redirect_to(root_url) + end + end + + context 'with invalid parameters' do + it 'responds with status 422 for nil input' do + invalid_response = { + :user_id => nil, + '1' => 1 + } + patch survey_response_url(survey_response), params: { survey_response: invalid_response } + expect(response).to have_http_status(:unprocessable_entity) + end + end +end diff --git a/rails_root/spec/requests/survey_responses_spec.rb b/rails_root/spec/requests/survey_responses_spec.rb deleted file mode 100644 index d8790c5..0000000 --- a/rails_root/spec/requests/survey_responses_spec.rb +++ /dev/null @@ -1,326 +0,0 @@ -# frozen_string_literal: true - -# spec/requests/survey_responses_spec.rb -require 'rails_helper' - -RSpec.describe 'SurveyResponses', type: :request do - let(:survey_profile) { FactoryBot.create(:survey_profile) } - let(:survey_response) { FactoryBot.create(:survey_response) } - let(:survey_answer) { FactoryBot.create(:survey_answer) } - let(:survey_question) { FactoryBot.create(:survey_question) } - let(:create_response_attr) do - { - survey_question.id => 2 - } - end - - describe 'GET /index' do - it 'renders a successful response' do - get survey_responses_url - expect(response).to be_successful - end - end - - describe 'GET /show/:id' do - context 'valid response and profile exist' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return('1') - end - it 'renders a successful response' do - profile = FactoryBot.create(:survey_profile, user_id: 1) - my_response = FactoryBot.create(:survey_response, profile:) - get survey_response_url(my_response) - expect(response).to have_http_status(:success) - end - end - - context 'user not logged in' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(nil) - end - - it 'redirects to the root page' do - get survey_response_url(survey_response) - expect(response).to redirect_to(root_url) - end - end - - context 'responses with different profile' do - before do - survey_response - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) - end - - it 'redirects to the root page' do - get survey_response_url(survey_response) - expect(response).to redirect_to(root_url) - end - end - end - - describe 'GET /new' do - context 'user profile exist' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(survey_profile.user_id) - end - it 'returns a successful response' do - get new_survey_response_path - expect(response).to have_http_status(:success) - end - - it 'renders the new template' do - get new_survey_response_path - expect(response).to render_template(:new) - end - end - - context 'user does not log in' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(nil) - end - it 'redirects to the root page' do - get new_survey_response_path - expect(response).to redirect_to(root_url) - end - - context 'user profile not exist' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) - end - it 'redirects to the root page' do - get new_survey_response_path - expect(response).to redirect_to(root_url) - end - end - end - end - - describe 'GET /edit' do - context 'valid response and profile exist' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return('1') - end - - it 'renders a successful response' do - profile = FactoryBot.create(:survey_profile, user_id: 1) - my_response = FactoryBot.create(:survey_response, profile:) - get edit_survey_response_path(my_response) - expect(response).to have_http_status(:success) - end - - it 'renders the edit template' do - profile = FactoryBot.create(:survey_profile, user_id: 1) - my_response = FactoryBot.create(:survey_response, profile:) - get edit_survey_response_path(my_response) - expect(response).to render_template(:edit) - end - end - - context 'user does not log in' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(nil) - end - it 'redirects to the root page' do - get edit_survey_response_path(survey_response) - expect(response).to redirect_to(root_url) - end - end - - context 'responses with different profile' do - before do - survey_response - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) - end - - it 'redirects to the root page' do - get edit_survey_response_path(survey_response) - expect(response).to redirect_to(root_url) - end - end - end - - describe 'POST /create' do - context 'with valid parameters' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(survey_profile.user_id) - end - - it 'creates a new SurveyResponse when click Next' do - expect do - post survey_responses_path, params: { survey_response: create_response_attr, commit: 'Next' } - end.to change(SurveyResponse, :count).by(1) - end - - it 'redirects to the SurveyResponse edit page when click Next' do - post survey_responses_path, params: { survey_response: create_response_attr, commit: 'Next' } - expect(response).to redirect_to(edit_survey_response_path(SurveyResponse.last)) - end - - it 'creates a new SurveyResponse when click Save' do - expect do - post survey_responses_path, params: { survey_response: create_response_attr, commit: 'Save' } - end.to change(SurveyResponse, :count).by(1) - end - - it 'redirects to the SurveyResponse edit page when click Save' do - post survey_responses_path, params: { survey_response: create_response_attr, commit: 'Save' } - expect(response).to redirect_to(edit_survey_response_path(SurveyResponse.last)) - end - - it 'creates a new SurveyResponse when click Previous' do - expect do - post survey_responses_path, params: { survey_response: create_response_attr, commit: 'Previous' } - end.to change(SurveyResponse, :count).by(1) - end - - it 'redirects to the SurveyResponse edit page when click Previous' do - post survey_responses_path, params: { survey_response: create_response_attr, commit: 'Previous' } - expect(response).to redirect_to(edit_survey_response_path(SurveyResponse.last)) - end - - it 'creates a new SurveyResponse when click Submit' do - expect do - post survey_responses_path, params: { survey_response: create_response_attr, commit: 'Submit' } - end.to change(SurveyResponse, :count).by(1) - end - - it 'redirects to the SurveyResponse show page when click Submit' do - post survey_responses_path, params: { survey_response: create_response_attr, commit: 'Submit' } - expect(response).to redirect_to(survey_response_path(SurveyResponse.last)) - end - - it 'updates the requested survey_response answers' do - my_question = survey_question - post survey_responses_path, params: { survey_response: { my_question.id => 2 } } - answer = SurveyAnswer.where(question: my_question, response: SurveyResponse.last).first - expect(answer.choice).to eq(2) - end - end - - context 'without user id' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } - end - it 'returns to root' do - post survey_responses_path - expect(response).to redirect_to(root_url) - end - end - - context 'user profile not exist' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) - end - it 'redirects to the root page' do - post survey_responses_path - expect(response).to redirect_to(root_url) - end - end - - context 'with invalid parameters' do - let(:invalid_attributes) do - # any value in form is null - { - profile_id: nil, - share_code: 1 - } - end - before do - allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(survey_profile.user_id) - end - - it 'does not create a new SurveyResponse - bad attributes' do - expect do - post survey_responses_path, params: { survey_response: invalid_attributes } - end.to_not change(SurveyResponse, :count) - end - - it 'returns a failure response (i.e., to display the "new" template)' do - post survey_responses_url, params: { survey_response: invalid_attributes } - expect(response).to have_http_status(:unprocessable_entity) - end - end - end - - describe 'PATCH /update' do - context 'with valid parameters' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(survey_answer.response.profile.user_id) - end - - it 'updates the requested survey_response answers' do - patch survey_response_url(survey_answer.response), params: { survey_response: { survey_answer.question.id => 2 } } - survey_answer.reload - expect(survey_answer.choice).to eq(2) - end - - it 'redirects to the survey_response' do - patch survey_response_url(survey_answer.response), params: { survey_response: { survey_answer.question.id => 2 } } - expect(response).to redirect_to(survey_answer.response) - end - end - - context 'without user id' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:session) { { page_number: 2 } } - end - it 'returns to root' do - my_answer = survey_answer - patch survey_response_url(my_answer.response), params: { survey_response: { my_answer.question.id => 2 } } - expect(response).to redirect_to(root_url) - end - end - - context 'user profile not exist' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:session) { { user_id: 99, page_number: 2 } } - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) - end - it 'redirects to the root page' do - my_answer = survey_answer - patch survey_response_url(my_answer.response), params: { survey_response: { my_answer.question.id => 2 } } - expect(response).to redirect_to(root_url) - end - end - - context 'responses with different profile' do - before do - allow_any_instance_of(SurveyResponsesController).to receive(:current_user_id).and_return(99) - end - - it 'redirects to the root page' do - patch survey_response_url(survey_answer.response), params: { survey_response: { survey_answer.question.id => 2 } } - expect(response).to redirect_to(root_url) - end - end - - context 'with invalid parameters' do - it 'responds with status 422 for nil input' do - invalid_response = { - :user_id => nil, - '1' => 1 - } - patch survey_response_url(survey_response), params: { survey_response: invalid_response } - expect(response).to have_http_status(:unprocessable_entity) - end - end - end - - describe 'DELETE /destroy' do - it 'destroys the requested survey_response' do - my_response = survey_response - expect do - delete survey_response_url(my_response) - end.to change(SurveyResponse, :count).by(-1) - end - - it 'redirects to the survey_responses list' do - delete survey_response_url(survey_response) - expect(response).to redirect_to(survey_responses_url) - end - end -end From 76cdcbad31dc0ef41d573e0a78273cad2979c09c Mon Sep 17 00:00:00 2001 From: 61315 Date: Sun, 14 Apr 2024 17:35:09 -0500 Subject: [PATCH 2/5] chore: bounty hunt (coverage) --- rails_root/app/controllers/home_controller.rb | 18 +++++---- rails_root/app/views/home/index.html.erb | 10 ++--- .../spec/controllers/auth0_controller_spec.rb | 27 +++++++++++++ .../spec/controllers/home_controller_spec.rb | 39 +++++++++++++++++++ 4 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 rails_root/spec/controllers/auth0_controller_spec.rb create mode 100644 rails_root/spec/controllers/home_controller_spec.rb diff --git a/rails_root/app/controllers/home_controller.rb b/rails_root/app/controllers/home_controller.rb index 8480c05..f2f9488 100644 --- a/rails_root/app/controllers/home_controller.rb +++ b/rails_root/app/controllers/home_controller.rb @@ -11,21 +11,25 @@ def index return if @survey_profile.nil? @survey_responses = fetch_survey_responses + @invitations = fetch_invitations end private def fetch_survey_responses - SurveyResponse.where(profile_id: @survey_profile.id).map do |response| - { response:, invited_by: fetch_invited_by(response) } + SurveyResponse.where(profile_id: @survey_profile.id) + end + + def fetch_invitations + @survey_responses.map do |response| + invitation = Invitation.find_by(response_id: response.id) + invitation ? fetch_invited_by(invitation) : 'N/A' end end - def fetch_invited_by(response) - invitation = Invitation.find_by(response_id: response.id) - parent_response = SurveyResponse.find(invitation.parent_response_id) if invitation + def fetch_invited_by(invitation) + parent_response = SurveyResponse.find(invitation.parent_response_id) profile = SurveyProfile.find(parent_response.profile_id) if parent_response - name = "#{profile.first_name} #{profile.last_name}" if profile - name || 'N/A' + "#{profile.first_name} #{profile.last_name}" if profile end end diff --git a/rails_root/app/views/home/index.html.erb b/rails_root/app/views/home/index.html.erb index 6ad4ac1..b454c2d 100644 --- a/rails_root/app/views/home/index.html.erb +++ b/rails_root/app/views/home/index.html.erb @@ -21,12 +21,12 @@ <% if !@survey_responses.nil?%> - <% @survey_responses.each do |response_hash| %> + <% @survey_responses.zip(@invitations).each do |response, invited_by| %> - <%= response_hash[:response].created_at %> - <%= response_hash[:invited_by] %> - <%= response_hash[:response].share_code %> - <%= link_to "Show", survey_response_path(response_hash[:response]) %> + <%= response.created_at %> + <%= invited_by %> + <%= response.share_code %> + <%= link_to "Show", survey_response_path(response) %> <% end %> diff --git a/rails_root/spec/controllers/auth0_controller_spec.rb b/rails_root/spec/controllers/auth0_controller_spec.rb new file mode 100644 index 0000000..4127fae --- /dev/null +++ b/rails_root/spec/controllers/auth0_controller_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Auth0Controller, type: :controller do + describe '#claim_invitation' do + before do + allow(controller).to receive(:redirect_to) + end + + context 'when the invitation does not exist or has expired' do + it 'deletes the invitation from the session and returns false' do + # Set up the session with an invitation that does not exist or has expired + session[:invitation] = { 'from' => 'nonexistent', 'expiration' => 1.hour.ago } + + # Call the method + result = controller.send(:claim_invitation) + + # Check that the invitation was deleted from the session + expect(session[:invitation]).to be_nil + + # Check that the method returned false + expect(result).to be(false) + end + end + end +end diff --git a/rails_root/spec/controllers/home_controller_spec.rb b/rails_root/spec/controllers/home_controller_spec.rb new file mode 100644 index 0000000..0617e9f --- /dev/null +++ b/rails_root/spec/controllers/home_controller_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# spec/controllers/home_controller_spec.rb +require 'rails_helper' + +RSpec.describe HomeController, type: :controller do + before do + @inviter_profile = SurveyProfile.create!(user_id: '1', first_name: 'Gary', last_name: 'Chalmers', campus_name: 'Springfield Elementary', district_name: 'Springfield', role: 'Superintendent') + invitee_profile = SurveyProfile.create!(user_id: '2', first_name: 'Seymour', last_name: 'Skinner', campus_name: 'Springfield Elementary', district_name: 'Springfield', role: 'Principal') + parent_survey_response = SurveyResponse.create!(share_code: 'SHARECODE', profile_id: @inviter_profile.id) + + @invitation = Invitation.create!(parent_response_id: parent_survey_response.id, visited: false, last_sent: Time.now) + sharecode_from_invitation = @invitation.parent_response.share_code + @new_response_to_fill = SurveyResponse.create(profile: invitee_profile, share_code: sharecode_from_invitation) + @invitation.update!(response_id: @new_response_to_fill.id, claimed_by_id: invitee_profile.id) + + session[:userinfo] = { 'sub' => invitee_profile.user_id } + end + + describe 'GET #index' do + it 'fetches survey responses' do + get :index + expect(assigns(:survey_responses)).to eq([@new_response_to_fill]) + end + + it 'fetches invitations' do + get :index + + parent_response = @invitation.parent_response + profile = parent_response.profile + + expected_invited_by = profile.nil? ? 'N/A' : "#{profile.first_name} #{profile.last_name}" + + actual_invitations = assigns(:invitations) + + expect(actual_invitations).to eq([expected_invited_by]) + end + end +end From 180b61c46d0cdd2033c4d3b2c35880738b435e1a Mon Sep 17 00:00:00 2001 From: minseopark <46559594+61315@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:01:00 -0500 Subject: [PATCH 3/5] Update .simplecov --- rails_root/.simplecov | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rails_root/.simplecov b/rails_root/.simplecov index 7524334..aa5e09f 100644 --- a/rails_root/.simplecov +++ b/rails_root/.simplecov @@ -1,8 +1,12 @@ # frozen_string_literal: true +require 'simplecov' + SimpleCov.start 'rails' do enable_coverage :branch # see https://github.com/colszowka/simplecov#branch-coverage-ruby--25 add_filter '/app/jobs/' add_filter '/app/mailers/' add_filter '/app/channels/' end + +SimpleCov.merge_timeout 3600 From c5a9e6badd3df45e8942305408abe347ecc534cc Mon Sep 17 00:00:00 2001 From: 61315 Date: Mon, 15 Apr 2024 20:15:03 -0500 Subject: [PATCH 4/5] feat: display new invitation link with copy button --- .../app/controllers/invitations_controller.rb | 13 +- .../invitations/invitation_created.html.erb | 3 - .../app/views/survey_responses/show.html.erb | 132 +++++++++++++----- rails_root/config/routes.rb | 4 - rails_root/features/invitation.feature | 1 - .../step_definitions/invitation_steps.rb | 20 +-- .../invitations_controller_spec.rb | 9 -- 7 files changed, 110 insertions(+), 72 deletions(-) delete mode 100644 rails_root/app/views/invitations/invitation_created.html.erb diff --git a/rails_root/app/controllers/invitations_controller.rb b/rails_root/app/controllers/invitations_controller.rb index c66b3de..88ddf08 100644 --- a/rails_root/app/controllers/invitations_controller.rb +++ b/rails_root/app/controllers/invitations_controller.rb @@ -6,7 +6,10 @@ def create @parent_survey_response = SurveyResponse.find_by!(id: params[:parent_survey_response_id]) @invitation = Invitation.create!(parent_response: @parent_survey_response, last_sent: Time.now, visited: false) - redirect_to invitation_created_invitation_path(@invitation.token) + render json: { + message: "Invitation link created: #{invitation_url(@invitation.token)}", + invitation_url: invitation_url(@invitation.token) + } end def show @@ -32,14 +35,6 @@ def not_found render :not_found end - def invitation_created - @invitation = Invitation.find_by(token: params[:token]) - - return unless @invitation.nil? - - redirect_to not_found_invitations_path - end - private def claim_invitation(user_profile) diff --git a/rails_root/app/views/invitations/invitation_created.html.erb b/rails_root/app/views/invitations/invitation_created.html.erb deleted file mode 100644 index be2c68e..0000000 --- a/rails_root/app/views/invitations/invitation_created.html.erb +++ /dev/null @@ -1,3 +0,0 @@ - -

Invitation Created

-

Your invitation link is: <%= invitation_url(@invitation.token) %>

\ No newline at end of file diff --git a/rails_root/app/views/survey_responses/show.html.erb b/rails_root/app/views/survey_responses/show.html.erb index 0157407..55f61b0 100644 --- a/rails_root/app/views/survey_responses/show.html.erb +++ b/rails_root/app/views/survey_responses/show.html.erb @@ -1,5 +1,4 @@

<%= notice %>

- <%# FIXME: Move this to a stylesheet when we have time %> -

Your leadership type is: (tbd)

@@ -93,54 +91,112 @@ <%= ans.question.text %> <%= choices[ans.choice] %> <% 4.times do |i| %> - - + > - - <% end %> - - - + + <% end %> + + + <%= ans.question.explanation %> - - - <% end %> - + + + <% end %> + +
+ <% end %> +
+ +
+ <%# this is the view containing the link %> + - -
-
-
- <%= link_to "Edit Response", + +
+
+ <%= link_to "Edit Response", edit_survey_response_path(@survey_response), class: "btn btn-outline-primary" - %> - <%= button_to "Create Invitation", - invitations_path(parent_survey_response_id: @survey_response.id), - method: :post, - id: "invitation-button", - form_class: "btn btn-outline-success", - class: "btn-passthrough" - %> - <%= button_to "Delete Response", + %> + <%= button_tag "Create Invitation", + data: { parent_survey_response_id: @survey_response.id }, + id: "invitation-button", + class: "btn btn-outline-success" + %> + <%= button_to "Delete Response", @survey_response, method: :delete, form_class: "btn btn-outline-danger", class: "btn-passthrough" - %> + %> +
-
-
-
-
- <%= link_to "Back to survey responses", survey_responses_path %> - <%= link_to "Back to home", root_path %> -
-
-
\ No newline at end of file + <%# show invitation link if it exist %> + +
+
+
+ <%= link_to "Back to survey responses", survey_responses_path %> + <%= link_to "Back to home", root_path %> +
+
+
\ No newline at end of file diff --git a/rails_root/config/routes.rb b/rails_root/config/routes.rb index ab9a432..4ff168f 100644 --- a/rails_root/config/routes.rb +++ b/rails_root/config/routes.rb @@ -19,10 +19,6 @@ collection do get :not_found end - - member do - get :invitation_created - end end get '/auth/auth0/callback' => 'auth0#callback' diff --git a/rails_root/features/invitation.feature b/rails_root/features/invitation.feature index 069bb37..a13ff7b 100644 --- a/rails_root/features/invitation.feature +++ b/rails_root/features/invitation.feature @@ -9,7 +9,6 @@ Feature: Invitation When I create an invitation at the bottom of the response page Then the invitation's sharecode should be set to the response's sharecode And the invitation's parent_response_id should be set to the response's id - And I should see a link that can be copied Scenario: Generate unique invitation URL Given an invitation exists diff --git a/rails_root/features/step_definitions/invitation_steps.rb b/rails_root/features/step_definitions/invitation_steps.rb index a27cc9c..d237300 100644 --- a/rails_root/features/step_definitions/invitation_steps.rb +++ b/rails_root/features/step_definitions/invitation_steps.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'webmock/cucumber' +# require 'webmock/cucumber' Given('I have completed the survey as user {string}') do |id| profile = SurveyProfile.find_or_create_by(user_id: id) @@ -12,9 +12,17 @@ click_button 'Create Invitation' - # Wait for the flash message to appear and extract the invitation token from it - expect(page).to have_content('Invitation Created') - @token = page.text.match(%r{Your invitation link is: #{Capybara.current_host}/invitations/([a-zA-Z0-9\-_]+)})[1] + # TODO: Set up Capybara for AJAX calls + response = page.driver.post(invitations_path, { + parent_survey_response_id: @survey_response.id + }) + + json_response = JSON.parse(response.body) + + invitation_link = json_response['invitation_url'] + + # extract token + @token = invitation_link.match(%r{#{Capybara.current_host}/invitations/([a-zA-Z0-9\-_]+)})[1] @invitation = Invitation.find_by(token: @token) end @@ -26,10 +34,6 @@ expect(@invitation.parent_response_id).to eq(@survey_response.id) end -Then('I should see a link that can be copied') do - expect(page.body).to match(%r{Your invitation link is: #{Capybara.current_host}/invitations/#{@token}}) -end - ### Then('the invitation should have a unique token') do diff --git a/rails_root/spec/controllers/invitations_controller_spec.rb b/rails_root/spec/controllers/invitations_controller_spec.rb index 5aa39ea..34ae43a 100644 --- a/rails_root/spec/controllers/invitations_controller_spec.rb +++ b/rails_root/spec/controllers/invitations_controller_spec.rb @@ -76,13 +76,4 @@ end end end - - describe 'GET #invitation_created' do - context 'when invitation is not found' do - it 'redirects to not_found' do - get :invitation_created, params: { token: 'nonexistent_token' } - expect(response).to redirect_to(not_found_invitations_path) - end - end - end end From 412c66b1ab193a70bd8d6588e793a25d725666f3 Mon Sep 17 00:00:00 2001 From: 61315 Date: Mon, 15 Apr 2024 21:10:12 -0500 Subject: [PATCH 5/5] fix: response instance made by invitation logic breaks pagination --- rails_root/app/controllers/survey_responses_controller.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rails_root/app/controllers/survey_responses_controller.rb b/rails_root/app/controllers/survey_responses_controller.rb index 8ed2979..9687c4b 100644 --- a/rails_root/app/controllers/survey_responses_controller.rb +++ b/rails_root/app/controllers/survey_responses_controller.rb @@ -62,6 +62,9 @@ def edit return return_to_root 'Your profile could not be found. Please complete your profile.' unless SurveyProfile.exists?(user_id: current_user_id) return return_to_root 'You cannot edit this result.' if current_user_id != @survey_response.profile.user_id + # Initialize page number to 1 if not already set + session[:page_number] = 1 if session[:page_number].nil? + @pagination, @questions, @section = paginate(collection: SurveyQuestion.all, params: { per_page: 10, page: session[:page_number] }) end