praxis 0.15.0 → 0.16.0

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.
@@ -11,7 +11,7 @@ describe Praxis::ActionDefinition do
11
11
 
12
12
  media_type 'application/json'
13
13
  version '1.0'
14
- routing { prefix '/api/hello_world' }
14
+ prefix '/api/hello_world'
15
15
  action_defaults do
16
16
  payload { attribute :inherited, String }
17
17
  headers { header "Inherited", String }
@@ -61,6 +61,44 @@ describe Praxis::ActionDefinition do
61
61
  it 'has some tests after we stop using ApiDefinition.instance'
62
62
  end
63
63
 
64
+ describe 'when a trait is used' do
65
+ subject(:action) do
66
+ Praxis::ActionDefinition.new(:bar, resource_definition) do
67
+ trait :test
68
+ routing { get '/:one' }
69
+ params { attribute :one, String }
70
+ end
71
+ end
72
+
73
+ let(:trait) do
74
+ Praxis::Trait.new do
75
+ routing do
76
+ prefix '/test_trait/:app_name'
77
+ end
78
+
79
+ params do
80
+ attribute :app_name, String
81
+ attribute :name, String
82
+ end
83
+
84
+ end
85
+ end
86
+ let(:traits) { {test: trait} }
87
+
88
+ before do
89
+ allow(Praxis::ApiDefinition.instance).to receive(:traits).and_return(traits)
90
+ end
91
+
92
+ its('params.attributes.keys') { should eq [:inherited, :app_name, :name, :one]}
93
+ its('routes.first.path.to_s') { should eq '/api/hello_world/test_trait/:app_name/:one' }
94
+ its(:traits) { should eq [:test] }
95
+
96
+ it 'is reflected in the describe output' do
97
+ expect(action.describe[:traits]).to eq [:test]
98
+ end
99
+
100
+ end
101
+
64
102
  describe '#params' do
65
103
  it 'merges in more params' do
66
104
  subject.params do
@@ -98,9 +136,8 @@ describe Praxis::ActionDefinition do
98
136
  header "more"
99
137
  end
100
138
 
101
- expect(subject.headers.attributes.keys).to match_array([
102
- "X_REQUESTED_WITH", "Inherited", "more"
103
- ])
139
+ expected_array = ["X_REQUESTED_WITH", "Inherited", "more"]
140
+ expect(subject.headers.attributes.keys).to match_array(expected_array)
104
141
  end
105
142
  end
106
143
 
@@ -153,7 +190,7 @@ describe Praxis::ActionDefinition do
153
190
 
154
191
  context 'with nodoc!' do
155
192
  before do
156
- action.nodoc!
193
+ action.nodoc!
157
194
  end
158
195
 
159
196
  it 'has :doc_visibility set in metadata' do
@@ -165,4 +202,69 @@ describe Praxis::ActionDefinition do
165
202
  end
166
203
 
167
204
  end
205
+
206
+ context 'with a base_path and base_params on ApiDefinition' do
207
+ # Without getting a fresh new ApiDefinition it is very difficult to test stuff using the Singleton
208
+ # So for some tests we're gonna create a new instance and work with it to avoid the singleton issues
209
+ let(:non_singleton_api) do
210
+ api_def=Praxis::ApiDefinition.__send__(:new)
211
+ api_def.instance_eval do |api|
212
+
213
+ api.info do
214
+ base_path '/apps/:app_name'
215
+ end
216
+
217
+ api.info '1.0' do
218
+ base_params do
219
+ attribute :app_name, String
220
+ end
221
+ end
222
+
223
+ end
224
+ api_def
225
+ end
226
+
227
+ before do
228
+ allow(Praxis::ApiDefinition).to receive(:instance).and_return(non_singleton_api)
229
+ end
230
+
231
+ its('routes.first.path.to_s') { should eq '/apps/:app_name/api/hello_world/:one' }
232
+ its('params.attributes.keys') { should eq [:inherited, :app_name, :one]}
233
+
234
+ context 'where the action overrides a base_param' do
235
+
236
+ let(:resource_definition) do
237
+ Class.new do
238
+ include Praxis::ResourceDefinition
239
+
240
+ def self.name
241
+ 'FooBar'
242
+ end
243
+ version '1.0'
244
+ prefix '/api/hello_world'
245
+ action_defaults do
246
+ payload { attribute :inherited, String }
247
+ headers { header "Inherited", String }
248
+ end
249
+ end
250
+ end
251
+
252
+ let(:action) do
253
+ Praxis::ActionDefinition.new(:foo, resource_definition) do
254
+ routing { get '' }
255
+ params { attribute :app_name, Integer }
256
+ end
257
+ end
258
+
259
+ subject(:attributes) { action.params.attributes }
260
+
261
+ its(:keys) { should eq [:app_name]}
262
+
263
+ it 'overrides the base param' do
264
+ expect(attributes[:app_name].type).to eq(Attributor::Integer)
265
+ end
266
+
267
+ end
268
+
269
+ end
168
270
  end
