diff --git a/Changelog.md b/Changelog.md index 8ce7cce912..c82ad22ecc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -26,6 +26,7 @@ - Add unit tests for `marks_graders_controller` (#7382) - Convert front-end tests from enzyme to react testing library; add `@testing-library/user-event` (#7379) - Refactor the `Result` component and its children to use React context API (#7380) +- Implement `contain_message` and `have_message` custom Rspec matchers to check for flash message content (#7386) - Update Python version to 3.13 in seed autotest schemas (#7388) - Rename jupyter notebook content functions and files to generalize to html content (#7391) diff --git a/spec/controllers/annotation_categories_controller_spec.rb b/spec/controllers/annotation_categories_controller_spec.rb index ce416238cf..e9678808b5 100644 --- a/spec/controllers/annotation_categories_controller_spec.rb +++ b/spec/controllers/annotation_categories_controller_spec.rb @@ -702,8 +702,7 @@ expect(response).to have_http_status(:found) expect(flash[:error]).to be_nil - expect(flash[:success].map { |f| extract_text f }).to eq([I18n.t('upload_success', - count: 2)].map { |f| extract_text f }) + expect(flash[:success]).to have_message(I18n.t('upload_success', count: 2)) expect(response).to redirect_to(action: 'index', assignment_id: assignment.id) expect(AnnotationCategory.all.size).to eq(2) @@ -729,8 +728,7 @@ expect(response).to have_http_status :found expect(flash[:error]).to be_nil - expect(flash[:success].map { |f| extract_text f }).to eq([I18n.t('upload_success', - count: 3)].map { |f| extract_text f }) + expect(flash[:success]).to have_message(I18n.t('upload_success', count: 3)) expect(response).to redirect_to(action: 'index', assignment_id: assignment.id) expect(AnnotationCategory.all.size).to eq 3 diff --git a/spec/controllers/assignments_controller_spec.rb b/spec/controllers/assignments_controller_spec.rb index 50024893b1..00ff86a0c4 100644 --- a/spec/controllers/assignments_controller_spec.rb +++ b/spec/controllers/assignments_controller_spec.rb @@ -2277,7 +2277,7 @@ grouping # lazy initialization delete_as instructor, :destroy, params: { course_id: course.id, id: assignment.id } expect(Assignment.exists?(assignment.id)).to be(true) - expect(flash[:error]).to eq(["<p>#{I18n.t('assignments.assignment_has_groupings')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('assignments.assignment_has_groupings')) expect(flash.to_hash.length).to eq(1) expect(flash[:error].length).to eq(1) expect(response).to have_http_status(:found) @@ -2286,8 +2286,8 @@ it 'should successfully DELETE assignment (no groups)' do delete_as instructor, :destroy, params: { course_id: course.id, id: assignment.id } expect(Assignment.exists?(assignment.id)).to be(false) - expect(flash[:success]).to eq(I18n.t('flash.actions.destroy.success', - resource_name: assignment.short_identifier)) + expect(flash[:success]).to have_message(I18n.t('flash.actions.destroy.success', + resource_name: assignment.short_identifier)) expect(flash.to_hash.length).to eq(1) expect(response).to have_http_status(:found) end @@ -2318,10 +2318,8 @@ delete_as instructor, :destroy, params: { course_id: course.id, id: assignment.id } - expect(flash[:error][0]).to include( - I18n.t('activerecord.errors.models.assignment_deletion', - problem_message: 'some error') - ) + expect(flash[:error]).to contain_message(I18n.t('activerecord.errors.models.assignment_deletion', + problem_message: 'some error')) expect(Assignment.exists?(assignment.id)).to be true expect(response).to redirect_to(edit_course_assignment_path(course.id, assignment.id)) end diff --git a/spec/controllers/automated_tests_controller_spec.rb b/spec/controllers/automated_tests_controller_spec.rb index d9321c06c0..c23ff792ce 100644 --- a/spec/controllers/automated_tests_controller_spec.rb +++ b/spec/controllers/automated_tests_controller_spec.rb @@ -279,7 +279,7 @@ end it 'flashes an error message' do - expect(flash[:error].join('\n')).to include(I18n.t('errors.invalid_path')) + expect(flash[:error]).to contain_message(I18n.t('errors.invalid_path')) end it 'does not save the file' do @@ -294,7 +294,7 @@ end it 'flashes an error message' do - expect(flash[:error].join('\n')).to include(I18n.t('errors.invalid_path')) + expect(flash[:error]).to contain_message(I18n.t('errors.invalid_path')) end it 'does not create the folder' do @@ -309,7 +309,7 @@ end it 'flashes an error message' do - expect(flash[:error].join('\n')).to include(I18n.t('errors.invalid_path')) + expect(flash[:error]).to contain_message(I18n.t('errors.invalid_path')) end it 'does not delete the folder' do @@ -324,7 +324,7 @@ end it 'flashes an error message' do - expect(flash[:error].join('\n')).to include(I18n.t('errors.invalid_path')) + expect(flash[:error]).to contain_message(I18n.t('errors.invalid_path')) end it 'does not delete the file' do diff --git a/spec/controllers/courses_controller_spec.rb b/spec/controllers/courses_controller_spec.rb index 7b7de2d202..35b652074d 100644 --- a/spec/controllers/courses_controller_spec.rb +++ b/spec/controllers/courses_controller_spec.rb @@ -367,8 +367,7 @@ test2 = Assignment.find_by(short_identifier: @test_asn2) expect(test2).not_to be_nil expect(flash[:error]).to be_nil - expect(flash[:success].map { |f| extract_text f }).to eq([I18n.t('upload_success', - count: 2)].map { |f| extract_text f }) + expect(flash[:success]).to have_message(I18n.t('upload_success', count: 2)) expect(response).to redirect_to(course_assignments_path(course)) end diff --git a/spec/controllers/criteria_controller_spec.rb b/spec/controllers/criteria_controller_spec.rb index 8d8af0553b..83dde7d93a 100644 --- a/spec/controllers/criteria_controller_spec.rb +++ b/spec/controllers/criteria_controller_spec.rb @@ -420,8 +420,7 @@ params: { course_id: course.id, id: flexible_criterion.id }, format: :js expect(assigns(:criterion)).to be_truthy - i18t_strings = [I18n.t('flash.criteria.destroy.success')].map { |f| extract_text f } - expect(i18t_strings).to eql(flash[:success].map { |f| extract_text f }) + expect(flash[:success]).to have_message(I18n.t('flash.criteria.destroy.success')) expect(subject).to respond_with(:success) expect { FlexibleCriterion.find(flexible_criterion.id) }.to raise_error(ActiveRecord::RecordNotFound) @@ -818,8 +817,7 @@ end it 'displays an error message' do - expect(flash[:error].map { |f| extract_text f }) - .to eq([I18n.t('criteria.errors.criteria_not_found')].map { |f| extract_text f }) + expect(flash[:error]).to have_message(I18n.t('criteria.errors.criteria_not_found')) end end end @@ -832,8 +830,7 @@ params: { course_id: course.id, id: rubric_criterion.id }, format: :js expect(assigns(:criterion)).to be_truthy - i18t_string = [I18n.t('flash.criteria.destroy.success')].map { |f| extract_text f } - expect(i18t_string).to eql(flash[:success].map { |f| extract_text f }) + expect(flash[:success]).to have_message(I18n.t('flash.criteria.destroy.success')) expect(subject).to respond_with(:success) expect { RubricCriterion.find(rubric_criterion.id) }.to raise_error(ActiveRecord::RecordNotFound) @@ -878,8 +875,7 @@ post_as instructor, :upload, params: { course_id: course.id, assignment_id: assignment.id, upload_file: empty_file } - expect(flash[:error].map { |f| extract_text f }) - .to eq([I18n.t('upload_errors.blank')].map { |f| extract_text f }) + expect(flash[:error]).to have_message(I18n.t('upload_errors.blank')) end it 'deletes all criteria previously created' do @@ -918,8 +914,7 @@ 'cr90', 'cr40', 'cr50') - expect(flash[:success].map { |f| extract_text f }) - .to eq([I18n.t('upload_success', count: 8)].map { |f| extract_text f }) + expect(flash[:success]).to have_message(I18n.t('upload_success', count: 8)) end it 'creates rubric criteria with properly formatted entries' do @@ -1043,8 +1038,7 @@ 'cr90', 'cr40', 'cr50') - expect(flash[:success].map { |f| extract_text f }) - .to eq([I18n.t('upload_success', count: 8)].map { |f| extract_text f }) + expect(flash[:success]).to have_message(I18n.t('upload_success', count: 8)) end it 'creates criteria correctly when a valid yml file with the wrong extension is uploaded' do @@ -1059,8 +1053,7 @@ 'cr90', 'cr40', 'cr50') - expect(flash[:success].map { |f| extract_text f }) - .to eq([I18n.t('upload_success', count: 8)].map { |f| extract_text f }) + expect(flash[:success]).to have_message(I18n.t('upload_success', count: 8)) end it 'does not create criteria with format errors in entries' do @@ -1068,8 +1061,8 @@ upload_file: invalid_mixed_file } expect(assignment.criteria.pluck(:name)).not_to include('cr40', 'cr50', 'cr70') - expect(flash[:error].map { |f| extract_text f }) - .to eq([I18n.t('criteria.errors.invalid_format') + ' cr40, cr70, cr50'].map { |f| extract_text f }) + expect(flash[:error]).to contain_message(I18n.t('criteria.errors.invalid_format')) + expect(flash[:error]).to contain_message(' cr40, cr70, cr50') end it 'does not create criteria with an invalid mark' do @@ -1084,8 +1077,8 @@ upload_file: missing_levels_file } expect(assignment.criteria.where(name: %w[no_levels empty_levels])).to be_empty - expect(flash[:error].map { |f| extract_text f }) - .to eq([I18n.t('criteria.errors.invalid_format') + ' no_levels, empty_levels'].map { |f| extract_text f }) + expect(flash[:error]).to contain_message(I18n.t('criteria.errors.invalid_format')) + expect(flash[:error]).to contain_message(' no_levels, empty_levels') end it 'does not create criteria that have both visibility options set to false' do diff --git a/spec/controllers/exam_templates_controller_spec.rb b/spec/controllers/exam_templates_controller_spec.rb index 6985881f98..b87135b6f9 100644 --- a/spec/controllers/exam_templates_controller_spec.rb +++ b/spec/controllers/exam_templates_controller_spec.rb @@ -50,7 +50,7 @@ before { post_as user, :create, params: params } it 'flashes an exam template create failure error message' do - expect(flash[:error].map { |f| extract_text f }).to eq [I18n.t('exam_templates.create.failure')] + expect(flash[:error]).to have_message(I18n.t('exam_templates.create.failure')) end end @@ -113,7 +113,7 @@ end it 'displays a flash error message' do - expect(flash[:error].map { |f| extract_text f }).to eq [I18n.t('exam_templates.update.failure')] + expect(flash[:error]).to have_message(I18n.t('exam_templates.update.failure')) end it 'responds with 302' do @@ -160,8 +160,7 @@ end it 'should send appropriate error message' do - expect(flash[:error].map { |f| extract_text f }) - .to eq([I18n.t('exam_templates.upload_scans.search_failure')].map { |f| extract_text f }) + expect(flash[:error]).to have_message(I18n.t('exam_templates.upload_scans.search_failure')) end end @@ -177,8 +176,7 @@ end it 'should send appropriate error message' do - expect(flash[:error].map { |f| extract_text f }) - .to eq([I18n.t('exam_templates.upload_scans.missing')].map { |f| extract_text f }) + expect(flash[:error]).to have_message(I18n.t('exam_templates.upload_scans.missing')) end end @@ -195,8 +193,7 @@ end it 'should send appropriate error message' do - expect(flash[:error].map { |f| extract_text f }) - .to eq([I18n.t('exam_templates.upload_scans.invalid')].map { |f| extract_text f }) + expect(flash[:error]).to have_message(I18n.t('exam_templates.upload_scans.invalid')) end end end diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 2029a142da..b7bb450347 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -46,7 +46,7 @@ end it 'assigns the error message to flash[:error]' do - expect(flash[:error][0]).to include("Group #{group_name} already exists") + expect(flash[:error]).to contain_message("Group #{group_name} already exists") end end end @@ -181,9 +181,7 @@ new_groupname: 'placeholder_group' } - expect(flash[:error].map do |f| - extract_text f - end).to eq [I18n.t('groups.group_name_already_in_use_diff_assignment')] + expect(flash[:error]).to have_message(I18n.t('groups.group_name_already_in_use_diff_assignment')) end end @@ -198,9 +196,7 @@ new_groupname: 'placeholder_group' } - expect(flash[:error].map do |f| - extract_text f - end).to eq [I18n.t('groups.group_name_already_in_use_diff_assignment')] + expect(flash[:error]).to have_message(I18n.t('groups.group_name_already_in_use_diff_assignment')) end end end diff --git a/spec/controllers/job_messages_controller_spec.rb b/spec/controllers/job_messages_controller_spec.rb index bb878bc7a0..73de0ab514 100644 --- a/spec/controllers/job_messages_controller_spec.rb +++ b/spec/controllers/job_messages_controller_spec.rb @@ -51,7 +51,7 @@ let(:status_type) { :queued } it 'should flash a notice message' do - expect(flash[:notice]).to include "<p>#{I18n.t('poll_job.queued')}</p>" + expect(flash[:notice]).to contain_message(I18n.t('poll_job.queued')) end it 'should not set the session[:job_id] to nil' do @@ -67,7 +67,7 @@ let(:status_type) { :working } it 'should flash a notice message' do - expect(flash[:notice]).to include "<p>#{ApplicationJob.show_status(status)}</p>" + expect(flash[:notice]).to contain_message(ApplicationJob.show_status(status)) end it 'should not set the session[:job_id] to nil' do diff --git a/spec/controllers/main_controller_spec.rb b/spec/controllers/main_controller_spec.rb index 607b5d9c66..907e73bf66 100644 --- a/spec/controllers/main_controller_spec.rb +++ b/spec/controllers/main_controller_spec.rb @@ -9,12 +9,12 @@ context 'A non-authenticated user' do it 'should not be able to login with a blank username' do post :login, params: { user_login: '', user_password: 'a' } - expect(ActionController::Base.helpers.strip_tags(flash[:error][0])).to eq(I18n.t('main.username_not_blank')) + expect(flash[:error]).to have_message(I18n.t('main.username_not_blank')) end it 'should not be able to login with a blank password' do post :login, params: { user_login: 'a', user_password: '' } - expect(ActionController::Base.helpers.strip_tags(flash[:error][0])).to eq(I18n.t('main.password_not_blank')) + expect(flash[:error]).to have_message(I18n.t('main.password_not_blank')) end describe 'login_remote_auth' do @@ -143,7 +143,7 @@ context 'after logging in with a bad username' do it 'should not be able to login with an incorrect username' do post :login, params: { user_login: instructor.user_name + 'BAD', user_password: 'a' } - expect(ActionController::Base.helpers.strip_tags(flash[:error][0])).to eq(I18n.t('main.login_failed')) + expect(flash[:error]).to have_message(I18n.t('main.login_failed')) end end diff --git a/spec/controllers/marks_graders_controller_spec.rb b/spec/controllers/marks_graders_controller_spec.rb index 615d9e803c..3f41729aca 100644 --- a/spec/controllers/marks_graders_controller_spec.rb +++ b/spec/controllers/marks_graders_controller_spec.rb @@ -43,7 +43,7 @@ expect(flash[:error]).to be_nil expect(response).to redirect_to(action: 'index', grade_entry_form_id: - grade_entry_form_with_data.id) + grade_entry_form_with_data.id) # check that the ta was assigned to each student @student_user_names.each do |name| @@ -80,7 +80,7 @@ @student_user_names.each do |name| expect( GradeEntryStudentTa.joins(grade_entry_student: :user) - .exists?(grade_entry_student: { users: { user_name: name } }) + .exists?(grade_entry_student: { users: { user_name: name } }) ).to be true end expect(ges.tas.count).to eq 0 @@ -167,7 +167,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('groups.select_a_student')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('groups.select_a_student')) end end @@ -181,7 +181,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('graders.select_a_grader')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('graders.select_a_grader')) end end @@ -194,7 +194,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('groups.select_a_student')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('groups.select_a_student')) end end @@ -207,7 +207,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('graders.select_a_grader')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('graders.select_a_grader')) end end end @@ -250,7 +250,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('groups.select_a_student')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('groups.select_a_student')) end end @@ -264,7 +264,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('graders.select_a_grader')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('graders.select_a_grader')) end end @@ -277,7 +277,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('groups.select_a_student')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('groups.select_a_student')) end end @@ -290,7 +290,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('graders.select_a_grader')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('graders.select_a_grader')) end end end @@ -333,7 +333,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('groups.select_a_student')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('groups.select_a_student')) end end @@ -347,7 +347,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('graders.select_a_grader')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('graders.select_a_grader')) end end @@ -360,7 +360,7 @@ } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('groups.select_a_student')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('groups.select_a_student')) end end @@ -372,7 +372,7 @@ student_id: 1 } expect(response).to have_http_status(:bad_request) - expect(flash[:error]).to eq(["<p>#{I18n.t('graders.select_a_grader')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('graders.select_a_grader')) end end end diff --git a/spec/controllers/notes_controller_spec.rb b/spec/controllers/notes_controller_spec.rb index b0aa4a72fb..b66d27ce32 100644 --- a/spec/controllers/notes_controller_spec.rb +++ b/spec/controllers/notes_controller_spec.rb @@ -143,7 +143,8 @@ params: { course_id: course.id, noteable_type: 'Grouping', note: { noteable_id: grouping.id, notes_message: @message } } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.create.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.create.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') expect(Note.count).to eq @notes + 1 end @@ -156,7 +157,8 @@ params: { course_id: course.id, noteable_type: 'Student', note: { noteable_id: student.id, notes_message: @message } } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.create.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.create.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') expect(Note.count).to eq @notes + 1 end @@ -169,7 +171,8 @@ params: { course_id: course.id, noteable_type: 'Assignment', note: { noteable_id: assignment.id, notes_message: @message } } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.create.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.create.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') expect(Note.count).to eq @notes + 1 end @@ -245,7 +248,8 @@ :update, params: { course_id: course.id, id: @note.id, note: { notes_message: @new_message } } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.update.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.update.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') end end @@ -265,15 +269,15 @@ @note = create(:note, creator_id: @ta.id) delete_as @ta, :destroy, params: { course_id: course.id, id: @note.id } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.destroy.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.destroy.success', + resource_name: Note.model_name.human)) end it 'for a note belonging to someone else (delete as TA)' do @note = create(:note) delete_as @ta, :destroy, params: { course_id: course.id, id: @note.id } expect(assigns(:note)).not_to be_nil - i18t_string = [I18n.t('action_policy.policy.note.modify?')].map { |f| extract_text f } - expect(flash[:error].map { |f| extract_text f }).to eq(i18t_string) + expect(flash[:error]).to have_message(I18n.t('action_policy.policy.note.modify?')) end end end @@ -313,8 +317,7 @@ it 'for invalid type' do get_as @instructor, :noteable_object_selector, params: { course_id: course.id, noteable_type: 'gibberish' } - i18t_string = [I18n.t('notes.new.invalid_selector')].map { |f| extract_text f } - expect(flash[:error].map { |f| extract_text f }).to eq(i18t_string) + expect(flash[:error]).to have_message(I18n.t('notes.new.invalid_selector')) expect(assigns(:assignments)).not_to be_nil expect(assigns(:groupings)).not_to be_nil expect(assigns(:students)).to be_nil @@ -373,7 +376,8 @@ params: { course_id: course.id, noteable_type: 'Grouping', note: { noteable_id: grouping.id, notes_message: @message } } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.create.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.create.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') expect(Note.count).to eq @notes + 1 end @@ -386,7 +390,8 @@ params: { course_id: course.id, noteable_type: 'Student', note: { noteable_id: student.id, notes_message: @message } } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.create.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.create.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') expect(Note.count).to eq @notes + 1 end @@ -399,7 +404,8 @@ params: { course_id: course.id, noteable_type: 'Assignment', note: { noteable_id: assignment.id, notes_message: @message } } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.create.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.create.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') expect(Note.count).to eq @notes + 1 end @@ -442,7 +448,8 @@ post_as @instructor, :update, params: { course_id: course.id, id: @note.id, note: { notes_message: @new_message } } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.update.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.update.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') end @@ -452,7 +459,8 @@ post_as @instructor, :update, params: { course_id: course.id, id: @note.id, note: { notes_message: @new_message } } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.update.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.update.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') end @@ -460,7 +468,8 @@ @note = create(:note, creator_id: @instructor.id) delete_as @instructor, :destroy, params: { course_id: course.id, id: @note.id } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.destroy.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.destroy.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') end @@ -468,7 +477,8 @@ @note = create(:note, creator_id: create(:ta).id) delete_as @instructor, :destroy, params: { course_id: course.id, id: @note.id } expect(assigns(:note)).not_to be_nil - expect(flash[:success]).to eq I18n.t('flash.actions.destroy.success', resource_name: Note.model_name.human) + expect(flash[:success]).to have_message(I18n.t('flash.actions.destroy.success', + resource_name: Note.model_name.human)) expect(response).to redirect_to(controller: 'notes') end diff --git a/spec/controllers/peer_reviews_controller_spec.rb b/spec/controllers/peer_reviews_controller_spec.rb index e25bb80d46..7a29e63603 100644 --- a/spec/controllers/peer_reviews_controller_spec.rb +++ b/spec/controllers/peer_reviews_controller_spec.rb @@ -263,9 +263,8 @@ end it 'flashes the correct message' do - expect(flash[:success].map { |f| extract_text f }).to eq [I18n.t( - 'peer_reviews.unassigned_reviewers_successfully', deleted_count: 1.to_s - )] + expect(flash[:success]).to have_message(I18n.t('peer_reviews.unassigned_reviewers_successfully', + deleted_count: 1.to_s)) end it 'removes selected reviewer as reviewer for selected reviewee' do @@ -296,9 +295,8 @@ end it 'flashes the correct message' do - expect(flash[:success].map { |f| extract_text f }).to eq [I18n.t( - 'peer_reviews.unassigned_reviewers_successfully', deleted_count: 8.to_s - )] + expect(flash[:success]).to have_message(I18n.t('peer_reviews.unassigned_reviewers_successfully', + deleted_count: 8.to_s)) end end end @@ -331,9 +329,7 @@ end it 'flashes the correct message' do - expect(flash[:error].map { |f| extract_text f }).to eq [I18n.t( - 'peer_reviews.errors.cannot_unassign_any_reviewers' - )] + expect(flash[:error]).to have_message(I18n.t('peer_reviews.errors.cannot_unassign_any_reviewers')) end it 'does not delete any peer reviews' do @@ -361,9 +357,7 @@ end it 'flashes the correct message' do - expect(flash[:error].map { |f| extract_text f }).to eq [I18n.t( - 'peer_reviews.errors.cannot_unassign_any_reviewers' - )] + expect(flash[:error]).to have_message(I18n.t('peer_reviews.errors.cannot_unassign_any_reviewers')) end it 'does not delete any peer reviews' do @@ -389,9 +383,9 @@ reviewer_group_name: review.reviewer.group.group_name, reviewee_group_name: review.result.grouping.group.group_name) end - flashed_error = flash[:error].map { |f| extract_text f }[0] - expect(flashed_error).to include('Successfully unassigned 1 peer reviewer(s)') - expect(flashed_error).to include(I18n.t('additional_not_shown', count: undeleted_reviews.length - 6)) + expect(flash[:error]).to contain_message('Successfully unassigned 1 peer reviewer(s)') + expect(flash[:error]).to contain_message(I18n.t('additional_not_shown', + count: undeleted_reviews.length - 6)) end it 'deletes the correct number of peer reviews' do @@ -426,9 +420,9 @@ reviewee_group_name: review.result.grouping.group.group_name) end - flashed_error = flash[:error].map { |f| extract_text f }[0] - expect(flashed_error).to include('Successfully unassigned 1 peer reviewer(s)') - expect(flashed_error).to include(I18n.t('additional_not_shown', count: undeleted_reviews.length - 6)) + expect(flash[:error]).to contain_message('Successfully unassigned 1 peer reviewer(s)') + expect(flash[:error]).to contain_message(I18n.t('additional_not_shown', + count: undeleted_reviews.length - 6)) end it 'deletes the correct number of peer reviews' do @@ -451,8 +445,7 @@ end it 'flashes the correct message' do - flashed_error = flash[:error].map { |f| extract_text f }[0] - expect(flashed_error).to include('Successfully unassigned 6 peer reviewer(s)') + expect(flash[:error]).to contain_message('Successfully unassigned 6 peer reviewer(s)') end it 'deletes the correct number of peer reviews' do @@ -486,9 +479,10 @@ end it 'flashes the correct message' do - flashed_error = flash[:error].map { |f| extract_text f }[0] - expect(flashed_error).to include('Successfully unassigned 2 peer reviewer(s), but could not unassign the ' \ - 'following due to existing marks or annotations: ') + expect(flash[:error]).to contain_message( + 'Successfully unassigned 2 peer reviewer(s), but could not unassign the ' \ + 'following due to existing marks or annotations: ' + ) end it 'deletes the correct number of peer reviews' do diff --git a/spec/controllers/sections_controller_spec.rb b/spec/controllers/sections_controller_spec.rb index fa4740ac9d..ffaaf679ea 100644 --- a/spec/controllers/sections_controller_spec.rb +++ b/spec/controllers/sections_controller_spec.rb @@ -52,26 +52,21 @@ post_as @instructor, :create, params: { course_id: course.id, section: { name: 'section_01' } } expect(response).to be_redirect - i18t_string = [I18n.t('sections.create.success', name: 'section_01')].map { |f| extract_text f } - expect(flash[:success].map { |f| extract_text f }).to eq(i18t_string) + expect(flash[:success]).to have_message(I18n.t('sections.create.success', name: 'section_01')) expect(Section.find_by(name: 'section_01')).to be_truthy end it 'not be able to create a section with the same name as a existing one' do post_as @instructor, :create, params: { course_id: course.id, section: { name: section.name } } expect(response).to have_http_status(:ok) - expect(flash[:error].map { |f| extract_text f }).to eq([I18n.t('sections.create.error')].map do |f| - extract_text f - end) + expect(flash[:error]).to have_message(I18n.t('sections.create.error')) end it 'not be able to create a section with a blank name' do post_as @instructor, :create, params: { course_id: course.id, section: { name: '' } } expect(Section.find_by(name: '')).to be_nil expect(response).to have_http_status(:ok) - expect(flash[:error].map { |f| extract_text f }).to eq([I18n.t('sections.create.error')].map do |f| - extract_text f - end) + expect(flash[:error]).to have_message(I18n.t('sections.create.error')) end it 'on edit section' do @@ -83,8 +78,7 @@ put_as @instructor, :update, params: { course_id: course.id, id: section.id, section: { name: 'no section' } } expect(response).to be_redirect - i18t_string = [I18n.t('sections.update.success', name: 'no section')].map { |f| extract_text f } - expect(flash[:success].map { |f| extract_text f }).to eq(i18t_string) + expect(flash[:success]).to have_message(I18n.t('sections.update.success', name: 'no section')) expect(Section.find_by(name: 'no section')).to be_truthy end @@ -96,24 +90,20 @@ it 'not be able to edit a section name to an existing name' do put_as @instructor, :update, params: { course_id: course.id, id: section.id, section: { name: section2.name } } expect(response).to have_http_status(:ok) - expect(flash[:error].map { |f| extract_text f }).to eq([I18n.t('sections.update.error')].map do |f| - extract_text f - end) + expect(flash[:error]).to have_message(I18n.t('sections.update.error')) end context 'with an already created section' do it 'be able to delete a section' do delete_as @instructor, :destroy, params: { course_id: course.id, id: section.id } - i18t_string = [I18n.t('sections.destroy.success')].map { |f| extract_text f } - expect(flash[:success].map { |f| extract_text f }).to eq(i18t_string) + expect(flash[:success]).to have_message(I18n.t('sections.destroy.success')) end it 'not be able to delete a section with students in it' do student = create(:student) section.students << student delete_as @instructor, :destroy, params: { course_id: course.id, id: section.id } - i18t_string = [I18n.t('sections.destroy.not_empty')].map { |f| extract_text f } - expect(flash[:error].map { |f| extract_text f }).to eq(i18t_string) + expect(flash[:error]).to have_message(I18n.t('sections.destroy.not_empty')) expect(Section.find(section.id)).to be_truthy end end diff --git a/spec/controllers/starter_file_groups_controller_spec.rb b/spec/controllers/starter_file_groups_controller_spec.rb index 0864044ec0..2eacbbf7c3 100644 --- a/spec/controllers/starter_file_groups_controller_spec.rb +++ b/spec/controllers/starter_file_groups_controller_spec.rb @@ -234,7 +234,7 @@ let(:new_folders) { %w[../../hello] } it 'flashes an error message' do - expect(flash[:error].join('\n')).to include(I18n.t('errors.invalid_path')) + expect(flash[:error]).to contain_message(I18n.t('errors.invalid_path')) end it 'does not create the folder' do @@ -270,7 +270,7 @@ let(:delete_files) { %w[../../../../../LICENSE] } it 'flashes an error message' do - expect(flash[:error].join('\n')).to include(I18n.t('errors.invalid_path')) + expect(flash[:error]).to contain_message(I18n.t('errors.invalid_path')) end it 'does not delete the file' do @@ -310,7 +310,7 @@ let(:delete_folders) { %w[../../../../../doc] } it 'flashes an error message' do - expect(flash[:error].join('\n')).to include(I18n.t('errors.invalid_path')) + expect(flash[:error]).to contain_message(I18n.t('errors.invalid_path')) end it 'does not delete the folder' do @@ -333,7 +333,7 @@ it 'should flash an error message' do subject - expect(flash[:error].join('\n')).to include(I18n.t('errors.invalid_path')) + expect(flash[:error]).to contain_message(I18n.t('errors.invalid_path')) end end end diff --git a/spec/controllers/submissions_controller_spec.rb b/spec/controllers/submissions_controller_spec.rb index 257e8fc954..afb8992dd5 100644 --- a/spec/controllers/submissions_controller_spec.rb +++ b/spec/controllers/submissions_controller_spec.rb @@ -900,7 +900,7 @@ params: { course_id: course.id, assignment_id: @assignment.id, grouping_id: @grouping1.id, current_revision_identifier: revision_identifier } - expect(flash[:error]).to eq(["<p>#{I18n.t('submissions.collect.could_not_collect_released')}</p>"]) + expect(flash[:error]).to have_message(I18n.t('submissions.collect.could_not_collect_released')) end end end @@ -1783,7 +1783,7 @@ it 'flashes an error message' do subject - expect(flash[:error].join('\n')).to include(I18n.t('errors.invalid_path')) + expect(flash[:error]).to have_message(I18n.t('errors.invalid_path')) end end diff --git a/spec/controllers/tags_controller_spec.rb b/spec/controllers/tags_controller_spec.rb index c85694b821..aaf6549be5 100644 --- a/spec/controllers/tags_controller_spec.rb +++ b/spec/controllers/tags_controller_spec.rb @@ -46,7 +46,7 @@ post_as instructor, :create, params: { tag: { name: '', description: 'tag description' }, assignment_id: assignment.id, course_id: course.id } expect(Tag.find_by(name: '', description: 'tag description')).to be_nil - expect(flash[:error][0]).to include(I18n.t('flash.actions.create.error', resource_name: Tag.model_name.human)) + expect(flash[:error]).to have_message(I18n.t('flash.actions.create.error', resource_name: Tag.model_name.human)) end it 'associates the new tag with a grouping when passed grouping_id' do @@ -104,8 +104,7 @@ expect(response).to have_http_status(:found) expect(flash[:error]).to be_nil - expect(flash[:success].map { |f| extract_text f }).to eq([I18n.t('upload_success', - count: 2)].map { |f| extract_text f }) + expect(flash[:success]).to have_message(I18n.t('upload_success', count: 2)) expect(response).to redirect_to course_tags_path(course, assignment_id: assignment.id) expect(Tag.find_by(name: 'tag').description).to eq('desc') diff --git a/spec/controllers/tas_controller_spec.rb b/spec/controllers/tas_controller_spec.rb index aa7f6d5447..705b3ec9bd 100644 --- a/spec/controllers/tas_controller_spec.rb +++ b/spec/controllers/tas_controller_spec.rb @@ -300,7 +300,8 @@ it 'does not delete the TA, shows an error message, and gets a bad request response' do expect(Ta.count).to eq(1) expect(flash.now[:success]).to be_nil - expect(flash[:error].first).to include(I18n.t('flash.tas.destroy.error', user_name: ta.user_name, message: '')) + expect(flash[:error]).to contain_message(I18n.t('flash.tas.destroy.error', user_name: ta.user_name, + message: '')) expect(response).to have_http_status(:bad_request) end end @@ -317,8 +318,8 @@ it 'does not delete the TA, shows an error message and gets a conflict response' do expect(Ta.count).to eq(1) expect(flash.now[:success]).to be_nil - expect(flash[:error].first).to include(I18n.t('flash.tas.destroy.restricted', user_name: ta.user_name, - message: '')) + expect(flash[:error]).to contain_message(I18n.t('flash.tas.destroy.restricted', user_name: ta.user_name, + message: '')) expect(response).to have_http_status(:conflict) end end @@ -341,7 +342,7 @@ it 'deletes TA, flashes success, and gets an ok response' do expect(Ta.exists?).to be(false) - expect(flash.now[:success].first).to include(I18n.t('flash.tas.destroy.success', user_name: ta.user_name)) + expect(flash.now[:success]).to contain_message(I18n.t('flash.tas.destroy.success', user_name: ta.user_name)) expect(response).to have_http_status(:ok) end diff --git a/spec/support/custom_matchers.rb b/spec/support/custom_matchers.rb new file mode 100644 index 0000000000..8ab8f65866 --- /dev/null +++ b/spec/support/custom_matchers.rb @@ -0,0 +1,27 @@ +# :nocov: +RSpec::Matchers.define :have_message do |expected| + match do |actual| + actual_messages = Array(actual).map { |m| extract_text(m.to_s) } + actual_messages.any? { |m| m.strip == extract_text(expected).strip } + end + + failure_message do |actual| + actual_stripped = Array(actual).map { |m| extract_text(m.to_s) } + "expected that #{actual_stripped.inspect} would exactly match message #{expected.inspect}" + end +end +# :nocov: + +# :nocov: +RSpec::Matchers.define :contain_message do |expected| + match do |actual| + actual_messages = Array(actual).map { |m| extract_text(m.to_s) } + actual_messages.any? { |m| m.include?(extract_text(expected)) } + end + + failure_message do |actual| + actual_stripped = Array(actual).map { |m| extract_text(m.to_s) } + "expected that #{actual_stripped.inspect} would contain message #{expected.inspect}" + end +end +# :nocov: