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 (
@@ -111,12 +111,7 @@ public function testMapRequestPayload(string $format, array $parameters, ?string
111111
112112 $ response = $ client ->getResponse ();
113113 $ responseContent = $ response ->getContent ();
114-
115- if ($ expectedResponse ) {
116- $ assertion ($ expectedResponse , $ responseContent );
117- } else {
118- self ::assertSame ('' , $ responseContent );
119- }
114+ $ responseAssertion ($ responseContent );
120115
121116 self ::assertSame ($ expectedStatusCode , $ response ->getStatusCode ());
122117 }
@@ -127,7 +122,9 @@ public static function mapRequestPayloadProvider(): iterable
127122 'format ' => 'json ' ,
128123 'parameters ' => [],
129124 'content ' => '' ,
130- 'expectedResponse ' => '' ,
125+ 'responseAssertion ' => static function (string $ response ) {
126+ self ::assertSame ('' , $ response );
127+ },
131128 'expectedStatusCode ' => 204 ,
132129 ];
133130
@@ -140,12 +137,16 @@ public static function mapRequestPayloadProvider(): iterable
140137 "approved": false
141138 }
142139 JSON,
143- 'expectedResponse ' => <<<'JSON'
144- {
145- "comment": "Hello everyone!",
146- "approved": false
147- }
148- JSON,
140+ 'responseAssertion ' => static function (string $ response ) {
141+ self ::assertJsonStringEqualsJsonString (<<<'JSON'
142+ {
143+ "comment": "Hello everyone!",
144+ "approved": false
145+ }
146+ JSON,
147+ $ response
148+ );
149+ },
149150 'expectedStatusCode ' => 200 ,
150151 ];
151152
@@ -158,22 +159,28 @@ public static function mapRequestPayloadProvider(): iterable
158159 "approved": false,
159160 }
160161 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,
162+ 'responseAssertion ' => static function (string $ response ) {
163+ self ::assertJsonStringEqualsJsonString (<<<'JSON'
164+ {
165+ "type": "https:\/\/tools.ietf.org\/html\/rfc2616#section-10",
166+ "title": "An error occurred",
167+ "status": 400,
168+ "detail": "Bad Request"
169+ }
170+ JSON,
171+ $ response
172+ );
173+ },
169174 'expectedStatusCode ' => 400 ,
170175 ];
171176
172177 yield 'unsupported format ' => [
173178 'format ' => 'dummy ' ,
174179 'parameters ' => [],
175180 'content ' => 'Hello ' ,
176- 'expectedResponse ' => '415 Unsupported Media Type ' ,
181+ 'responseAssertion ' => static function (string $ response ) {
182+ self ::assertStringContainsString ('415 Unsupported Media Type ' , $ response );
183+ },
177184 'expectedStatusCode ' => 415 ,
178185 ];
179186
@@ -186,12 +193,16 @@ public static function mapRequestPayloadProvider(): iterable
186193 <approved>true</approved>
187194 </request>
188195 XML,
189- 'expectedResponse ' => <<<'XML'
190- <response>
191- <comment>Hello everyone!</comment>
192- <approved>1</approved>
193- </response>
194- XML,
196+ 'responseAssertion ' => static function (string $ response ) {
197+ self ::assertXmlStringEqualsXmlString (<<<'XML'
198+ <response>
199+ <comment>Hello everyone!</comment>
200+ <approved>1</approved>
201+ </response>
202+ XML,
203+ $ response
204+ );
205+ },
195206 'expectedStatusCode ' => 200 ,
196207 ];
197208
@@ -204,24 +215,28 @@ public static function mapRequestPayloadProvider(): iterable
204215 "approved": "string instead of bool"
205216 }
206217 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"
218+ 'responseAssertion ' => static function (string $ response ) {
219+ self ::assertJsonStringEqualsJsonString (<<<'JSON'
220+ {
221+ "type": "https:\/\/symfony.com\/errors\/validation",
222+ "title": "Validation Failed",
223+ "status": 422,
224+ "detail": "approved: This value should be of type bool.",
225+ "violations": [
226+ {
227+ "propertyPath": "approved",
228+ "title": "This value should be of type bool.",
229+ "template": "This value should be of type {{ type }}.",
230+ "parameters": {
231+ "{{ type }}": "bool"
232+ }
220233 }
221- }
222- ]
223- }
224- JSON,
234+ ]
235+ }
236+ JSON,
237+ $ response
238+ );
239+ },
225240 'expectedStatusCode ' => 422 ,
226241 ];
227242
@@ -234,36 +249,20 @@ public static function mapRequestPayloadProvider(): iterable
234249 "approved": true
235250 }
236251 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,
252+ 'responseAssertion ' => static function (string $ response ) {
253+ self ::assertJson ($ response );
254+
255+ $ json = json_decode ($ response , true );
256+
257+ self ::assertSame ('https://symfony.com/errors/validation ' , $ json ['type ' ] ?? null );
258+ self ::assertSame ('Validation Failed ' , $ json ['title ' ] ?? null );
259+ self ::assertSame (422 , $ json ['status ' ] ?? null );
260+ 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 );
261+ self ::assertIsArray ($ json ['violations ' ] ?? null );
262+ self ::assertCount (2 , $ json ['violations ' ]);
263+ self ::assertSame ('urn:uuid:c1051bb4-d103-4f74-8988-acbcafc7fdc3 ' , $ json ['violations ' ][0 ]['type ' ] ?? null );
264+ self ::assertSame ('urn:uuid:9ff3fdc4-b214-49db-8718-39c315e33d45 ' , $ json ['violations ' ][1 ]['type ' ] ?? null );
265+ },
267266 'expectedStatusCode ' => 422 ,
268267 ];
269268
@@ -276,76 +275,54 @@ public static function mapRequestPayloadProvider(): iterable
276275 <approved>false</approved>
277276 </request>
278277 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,
278+ 'responseAssertion ' => static function (string $ response ) {
279+ $ crawler = new Crawler ($ response );
280+
281+ self ::assertSame ('https://symfony.com/errors/validation ' , $ crawler ->filterXPath ('response/type ' )->text ());
282+ self ::assertSame ('Validation Failed ' , $ crawler ->filterXPath ('response/title ' )->text ());
283+ self ::assertSame ('422 ' , $ crawler ->filterXPath ('response/status ' )->text ());
284+ self ::assertSame ('comment: This value is too short. It should have 10 characters or more. ' , $ crawler ->filterXPath ('response/detail ' )->text ());
285+ self ::assertCount (1 , $ crawler ->filterXPath ('response/violations ' ));
286+ self ::assertSame ('urn:uuid:9ff3fdc4-b214-49db-8718-39c315e33d45 ' , $ crawler ->filterXPath ('response/violations/type ' )->text ());
287+ },
299288 'expectedStatusCode ' => 422 ,
300289 ];
301290
302291 yield 'valid input ' => [
303292 'format ' => 'json ' ,
304293 'input ' => ['comment ' => 'Hello everyone! ' , 'approved ' => '0 ' ],
305294 'content ' => null ,
306- 'expectedResponse ' => <<<'JSON'
307- {
308- "comment": "Hello everyone!",
309- "approved": false
310- }
311- JSON,
295+ 'responseAssertion ' => static function (string $ response ) {
296+ self ::assertJsonStringEqualsJsonString (<<<'JSON'
297+ {
298+ "comment": "Hello everyone!",
299+ "approved": false
300+ }
301+ JSON,
302+ $ response
303+ );
304+ },
312305 'expectedStatusCode ' => 200 ,
313306 ];
314307
315308 yield 'validation error input ' => [
316309 'format ' => 'json ' ,
317310 'input ' => ['comment ' => '' , 'approved ' => '1 ' ],
318311 '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,
312+ 'responseAssertion ' => static function (string $ response ) {
313+ self ::assertJson ($ response );
314+
315+ $ json = json_decode ($ response , true );
316+
317+ self ::assertSame ('https://symfony.com/errors/validation ' , $ json ['type ' ] ?? null );
318+ self ::assertSame ('Validation Failed ' , $ json ['title ' ] ?? null );
319+ self ::assertSame (422 , $ json ['status ' ] ?? null );
320+ 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 );
321+ self ::assertIsArray ($ json ['violations ' ] ?? null );
322+ self ::assertCount (2 , $ json ['violations ' ]);
323+ self ::assertSame ('urn:uuid:c1051bb4-d103-4f74-8988-acbcafc7fdc3 ' , $ json ['violations ' ][0 ]['type ' ] ?? null );
324+ self ::assertSame ('urn:uuid:9ff3fdc4-b214-49db-8718-39c315e33d45 ' , $ json ['violations ' ][1 ]['type ' ] ?? null );
325+ },
349326 'expectedStatusCode ' => 422 ,
350327 ];
351328 }
0 commit comments