1+ using System . Collections . Generic ;
12using System . Net ;
23using System . Net . Http ;
34using System . Threading . Tasks ;
45using Bogus ;
6+ using JsonApiDotNetCore . Models ;
57using JsonApiDotNetCoreExample ;
68using JsonApiDotNetCoreExample . Data ;
79using JsonApiDotNetCoreExample . Models ;
10+ using JsonApiDotNetCoreExampleTests . Helpers . Extensions ;
811using Microsoft . AspNetCore . Hosting ;
912using Newtonsoft . Json ;
1013using Xunit ;
@@ -22,6 +25,14 @@ public DeeplyNestedInclusionTests(TestFixture<TestStartup> fixture)
2225 _fixture = fixture ;
2326 }
2427
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+
2536 [ Fact ]
2637 public async Task Can_Include_Nested_Relationships ( )
2738 {
@@ -53,5 +64,253 @@ public async Task Can_Include_Nested_Relationships()
5364 Assert . NotNull ( responseTodoItem . Collection ) ;
5465 Assert . NotNull ( responseTodoItem . Collection . Owner ) ;
5566 }
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+ }
56315 }
57316}
0 commit comments