99use PHPUnit \Framework \TestCase ;
1010use function array_walk_recursive ;
1111use function collect ;
12- use function http_build_query ;
1312use function implode ;
1413use function is_bool ;
1514use function is_null ;
@@ -46,7 +45,17 @@ final class TestBuilder
4645 /**
4746 * @var Collection
4847 */
49- private $ document ;
48+ private $ headers ;
49+
50+ /**
51+ * @var Collection|null
52+ */
53+ private $ json ;
54+
55+ /**
56+ * @var Collection|null
57+ */
58+ private $ payload ;
5059
5160 /**
5261 * TestBuilder constructor.
@@ -58,7 +67,7 @@ public function __construct($test)
5867 $ this ->test = $ test ;
5968 $ this ->accept = $ this ->contentType = 'application/vnd.api+json ' ;
6069 $ this ->query = collect ();
61- $ this ->document = collect ();
70+ $ this ->headers = collect ();
6271 }
6372
6473 /**
@@ -100,6 +109,28 @@ public function contentType(?string $mediaType): self
100109 return $ this ;
101110 }
102111
112+ /**
113+ * Set the request content type to 'application/x-www-form-urlencoded'.
114+ *
115+ * @return $this
116+ */
117+ public function asFormUrlEncoded (): self
118+ {
119+ return $ this ->contentType ('application/x-www-form-urlencoded ' );
120+ }
121+
122+ /**
123+ * Set the request content type to multipart form data.
124+ *
125+ * @return $this
126+ */
127+ public function asMultiPartFormData (): self
128+ {
129+ return $ this ->contentType (
130+ 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW '
131+ );
132+ }
133+
103134 /**
104135 * Add query parameters to the request.
105136 *
@@ -127,7 +158,7 @@ public function includePaths(string ...$paths): self
127158 }
128159
129160 /**
130- * Set the sparse fieldsets for a resource type.
161+ * Set the sparse field sets for a resource type.
131162 *
132163 * @param string $resourceType
133164 * @param string|string[] $fieldNames
@@ -183,17 +214,40 @@ public function page(iterable $page): self
183214 /**
184215 * Set the data member of the request JSON API document.
185216 *
186- * @param mixed |null $data
217+ * @param iterable |null $data
187218 * @return $this
219+ * @deprecated 4.0 use `withData`.
188220 */
189221 public function data ($ data ): self
222+ {
223+ return $ this ->withData ($ data );
224+ }
225+
226+ /**
227+ * Set the data member of the request JSON API document.
228+ *
229+ * @param iterable|null $data
230+ * @return $this
231+ */
232+ public function withData ($ data ): self
190233 {
191234 if (is_null ($ data )) {
192- $ this ->document ->put ('data ' , null );
193- } else {
194- $ this ->document ->put ('data ' , collect ($ data ));
235+ return $ this ->withJson (['data ' => null ]);
195236 }
196237
238+ return $ this ->withJson (['data ' => collect ($ data )]);
239+ }
240+
241+ /**
242+ * Set the JSON request document.
243+ *
244+ * @param $json
245+ * @return $this
246+ */
247+ public function withJson ($ json ): self
248+ {
249+ $ this ->json = collect ($ json );
250+
197251 return $ this ;
198252 }
199253
@@ -203,10 +257,11 @@ public function data($data): self
203257 * @param mixed $document
204258 * @param string|null $contentType
205259 * @return $this
260+ * @deprecated 4.0
206261 */
207262 public function content ($ document , string $ contentType = null ): self
208263 {
209- $ this ->document = collect ($ document );
264+ $ this ->json = collect ($ document );
210265
211266 if ($ contentType ) {
212267 $ this ->contentType ($ contentType );
@@ -215,6 +270,44 @@ public function content($document, string $contentType = null): self
215270 return $ this ;
216271 }
217272
273+ /**
274+ * Set the request payload for a non-JSON API request.
275+ *
276+ * @param $parameters
277+ * @return $this
278+ */
279+ public function withPayload ($ parameters ): self
280+ {
281+ $ this ->payload = collect ($ parameters );
282+ // we need a content length as it is used by the JSON API implementation to determine if there is body.
283+ $ this ->headers ['CONTENT_LENGTH ' ] = '1 ' ;
284+
285+ return $ this ;
286+ }
287+
288+ /**
289+ * @param iterable $headers
290+ * @return $this
291+ */
292+ public function withHeaders (iterable $ headers ): self
293+ {
294+ $ this ->headers = $ this ->headers ->merge ($ headers );
295+
296+ return $ this ;
297+ }
298+
299+ /**
300+ * @param string $name
301+ * @param string $value
302+ * @return $this
303+ */
304+ public function withHeader (string $ name , string $ value ): self
305+ {
306+ $ this ->headers ->put ($ name , $ value );
307+
308+ return $ this ;
309+ }
310+
218311 /**
219312 * Visit the given URI with a GET request, expecting JSON API content.
220313 *
@@ -251,6 +344,16 @@ public function patch(string $uri, iterable $headers = []): TestResponse
251344 return $ this ->call ('PATCH ' , $ uri , $ headers );
252345 }
253346
347+ /**
348+ * @param string $uri
349+ * @param array|iterable $headers
350+ * @return TestResponse
351+ */
352+ public function put (string $ uri , iterable $ headers = []): TestResponse
353+ {
354+ return $ this ->call ('PUT ' , $ uri , $ headers );
355+ }
356+
254357 /**
255358 * Visit the given URI with a DELETE request, expecting JSON API content.
256359 *
@@ -275,17 +378,24 @@ public function call(string $method, string $uri, iterable $headers = []): TestR
275378 $ uri .= '? ' . $ this ->buildQuery ();
276379 }
277380
278- $ headers = collect ([
279- 'Accept ' => $ this ->accept ,
280- 'CONTENT_TYPE ' => $ this ->contentType ,
281- ])->filter ()->merge ($ headers );
381+ $ headers = $ this ->buildHeaders ($ headers );
282382
283- $ response = TestResponse::cast ($ this ->test ->json (
284- $ method ,
285- $ uri ,
286- $ this ->document ->toArray (),
287- $ headers ->toArray ()
288- ));
383+ if ($ this ->payload ) {
384+ $ response = $ this ->test ->{strtolower ($ method )}(
385+ $ uri ,
386+ $ this ->payload ->toArray (),
387+ $ headers
388+ );
389+ } else {
390+ $ response = $ this ->test ->json (
391+ $ method ,
392+ $ uri ,
393+ $ this ->json ? $ this ->json ->toArray () : [],
394+ $ headers
395+ );
396+ }
397+
398+ $ response = TestResponse::cast ($ response );
289399
290400 if ($ this ->expectedResourceType ) {
291401 $ response ->willSeeResourceType ($ this ->expectedResourceType );
@@ -315,6 +425,19 @@ private function buildQuery(): string
315425 }
316426 });
317427
318- return http_build_query ($ query );
428+ return Arr::query ($ query );
429+ }
430+
431+ /**
432+ * @param iterable $headers
433+ * @return array
434+ */
435+ private function buildHeaders (iterable $ headers ): array
436+ {
437+ return collect (['Accept ' => $ this ->accept , 'CONTENT_TYPE ' => $ this ->contentType ])
438+ ->filter ()
439+ ->merge ($ this ->headers )
440+ ->merge ($ headers )
441+ ->toArray ();
319442 }
320443}
0 commit comments