1414use Symfony \Component \HttpFoundation \RequestStack ;
1515use Symfony \Component \HttpFoundation \Response ;
1616use Symfony \Component \HttpKernel \KernelInterface ;
17+ use Symfony \Component \HttpKernel \TerminableInterface ;
1718use Symfony \Component \Routing \RouterInterface ;
1819use Throwable ;
1920
@@ -23,8 +24,12 @@ class ApiContext implements Context
2324 private StringManager $ stringManager ;
2425 private RouterInterface $ router ;
2526 private RequestStack $ requestStack ;
26- private ?Response $ response ;
27- private KernelInterface $ kernel ;
27+ private Response $ response ;
28+ private KernelInterface &TerminableInterface $ kernel ;
29+
30+ /**
31+ * @var list<ResetManagerInterface>
32+ */
2833 private array $ resetManagers = [];
2934
3035 /**
@@ -38,19 +43,19 @@ class ApiContext implements Context
3843 protected array $ serverParams = [];
3944
4045 /**
41- * @var array<mixed> $requestParams
46+ * @var array<string, mixed> $requestParams
4247 */
4348 protected array $ requestParams = [];
4449
4550 /**
46- * @var array<mixed > $savedValues
51+ * @var array<string, string|list<string> > $savedValues
4752 */
4853 protected array $ savedValues = [];
4954
5055 public function __construct (
5156 RouterInterface $ router ,
5257 RequestStack $ requestStack ,
53- KernelInterface $ kernel
58+ KernelInterface & TerminableInterface $ kernel
5459 ) {
5560 $ this ->router = $ router ;
5661 $ this ->requestStack = $ requestStack ;
@@ -116,8 +121,13 @@ public function theRequestContainsParams(PyStringNode $params): void
116121
117122 $ newRequestParams = (array ) json_decode ($ processedParams , true , 512 , JSON_THROW_ON_ERROR );
118123 $ newRequestParams = $ this ->convertRunnableCodeParams ($ newRequestParams );
119- $ this ->requestParams = array_merge ($ this ->requestParams , $ newRequestParams );
120- $ this ->savedValues = array_merge ($ this ->savedValues , $ newRequestParams );
124+ /** @var array<string, mixed> $requestParams */
125+ $ requestParams = array_merge ($ this ->requestParams , $ newRequestParams );
126+ $ this ->requestParams = $ requestParams ;
127+
128+ /** @var array<string, mixed> $savedValues */
129+ $ savedValues = array_merge ($ this ->savedValues , $ newRequestParams );
130+ $ this ->savedValues = $ savedValues ;
121131 }
122132
123133 /**
@@ -130,19 +140,32 @@ public function iSendRequestToRoute(
130140 $ routeParams = $ this ->popRouteAttributesFromRequestParams ($ route , $ this ->requestParams );
131141 $ postFields = [];
132142 $ queryString = '' ;
143+ $ content = null ;
133144
134145 $ url = $ this ->router ->generate ($ route , $ routeParams );
135- $ url = preg_replace ('|^/app[^\ .]*\.php| ' , '' , $ url );
146+ $ url = preg_replace ('|^/app[^.]*\.php| ' , '' , $ url );
136147
137148 if (Request::METHOD_GET === $ method ) {
138149 $ queryString = http_build_query ($ this ->requestParams );
139150 }
140151
141152 if (in_array ($ method , [Request::METHOD_POST , Request::METHOD_PATCH , Request::METHOD_PUT ], true )) {
142- $ postFields = $ this ->requestParams ;
153+ $ isJsonRequest = array_key_exists ('Content-Type ' , $ this ->headers ) &&
154+ str_contains (strtolower ($ this ->headers ['Content-Type ' ]), 'application/json ' );
155+
156+ if ($ isJsonRequest ) {
157+ $ content = json_encode ($ this ->requestParams , JSON_THROW_ON_ERROR );
158+ } else {
159+ $ postFields = $ this ->requestParams ;
160+ }
143161 }
144162
145- $ request = Request::create ($ url . '? ' . $ queryString , $ method , $ postFields );
163+ $ request = Request::create (
164+ uri: $ url . '? ' . $ queryString ,
165+ method: $ method ,
166+ parameters: $ postFields ,
167+ content: $ content
168+ );
146169 $ request ->headers ->add ($ this ->headers );
147170 $ request ->server ->add ($ this ->serverParams );
148171
@@ -171,19 +194,21 @@ private function handleRequestWithKernel(Request $request): Response
171194 }
172195
173196 /**
174- * @param array<string,string > $requestParams
197+ * @param array<string, mixed > $requestParams
175198 *
176- * @return array<string,string >
199+ * @return array<string, mixed >
177200 */
178201 private function popRouteAttributesFromRequestParams (string $ route , array &$ requestParams ): array
179202 {
180203 $ routeParams = [];
204+ $ routeDecl = $ this ->router ->getRouteCollection ()->get ($ route );
181205
182- if (is_array ($ requestParams ) && ($ routeDecl = $ this ->router ->getRouteCollection ()->get ($ route ))) {
206+ if ($ routeDecl !== null ) {
207+ /** @var array<string, string> $requirements */
183208 $ requirements = $ routeDecl ->getRequirements ();
184209
185210 foreach ($ requirements as $ attribute => $ requirement ) {
186- if (isset ($ requestParams [$ attribute ]) && strpos ($ attribute , '_ ' ) !== 0 ) {
211+ if (isset ($ requestParams [$ attribute ]) && ! str_starts_with ($ attribute , '_ ' )) {
187212 $ routeParams [$ attribute ] = $ requestParams [$ attribute ];
188213 unset($ requestParams [$ attribute ]);
189214 }
@@ -282,15 +307,20 @@ public function responseShouldBeJsonWithVariableFields(string $variableFields, P
282307 $ this ->compareStructureResponse ($ variableFields , $ string , $ this ->getResponse ()->getContent ());
283308 }
284309
285- protected function compareStructureResponse (string $ variableFields , PyStringNode $ string , string $ actualJSON ): void
286- {
310+ protected function compareStructureResponse (
311+ string $ variableFieldsString ,
312+ PyStringNode $ string ,
313+ string $ actualJSON
314+ ): void {
287315 if ($ actualJSON === '' ) {
288316 throw new RuntimeException ('Response is not JSON ' );
289317 }
290318
291- $ expectedResponse = (array ) json_decode (trim ($ string ->getRaw ()), true );
292- $ actualResponse = (array ) json_decode ($ actualJSON , true );
293- $ variableFields = $ variableFields ? array_map ('trim ' , explode (', ' , $ variableFields )) : [];
319+ $ expectedResponse = json_decode (trim ($ string ->getRaw ()), true , 512 , JSON_THROW_ON_ERROR );
320+ $ actualResponse = json_decode ($ actualJSON , true , 512 , JSON_THROW_ON_ERROR );
321+ $ variableFields = $ variableFieldsString
322+ ? array_map ('trim ' , explode (', ' , $ variableFieldsString ))
323+ : [];
294324
295325 if (!$ this ->similarArrayManager ->isArraysSimilar ($ expectedResponse , $ actualResponse , $ variableFields )) {
296326 $ prettyJSON = json_encode ($ actualResponse , JSON_PRETTY_PRINT );
@@ -343,7 +373,7 @@ protected function checkResponseHeader(string $headerName, string $headerValue):
343373
344374 $ responseHeaderValue = $ response ->headers ->get ($ givenHeaderName );
345375
346- if (null === $ responseHeaderValue || ! substr_count ($ responseHeaderValue , $ givenHeaderValue ) > 0 ) {
376+ if (null === $ responseHeaderValue || substr_count ($ responseHeaderValue , $ givenHeaderValue ) < 1 ) {
347377 $ message = sprintf (
348378 'Response header %s does not match. Expected: %s, given value: %s ' ,
349379 $ givenHeaderName ,
@@ -413,10 +443,6 @@ private function resetRequestOptions(): void
413443
414444 protected function getResponse (): Response
415445 {
416- if ($ this ->response === null ) {
417- throw new RuntimeException ('Response is null. ' );
418- }
419-
420446 return $ this ->response ;
421447 }
422448
0 commit comments