roar-jsonapi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,161 @@
1
+ require 'test_helper'
2
+ require 'roar/json/json_api'
3
+
4
+ class FieldsetsOptionsTest < Minitest::Spec
5
+ Include = Roar::JSON::JSONAPI::Options::Include
6
+
7
+ describe 'with non-empty :include and non-empty :fields option' do
8
+ it 'rewrites :include and parses :fields' do
9
+ [{ include: [:articles],
10
+ fields: { articles: [:title, :body], people: [] } },
11
+ { include: ['articles'],
12
+ fields: { articles: ['title,body'], people: [] } },
13
+ { include: 'articles',
14
+ fields: { 'articles' => 'title,body', 'people' => '' } }].each do |options|
15
+ options = Include.(options, relationships: { 'articles' => 'articles' })
16
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
17
+ included: {
18
+ include: [:articles],
19
+ articles: {
20
+ include: [:id, :attributes, :relationships],
21
+ attributes: { include: [:title, :body] },
22
+ relationships: { include: [:title, :body] },
23
+ _json_api_parsed: true
24
+ },
25
+ people: {
26
+ attributes: { include: [] },
27
+ relationships: { include: [] },
28
+ _json_api_parsed: true
29
+ }
30
+ })
31
+ end
32
+ end
33
+ end
34
+
35
+ describe 'with empty :include option' do
36
+ it 'rewrites :include' do
37
+ [{ include: [] },
38
+ { include: [''] },
39
+ { include: '' }].each do |options|
40
+ options = Include.(options, {})
41
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
42
+ included: { include: [] })
43
+ end
44
+ end
45
+ end
46
+
47
+ describe 'with empty :include option and non-empty :fields option' do
48
+ it 'parses :fields (_self), but does not include other resources' do
49
+ [{ include: [], fields: { articles: [:title, :body], people: [] } },
50
+ { include: [''], fields: { articles: ['title,body'], people: [] } },
51
+ { include: '', fields: { 'articles' => 'title,body', 'people' => '' } }].each do |options|
52
+ options = Include.(options, relationships: { '_self' => 'articles' })
53
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
54
+ included: {
55
+ include: [],
56
+ people: {
57
+ attributes: { include: [] },
58
+ relationships: { include: [] },
59
+ _json_api_parsed: true
60
+ }
61
+ },
62
+ attributes: { include: [:title, :body] },
63
+ relationships: { include: [:title, :body] })
64
+ end
65
+ end
66
+
67
+ it 'parses :fields, but does not include other resources' do
68
+ [{ include: [], fields: { articles: [:title, :body], people: [:email] } },
69
+ { include: [''], fields: { articles: ['title,body'], people: ['email'] } },
70
+ { include: '', fields: { 'articles' => 'title,body', 'people' => 'email' } }].each do |options|
71
+ options = Include.(options, relationships: { 'author' => 'people', 'articles' => 'articles' })
72
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
73
+ included: {
74
+ include: [],
75
+ articles: {
76
+ attributes: { include: [:title, :body] },
77
+ relationships: { include: [:title, :body] },
78
+ _json_api_parsed: true
79
+ },
80
+ author: {
81
+ attributes: { include: [:email] },
82
+ relationships: { include: [:email] },
83
+ _json_api_parsed: true
84
+ }
85
+ })
86
+ end
87
+ end
88
+ end
89
+
90
+ describe 'with non-empty :include option' do
91
+ it 'rewrites :include given a relationship name' do
92
+ [{ include: [:comments] },
93
+ { include: ['comments'] },
94
+ { include: 'comments' }].each do |options|
95
+ options = Include.(options, {})
96
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
97
+ included: {
98
+ include: [:comments],
99
+ comments: {
100
+ include: [:id, :attributes, :relationships],
101
+ _json_api_parsed: true
102
+ }
103
+ })
104
+ end
105
+ end
106
+
107
+ it 'rewrites :include given a dot-separated path of relationship names' do
108
+ [{ include: [:"comments.author.employer"] },
109
+ { include: ['comments.author.employer'] },
110
+ { include: 'comments.author.employer' }].each do |options|
111
+ options = Include.(options, {})
112
+ options.must_equal(include: [:id, :attributes, :relationships, :included],
113
+ included: {
114
+ include: [:comments],
115
+ comments: {
116
+ include: [:id, :attributes, :relationships, :included],
117
+ included: {
118
+ author: {
119
+ include: [:id, :attributes, :relationships, :included],
120
+ included: {
121
+ employer: {
122
+ include: [:id, :attributes, :relationships],
123
+ _json_api_parsed: true
124
+ }
125
+ },
126
+ _json_api_parsed: true
127
+ }
128
+ },
129
+ _json_api_parsed: true
130
+ }
131
+ })
132
+ end
133
+ end
134
+
135
+ it 'does not rewrite :include if _json_api_parsed: true' do
136
+ options = Include.({ include: [:id, :attributes],
137
+ _json_api_parsed: true }, {})
138
+ options.must_equal(include: [:id, :attributes],
139
+ _json_api_parsed: true)
140
+ end
141
+ end
142
+
143
+ describe 'with falsey :include options' do
144
+ it 'does not rewrite include: false' do
145
+ options = Include.({ include: false }, {})
146
+ options.must_equal(include: false)
147
+ end
148
+
149
+ it 'does not rewrite include: nil' do
150
+ options = Include.({ include: nil }, {})
151
+ options.must_equal(include: nil)
152
+ end
153
+ end
154
+
155
+ describe 'with falsey :fields options' do
156
+ it 'does not parse fields: nil' do
157
+ options = Include.({ fields: nil }, {})
158
+ options.must_equal(fields: nil)
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,293 @@
1
+ require 'test_helper'
2
+ require 'roar/json/json_api'
3
+ require 'json'
4
+
5
+ class JSONAPIFieldsetsTest < Minitest::Spec
6
+ Article = Struct.new(:id, :title, :summary, :comments, :author)
7
+ Comment = Struct.new(:id, :body, :good, :comment_author)
8
+ Author = Struct.new(:id, :name, :email)
9
+
10
+ describe 'Single Resource Object With Options' do
11
+ class DocumentSingleResourceObjectDecorator < Roar::Decorator
12
+ include Roar::JSON::JSONAPI.resource :articles
13
+
14
+ attributes do
15
+ property :title
16
+ property :summary
17
+ end
18
+
19
+ has_many :comments do
20
+ attributes do
21
+ property :body
22
+ property :good
23
+ end
24
+
25
+ has_one :comment_author, class: Comment do
26
+ type :authors
27
+
28
+ attributes do
29
+ property :name
30
+ property :email
31
+ end
32
+ end
33
+ end
34
+
35
+ has_one :author do
36
+ type :authors
37
+
38
+ attributes do
39
+ property :name
40
+ property :email
41
+ end
42
+ end
43
+ end
44
+
45
+ let(:comments) {
46
+ [
47
+ Comment.new('c:1', 'Cool!', true,
48
+ Author.new('a:2', 'Tim', 'troll@trollblazer.io')),
49
+ Comment.new('c:2', 'Nah', false)
50
+ ]
51
+ }
52
+
53
+ let(:article) {
54
+ Article.new(1, 'My Article', 'An interesting read.', comments,
55
+ Author.new('a:1', 'Celso', 'celsito@trb.to'))
56
+ }
57
+
58
+ it 'includes scalars' do
59
+ DocumentSingleResourceObjectDecorator.new(article)
60
+ .to_json(
61
+ fields: { articles: 'title' }
62
+ )
63
+ .must_equal_json(%(
64
+ {
65
+ "data": {
66
+ "id": "1",
67
+ "attributes": {
68
+ "title": "My Article"
69
+ },
70
+ "type": "articles"
71
+ }
72
+ }
73
+ ))
74
+ end
75
+
76
+ it 'includes compound objects' do
77
+ DocumentSingleResourceObjectDecorator.new(article)
78
+ .to_json(
79
+ fields: { articles: 'title' },
80
+ include: :comments
81
+ )
82
+ .must_equal_json(%(
83
+ {
84
+ "data": {
85
+ "id": "1",
86
+ "attributes": {
87
+ "title": "My Article"
88
+ },
89
+ "type": "articles"
90
+ },
91
+ "included": [
92
+ {
93
+ "type": "comments",
94
+ "id": "c:1",
95
+ "attributes": {
96
+ "body": "Cool!",
97
+ "good": true
98
+ },
99
+ "relationships": {
100
+ "comment-author": {
101
+ "data": {
102
+ "type": "authors",
103
+ "id": "a:2"
104
+ }
105
+ }
106
+ }
107
+ },
108
+ {
109
+ "type": "comments",
110
+ "id": "c:2",
111
+ "attributes": {
112
+ "body": "Nah",
113
+ "good": false
114
+ },
115
+ "relationships": {
116
+ "comment-author": {
117
+ "data": null
118
+ }
119
+ }
120
+ }
121
+ ]
122
+ }
123
+ ))
124
+ end
125
+
126
+ it 'includes nested compound objects' do
127
+ DocumentSingleResourceObjectDecorator.new(article)
128
+ .to_json(
129
+ fields: { articles: 'title' },
130
+ include: 'comments.author'
131
+ )
132
+ .must_equal_json(%(
133
+ {
134
+ "data": {
135
+ "id": "1",
136
+ "attributes": {
137
+ "title": "My Article"
138
+ },
139
+ "type": "articles"
140
+ },
141
+ "included": [
142
+ {
143
+ "type": "comments",
144
+ "id": "c:1",
145
+ "attributes": {
146
+ "body": "Cool!",
147
+ "good": true
148
+ },
149
+ "relationships": {
150
+ "comment-author": {
151
+ "data": {
152
+ "type": "authors",
153
+ "id": "a:2"
154
+ }
155
+ }
156
+ },
157
+ "included": [
158
+ {
159
+ "type": "authors",
160
+ "id": "a:2",
161
+ "attributes": {
162
+ "email": "troll@trollblazer.io",
163
+ "name": "Tim"
164
+ }
165
+ }
166
+ ]
167
+ },
168
+ {
169
+ "type": "comments",
170
+ "id": "c:2",
171
+ "attributes": {
172
+ "body": "Nah",
173
+ "good": false
174
+ },
175
+ "relationships": {
176
+ "comment-author": {
177
+ "data": null
178
+ }
179
+ }
180
+ }
181
+ ]
182
+ }
183
+ ))
184
+ end
185
+
186
+ it 'includes other compound objects' do
187
+ DocumentSingleResourceObjectDecorator.new(article)
188
+ .to_json(
189
+ fields: { articles: 'title' },
190
+ include: :author
191
+ )
192
+ .must_equal_json(%(
193
+ {
194
+ "data": {
195
+ "id": "1",
196
+ "attributes": {
197
+ "title": "My Article"
198
+ },
199
+ "type": "articles"
200
+ },
201
+ "included": [
202
+ {
203
+ "type": "authors",
204
+ "id": "a:1",
205
+ "attributes": {
206
+ "email": "celsito@trb.to",
207
+ "name": "Celso"
208
+ }
209
+ }
210
+ ]
211
+ }
212
+ ))
213
+ end
214
+
215
+ describe 'collection' do
216
+ it 'supports :includes' do
217
+ DocumentSingleResourceObjectDecorator.for_collection.new([article])
218
+ .to_hash(
219
+ fields: { articles: 'title' },
220
+ include: :author
221
+ )
222
+ .must_equal Hash[{
223
+ 'data' => [
224
+ { 'type' => 'articles',
225
+ 'id' => '1',
226
+ 'attributes' => { 'title'=>'My Article' } }
227
+ ],
228
+ 'included' =>
229
+ [{ 'type' => 'authors', 'id' => 'a:1', 'attributes' => { 'name' => 'Celso', 'email' => 'celsito@trb.to' } }]
230
+ }]
231
+ end
232
+
233
+ # include: ROAR API
234
+ it 'blaaaaaaa' do
235
+ DocumentSingleResourceObjectDecorator.for_collection.new([article])
236
+ .to_hash(
237
+ fields: { articles: 'title', authors: [:email] },
238
+ include: :author
239
+ )
240
+ .must_equal Hash[{
241
+ 'data' => [
242
+ { 'type' => 'articles',
243
+ 'id' => '1',
244
+ 'attributes' => { 'title'=>'My Article' } }
245
+ ],
246
+ 'included' =>
247
+ [{ 'type' => 'authors', 'id' => 'a:1', 'attributes' => { 'email'=>'celsito@trb.to' } }]
248
+ }]
249
+ end
250
+ end
251
+ end
252
+
253
+ describe 'Collection Resources With Options' do
254
+ class CollectionResourceObjectDecorator < Roar::Decorator
255
+ include Roar::JSON::JSONAPI.resource :articles
256
+
257
+ attributes do
258
+ property :title
259
+ property :summary
260
+ end
261
+ end
262
+
263
+ let(:document) {
264
+ %({
265
+ "data": [
266
+ {
267
+ "id": "1",
268
+ "attributes": {
269
+ "title": "My Article"
270
+ },
271
+ "type": "articles"
272
+ },
273
+ {
274
+ "id": "2",
275
+ "attributes": {
276
+ "title": "My Other Article"
277
+ },
278
+ "type": "articles"
279
+ }
280
+ ]
281
+ })
282
+ }
283
+
284
+ it do
285
+ CollectionResourceObjectDecorator.for_collection.new([
286
+ Article.new(1, 'My Article', 'An interesting read.'),
287
+ Article.new(2, 'My Other Article', 'An interesting read.')
288
+ ]).to_json(
289
+ fields: { articles: :title }
290
+ ).must_equal_json document
291
+ end
292
+ end
293
+ end