@@ -57,31 +57,13 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
5757 data = new
5858 {
5959 type = "supportTickets" ,
60- id = existingTicket . StringId
61- } ,
62- meta = new
63- {
64- category = "bug" ,
65- priority = 1 ,
66- components = new [ ]
67- {
68- "login" ,
69- "single-sign-on"
70- } ,
71- relatedTo = new [ ]
60+ id = existingTicket . StringId ,
61+ attributes = new
7262 {
73- new
74- {
75- id = 123 ,
76- link = "https://www.ticket-system.com/bugs/123"
77- } ,
78- new
79- {
80- id = 789 ,
81- link = "https://www.ticket-system.com/bugs/789"
82- }
63+ description = existingTicket . Description
8364 }
84- }
65+ } ,
66+ meta = GetExampleMetaData ( )
8567 } ;
8668
8769 string route = $ "/supportTickets/{ existingTicket . StringId } ";
@@ -93,57 +75,138 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
9375 httpResponse . ShouldHaveStatusCode ( HttpStatusCode . NoContent ) ;
9476
9577 store . Document . Should ( ) . NotBeNull ( ) ;
96- store . Document . Meta . Should ( ) . HaveCount ( 4 ) ;
9778
98- store . Document . Meta . Should ( ) . ContainKey ( "category" ) . WhoseValue . With ( value =>
79+ ValidateMetaData ( store . Document . Meta ) ;
80+ }
81+
82+ [ Fact ]
83+ public async Task Accepts_top_level_meta_in_post_resource_request ( )
84+ {
85+ // Arrange
86+ var store = _testContext . Factory . Services . GetRequiredService < RequestDocumentStore > ( ) ;
87+
88+ SupportTicket existingTicket = _fakers . SupportTicket . GenerateOne ( ) ;
89+
90+ var requestBody = new
91+ {
92+ data = new
93+ {
94+ type = "supportTickets" ,
95+ attributes = new
96+ {
97+ description = existingTicket . Description
98+ }
99+ } ,
100+ meta = GetExampleMetaData ( )
101+ } ;
102+
103+ string route = $ "/supportTickets";
104+
105+ // Act
106+ ( HttpResponseMessage httpResponse , Document responseDocument ) = await _testContext . ExecutePostAsync < Document > ( route , requestBody ) ;
107+
108+ // Assert
109+ httpResponse . ShouldHaveStatusCode ( HttpStatusCode . Created ) ;
110+
111+ store . Document . Should ( ) . NotBeNull ( ) ;
112+
113+ ValidateMetaData ( store . Document . Meta ) ;
114+ }
115+
116+ private static Object GetExampleMetaData ( )
117+ {
118+ return new
119+ {
120+ category = "bug" ,
121+ priority = 1 ,
122+ urgent = true ,
123+ components = new [ ]
124+ {
125+ "login" ,
126+ "single-sign-on"
127+ } ,
128+ relatedTo = new [ ]
129+ {
130+ new
131+ {
132+ id = 123 ,
133+ link = "https://www.ticket-system.com/bugs/123"
134+ } ,
135+ new
136+ {
137+ id = 789 ,
138+ link = "https://www.ticket-system.com/bugs/789"
139+ }
140+ } ,
141+ contextInfo = new Dictionary < string , object ? >
142+ {
143+ [ "source" ] = "form-submission" ,
144+ [ "retries" ] = 1 ,
145+ [ "authenticated" ] = false
146+ }
147+ } ;
148+ }
149+
150+ private static void ValidateMetaData ( IDictionary < string , object ? > ? meta )
151+ {
152+ meta . Should ( ) . NotBeNull ( ) ;
153+ meta . Should ( ) . HaveCount ( 6 ) ;
154+
155+ meta . Should ( ) . ContainKey ( "category" ) . WhoseValue . With ( value =>
99156 {
100157 JsonElement element = value . Should ( ) . BeOfType < JsonElement > ( ) . Subject ;
101158 element . GetString ( ) . Should ( ) . Be ( "bug" ) ;
102159 } ) ;
103160
104- store . Document . Meta . Should ( ) . ContainKey ( "priority" ) . WhoseValue . With ( value =>
161+ meta . Should ( ) . ContainKey ( "priority" ) . WhoseValue . With ( value =>
105162 {
106163 JsonElement element = value . Should ( ) . BeOfType < JsonElement > ( ) . Subject ;
107164 element . GetInt32 ( ) . Should ( ) . Be ( 1 ) ;
108165 } ) ;
109166
110- store . Document . Meta . Should ( ) . ContainKey ( "components" ) . WhoseValue . With ( value =>
167+ meta . Should ( ) . ContainKey ( "components" ) . WhoseValue . With ( value =>
111168 {
112169 string innerJson = value . Should ( ) . BeOfType < JsonElement > ( ) . Subject . ToString ( ) ;
113170
114171 innerJson . Should ( ) . BeJson ( """
115- [
116- "login",
117- "single-sign-on"
118- ]
119- """ ) ;
172+ [
173+ "login",
174+ "single-sign-on"
175+ ]
176+ """ ) ;
120177 } ) ;
121178
122- store . Document . Meta . Should ( ) . ContainKey ( "relatedTo" ) . WhoseValue . With ( value =>
179+ meta . Should ( ) . ContainKey ( "relatedTo" ) . WhoseValue . With ( value =>
123180 {
124181 string innerJson = value . Should ( ) . BeOfType < JsonElement > ( ) . Subject . ToString ( ) ;
125182
126183 innerJson . Should ( ) . BeJson ( """
127- [
128- {
129- "id": 123,
130- "link": "https://www.ticket-system.com/bugs/123"
131- },
132- {
133- "id": 789,
134- "link": "https://www.ticket-system.com/bugs/789"
135- }
136- ]
137- """ ) ;
184+ [
185+ {
186+ "id": 123,
187+ "link": "https://www.ticket-system.com/bugs/123"
188+ },
189+ {
190+ "id": 789,
191+ "link": "https://www.ticket-system.com/bugs/789"
192+ }
193+ ]
194+ """ ) ;
138195 } ) ;
139- }
140196
141- // TODO: Add more tests, creating a mixture of:
142- // - Different endpoints: post resource, patch resource, post relationship, patch relationship, delete relationship, atomic:operations
143- // - Meta at different depths in the request body
144- // For example, assert on store.Document.Data.SingleValue.Meta
145- // See IHasMeta usage at https://github.com/json-api-dotnet/JsonApiDotNetCore/tree/openapi/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiObjects for where meta can occur
146- // - Varying data structures: primitive types such as string/int/bool, arrays, dictionaries, and nested combinations of them
197+ meta . Should ( ) . ContainKey ( "contextInfo" ) . WhoseValue . With ( value =>
198+ {
199+ string innerJson = value . Should ( ) . BeOfType < JsonElement > ( ) . Subject . ToString ( ) ;
200+
201+ innerJson . Should ( ) . BeJson ( """
202+ {
203+ "source": "form-submission",
204+ "retries": 1,
205+ "authenticated": false
206+ }
207+ """ ) ;
208+ } ) ;
209+ }
147210
148211 private sealed class CapturingDocumentAdapter : IDocumentAdapter
149212 {
0 commit comments