error_spec.rb 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. require 'rails_helper'
  2. RSpec.describe 'Error handling', type: :request do
  3. shared_examples 'JSON response format' do
  4. let(:as) { :json }
  5. it { expect(response).to have_http_status(http_status) }
  6. it { expect(json_response).to be_a_kind_of(Hash) }
  7. it do
  8. # There is a special case where we mask technical errors and return
  9. # a random error code that can be easily found in the logs by an
  10. # administrator. However, this makes it hard to check for the exact error
  11. # message. Therefore we only check for the substring in this particular case
  12. if message == 'Please contact your administrator' || message == 'Mysql2::Error' || message == 'PG::ForeignKeyViolation'
  13. expect(json_response['error']).to include(message)
  14. else
  15. expect(json_response['error']).to eq(message)
  16. end
  17. end
  18. end
  19. shared_examples 'HTML response format' do
  20. let(:as) { :html }
  21. it { expect(response).to have_http_status(http_status) }
  22. it { expect(response.content_type).to eq('text/html') }
  23. it { expect(response.body).to include('<html') }
  24. it { expect(response.body).to include("<title>#{title}</title>") }
  25. it { expect(response.body).to include("<h1>#{headline}</h1>") }
  26. it { expect(response.body).to include(message) }
  27. end
  28. context 'URL route does not exist' do
  29. before do
  30. get url, as: as
  31. end
  32. let(:url) { '/not_existing_url' }
  33. let(:message) { "No route matches [GET] #{url}" }
  34. let(:http_status) { :not_found }
  35. context 'requesting JSON' do
  36. include_examples 'JSON response format'
  37. end
  38. context 'requesting HTML' do
  39. let(:title) { '404: Not Found' }
  40. let(:headline) { '404: Requested resource was not found' }
  41. include_examples 'HTML response format'
  42. context 'when request ends with URL' do
  43. let(:url) { "//////#{message}" }
  44. let(:message) { 'this__website__is__closed__visit__our__new__site:_someother.com' }
  45. include_examples 'HTML response format'
  46. end
  47. end
  48. end
  49. context 'request is not authenticated' do
  50. before do
  51. authenticated_as(create(:agent), password: 'wrongpw')
  52. get '/api/v1/organizations', as: as
  53. end
  54. let(:message) { 'Invalid BasicAuth credentials' }
  55. let(:http_status) { :unauthorized }
  56. context 'requesting JSON' do
  57. include_examples 'JSON response format'
  58. end
  59. context 'requesting HTML' do
  60. let(:title) { '401: Unauthorized' }
  61. let(:headline) { '401: Unauthorized' }
  62. include_examples 'HTML response format'
  63. end
  64. end
  65. context 'request is forbidden' do
  66. before do
  67. get '/api/v1/organizations', as: as
  68. end
  69. let(:message) { 'Authentication required' }
  70. let(:http_status) { :forbidden }
  71. context 'requesting JSON' do
  72. include_examples 'JSON response format'
  73. end
  74. context 'requesting HTML' do
  75. let(:title) { '403: Forbidden' }
  76. let(:headline) { '403: Forbidden' }
  77. include_examples 'HTML response format'
  78. end
  79. end
  80. context 'exception is raised' do
  81. before do
  82. authenticated_as(create(user))
  83. get '/tests/raised_exception', params: { exception: exception.name, message: message }, as: as
  84. end
  85. shared_examples 'exception check' do |message, exception, http_status, title, headline|
  86. context "#{exception} is raised" do
  87. let(:exception) { exception }
  88. let(:http_status) { http_status }
  89. let(:message) { message }
  90. context 'requesting JSON' do
  91. include_examples 'JSON response format'
  92. end
  93. context 'requesting HTML' do
  94. let(:title) { title }
  95. let(:headline) { headline }
  96. include_examples 'HTML response format'
  97. end
  98. end
  99. end
  100. shared_examples 'handles exception' do |exception, http_status, title, headline, message = 'some error message'|
  101. include_examples 'exception check', message, exception, http_status, title, headline
  102. end
  103. shared_examples 'masks exception' do |exception, http_status, title, headline|
  104. include_examples 'exception check', 'Please contact your administrator', exception, http_status, title, headline
  105. end
  106. context 'with agent user' do
  107. let(:user) { :agent }
  108. include_examples 'handles exception', Exceptions::NotAuthorized, :unauthorized, '401: Unauthorized', '401: Unauthorized'
  109. include_examples 'handles exception', Exceptions::Forbidden, :forbidden, '403: Forbidden', '403: Forbidden'
  110. include_examples 'handles exception', Pundit::NotAuthorizedError, :forbidden, '403: Forbidden', '403: Forbidden', 'Not authorized'
  111. include_examples 'handles exception', ActiveRecord::RecordNotFound, :not_found, '404: Not Found', '404: Requested resource was not found'
  112. include_examples 'handles exception', Exceptions::UnprocessableEntity, :unprocessable_entity, '422: Unprocessable Entity', '422: The change you wanted was rejected.'
  113. include_examples 'masks exception', ArgumentError, :unprocessable_entity, '422: Unprocessable Entity', '422: The change you wanted was rejected.'
  114. include_examples 'masks exception', StandardError, :internal_server_error, '500: Something went wrong', "500: We're sorry, but something went wrong."
  115. end
  116. context 'with admin user' do
  117. let(:user) { :admin }
  118. include_examples 'handles exception', Exceptions::NotAuthorized, :unauthorized, '401: Unauthorized', '401: Unauthorized'
  119. include_examples 'handles exception', Exceptions::Forbidden, :forbidden, '403: Forbidden', '403: Forbidden'
  120. include_examples 'handles exception', Pundit::NotAuthorizedError, :forbidden, '403: Forbidden', '403: Forbidden', 'Not authorized'
  121. include_examples 'handles exception', ActiveRecord::RecordNotFound, :not_found, '404: Not Found', '404: Requested resource was not found'
  122. include_examples 'handles exception', Exceptions::UnprocessableEntity, :unprocessable_entity, '422: Unprocessable Entity', '422: The change you wanted was rejected.'
  123. include_examples 'handles exception', ArgumentError, :unprocessable_entity, '422: Unprocessable Entity', '422: The change you wanted was rejected.'
  124. include_examples 'handles exception', StandardError, :internal_server_error, '500: Something went wrong', "500: We're sorry, but something went wrong."
  125. end
  126. end
  127. end