emerson 0.1.0.pre.1 → 0.1.0.pre.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -23
- data/.wiprc +0 -0
- data/.yardopts +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +177 -0
- data/Rakefile +18 -1
- data/emerson.gemspec +28 -15
- data/lib/emerson.rb +58 -1
- data/lib/emerson/engine.rb +5 -0
- data/lib/emerson/matchers.rb +5 -0
- data/lib/emerson/matchers/action_controller.rb +30 -0
- data/lib/emerson/matchers/action_controller/send_json_matcher.rb +106 -0
- data/lib/emerson/matchers/integrations/rspec.rb +11 -0
- data/lib/emerson/matchers/integrations/test_unit.rb +12 -0
- data/lib/emerson/responder.rb +61 -51
- data/lib/emerson/response.rb +17 -3
- data/lib/emerson/scope.rb +2 -7
- data/lib/emerson/version.rb +1 -1
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +65 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/jasmine.rb +3 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +6 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/spec/support/fixtures/responses/products/extend-array.json +1 -0
- data/spec/dummy/spec/support/fixtures/responses/products/extend-failure.json +1 -0
- data/spec/dummy/spec/support/fixtures/responses/products/extend-success.json +4 -0
- data/spec/dummy/spec/support/fixtures/responses/products/simple.json +4 -0
- data/spec/emerson/matchers/action_controller/send_json_matcher_spec.rb +126 -0
- data/spec/emerson/responder_spec.rb +222 -0
- data/spec/emerson/response_spec.rb +75 -0
- data/spec/emerson/scope_spec.rb +146 -0
- data/spec/emerson_spec.rb +105 -0
- data/spec/spec_helper.rb +67 -0
- data/spec/support/helpers/controller_helpers.rb +98 -0
- data/spec/support/helpers/feature_helpers.rb +12 -0
- data/spec/support/helpers/resource_helpers.rb +95 -0
- data/spec/support/helpers/template_helpers.rb +31 -0
- data/vendor/assets/javascripts/emerson.js +1 -0
- data/vendor/assets/javascripts/emerson/sink.js +3 -0
- metadata +309 -11
- data/lib/emerson/rails.rb +0 -6
- data/lib/emerson/rails/engine.rb +0 -7
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/422.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The change you wanted was rejected.</h1>
|
23
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/500.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>We're sorry, but something went wrong.</h1>
|
23
|
+
</div>
|
24
|
+
</body>
|
25
|
+
</html>
|
File without changes
|
@@ -0,0 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
+
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
6
|
+
require 'rails/commands'
|
@@ -0,0 +1 @@
|
|
1
|
+
{ "$extends" : ["products/simple.json", "products/extend-success.json"] }
|
@@ -0,0 +1 @@
|
|
1
|
+
{ "$extends" : "products/bogus.json" }
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Emerson::Matchers::ActionController::SendJsonMatcher, :type => :controller do
|
4
|
+
let(:do_request) { get :index, :format => :json }
|
5
|
+
let!(:products) { { :one => 1, :two => 2 } }
|
6
|
+
|
7
|
+
controller(:products)
|
8
|
+
|
9
|
+
before do
|
10
|
+
controller do
|
11
|
+
respond_to :json
|
12
|
+
|
13
|
+
def index
|
14
|
+
respond_with(products)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
do_request
|
19
|
+
expect(response.body).to eq(products.to_json)
|
20
|
+
end
|
21
|
+
|
22
|
+
context "provided a Hash representing the expected JSON" do
|
23
|
+
it "provides a helpful description" do
|
24
|
+
matcher = send_json({})
|
25
|
+
expect(matcher.description).to eq('send JSON: (provided)')
|
26
|
+
end
|
27
|
+
|
28
|
+
it "accepts exact matches" do
|
29
|
+
expect(response).to send_json(products)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "accepts valid matches with re-ordered pairs" do
|
33
|
+
expect(response).to send_json({ :two => 2, :one => 1})
|
34
|
+
end
|
35
|
+
|
36
|
+
it "rejects invalid matches" do
|
37
|
+
expect(response).to_not send_json({})
|
38
|
+
expect(response).to_not send_json({ :one => 2, :two => 1 })
|
39
|
+
expect(response).to_not send_json(products.to_json)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "provided an Array representing the expected JSON" do
|
44
|
+
let(:products) { [:one, :two] }
|
45
|
+
|
46
|
+
it "provides a helpful description" do
|
47
|
+
matcher = send_json([])
|
48
|
+
expect(matcher.description).to eq('send JSON: (provided)')
|
49
|
+
end
|
50
|
+
|
51
|
+
it "accepts exact matches" do
|
52
|
+
expect(response).to send_json(products)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "rejects invalid matches" do
|
56
|
+
expect(response).to_not send_json({})
|
57
|
+
expect(response).to_not send_json([])
|
58
|
+
expect(response).to_not send_json([:two, :one])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "provided a String representing a JSON fixture lookup" do
|
63
|
+
let(:name) { 'products/simple' }
|
64
|
+
|
65
|
+
it "provides a helpful description" do
|
66
|
+
matcher = send_json(name)
|
67
|
+
expect(matcher.description).to eq('send JSON: products/simple.json')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "accepts valid matches" do
|
71
|
+
expect(response).to send_json(name)
|
72
|
+
expect(response).to send_json("#{name}.json")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "rejects invalid matches" do
|
76
|
+
expect(response).to_not send_json('products/bogus')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "provided something other than a Hash or String" do
|
81
|
+
it "raises an exception" do
|
82
|
+
expect { send_json(:symbol) }.to raise_error(ArgumentError)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "given JSON with the `$extends` keyword" do
|
87
|
+
let(:products) { { :one => 1, :two => 2, :addition => 'more' } }
|
88
|
+
|
89
|
+
it "accepts valid matches" do
|
90
|
+
expect(response).to send_json('products/extend-success')
|
91
|
+
expect(response).to send_json('products/extend-array')
|
92
|
+
end
|
93
|
+
|
94
|
+
it "rejects valid matches" do
|
95
|
+
expect(response).to_not send_json('products/extend-failure')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "given a failed match" do
|
100
|
+
it "provides a helpful failure message" do
|
101
|
+
matcher = send_json({ :bogus => 'value' })
|
102
|
+
expect(matcher.matches?(response)).to eq(false)
|
103
|
+
|
104
|
+
message = matcher.failure_message
|
105
|
+
expect(message).to match(failure_message)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def failure_message
|
112
|
+
<<-EOMSG
|
113
|
+
Expected actual response:
|
114
|
+
------------------------------------------------------------
|
115
|
+
{
|
116
|
+
"one": 1,
|
117
|
+
"two": 2
|
118
|
+
}
|
119
|
+
to match:
|
120
|
+
------------------------------------------------------------
|
121
|
+
{
|
122
|
+
"bogus": "value"
|
123
|
+
}
|
124
|
+
EOMSG
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Emerson::Responder, :type => :controller do
|
4
|
+
render_views
|
5
|
+
let!(:products) { resources(:product, 2) }
|
6
|
+
|
7
|
+
describe "GET #index" do
|
8
|
+
controller(:products)
|
9
|
+
|
10
|
+
before do
|
11
|
+
controller do
|
12
|
+
def index
|
13
|
+
respond_with(products)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
templates do
|
18
|
+
def index
|
19
|
+
<<-ERB
|
20
|
+
<ul>
|
21
|
+
<% products.each do |product| %>
|
22
|
+
<li><%= product.name %></li>
|
23
|
+
<% end %>
|
24
|
+
</ul>
|
25
|
+
ERB
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "as HTML" do
|
31
|
+
it "is successful" do
|
32
|
+
get(:index)
|
33
|
+
expect(response).to be_success
|
34
|
+
end
|
35
|
+
|
36
|
+
it "responds with the expected template" do
|
37
|
+
get(:index)
|
38
|
+
expect(response).to render_template(:template => 'index')
|
39
|
+
end
|
40
|
+
|
41
|
+
it "responds with the expected locals" do
|
42
|
+
get(:index)
|
43
|
+
expect(response.body).to have_css('ul > li', :text => products[0].name)
|
44
|
+
expect(response.body).to have_css('ul > li', :text => products[1].name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "as JSON (application/json - default)" do
|
49
|
+
it "is successful" do
|
50
|
+
get(:index, :format => :json)
|
51
|
+
expect(response).to be_success
|
52
|
+
end
|
53
|
+
|
54
|
+
it "responds with the expected JSON" do
|
55
|
+
get(:index, :format => :json)
|
56
|
+
expect(response).to send_json({
|
57
|
+
:data => {
|
58
|
+
:products => products
|
59
|
+
},
|
60
|
+
:view => "<ul><li>#{products[0].name}</li><li>#{products[1].name}</li></ul>"
|
61
|
+
})
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "as JSON (application/vnd.emerson+json)" do
|
66
|
+
before do
|
67
|
+
request.env['HTTP_ACCEPT'] = 'application/vnd.emerson+json'
|
68
|
+
end
|
69
|
+
|
70
|
+
it "is successful" do
|
71
|
+
get(:index, :format => :json)
|
72
|
+
expect(response).to be_success
|
73
|
+
end
|
74
|
+
|
75
|
+
it "responds with the expected JSON" do
|
76
|
+
get(:index, :format => :json)
|
77
|
+
|
78
|
+
expect(response).to send_json({
|
79
|
+
:data => {
|
80
|
+
:products => products
|
81
|
+
},
|
82
|
+
:view => "<ul><li>#{products[0].name}</li><li>#{products[1].name}</li></ul>"
|
83
|
+
})
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when a custom `.json` template is found" do
|
87
|
+
before do
|
88
|
+
stub_template('products/index.json.erb' => "<%= products.map(&:name).to_json.html_safe %>")
|
89
|
+
end
|
90
|
+
|
91
|
+
it "responds using the template for the :view" do
|
92
|
+
get(:index, :format => :json)
|
93
|
+
|
94
|
+
expect(response).to send_json({
|
95
|
+
:data => {
|
96
|
+
:products => products
|
97
|
+
},
|
98
|
+
:view => products.map(&:name).to_json
|
99
|
+
})
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "when the target template is missing" do
|
104
|
+
before do
|
105
|
+
controller do
|
106
|
+
def index
|
107
|
+
respond_with(products, :path => 'bogus/path')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it "fails over to the default behavior" do
|
113
|
+
get(:index, :format => :json)
|
114
|
+
expect(response).to send_json(products)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "as JSON (application/vnd.emerson.data+json)" do
|
120
|
+
before do
|
121
|
+
request.env['HTTP_ACCEPT'] = 'application/vnd.emerson.data+json'
|
122
|
+
end
|
123
|
+
|
124
|
+
it "is successful" do
|
125
|
+
get(:index, :format => :json)
|
126
|
+
expect(response).to be_success
|
127
|
+
end
|
128
|
+
|
129
|
+
it "responds with the expected JSON" do
|
130
|
+
get(:index, :format => :json)
|
131
|
+
|
132
|
+
expect(response).to send_json({
|
133
|
+
:data => {
|
134
|
+
:products => products
|
135
|
+
}
|
136
|
+
})
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context "as JSON (application/vnd.emerson.view+json)" do
|
141
|
+
before do
|
142
|
+
request.env['HTTP_ACCEPT'] = 'application/vnd.emerson.view+json'
|
143
|
+
end
|
144
|
+
|
145
|
+
it "is successful" do
|
146
|
+
get(:index, :format => :json)
|
147
|
+
expect(response).to be_success
|
148
|
+
end
|
149
|
+
|
150
|
+
it "responds with the expected JSON" do
|
151
|
+
get(:index, :format => :json)
|
152
|
+
|
153
|
+
expect(response).to send_json({
|
154
|
+
:view => "<ul><li>#{products[0].name}</li><li>#{products[1].name}</li></ul>"
|
155
|
+
})
|
156
|
+
end
|
157
|
+
|
158
|
+
context "when a custom `.json` template is found" do
|
159
|
+
before do
|
160
|
+
stub_template('products/index.json.erb' => "<%= products.map(&:name).to_json.html_safe %>")
|
161
|
+
end
|
162
|
+
|
163
|
+
it "responds using the template for the :view" do
|
164
|
+
get(:index, :format => :json)
|
165
|
+
|
166
|
+
expect(response).to send_json({
|
167
|
+
:view => products.map(&:name).to_json
|
168
|
+
})
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "with Scope" do
|
174
|
+
let(:user) { resource(:user) }
|
175
|
+
|
176
|
+
before do
|
177
|
+
user.products = [products.first]
|
178
|
+
end
|
179
|
+
|
180
|
+
context "when :path is customized as :scoped" do
|
181
|
+
before do
|
182
|
+
template('users/products/index.html.erb' => '<p>custom template</p>')
|
183
|
+
|
184
|
+
controller do
|
185
|
+
scope :products, :by => :user
|
186
|
+
|
187
|
+
def index
|
188
|
+
respond_with(scoped, :path => :scoped)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
it "responds with the expected template" do
|
194
|
+
get(:index, :user_id => user.id)
|
195
|
+
expect(response.body).to have_css('p', :text => 'custom template')
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
context "when :layout is customized as :scoped" do
|
200
|
+
before do
|
201
|
+
template({
|
202
|
+
'users.html.erb' => '<p>custom layout</p>',
|
203
|
+
:layout => true
|
204
|
+
})
|
205
|
+
|
206
|
+
controller do
|
207
|
+
scope :products, :by => :user
|
208
|
+
|
209
|
+
def index
|
210
|
+
respond_with(scoped, :layout => :scoped)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
it "responds with the expected layout" do
|
216
|
+
get(:index, :user_id => user.id)
|
217
|
+
expect(response.body).to have_css('p', :text => 'custom layout')
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Emerson::Response, :type => :controller do
|
4
|
+
it "is not automatically included" do
|
5
|
+
expect(ApplicationController.included_modules).to_not include(Emerson::Response)
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when included" do
|
9
|
+
before do
|
10
|
+
expect(controller_class).to include(Emerson::Response)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "includes Emerson::Scope" do
|
14
|
+
expect(controller_class).to include(Emerson::Scope)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "configures the responder" do
|
18
|
+
expect(controller_class.responder).to eq(Emerson::Responder)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "configures the :respond_to mimes" do
|
22
|
+
expect(controller_class.mimes_for_respond_to).to eq({ :html => {}, :json => {} })
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when the :responder feature is disabled" do
|
27
|
+
let(:inline_controller) do
|
28
|
+
Class.new(ApplicationController) do
|
29
|
+
include Emerson::Response
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
around do |example|
|
34
|
+
with_features(nil) { example.run }
|
35
|
+
end
|
36
|
+
|
37
|
+
it "does not configure the responder" do
|
38
|
+
expect(inline_controller.responder).to eq(ActionController::Responder)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "does not configure the :respond_to mimes" do
|
42
|
+
expect(inline_controller.mimes_for_respond_to).to eq({})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when the :scope feature is disabled" do
|
47
|
+
let(:inline_controller) do
|
48
|
+
Class.new(ApplicationController) do
|
49
|
+
include Emerson::Response
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
around do |example|
|
54
|
+
with_features(nil) { example.run }
|
55
|
+
end
|
56
|
+
|
57
|
+
it "does not include Emerson::Scope" do
|
58
|
+
expect(inline_controller).to_not include(Emerson::Scope)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
controller(ApplicationController) do
|
65
|
+
include Emerson::Response
|
66
|
+
|
67
|
+
def self.name
|
68
|
+
'ProductsController'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def controller_class
|
73
|
+
described_class
|
74
|
+
end
|
75
|
+
end
|