@@ -1,43 +1,54 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Praxis::ApiDefinition do
4
-
5
- subject(:api){ Praxis::ApiDefinition.instance }
6
-
4
+
5
+ subject(:api){ Praxis::ApiDefinition.instance }
6
+
7
7
  # Without getting a fresh new ApiDefinition it is very difficult to test stuff using the Singleton
8
8
  # So for some tests we're gonna create a new instance and work with it to avoid the singleton issues
9
9
  let(:non_singleton_api) do
10
10
  api_def=Praxis::ApiDefinition.__send__(:new)
11
11
  api_def.instance_eval do |api|
12
- api.response_template :template1, &Proc.new {}
13
- api.trait :trait1, &Proc.new {}
12
+ api.response_template :template1, &Proc.new {}
13
+ api.trait :trait1, &Proc.new {}
14
+ api.trait :trait_2 do
15
+ description 'the second testing trait'
16
+ end
17
+
18
+ api.info '1.0' do
19
+ base_path '/apps/:app_name'
20
+ base_params do
21
+ attribute :app_name, String
22
+ end
23
+ end
14
24
  end
15
25
  api_def
16
26
  end
17
-
27
+
18
28
  let(:info_block) do
19
29
  Proc.new do
20
30
  name "Name"
21
31
  title "Title"
22
32
  end
23
- end
24
-
33
+ end
34
+
25
35
  context 'singleton' do
26
36
  it 'should be a Singleton' do
27
37
  expect(Praxis::ApiDefinition.ancestors).to include( Singleton )
28
38
  expect(subject).to eq(Praxis::ApiDefinition.instance )
29
39
  end
30
-
40
+
31
41
  it 'has the :ok and :created response templates registered' do
32
42
  expect(api.responses.keys).to include(:ok)
33
43
  expect(api.responses.keys).to include(:created)
34
- end
44
+ end
35
45
  end
36
-
46
+
47
+
37
48
  context '.response_template' do
38
49
  let(:response_template){ Proc.new {} }
39
50
  let(:api){ non_singleton_api }
40
-
51
+
41
52
  it 'has the defined template1 response_template' do
42
53
  expect(api.responses.keys).to include(:template1)
43
54
  expect(api.response(:template1)).to be_kind_of(Praxis::ResponseTemplate)
@@ -48,7 +59,7 @@ describe Praxis::ApiDefinition do
48
59
  expect(api.response(:foobar)).to be_kind_of(Praxis::ResponseTemplate)
49
60
  end
50
61
  end
51
-
62
+
52
63
  context '.response' do
53
64
  let(:api){ non_singleton_api }
54
65
 
@@ -56,32 +67,39 @@ describe Praxis::ApiDefinition do
56
67
  expect(api.response(:template1)).to be_kind_of(Praxis::ResponseTemplate)
57
68
  end
58
69
  end
59
-
70
+
60
71
  context '.trait' do
61
72
  let(:api){ non_singleton_api }
62
-
73
+
63
74
  let(:trait2){ Proc.new{} }
75
+
64
76
  it 'has the defined trait1 ' do
65
77
  expect(api.traits.keys).to include(:trait1)
66
- expect(api.traits[:trait1]).to be_kind_of(Proc)
78
+ expect(api.traits[:trait1]).to be_kind_of(Praxis::Trait)
67
79
  end
68
-
69
- it 'saves it verbatim' do
70
- api.trait :trait2, &trait2
71
- expect(api.traits[:trait2]).to be(trait2)
72
- end
73
-
80
+
74
81
  it 'complains trying to register traits with same name' do
75
82
  api.trait :trait2, &trait2
