1
+ using System . Collections . Generic ;
1
2
using System . Net ;
2
3
using System . Net . Http ;
3
4
using System . Threading . Tasks ;
4
5
using Bogus ;
6
+ using JsonApiDotNetCore . Models ;
5
7
using JsonApiDotNetCoreExample ;
6
8
using JsonApiDotNetCoreExample . Data ;
7
9
using JsonApiDotNetCoreExample . Models ;
10
+ using JsonApiDotNetCoreExampleTests . Helpers . Extensions ;
8
11
using Microsoft . AspNetCore . Hosting ;
9
12
using Newtonsoft . Json ;
10
13
using Xunit ;
@@ -22,6 +25,14 @@ public DeeplyNestedInclusionTests(TestFixture<TestStartup> fixture)
22
25
_fixture = fixture ;
23
26
}
24
27
28
+ private void ResetContext ( AppDbContext context )
29
+ {
30
+ context . TodoItems . RemoveRange ( context . TodoItems ) ;
31
+ context . TodoItemCollections . RemoveRange ( context . TodoItemCollections ) ;
32
+ context . People . RemoveRange ( context . People ) ;
33
+ context . PersonRoles . RemoveRange ( context . PersonRoles ) ;
34
+ }
35
+
25
36
[ Fact ]
26
37
public async Task Can_Include_Nested_Relationships ( )
27
38
{
@@ -53,5 +64,253 @@ public async Task Can_Include_Nested_Relationships()
53
64
Assert . NotNull ( responseTodoItem . Collection ) ;
54
65
Assert . NotNull ( responseTodoItem . Collection . Owner ) ;
55
66
}
67
+
68
+ [ Fact ]
69
+ public async Task Can_Include_Nested_HasMany_Relationships ( )
70
+ {
71
+ // arrange
72
+ const string route = "/api/v1/todo-items?include=collection.todo-items" ;
73
+
74
+ var todoItem = new TodoItem {
75
+ Collection = new TodoItemCollection {
76
+ Owner = new Person ( ) ,
77
+ TodoItems = new List < TodoItem > {
78
+ new TodoItem ( ) ,
79
+ new TodoItem ( )
80
+ }
81
+ }
82
+ } ;
83
+
84
+
85
+ var context = _fixture . GetService < AppDbContext > ( ) ;
86
+ ResetContext ( context ) ;
87
+
88
+ context . TodoItems . Add ( todoItem ) ;
89
+ await context . SaveChangesAsync ( ) ;
90
+
91
+ // act
92
+ var response = await _fixture . Client . GetAsync ( route ) ;
93
+
94
+ // assert
95
+ Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
96
+
97
+ var body = await response . Content . ReadAsStringAsync ( ) ;
98
+ var documents = JsonConvert . DeserializeObject < Documents > ( body ) ;
99
+ var included = documents . Included ;
100
+
101
+ Assert . Equal ( 4 , included . Count ) ;
102
+
103
+ Assert . Equal ( 3 , included . CountOfType ( "todo-items" ) ) ;
104
+ Assert . Equal ( 1 , included . CountOfType ( "todo-collections" ) ) ;
105
+ }
106
+
107
+ [ Fact ]
108
+ public async Task Can_Include_Nested_HasMany_Relationships_BelongsTo ( )
109
+ {
110
+ // arrange
111
+ const string route = "/api/v1/todo-items?include=collection.todo-items.owner" ;
112
+
113
+ var todoItem = new TodoItem {
114
+ Collection = new TodoItemCollection {
115
+ Owner = new Person ( ) ,
116
+ TodoItems = new List < TodoItem > {
117
+ new TodoItem {
118
+ Owner = new Person ( )
119
+ } ,
120
+ new TodoItem ( )
121
+ }
122
+ }
123
+ } ;
124
+
125
+ var context = _fixture . GetService < AppDbContext > ( ) ;
126
+ ResetContext ( context ) ;
127
+
128
+ context . TodoItems . Add ( todoItem ) ;
129
+ await context . SaveChangesAsync ( ) ;
130
+
131
+ // act
132
+ var response = await _fixture . Client . GetAsync ( route ) ;
133
+
134
+ // assert
135
+ Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
136
+
137
+ var body = await response . Content . ReadAsStringAsync ( ) ;
138
+ var documents = JsonConvert . DeserializeObject < Documents > ( body ) ;
139
+ var included = documents . Included ;
140
+
141
+ Assert . Equal ( 5 , included . Count ) ;
142
+
143
+ Assert . Equal ( 3 , included . CountOfType ( "todo-items" ) ) ;
144
+ Assert . Equal ( 1 , included . CountOfType ( "people" ) ) ;
145
+ Assert . Equal ( 1 , included . CountOfType ( "todo-collections" ) ) ;
146
+ }
147
+
148
+ [ Fact ]
149
+ public async Task Can_Include_Nested_Relationships_With_Multiple_Paths ( )
150
+ {
151
+ // arrange
152
+ const string route = "/api/v1/todo-items?include=collection.owner.role,collection.todo-items.owner" ;
153
+
154
+ var todoItem = new TodoItem {
155
+ Collection = new TodoItemCollection {
156
+ Owner = new Person {
157
+ Role = new PersonRole ( )
158
+ } ,
159
+ TodoItems = new List < TodoItem > {
160
+ new TodoItem {
161
+ Owner = new Person ( )
162
+ } ,
163
+ new TodoItem ( )
164
+ }
165
+ }
166
+ } ;
167
+
168
+ var context = _fixture . GetService < AppDbContext > ( ) ;
169
+ ResetContext ( context ) ;
170
+
171
+ context . TodoItems . Add ( todoItem ) ;
172
+ await context . SaveChangesAsync ( ) ;
173
+
174
+ // act
175
+ var response = await _fixture . Client . GetAsync ( route ) ;
176
+
177
+ // assert
178
+ Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
179
+
180
+ var body = await response . Content . ReadAsStringAsync ( ) ;
181
+ var documents = JsonConvert . DeserializeObject < Documents > ( body ) ;
182
+ var included = documents . Included ;
183
+
184
+ Assert . Equal ( 7 , included . Count ) ;
185
+
186
+ Assert . Equal ( 3 , included . CountOfType ( "todo-items" ) ) ;
187
+ Assert . Equal ( 2 , included . CountOfType ( "people" ) ) ;
188
+ Assert . Equal ( 1 , included . CountOfType ( "person-roles" ) ) ;
189
+ Assert . Equal ( 1 , included . CountOfType ( "todo-collections" ) ) ;
190
+ }
191
+
192
+ [ Fact ]
193
+ public async Task Included_Resources_Are_Correct ( )
194
+ {
195
+ // arrange
196
+ var role = new PersonRole ( ) ;
197
+ var assignee = new Person { Role = role } ;
198
+ var collectionOwner = new Person ( ) ;
199
+ var someOtherOwner = new Person ( ) ;
200
+ var collection = new TodoItemCollection { Owner = collectionOwner } ;
201
+ var todoItem1 = new TodoItem { Collection = collection , Assignee = assignee } ;
202
+ var todoItem2 = new TodoItem { Collection = collection , Assignee = assignee } ;
203
+ var todoItem3 = new TodoItem { Collection = collection , Owner = someOtherOwner } ;
204
+ var todoItem4 = new TodoItem { Collection = collection , Owner = assignee } ;
205
+
206
+ var context = _fixture . GetService < AppDbContext > ( ) ;
207
+ ResetContext ( context ) ;
208
+
209
+ context . TodoItems . Add ( todoItem1 ) ;
210
+ context . TodoItems . Add ( todoItem2 ) ;
211
+ context . TodoItems . Add ( todoItem3 ) ;
212
+ context . TodoItems . Add ( todoItem4 ) ;
213
+ context . PersonRoles . Add ( role ) ;
214
+ context . People . Add ( assignee ) ;
215
+ context . People . Add ( collectionOwner ) ;
216
+ context . People . Add ( someOtherOwner ) ;
217
+ context . TodoItemCollections . Add ( collection ) ;
218
+
219
+
220
+ await context . SaveChangesAsync ( ) ;
221
+
222
+ string route =
223
+ "/api/v1/todo-items/" + todoItem1 . Id + "?include=" +
224
+ "collection.owner," +
225
+ "assignee.role," +
226
+ "assignee.assigned-todo-items" ;
227
+
228
+ // act
229
+ var response = await _fixture . Client . GetAsync ( route ) ;
230
+
231
+ // assert
232
+ Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
233
+
234
+ var body = await response . Content . ReadAsStringAsync ( ) ;
235
+ var documents = JsonConvert . DeserializeObject < Document > ( body ) ;
236
+ var included = documents . Included ;
237
+
238
+ // 1 collection, 1 owner,
239
+ // 1 assignee, 1 assignee role,
240
+ // 2 assigned todo items (including the primary resource)
241
+ Assert . Equal ( 6 , included . Count ) ;
242
+
243
+ var collectionDocument = included . FindResource ( "todo-collections" , collection . Id ) ;
244
+ var ownerDocument = included . FindResource ( "people" , collectionOwner . Id ) ;
245
+ var assigneeDocument = included . FindResource ( "people" , assignee . Id ) ;
246
+ var roleDocument = included . FindResource ( "person-roles" , role . Id ) ;
247
+ var assignedTodo1 = included . FindResource ( "todo-items" , todoItem1 . Id ) ;
248
+ var assignedTodo2 = included . FindResource ( "todo-items" , todoItem2 . Id ) ;
249
+
250
+ Assert . NotNull ( assignedTodo1 ) ;
251
+ Assert . Equal ( todoItem1 . Id . ToString ( ) , assignedTodo1 . Id ) ;
252
+
253
+ Assert . NotNull ( assignedTodo2 ) ;
254
+ Assert . Equal ( todoItem2 . Id . ToString ( ) , assignedTodo2 . Id ) ;
255
+
256
+ Assert . NotNull ( collectionDocument ) ;
257
+ Assert . Equal ( collection . Id . ToString ( ) , collectionDocument . Id ) ;
258
+
259
+ Assert . NotNull ( ownerDocument ) ;
260
+ Assert . Equal ( collectionOwner . Id . ToString ( ) , ownerDocument . Id ) ;
261
+
262
+ Assert . NotNull ( assigneeDocument ) ;
263
+ Assert . Equal ( assignee . Id . ToString ( ) , assigneeDocument . Id ) ;
264
+
265
+ Assert . NotNull ( roleDocument ) ;
266
+ Assert . Equal ( role . Id . ToString ( ) , roleDocument . Id ) ;
267
+ }
268
+
269
+ [ Fact ]
270
+ public async Task Can_Include_Doubly_HasMany_Relationships ( )
271
+ {
272
+ // arrange
273
+ var person = new Person {
274
+ TodoItemCollections = new List < TodoItemCollection > {
275
+ new TodoItemCollection {
276
+ TodoItems = new List < TodoItem > {
277
+ new TodoItem ( ) ,
278
+ new TodoItem ( )
279
+ }
280
+ } ,
281
+ new TodoItemCollection {
282
+ TodoItems = new List < TodoItem > {
283
+ new TodoItem ( ) ,
284
+ new TodoItem ( ) ,
285
+ new TodoItem ( )
286
+ }
287
+ }
288
+ }
289
+ } ;
290
+
291
+ var context = _fixture . GetService < AppDbContext > ( ) ;
292
+ ResetContext ( context ) ;
293
+
294
+ context . People . Add ( person ) ;
295
+
296
+ await context . SaveChangesAsync ( ) ;
297
+
298
+ string route = "/api/v1/people/" + person . Id + "?include=todo-collections.todo-items" ;
299
+
300
+ // act
301
+ var response = await _fixture . Client . GetAsync ( route ) ;
302
+
303
+ // assert
304
+ Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
305
+
306
+ var body = await response . Content . ReadAsStringAsync ( ) ;
307
+ var documents = JsonConvert . DeserializeObject < Document > ( body ) ;
308
+ var included = documents . Included ;
309
+
310
+ Assert . Equal ( 7 , included . Count ) ;
311
+
312
+ Assert . Equal ( 5 , included . CountOfType ( "todo-items" ) ) ;
313
+ Assert . Equal ( 2 , included . CountOfType ( "todo-collections" ) ) ;
314
+ }
56
315
}
57
316
}
0 commit comments