1111
1212namespace Symfony \Bundle \FrameworkBundle \Tests \Functional ;
1313
14+ use Symfony \Component \DomCrawler \Crawler ;
1415use Symfony \Component \HttpFoundation \JsonResponse ;
1516use Symfony \Component \HttpFoundation \Request ;
1617use Symfony \Component \HttpFoundation \Response ;
@@ -89,15 +90,14 @@ public static function mapQueryStringProvider(): iterable
8990 /**
9091 * @dataProvider mapRequestPayloadProvider
9192 */
92- public function testMapRequestPayload (string $ format , array $ parameters , ?string $ content , string $ expectedResponse , int $ expectedStatusCode )
93+ public function testMapRequestPayload (string $ format , array $ parameters , ?string $ content , ? callable $ responseAssertion , int $ expectedStatusCode )
9394 {
9495 $ client = self ::createClient (['test_case ' => 'ApiAttributesTest ' ]);
9596
96- [$ acceptHeader , $ assertion ] = [
97- 'html ' => ['text/html ' , self ::assertStringContainsString (...)],
98- 'json ' => ['application/json ' , self ::assertJsonStringEqualsJsonString (...)],
99- 'xml ' => ['text/xml ' , self ::assertXmlStringEqualsXmlString (...)],
100- 'dummy ' => ['application/dummy ' , self ::assertStringContainsString (...)],
97+ $ acceptHeader = [
98+ 'json ' => 'application/json ' ,
99+ 'xml ' => 'text/xml ' ,
100+ 'dummy ' => 'application/dummy ' ,
101101 ][$ format ];
102102
103103 $ client ->request (
@@ -112,8 +112,8 @@ public function testMapRequestPayload(string $format, array $parameters, ?string
112112 $ response = $ client ->getResponse ();
113113 $ responseContent = $ response ->getContent ();
114114
115- if ($ expectedResponse ) {
116- $ assertion ( $ expectedResponse , $ responseContent );
115+ if (null !== $ responseAssertion ) {
116+ $ responseAssertion ( $ responseContent );
117117 } else {
118118 self ::assertSame ('' , $ responseContent );
119119 }
@@ -127,7 +127,7 @@ public static function mapRequestPayloadProvider(): iterable
127127 'format ' => 'json ' ,
128128 'parameters ' => [],
129129 'content ' => '' ,
130- 'expectedResponse ' => '' ,
130+ 'responseAssertion ' => null ,
131131 'expectedStatusCode ' => 204 ,
132132 ];
133133
@@ -140,12 +140,16 @@ public static function mapRequestPayloadProvider(): iterable
140140 "approved": false
141141 }
142142 JSON,
143- 'expectedResponse ' => <<<'JSON'
144- {
145- "comment": "Hello everyone!",
146- "approved": false
147- }
148- JSON,
143+ 'responseAssertion ' => static function (string $ response ) {
144+ self ::assertJsonStringEqualsJsonString (<<<'JSON'
145+ {
146+ "comment": "Hello everyone!",
147+ "approved": false
148+ }
149+ JSON,
150+ $ response
151+ );
152+ },
149153 'expectedStatusCode ' => 200 ,
150154 ];
151155
@@ -158,22 +162,28 @@ public static function mapRequestPayloadProvider(): iterable
158162 "approved": false,
159163 }
160164 JSON,
161- 'expectedResponse ' => <<<'JSON'
162- {
163- "type": "https:\/\/tools.ietf.org\/html\/rfc2616#section-10",
164- "title": "An error occurred",
165- "status": 400,
166- "detail": "Bad Request"
167- }
168- JSON,
165+ 'responseAssertion ' => static function (string $ response ) {
166+ self ::assertJsonStringEqualsJsonString (<<<'JSON'
167+ {
168+ "type": "https:\/\/tools.ietf.org\/html\/rfc2616#section-10",
169+ "title": "An error occurred",
170+ "status": 400,
171+ "detail": "Bad Request"
172+ }
173+ JSON,
174+ $ response
175+ );
176+ },
169177 'expectedStatusCode ' => 400 ,
170178 ];
171179
172180 yield 'unsupported format ' => [
173181 'format ' => 'dummy ' ,
174182 'parameters ' => [],
175183 'content ' => 'Hello ' ,
176- 'expectedResponse ' => '415 Unsupported Media Type ' ,
184+ 'responseAssertion ' => static function (string $ response ) {
185+ self ::assertStringContainsString ('415 Unsupported Media Type ' , $ response );
186+ },
177187 'expectedStatusCode ' => 415 ,
178188 ];
179189
@@ -186,12 +196,16 @@ public static function mapRequestPayloadProvider(): iterable
186196 <approved>true</approved>
187197 </request>
188198 XML,
189- 'expectedResponse ' => <<<'XML'
190- <response>
191- <comment>Hello everyone!</comment>
192- <approved>1</approved>
193- </response>
194- XML,
199+ 'responseAssertion ' => static function (string $ response ) {
200+ self ::assertXmlStringEqualsXmlString (<<<'XML'
201+ <response>
202+ <comment>Hello everyone!</comment>
203+ <approved>1</approved>
204+ </response>
205+ XML,
206+ $ response
207+ );
208+ },
195209 'expectedStatusCode ' => 200 ,
196210 ];
197211
@@ -204,24 +218,28 @@ public static function mapRequestPayloadProvider(): iterable
204218 "approved": "string instead of bool"
205219 }
206220 JSON,
207- 'expectedResponse ' => <<<'JSON'
208- {
209- "type": "https:\/\/symfony.com\/errors\/validation",
210- "title": "Validation Failed",
211- "status": 422,
212- "detail": "approved: This value should be of type bool.",
213- "violations": [
214- {
215- "propertyPath": "approved",
216- "title": "This value should be of type bool.",
217- "template": "This value should be of type {{ type }}.",
218- "parameters": {
219- "{{ type }}": "bool"
221+ 'responseAssertion ' => static function (string $ response ) {
222+ self ::assertJsonStringEqualsJsonString (<<<'JSON'
223+ {
224+ "type": "https:\/\/symfony.com\/errors\/validation",
225+ "title": "Validation Failed",
226+ "status": 422,
227+ "detail": "approved: This value should be of type bool.",
228+ "violations": [
229+ {
230+ "propertyPath": "approved",
231+ "title": "This value should be of type bool.",
232+ "template": "This value should be of type {{ type }}.",
233+ "parameters": {
234+ "{{ type }}": "bool"
235+ }
220236 }
221- }
222- ]
223- }
224- JSON,
237+ ]
238+ }
239+ JSON,
240+ $ response
241+ );
242+ },
225243 'expectedStatusCode ' => 422 ,
226244 ];
227245
@@ -234,36 +252,20 @@ public static function mapRequestPayloadProvider(): iterable
234252 "approved": true
235253 }
236254 JSON,
237- 'expectedResponse ' => <<<'JSON'
238- {
239- "type": "https:\/\/symfony.com\/errors\/validation",
240- "title": "Validation Failed",
241- "status": 422,
242- "detail": "comment: This value should not be blank.\ncomment: This value is too short. It should have 10 characters or more.",
243- "violations": [
244- {
245- "propertyPath": "comment",
246- "title": "This value should not be blank.",
247- "template": "This value should not be blank.",
248- "parameters": {
249- "{{ value }}": "\"\""
250- },
251- "type": "urn:uuid:c1051bb4-d103-4f74-8988-acbcafc7fdc3"
252- },
253- {
254- "propertyPath": "comment",
255- "title": "This value is too short. It should have 10 characters or more.",
256- "template": "This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.",
257- "parameters": {
258- "{{ value }}": "\"\"",
259- "{{ limit }}": "10",
260- "{{ value_length }}": "0"
261- },
262- "type": "urn:uuid:9ff3fdc4-b214-49db-8718-39c315e33d45"
263- }
264- ]
265- }
266- JSON,
255+ 'responseAssertion ' => static function (string $ response ) {
256+ self ::assertJson ($ response );
257+
258+ $ json = json_decode ($ response , true );
259+
260+ self ::assertSame ('https://symfony.com/errors/validation ' , $ json ['type ' ] ?? null );
261+ self ::assertSame ('Validation Failed ' , $ json ['title ' ] ?? null );
262+ self ::assertSame (422 , $ json ['status ' ] ?? null );
263+ self ::assertSame ("comment: This value should not be blank. \ncomment: This value is too short. It should have 10 characters or more. " , $ json ['detail ' ] ?? null );
264+ self ::assertIsArray ($ json ['violations ' ] ?? null );
265+ self ::assertCount (2 , $ json ['violations ' ]);
266+ self ::assertSame ('urn:uuid:c1051bb4-d103-4f74-8988-acbcafc7fdc3 ' , $ json ['violations ' ][0 ]['type ' ] ?? null );
267+ self ::assertSame ('urn:uuid:9ff3fdc4-b214-49db-8718-39c315e33d45 ' , $ json ['violations ' ][1 ]['type ' ] ?? null );
268+ },
267269 'expectedStatusCode ' => 422 ,
268270 ];
269271
@@ -276,76 +278,54 @@ public static function mapRequestPayloadProvider(): iterable
276278 <approved>false</approved>
277279 </request>
278280 XML,
279- 'expectedResponse ' => <<<'XML'
280- <?xml version="1.0"?>
281- <response>
282- <type>https://symfony.com/errors/validation</type>
283- <title>Validation Failed</title>
284- <status>422</status>
285- <detail>comment: This value is too short. It should have 10 characters or more.</detail>
286- <violations>
287- <propertyPath>comment</propertyPath>
288- <title>This value is too short. It should have 10 characters or more.</title>
289- <template>This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.</template>
290- <parameters>
291- <item key="{{ value }}">"H"</item>
292- <item key="{{ limit }}">10</item>
293- <item key="{{ value_length }}">1</item>
294- </parameters>
295- <type>urn:uuid:9ff3fdc4-b214-49db-8718-39c315e33d45</type>
296- </violations>
297- </response>
298- XML,
281+ 'responseAssertion ' => static function (string $ response ) {
282+ $ crawler = new Crawler ($ response );
283+
284+ self ::assertSame ('https://symfony.com/errors/validation ' , $ crawler ->filterXPath ('response/type ' )->text ());
285+ self ::assertSame ('Validation Failed ' , $ crawler ->filterXPath ('response/title ' )->text ());
286+ self ::assertSame ('422 ' , $ crawler ->filterXPath ('response/status ' )->text ());
287+ self ::assertSame ("comment: This value is too short. It should have 10 characters or more. " , $ crawler ->filterXPath ('response/detail ' )->text ());
288+ self ::assertCount (1 , $ crawler ->filterXPath ('response/violations ' ));
289+ self ::assertSame ('urn:uuid:9ff3fdc4-b214-49db-8718-39c315e33d45 ' , $ crawler ->filterXPath ('response/violations/type ' )->text ());
290+ },
299291 'expectedStatusCode ' => 422 ,
300292 ];
301293
302294 yield 'valid input ' => [
303295 'format ' => 'json ' ,
304296 'input ' => ['comment ' => 'Hello everyone! ' , 'approved ' => '0 ' ],
305297 'content ' => null ,
306- 'expectedResponse ' => <<<'JSON'
307- {
308- "comment": "Hello everyone!",
309- "approved": false
310- }
311- JSON,
298+ 'responseAssertion ' => static function (string $ response ) {
299+ self ::assertJsonStringEqualsJsonString (<<<'JSON'
300+ {
301+ "comment": "Hello everyone!",
302+ "approved": false
303+ }
304+ JSON,
305+ $ response
306+ );
307+ },
312308 'expectedStatusCode ' => 200 ,
313309 ];
314310
315311 yield 'validation error input ' => [
316312 'format ' => 'json ' ,
317313 'input ' => ['comment ' => '' , 'approved ' => '1 ' ],
318314 'content ' => null ,
319- 'expectedResponse ' => <<<'JSON'
320- {
321- "type": "https:\/\/symfony.com\/errors\/validation",
322- "title": "Validation Failed",
323- "status": 422,
324- "detail": "comment: This value should not be blank.\ncomment: This value is too short. It should have 10 characters or more.",
325- "violations": [
326- {
327- "propertyPath": "comment",
328- "title": "This value should not be blank.",
329- "template": "This value should not be blank.",
330- "parameters": {
331- "{{ value }}": "\"\""
332- },
333- "type": "urn:uuid:c1051bb4-d103-4f74-8988-acbcafc7fdc3"
334- },
335- {
336- "propertyPath": "comment",
337- "title": "This value is too short. It should have 10 characters or more.",
338- "template": "This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.",
339- "parameters": {
340- "{{ value }}": "\"\"",
341- "{{ limit }}": "10",
342- "{{ value_length }}": "0"
343- },
344- "type": "urn:uuid:9ff3fdc4-b214-49db-8718-39c315e33d45"
345- }
346- ]
347- }
348- JSON,
315+ 'responseAssertion ' => static function (string $ response ) {
316+ self ::assertJson ($ response );
317+
318+ $ json = json_decode ($ response , true );
319+
320+ self ::assertSame ('https://symfony.com/errors/validation ' , $ json ['type ' ] ?? null );
321+ self ::assertSame ('Validation Failed ' , $ json ['title ' ] ?? null );
322+ self ::assertSame (422 , $ json ['status ' ] ?? null );
323+ self ::assertSame ("comment: This value should not be blank. \ncomment: This value is too short. It should have 10 characters or more. " , $ json ['detail ' ] ?? null );
324+ self ::assertIsArray ($ json ['violations ' ] ?? null );
325+ self ::assertCount (2 , $ json ['violations ' ]);
326+ self ::assertSame ('urn:uuid:c1051bb4-d103-4f74-8988-acbcafc7fdc3 ' , $ json ['violations ' ][0 ]['type ' ] ?? null );
327+ self ::assertSame ('urn:uuid:9ff3fdc4-b214-49db-8718-39c315e33d45 ' , $ json ['violations ' ][1 ]['type ' ] ?? null );
328+ },
349329 'expectedStatusCode ' => 422 ,
350330 ];
351331 }
0 commit comments