76
- expect{
83
+ expect{
77
84
  api.trait :trait2, &trait2
78
85
  }.to raise_error(Praxis::Exceptions::InvalidTrait, /Overwriting a previous trait with the same name/)
79
86
  end
80
87
  end
81
-
88
+
82
89
  context '.info' do
83
-
90
+
84
91
  let(:api){ non_singleton_api }
92
+ subject(:info) { api.info('1.0') }
93
+
94
+ context '.base_path' do
95
+ its(:base_path) { should eq '/apps/:app_name'}
96
+ end
97
+
98
+ context '.base_params' do
99
+ subject(:base_params) { info.base_params }
100
+ it { should be_kind_of(Attributor::Attribute) }
101
+ its(:attributes) { should include :app_name }
102
+ end
85
103
 
86
104
  context 'with a version' do
87
105
  it 'saves the data into the correct version hash' do
@@ -89,36 +107,39 @@ describe Praxis::ApiDefinition do
89
107
  api.info("9.0", &info_block)
90
108
  expect(api.infos.keys).to include("9.0")
91
109
  end
92
- it 'immediate invokes the block' do
93
- expect(api.infos["9.0"]).to receive(:instance_eval)
94
- api.info("9.0", &info_block)
95
- end
96
- end
110
+ end
111
+
97
112
  context 'without a version' do
98
- it 'saves it into nil if no version is passed' do
113
+ it 'saves it into global_info' do
99
114
  expect(api.infos.keys).to_not include(nil)
100
115
  api.info do
101
116
  description "Global Description"
102
117
  end
103
- expect(api.infos.keys).to include(nil)
118
+ expect(api.infos.keys).to_not include(nil)
119
+ expect(api.global_info.description).to eq 'Global Description'
104
120
  end
105
121
  end
106
122
  end
107
-
123
+
108
124
  context '.describe' do
109
125
  subject(:output){ api.describe }
110
126
 
111
127
  context 'using the spec_app definitions' do
112
128
  subject(:version_output){ output["1.0"][:info] }
113
- it 'saves the data into the correct version hash' do
114
- expect(api.infos.keys).to include(nil)
115
- expect(api.infos.keys).to include("1.0")
116
- end
117
129
 
130
+ context 'for the global_info data' do
131
+ subject(:info) { output[:global][:info] }
132
+ it { should include(:name, :title, :description) }
133
+ its([:name]) { should eq 'Spec App' }
134
+ its([:title]) { should eq 'A simple App to do some simple integration testing' }
135
+ its([:description]) { should eq 'This example API should really be replaced by a set of more full-fledged example apps in the future' }
136
+ end
137
+
118
138
  it 'outputs data for 1.0 info' do
119
139
  expect(output.keys).to include("1.0")
120
140
  expect(output["1.0"]).to include(:info)
121
141
  end
142
+
122
143
  it 'describes 1.0 Api info properly' do
123
144
  info = output["1.0"][:info]
124
145
  expect(info).to include(:schema_version, :name, :title, :description, :base_path)
@@ -129,21 +150,23 @@ describe Praxis::ApiDefinition do
129
150
  expect(info[:base_path]).to eq("/")
130
151
  end
131
152
  end
132
-
153
+
133
154
  context 'using a non-singleton object' do
134
155
  let(:api){ non_singleton_api }
135
-
156
+
136
157
  before do
137
158
  api.info("9.0", &info_block)
138
159
  api.info do
139
160
  description "Global Description"
140
161
  end
141
162
  end
142
- its(:keys){ should include("9.0") }
143
-
163
+ its(:keys) { should include("9.0") }
164
+ its(:keys) { should include :traits }
165
+ its([:traits, :trait_2]) { should eq api.traits[:trait_2].describe }
166
+
144
167
  context 'for v9.0 info' do
145
168
  subject(:v9_info){ output["9.0"][:info] }
146
-
169
+
147
170
  it 'has the info it was set in the call' do
148
171
  expect(v9_info).to include({schema_version: "1.0"})
149
172
  expect(v9_info).to include({name: "Name"})
@@ -152,8 +175,8 @@ describe Praxis::ApiDefinition do
152
175
  it 'inherited the description from the nil(global) one' do
153
176
  expect(v9_info).to include({description: "Global Description"})
154
177
  end
155
-
178
+
156
179
  end
157
180
  end
158
181
  end
159
- end
182
+ end
@@ -1,36 +1,50 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Praxis::ApiGeneralInfo do
4
-
4
+
5
5
  subject(:info){ Praxis::ApiGeneralInfo.new }
6
-
6
+
7
7
  let(:info_block) do
8
8
  Proc.new do
9
9
  name "Name"
10
10
  title "Title"
11
11
  description "Description"
12
12
  base_path "/base"
13
+ base_params do
14
+ attribute :name, String
15
+ end
13
16
  end
14
17
  end
15
-
16
- context 'DSLs' do
18
+
19
+ context 'setting' do
17
20
  it 'accepts the appropriate DSLs' do
18
- expect{
21
+ expect{
19
22
  info.instance_exec &info_block
20
23
  }.to_not raise_error
21
24
  end
22
-
23
25
  end
24
26
 
27
+ context 'getting values' do
28
+ before do
29
+ info.instance_exec &info_block
30
+ end
31
+
32
+ its(:name) { should eq 'Name' }
33
+
34
+ end
25
35
  context '.describe' do
26
- subject(:output){ info.describe }
27
- it 'works' do
36
+ before do
28
37
  info.instance_exec &info_block
29
- expect(output).to eq(
30
- {:schema_version=>"1.0", :name=>"Name", :title=>"Title",
31
- :description=>"Description", :base_path=>"/base"
32
- })
33
38
  end
34
-
39
+
40
+ subject(:output){ info.describe }
41
+ its([:schema_version]) {should eq '1.0' }
42
+ its([:name]) {should eq 'Name' }
43
+ its([:title]) {should eq 'Title' }
44
+ its([:description]) {should eq 'Description' }
45
+ its([:base_path]) {should eq '/base' }
46
+ its([:base_params]) { should have_key :name }
47
+ its([:base_params, :name, :type, :name]) { should eq 'String' }
48
+
35
49
  end
36
- end
50
+ end
@@ -9,8 +9,8 @@ describe Praxis::MediaType do
9
9
  end
10
10
 
11
11
  let(:resource) do
12
- double('address',
13
- id: 1,
12
+ double('address',
13
+ id: 1,
14
14
  name: 'Home',
15
15
  owner: owner_resource,
16
16
  manager: manager_resource,
@@ -38,7 +38,7 @@ describe Praxis::MediaType do
38
38
  end
39
39
 
40
40
 
41
-
41
+
42
42
  context 'accessor methods' do
43
43
  subject(:address_klass) { address.class }
44
44
 
@@ -62,7 +62,7 @@ describe Praxis::MediaType do
62
62
  end
63
63
 
64
64
  its(:description) { should be_kind_of(String) }
65
-
65
+
66
66
  context 'links' do
67
67
  context 'with a custom links attribute' do
68
68
  subject(:person) { Person.new(owner_resource) }
@@ -70,7 +70,7 @@ describe Praxis::MediaType do
70
70
  its(:links) { should be_kind_of(Array) }
71
71
  its(:links) { should eq(owner_resource.links) }
72
72
  end
73
-
73
+
74
74
  context 'using the links DSL' do
75
75
  subject(:address) { Address.new(resource) }
76
76
  its(:links) { should be_kind_of(Address::Links) }
@@ -114,7 +114,7 @@ describe Praxis::MediaType do
114
114
  let(:snapshots_summary) { volume.snapshots_summary }
115
115
  let(:output) { volume.render(:default) }
116
116
  subject { links[:snapshots] }
117
-
117
+
118
118
  its([:name]) { should eq(snapshots_summary.name) }
119
119
  its([:size]) { should eq(snapshots_summary.size) }
120
120
  its([:href]) { should eq(snapshots_summary.href) }
@@ -140,6 +140,33 @@ describe Praxis::MediaType do
140
140
  end
141
141
 
142
142
 
143
+ context 'describing' do
144
+
145
+ subject(:described){ Address.describe }
146
+
147
+ its(:keys) { should match_array( [:attributes, :description, :family, :id, :identifier, :key, :name, :views] ) }
148
+ its([:attributes]) { should be_kind_of(::Hash) }
149
+ its([:description]) { should be_kind_of(::String) }
150
+ its([:family]) { should be_kind_of(::String) }
151
+ its([:id]) { should be_kind_of(::String) }
152
+ its([:name]) { should be_kind_of(::String) }
153
+ its([:identifier]) { should be_kind_of(::String) }
154
+ its([:key]) { should be_kind_of(::Hash) }
155
+ its([:views]) { should be_kind_of(::Hash) }
156
+
157
+ its([:description]) { should eq(Address.description) }
158
+ its([:family]) { should eq(Address.family) }
159
+ its([:id]) { should eq(Address.id) }
160
+ its([:name]) { should eq(Address.name) }
161
+ its([:identifier]) { should eq(Address.identifier.to_s) }
162
+ it 'should include the defined views' do
163
+ expect( subject[:views].keys ).to match( [:default, :master] )
164
+ end
165
+ it 'should include the defined attributes' do
166
+ expect( subject[:attributes].keys ).to match( [:id, :name, :owner, :custodian, :residents, :residents_summary, :links] )
167
+ end
168
+ end
169
+
143
170
  context 'using blueprint caching' do
144
171
  it 'has specs'
145
172
  end