rails_dynamic_errors 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +31 -0
- data/app/controllers/rails_dynamic_errors/errors_controller.rb +52 -0
- data/app/views/rails_dynamic_errors/errors/show.html.erb +4 -0
- data/config/routes.rb +3 -0
- data/lib/engine_helper.rb +15 -0
- data/lib/generators/rails_dynamic_errors/install_generator.rb +38 -0
- data/lib/rails_dynamic_errors/engine.rb +32 -0
- data/lib/rails_dynamic_errors/middleware/dynamic_errors.rb +98 -0
- data/lib/rails_dynamic_errors/version.rb +4 -0
- data/lib/rails_dynamic_errors.rb +11 -0
- data/lib/tasks/rails_dynamic_errors_tasks.rake +4 -0
- data/spec/controllers/errors_controller_spec.rb +128 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/javascripts/booms.js +2 -0
- data/spec/dummy/app/assets/javascripts/things.js +2 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/assets/stylesheets/booms.css +4 -0
- data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/spec/dummy/app/assets/stylesheets/things.css +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/booms_controller.rb +6 -0
- data/spec/dummy/app/controllers/things_controller.rb +58 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/booms_helper.rb +2 -0
- data/spec/dummy/app/helpers/things_helper.rb +2 -0
- data/spec/dummy/app/models/thing.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/rails_dynamic_errors/errors/url_helpers.html.erb +2 -0
- data/spec/dummy/app/views/things/_form.html.erb +21 -0
- data/spec/dummy/app/views/things/edit.html.erb +6 -0
- data/spec/dummy/app/views/things/index.html.erb +27 -0
- data/spec/dummy/app/views/things/new.html.erb +5 -0
- data/spec/dummy/app/views/things/show.html.erb +9 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +43 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +67 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20140620101702_create_things.rb +9 -0
- data/spec/dummy/db/production.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +22 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +3309 -0
- data/spec/dummy/log/production.log +35 -0
- data/spec/dummy/log/test.log +30008 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/tmp/config/application.rb +11 -0
- data/spec/dummy/tmp/config/routes.rb +10 -0
- data/spec/features/application_link_helpers_spec.rb +14 -0
- data/spec/features/error_handling_spec.rb +167 -0
- data/spec/lib/generators/rails_dynamic_errors/install_generator_spec.rb +32 -0
- data/spec/lib/rails_dynamic_errors/engine_spec.rb +13 -0
- data/spec/lib/rails_dynamic_errors/middleware/dynamic_errors_spec.rb +171 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/error.rb +19 -0
- data/spec/views/errors/show.html.erb_spec.rb +24 -0
- metadata +265 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<style>
|
6
|
+
body {
|
7
|
+
background-color: #EFEFEF;
|
8
|
+
color: #2E2F30;
|
9
|
+
text-align: center;
|
10
|
+
font-family: arial, sans-serif;
|
11
|
+
}
|
12
|
+
|
13
|
+
div.dialog {
|
14
|
+
width: 25em;
|
15
|
+
margin: 4em auto 0 auto;
|
16
|
+
border: 1px solid #CCC;
|
17
|
+
border-right-color: #999;
|
18
|
+
border-left-color: #999;
|
19
|
+
border-bottom-color: #BBB;
|
20
|
+
border-top: #B00100 solid 4px;
|
21
|
+
border-top-left-radius: 9px;
|
22
|
+
border-top-right-radius: 9px;
|
23
|
+
background-color: white;
|
24
|
+
padding: 7px 4em 0 4em;
|
25
|
+
}
|
26
|
+
|
27
|
+
h1 {
|
28
|
+
font-size: 100%;
|
29
|
+
color: #730E15;
|
30
|
+
line-height: 1.5em;
|
31
|
+
}
|
32
|
+
|
33
|
+
body > p {
|
34
|
+
width: 33em;
|
35
|
+
margin: 0 auto 1em;
|
36
|
+
padding: 1em 0;
|
37
|
+
background-color: #F7F7F7;
|
38
|
+
border: 1px solid #CCC;
|
39
|
+
border-right-color: #999;
|
40
|
+
border-bottom-color: #999;
|
41
|
+
border-bottom-left-radius: 4px;
|
42
|
+
border-bottom-right-radius: 4px;
|
43
|
+
border-top-color: #DADADA;
|
44
|
+
color: #666;
|
45
|
+
box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
|
46
|
+
}
|
47
|
+
</style>
|
48
|
+
</head>
|
49
|
+
|
50
|
+
<body>
|
51
|
+
<!-- This file lives in public/404.html -->
|
52
|
+
<div class="dialog">
|
53
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
54
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
55
|
+
</div>
|
56
|
+
<p>If you are the application owner check the logs for more information.</p>
|
57
|
+
</body>
|
58
|
+
</html>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<style>
|
6
|
+
body {
|
7
|
+
background-color: #EFEFEF;
|
8
|
+
color: #2E2F30;
|
9
|
+
text-align: center;
|
10
|
+
font-family: arial, sans-serif;
|
11
|
+
}
|
12
|
+
|
13
|
+
div.dialog {
|
14
|
+
width: 25em;
|
15
|
+
margin: 4em auto 0 auto;
|
16
|
+
border: 1px solid #CCC;
|
17
|
+
border-right-color: #999;
|
18
|
+
border-left-color: #999;
|
19
|
+
border-bottom-color: #BBB;
|
20
|
+
border-top: #B00100 solid 4px;
|
21
|
+
border-top-left-radius: 9px;
|
22
|
+
border-top-right-radius: 9px;
|
23
|
+
background-color: white;
|
24
|
+
padding: 7px 4em 0 4em;
|
25
|
+
}
|
26
|
+
|
27
|
+
h1 {
|
28
|
+
font-size: 100%;
|
29
|
+
color: #730E15;
|
30
|
+
line-height: 1.5em;
|
31
|
+
}
|
32
|
+
|
33
|
+
body > p {
|
34
|
+
width: 33em;
|
35
|
+
margin: 0 auto 1em;
|
36
|
+
padding: 1em 0;
|
37
|
+
background-color: #F7F7F7;
|
38
|
+
border: 1px solid #CCC;
|
39
|
+
border-right-color: #999;
|
40
|
+
border-bottom-color: #999;
|
41
|
+
border-bottom-left-radius: 4px;
|
42
|
+
border-bottom-right-radius: 4px;
|
43
|
+
border-top-color: #DADADA;
|
44
|
+
color: #666;
|
45
|
+
box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
|
46
|
+
}
|
47
|
+
</style>
|
48
|
+
</head>
|
49
|
+
|
50
|
+
<body>
|
51
|
+
<!-- This file lives in public/422.html -->
|
52
|
+
<div class="dialog">
|
53
|
+
<h1>The change you wanted was rejected.</h1>
|
54
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
55
|
+
</div>
|
56
|
+
<p>If you are the application owner check the logs for more information.</p>
|
57
|
+
</body>
|
58
|
+
</html>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<style>
|
6
|
+
body {
|
7
|
+
background-color: #EFEFEF;
|
8
|
+
color: #2E2F30;
|
9
|
+
text-align: center;
|
10
|
+
font-family: arial, sans-serif;
|
11
|
+
}
|
12
|
+
|
13
|
+
div.dialog {
|
14
|
+
width: 25em;
|
15
|
+
margin: 4em auto 0 auto;
|
16
|
+
border: 1px solid #CCC;
|
17
|
+
border-right-color: #999;
|
18
|
+
border-left-color: #999;
|
19
|
+
border-bottom-color: #BBB;
|
20
|
+
border-top: #B00100 solid 4px;
|
21
|
+
border-top-left-radius: 9px;
|
22
|
+
border-top-right-radius: 9px;
|
23
|
+
background-color: white;
|
24
|
+
padding: 7px 4em 0 4em;
|
25
|
+
}
|
26
|
+
|
27
|
+
h1 {
|
28
|
+
font-size: 100%;
|
29
|
+
color: #730E15;
|
30
|
+
line-height: 1.5em;
|
31
|
+
}
|
32
|
+
|
33
|
+
body > p {
|
34
|
+
width: 33em;
|
35
|
+
margin: 0 auto 1em;
|
36
|
+
padding: 1em 0;
|
37
|
+
background-color: #F7F7F7;
|
38
|
+
border: 1px solid #CCC;
|
39
|
+
border-right-color: #999;
|
40
|
+
border-bottom-color: #999;
|
41
|
+
border-bottom-left-radius: 4px;
|
42
|
+
border-bottom-right-radius: 4px;
|
43
|
+
border-top-color: #DADADA;
|
44
|
+
color: #666;
|
45
|
+
box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
|
46
|
+
}
|
47
|
+
</style>
|
48
|
+
</head>
|
49
|
+
|
50
|
+
<body>
|
51
|
+
<!-- This file lives in public/500.html -->
|
52
|
+
<div class="dialog">
|
53
|
+
<h1>We're sorry, but something went wrong.</h1>
|
54
|
+
</div>
|
55
|
+
<p>If you are the application owner check the logs for more information.</p>
|
56
|
+
</body>
|
57
|
+
</html>
|
File without changes
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Dummy
|
2
|
+
class Application < Rails::Application
|
3
|
+
# This option is used to set the HTTP error codes for which
|
4
|
+
# rails_dynamic_errors will generate dynamic error pages. A good default
|
5
|
+
# setup is [404, 422], which will catch the two main errors (excluding the
|
6
|
+
# dreaded 500 Internal Server Error) for which Rails provides static HTML
|
7
|
+
# error pages.
|
8
|
+
# config.rails_dynamic_errors.http_error_status_codes_to_handle = [404, 422]
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Rails.application.routes.draw do
|
2
|
+
|
3
|
+
# This line mounts RailDynamicErrors' routes on the '/errors' path of your
|
4
|
+
# application. This means that any requests to URLs with this prefix in their
|
5
|
+
# path will go to RailsDynamicErrors for processing.
|
6
|
+
#
|
7
|
+
# If you would like to change where this engine is mounted, simply change the
|
8
|
+
# :at option to something different.
|
9
|
+
mount RailsDynamicErrors::Engine, at: '/errors'
|
10
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsDynamicErrors::Engine do
|
4
|
+
# Regression test to ensure that the application's URL helpers are available
|
5
|
+
# to the engine. This is necessary because the pages generated by the errors
|
6
|
+
# controller within the engine use the application's layouts, and these may
|
7
|
+
# contain URL helpers for the main application. By default the engine cannot
|
8
|
+
# access these. We can't just use 'main_app.<url_helper>' in the layouts,
|
9
|
+
# either, as that would break the layouts when used in the application.
|
10
|
+
it "should have access to application helpers" do
|
11
|
+
visit '/errors/url_helpers'
|
12
|
+
page.should have_link('New Thing', :href => new_thing_path)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsDynamicErrors do
|
4
|
+
context "when the error is manually generated via the errors path" do
|
5
|
+
it "displays the error code" do
|
6
|
+
visit '/errors/invalid_ninja'
|
7
|
+
page.should have_content("invalid_ninja")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "when the error is automatically generated via the middleware" do
|
12
|
+
before(:each) do
|
13
|
+
Rails.application.config.rails_dynamic_errors.http_error_status_codes_to_handle = []
|
14
|
+
end
|
15
|
+
|
16
|
+
it "does not interfere with valid requests" do
|
17
|
+
thing = Thing.create!(:name => "Test")
|
18
|
+
visit thing_path(thing)
|
19
|
+
page.should have_content("Name: Test")
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when the application is configured to show exceptions" do
|
23
|
+
around(:each) do |example|
|
24
|
+
original = set_environment_variable('action_dispatch.show_exceptions', true)
|
25
|
+
example.run
|
26
|
+
set_environment_variable('action_dispatch.show_exceptions', original)
|
27
|
+
end
|
28
|
+
|
29
|
+
context "and not configured to show detailed exceptions" do
|
30
|
+
around(:each) do |example|
|
31
|
+
original = set_environment_variable('action_dispatch.show_detailed_exceptions', false)
|
32
|
+
example.run
|
33
|
+
set_environment_variable('action_dispatch.show_exceptions', original)
|
34
|
+
end
|
35
|
+
|
36
|
+
context "receives a 404 error" do
|
37
|
+
context "and is configured to handle it" do
|
38
|
+
before(:each) do
|
39
|
+
Rails.application.config.rails_dynamic_errors.http_error_status_codes_to_handle = [404]
|
40
|
+
end
|
41
|
+
|
42
|
+
context "and the error was generated by an invalid route" do
|
43
|
+
it "displays a 404 error page" do
|
44
|
+
visit '/bogus_route'
|
45
|
+
page.should have_content("404 Not Found")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "and the error was generated by a valid route with a non-existent resource" do
|
50
|
+
it "displays a 404 error page" do
|
51
|
+
visit '/things/-1'
|
52
|
+
page.should have_content("404 Not Found")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "and is not configured to handle it" do
|
58
|
+
context "and the error was generated by an invalid route" do
|
59
|
+
it "displays the standard Rails 404 error page" do
|
60
|
+
visit '/bogus_route'
|
61
|
+
page.should_not have_content("404 Not Found")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "and the error was generated by a valid route with a non-existent resource" do
|
66
|
+
it "displays the standard Rails 404 error page" do
|
67
|
+
visit '/things/-1'
|
68
|
+
page.should_not have_content("404 Not Found")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "receives a 500 error" do
|
75
|
+
context "and is configured to handle it" do
|
76
|
+
before(:each) do
|
77
|
+
Rails.application.config.rails_dynamic_errors.http_error_status_codes_to_handle = [500]
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when an internal server error is encountered" do
|
81
|
+
it "displays a 500 error page" do
|
82
|
+
visit '/booms/1'
|
83
|
+
page.should have_content("500 Internal Server Error")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "and is not configured to handle it" do
|
89
|
+
it "displays the standard Rails 500 error page" do
|
90
|
+
visit '/booms/1'
|
91
|
+
page.should_not have_content("500 Internal Server Error")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "and configured to show detailed exceptions" do
|
98
|
+
around(:each) do |example|
|
99
|
+
original = set_environment_variable('action_dispatch.show_detailed_exceptions', true)
|
100
|
+
example.run
|
101
|
+
set_environment_variable('action_dispatch.show_exceptions', original)
|
102
|
+
end
|
103
|
+
|
104
|
+
context "receives a 404 error" do
|
105
|
+
context "and the error was generated by an invalid route" do
|
106
|
+
it "displays the standard Rails 404 error page" do
|
107
|
+
visit '/bogus_route'
|
108
|
+
page.should_not have_content("404 Not Found")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "and the error was generated by a valid route with a non-existent resource" do
|
113
|
+
it "displays the standard Rails 404 error page" do
|
114
|
+
visit '/things/-1'
|
115
|
+
page.should_not have_content("404 Not Found")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "receives a 500 error" do
|
121
|
+
context "when it is not configured to handle 500 errors" do
|
122
|
+
it "displays the standard Rails 500 error page" do
|
123
|
+
visit '/booms/1'
|
124
|
+
page.should_not have_content("500 Internal Server Error")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "when the application is not configured to show exceptions" do
|
132
|
+
around(:each) do |example|
|
133
|
+
original = set_environment_variable('action_dispatch.show_exceptions', false)
|
134
|
+
example.run
|
135
|
+
set_environment_variable('action_dispatch.show_exceptions', original)
|
136
|
+
end
|
137
|
+
|
138
|
+
context "receives a 404 error" do
|
139
|
+
context "and the error was generated by an invalid route" do
|
140
|
+
it "displays the standard Rails 404 error page" do
|
141
|
+
expect { visit '/bogus_route' }.to raise_error
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "and the error was generated by a valid route with a non-existent resource" do
|
146
|
+
it "displays the standard Rails 404 error page" do
|
147
|
+
expect { visit '/things/-1' }.to raise_error
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "receives a 500 error" do
|
153
|
+
context "when it is not configured to handle 500 errors" do
|
154
|
+
it "displays the standard Rails 500 error page" do
|
155
|
+
expect { visit '/booms/1' }.to raise_error
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def set_environment_variable(variable, value)
|
163
|
+
original_value = Rails.application.env_config[variable]
|
164
|
+
Rails.application.env_config[variable] = value
|
165
|
+
original_value
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'generator_spec'
|
3
|
+
|
4
|
+
describe RailsDynamicErrors::InstallGenerator do
|
5
|
+
destination File.expand_path("../../../../dummy/tmp/", __FILE__)
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
prepare_destination
|
9
|
+
config_dir = File.expand_path("../../../../dummy/tmp/config/", __FILE__)
|
10
|
+
FileUtils.mkdir(config_dir)
|
11
|
+
@config_application_file = File.join(config_dir, 'application.rb')
|
12
|
+
config_routes_file = File.join(config_dir, 'routes.rb')
|
13
|
+
File.open(@config_application_file, 'w') { |f| f.write("module Dummy\n class Application < Rails::Application\n end\nend") }
|
14
|
+
File.open(config_routes_file, 'w') { |f| f.write("Rails.application.routes.draw do\nend") }
|
15
|
+
run_generator
|
16
|
+
end
|
17
|
+
|
18
|
+
it "inserts options into config/application.rb" do
|
19
|
+
text = <<-INSERTION
|
20
|
+
# config.rails_dynamic_errors.http_error_status_codes_to_handle = [404, 422]
|
21
|
+
INSERTION
|
22
|
+
File.read(@config_application_file).should include(text)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "mounts the engine in config/routes.rb" do
|
26
|
+
assert_file "config/routes.rb", /mount RailsDynamicErrors::Engine/
|
27
|
+
end
|
28
|
+
|
29
|
+
it "mounts the engine in config/routes.rb at the 'errors' path" do
|
30
|
+
assert_file "config/routes.rb", /mount RailsDynamicErrors::Engine, at: '#{RailsDynamicErrors::DEFAULT_MOUNT_PATH}'/
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsDynamicErrors::Engine do
|
4
|
+
describe "::mounted_at" do
|
5
|
+
it "returns the path at which the engine is mounted within a Rails application" do
|
6
|
+
RailsDynamicErrors::Engine.mounted_at.should eq(RailsDynamicErrors::DEFAULT_MOUNT_PATH)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "creates a set of namespaced configuration options in the Rails application it is mounted within" do
|
10
|
+
Rails.application.config.rails_dynamic_errors.class.should eq(ActiveSupport::OrderedOptions)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsDynamicErrors::DynamicErrors do
|
4
|
+
before(:each) do
|
5
|
+
@rails_no_route_response = [404, {'X-Cascade' => 'pass'}, ['Not Found']]
|
6
|
+
@env_options = {}
|
7
|
+
|
8
|
+
# Engine this middleware is contained within is mountable, so we have to take
|
9
|
+
# that into account
|
10
|
+
RailsDynamicErrors::Engine.stub(:mounted_at).and_return('/errors')
|
11
|
+
|
12
|
+
# Prevent the actual Rails application from processing the request
|
13
|
+
Rails.application.routes.stub(:call)
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when the request is local" do
|
17
|
+
before(:each) do
|
18
|
+
@env_options['action_dispatch.show_detailed_exceptions'] = true
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when an exception bubbles up from the Rails application or a middleware further down the stack" do
|
22
|
+
it "re-raises the exception" do
|
23
|
+
exception = ActionController::RoutingError.new("Not Found")
|
24
|
+
app = double("app")
|
25
|
+
app.stub(:call) { raise exception }
|
26
|
+
input_env = env_for('/valid_route/-1', @env_options)
|
27
|
+
middleware = middleware_to_handle_codes(app, [404])
|
28
|
+
expect { middleware.call(input_env) }.to raise_error(exception)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when the response received has a 404 status code and X-Cascade header set to 'pass'" do
|
33
|
+
it "passed on the response" do
|
34
|
+
app = double("app")
|
35
|
+
app.stub(:call).and_return(@rails_no_route_response)
|
36
|
+
input_env = env_for('/invalid_route', @env_options)
|
37
|
+
middleware = middleware_to_handle_codes(app, [404])
|
38
|
+
response = middleware.call(input_env)
|
39
|
+
response.should eq(@rails_no_route_response)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when the request is remote" do
|
45
|
+
before(:each) do
|
46
|
+
@env_options['action_dispatch.show_detailed_exceptions'] = false
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when exceptions should be shown" do
|
50
|
+
before(:each) do
|
51
|
+
@env_options['action_dispatch.show_exceptions'] = true
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when an exception bubbles up from the Rails application or a middleware further down the stack" do
|
55
|
+
before(:each) do
|
56
|
+
@exception = ActionController::RoutingError.new("Not Found")
|
57
|
+
@app = double("app")
|
58
|
+
@app.stub(:call) { raise @exception }
|
59
|
+
@input_env = env_for('/valid_route/-1', @env_options)
|
60
|
+
end
|
61
|
+
|
62
|
+
context "and it is configured to handle the HTTP status code that exception is associated with" do
|
63
|
+
before(:each) do
|
64
|
+
@middleware = middleware_to_handle_codes(@app, [404])
|
65
|
+
end
|
66
|
+
|
67
|
+
it "updates the environment of the request to point to a path that will generate a dynamic error page for the status code" do
|
68
|
+
(code, output_env) = @middleware.call(@input_env)
|
69
|
+
@input_env['PATH_INFO'].should eq('/errors/404')
|
70
|
+
end
|
71
|
+
|
72
|
+
it "updates the environment of the request with the exception that caused the error" do
|
73
|
+
(code, output_env) = @middleware.call(@input_env)
|
74
|
+
@input_env['action_dispatch.exception'].should eq(@exception)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "calls the router of the Rails application it's embedded within to process the updated environment" do
|
78
|
+
Rails.application.routes.should_receive(:call).with(@input_env)
|
79
|
+
(code, output_env) = @middleware.call(@input_env)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "and it is not configured to handle the HTTP status code that exception is associated with" do
|
84
|
+
it "re-raises the exception" do
|
85
|
+
middleware = middleware_to_handle_codes(@app, [])
|
86
|
+
expect { middleware.call(@input_env) }.to raise_error(@exception)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when the response received has a 404 status code and X-Cascade header set to 'pass'" do
|
92
|
+
before(:each) do
|
93
|
+
@app = double("app")
|
94
|
+
@app.stub(:call).and_return([404, {'X-Cascade' => 'pass'}, ['Not Found']])
|
95
|
+
@input_env = env_for('/invalid_route', @env_options)
|
96
|
+
end
|
97
|
+
|
98
|
+
context "and it is configured to handle 404 status codes" do
|
99
|
+
before(:each) do
|
100
|
+
@middleware = middleware_to_handle_codes(@app, [404])
|
101
|
+
end
|
102
|
+
|
103
|
+
it "updates the environment of the request to point to a path that will generate a dynamic error page for the status code" do
|
104
|
+
(code, output_env) = @middleware.call(@input_env)
|
105
|
+
@input_env['PATH_INFO'].should eq('/errors/404')
|
106
|
+
end
|
107
|
+
|
108
|
+
it "updates the environment of the request with a routing exception" do
|
109
|
+
(code, output_env) = @middleware.call(@input_env)
|
110
|
+
@input_env['action_dispatch.exception'].class.should eq(ActionController::RoutingError)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "calls the router of the Rails application it's embedded within to process the updated environment" do
|
114
|
+
Rails.application.routes.should_receive(:call).with(@input_env)
|
115
|
+
(code, output_env) = @middleware.call(@input_env)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "and it is not configured to handle 404 status codes" do
|
120
|
+
it "passes on the response" do
|
121
|
+
middleware = middleware_to_handle_codes(@app, [])
|
122
|
+
response = middleware.call(@input_env)
|
123
|
+
response.should eq([404, {'X-Cascade' => 'pass'}, ['Not Found']])
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context "when exceptions should be raised" do
|
130
|
+
before(:each) do
|
131
|
+
@env_options['action_dispatch.show_exceptions'] = false
|
132
|
+
end
|
133
|
+
|
134
|
+
context "when an exception bubbles up from the Rails application or a middleware further down the stack" do
|
135
|
+
it "re-raises the exception" do
|
136
|
+
exception = ActionController::RoutingError.new("Not Found")
|
137
|
+
app = double("app")
|
138
|
+
app.stub(:call) { raise exception }
|
139
|
+
input_env = env_for('/valid_route/-1', @env_options)
|
140
|
+
middleware = middleware_to_handle_codes(app, [404])
|
141
|
+
expect { middleware.call(input_env) }.to raise_error(exception)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when the response received has a 404 status code and X-Cascade header set to 'pass'" do
|
146
|
+
it "passes on the response" do
|
147
|
+
app = double("app")
|
148
|
+
app.stub(:call).and_return([404, {'X-Cascade' => 'pass'}, ['Not Found']])
|
149
|
+
input_env = env_for('/invalid_route', @env_options)
|
150
|
+
middleware = middleware_to_handle_codes(app, [])
|
151
|
+
response = middleware.call(input_env)
|
152
|
+
response.should eq([404, {'X-Cascade' => 'pass'}, ['Not Found']])
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def middleware_to_handle_codes(app, codes)
|
159
|
+
handle_codes(codes)
|
160
|
+
RailsDynamicErrors::DynamicErrors.new(app)
|
161
|
+
end
|
162
|
+
|
163
|
+
def handle_codes(codes)
|
164
|
+
Rails.application.config.rails_dynamic_errors.http_error_status_codes_to_handle = codes
|
165
|
+
end
|
166
|
+
|
167
|
+
def env_for(url, options = {})
|
168
|
+
env = Rack::MockRequest.env_for(url, options)
|
169
|
+
env
|
170
|
+
end
|
171
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
2
|
+
ENV["RAILS_ENV"] ||= 'test'
|
3
|
+
require File.expand_path("../dummy/config/environment", __FILE__)
|
4
|
+
require 'rspec/rails'
|
5
|
+
require 'rspec/autorun'
|
6
|
+
require 'capybara/rspec'
|
7
|
+
|
8
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
9
|
+
# in spec/support/ and its subdirectories.
|
10
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
|
11
|
+
|
12
|
+
# Checks for pending migrations before tests are run.
|
13
|
+
# If you are not using ActiveRecord, you can remove this line.
|
14
|
+
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
|
15
|
+
|
16
|
+
RSpec.configure do |config|
|
17
|
+
# ## Mock Framework
|
18
|
+
#
|
19
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
20
|
+
#
|
21
|
+
# config.mock_with :mocha
|
22
|
+
# config.mock_with :flexmock
|
23
|
+
# config.mock_with :rr
|
24
|
+
|
25
|
+
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
26
|
+
config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
27
|
+
|
28
|
+
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
29
|
+
# examples within a transaction, remove the following line or assign false
|
30
|
+
# instead of true.
|
31
|
+
config.use_transactional_fixtures = true
|
32
|
+
|
33
|
+
# If true, the base class of anonymous controllers will be inferred
|
34
|
+
# automatically. This will be the default behavior in future versions of
|
35
|
+
# rspec-rails.
|
36
|
+
config.infer_base_class_for_anonymous_controllers = false
|
37
|
+
|
38
|
+
# Run specs in random order to surface order dependencies. If you find an
|
39
|
+
# order dependency and want to debug it, you can fix the order by providing
|
40
|
+
# the seed, which is printed after each run.
|
41
|
+
# --seed 1234
|
42
|
+
config.order = "random"
|
43
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# From ActionDispatch::ExceptionWrapper
|
2
|
+
HTTP_STATUS_CODE_RAILS_EXCEPTIONS = {
|
3
|
+
400 => ActionController::BadRequest ,
|
4
|
+
# 400 => ActionDispatch::ParamsParser::ParseError ,
|
5
|
+
# 400 => ActionController::ParameterMissing ,
|
6
|
+
404 => ActionController::RoutingError ,
|
7
|
+
# 404 => AbstractController::ActionNotFound ,
|
8
|
+
405 => ActionController::MethodNotAllowed ,
|
9
|
+
# 405 => ActionController::UnknownHttpMethod ,
|
10
|
+
406 => ActionController::UnknownFormat ,
|
11
|
+
422 => ActionController::InvalidAuthenticityToken,
|
12
|
+
501 => ActionController::NotImplemented ,
|
13
|
+
}
|
14
|
+
|
15
|
+
def build_environment_after_exception_for_status_code(status_code, message = nil)
|
16
|
+
@exception = HTTP_STATUS_CODE_RAILS_EXCEPTIONS.fetch(status_code, Exception).new(message)
|
17
|
+
controller.env["PATH_INFO"] = "/#{status_code}"
|
18
|
+
controller.env["action_dispatch.exception"] = @exception
|
19
|
+
end
|