Passed
Push — develop ( 30cf64...589229 )
by Guillaume
06:18 queued 04:10
created

TestResponse   F

Complexity

Total Complexity 134

Size/Duplication

Total Lines 1275
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 369
dl 0
loc 1275
rs 2
c 0
b 0
f 0
wmc 134

How to fix   Complexity   

Complex Class

Complex classes like TestResponse often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TestResponse, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Illuminate\Foundation\Testing;
4
5
use ArrayAccess;
6
use Closure;
7
use Illuminate\Contracts\View\View;
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Foundation\Testing\Assert as PHPUnit;
10
use Illuminate\Foundation\Testing\Constraints\SeeInOrder;
11
use Illuminate\Support\Arr;
12
use Illuminate\Support\Carbon;
13
use Illuminate\Support\Str;
14
use Illuminate\Support\Traits\Macroable;
15
use Illuminate\Support\Traits\Tappable;
16
use LogicException;
17
use Symfony\Component\HttpFoundation\StreamedResponse;
18
19
/**
20
 * @mixin \Illuminate\Http\Response
21
 */
22
class TestResponse implements ArrayAccess
23
{
24
    use Tappable, Macroable {
25
        __call as macroCall;
26
    }
27
28
    /**
29
     * The response to delegate to.
30
     *
31
     * @var \Illuminate\Http\Response
32
     */
33
    public $baseResponse;
34
35
    /**
36
     * The streamed content of the response.
37
     *
38
     * @var string
39
     */
40
    protected $streamedContent;
41
42
    /**
43
     * Create a new test response instance.
44
     *
45
     * @param  \Illuminate\Http\Response  $response
46
     * @return void
47
     */
48
    public function __construct($response)
49
    {
50
        $this->baseResponse = $response;
51
    }
52
53
    /**
54
     * Create a new TestResponse from another response.
55
     *
56
     * @param  \Illuminate\Http\Response  $response
57
     * @return static
58
     */
59
    public static function fromBaseResponse($response)
60
    {
61
        return new static($response);
62
    }
63
64
    /**
65
     * Assert that the response has a successful status code.
66
     *
67
     * @return $this
68
     */
69
    public function assertSuccessful()
70
    {
71
        PHPUnit::assertTrue(
72
            $this->isSuccessful(),
73
            'Response status code ['.$this->getStatusCode().'] is not a successful status code.'
74
        );
75
76
        return $this;
77
    }
78
79
    /**
80
     * Assert that the response has a 200 status code.
81
     *
82
     * @return $this
83
     */
84
    public function assertOk()
85
    {
86
        PHPUnit::assertTrue(
87
            $this->isOk(),
88
            'Response status code ['.$this->getStatusCode().'] does not match expected 200 status code.'
89
        );
90
91
        return $this;
92
    }
93
94
    /**
95
     * Assert that the response has a 201 status code.
96
     *
97
     * @return $this
98
     */
99
    public function assertCreated()
100
    {
101
        $actual = $this->getStatusCode();
102
103
        PHPUnit::assertTrue(
104
            201 === $actual,
105
            'Response status code ['.$actual.'] does not match expected 201 status code.'
106
        );
107
108
        return $this;
109
    }
110
111
    /**
112
     * Assert that the response has the given status code and no content.
113
     *
114
     * @param  int  $status
115
     * @return $this
116
     */
117
    public function assertNoContent($status = 204)
118
    {
119
        $this->assertStatus($status);
120
121
        PHPUnit::assertEmpty($this->getContent(), 'Response content is not empty.');
122
123
        return $this;
124
    }
125
126
    /**
127
     * Assert that the response has a not found status code.
128
     *
129
     * @return $this
130
     */
131
    public function assertNotFound()
132
    {
133
        PHPUnit::assertTrue(
134
            $this->isNotFound(),
135
            'Response status code ['.$this->getStatusCode().'] is not a not found status code.'
136
        );
137
138
        return $this;
139
    }
140
141
    /**
142
     * Assert that the response has a forbidden status code.
143
     *
144
     * @return $this
145
     */
146
    public function assertForbidden()
147
    {
148
        PHPUnit::assertTrue(
149
            $this->isForbidden(),
150
            'Response status code ['.$this->getStatusCode().'] is not a forbidden status code.'
151
        );
152
153
        return $this;
154
    }
155
156
    /**
157
     * Assert that the response has an unauthorized status code.
158
     *
159
     * @return $this
160
     */
161
    public function assertUnauthorized()
162
    {
163
        $actual = $this->getStatusCode();
164
165
        PHPUnit::assertTrue(
166
            401 === $actual,
167
            'Response status code ['.$actual.'] is not an unauthorized status code.'
168
        );
169
170
        return $this;
171
    }
172
173
    /**
174
     * Assert that the response has the given status code.
175
     *
176
     * @param  int  $status
177
     * @return $this
178
     */
179
    public function assertStatus($status)
180
    {
181
        $actual = $this->getStatusCode();
182
183
        PHPUnit::assertTrue(
184
            $actual === $status,
185
            "Expected status code {$status} but received {$actual}."
186
        );
187
188
        return $this;
189
    }
190
191
    /**
192
     * Assert whether the response is redirecting to a given URI.
193
     *
194
     * @param  string|null  $uri
195
     * @return $this
196
     */
197
    public function assertRedirect($uri = null)
198
    {
199
        PHPUnit::assertTrue(
200
            $this->isRedirect(), 'Response status code ['.$this->getStatusCode().'] is not a redirect status code.'
201
        );
202
203
        if (! is_null($uri)) {
204
            $this->assertLocation($uri);
205
        }
206
207
        return $this;
208
    }
209
210
    /**
211
     * Asserts that the response contains the given header and equals the optional value.
212
     *
213
     * @param  string  $headerName
214
     * @param  mixed  $value
215
     * @return $this
216
     */
217
    public function assertHeader($headerName, $value = null)
218
    {
219
        PHPUnit::assertTrue(
220
            $this->headers->has($headerName), "Header [{$headerName}] not present on response."
221
        );
222
223
        $actual = $this->headers->get($headerName);
224
225
        if (! is_null($value)) {
226
            PHPUnit::assertEquals(
227
                $value, $this->headers->get($headerName),
228
                "Header [{$headerName}] was found, but value [{$actual}] does not match [{$value}]."
229
            );
230
        }
231
232
        return $this;
233
    }
234
235
    /**
236
     * Asserts that the response does not contains the given header.
237
     *
238
     * @param  string  $headerName
239
     * @return $this
240
     */
241
    public function assertHeaderMissing($headerName)
242
    {
243
        PHPUnit::assertFalse(
244
            $this->headers->has($headerName), "Unexpected header [{$headerName}] is present on response."
245
        );
246
247
        return $this;
248
    }
249
250
    /**
251
     * Assert that the current location header matches the given URI.
252
     *
253
     * @param  string  $uri
254
     * @return $this
255
     */
256
    public function assertLocation($uri)
257
    {
258
        PHPUnit::assertEquals(
259
            app('url')->to($uri), app('url')->to($this->headers->get('Location'))
260
        );
261
262
        return $this;
263
    }
264
265
    /**
266
     * Asserts that the response contains the given cookie and equals the optional value.
267
     *
268
     * @param  string  $cookieName
269
     * @param  mixed  $value
270
     * @return $this
271
     */
272
    public function assertPlainCookie($cookieName, $value = null)
273
    {
274
        $this->assertCookie($cookieName, $value, false);
275
276
        return $this;
277
    }
278
279
    /**
280
     * Asserts that the response contains the given cookie and equals the optional value.
281
     *
282
     * @param  string  $cookieName
283
     * @param  mixed  $value
284
     * @param  bool  $encrypted
285
     * @param  bool  $unserialize
286
     * @return $this
287
     */
288
    public function assertCookie($cookieName, $value = null, $encrypted = true, $unserialize = false)
289
    {
290
        PHPUnit::assertNotNull(
291
            $cookie = $this->getCookie($cookieName),
292
            "Cookie [{$cookieName}] not present on response."
293
        );
294
295
        if (! $cookie || is_null($value)) {
296
            return $this;
297
        }
298
299
        $cookieValue = $cookie->getValue();
300
301
        $actual = $encrypted
302
            ? app('encrypter')->decrypt($cookieValue, $unserialize) : $cookieValue;
303
304
        PHPUnit::assertEquals(
305
            $value, $actual,
306
            "Cookie [{$cookieName}] was found, but value [{$actual}] does not match [{$value}]."
307
        );
308
309
        return $this;
310
    }
311
312
    /**
313
     * Asserts that the response contains the given cookie and is expired.
314
     *
315
     * @param  string  $cookieName
316
     * @return $this
317
     */
318
    public function assertCookieExpired($cookieName)
319
    {
320
        PHPUnit::assertNotNull(
321
            $cookie = $this->getCookie($cookieName),
322
            "Cookie [{$cookieName}] not present on response."
323
        );
324
325
        $expiresAt = Carbon::createFromTimestamp($cookie->getExpiresTime());
326
327
        PHPUnit::assertTrue(
328
            $expiresAt->lessThan(Carbon::now()),
329
            "Cookie [{$cookieName}] is not expired, it expires at [{$expiresAt}]."
330
        );
331
332
        return $this;
333
    }
334
335
    /**
336
     * Asserts that the response contains the given cookie and is not expired.
337
     *
338
     * @param  string  $cookieName
339
     * @return $this
340
     */
341
    public function assertCookieNotExpired($cookieName)
342
    {
343
        PHPUnit::assertNotNull(
344
            $cookie = $this->getCookie($cookieName),
345
            "Cookie [{$cookieName}] not present on response."
346
        );
347
348
        $expiresAt = Carbon::createFromTimestamp($cookie->getExpiresTime());
349
350
        PHPUnit::assertTrue(
351
            $expiresAt->greaterThan(Carbon::now()),
352
            "Cookie [{$cookieName}] is expired, it expired at [{$expiresAt}]."
353
        );
354
355
        return $this;
356
    }
357
358
    /**
359
     * Asserts that the response does not contains the given cookie.
360
     *
361
     * @param  string  $cookieName
362
     * @return $this
363
     */
364
    public function assertCookieMissing($cookieName)
365
    {
366
        PHPUnit::assertNull(
367
            $this->getCookie($cookieName),
368
            "Cookie [{$cookieName}] is present on response."
369
        );
370
371
        return $this;
372
    }
373
374
    /**
375
     * Get the given cookie from the response.
376
     *
377
     * @param  string  $cookieName
378
     * @return \Symfony\Component\HttpFoundation\Cookie|null
379
     */
380
    protected function getCookie($cookieName)
381
    {
382
        foreach ($this->headers->getCookies() as $cookie) {
383
            if ($cookie->getName() === $cookieName) {
384
                return $cookie;
385
            }
386
        }
387
    }
388
389
    /**
390
     * Assert that the given string is contained within the response.
391
     *
392
     * @param  string  $value
393
     * @return $this
394
     */
395
    public function assertSee($value)
396
    {
397
        PHPUnit::assertStringContainsString((string) $value, $this->getContent());
398
399
        return $this;
400
    }
401
402
    /**
403
     * Assert that the given strings are contained in order within the response.
404
     *
405
     * @param  array  $values
406
     * @return $this
407
     */
408
    public function assertSeeInOrder(array $values)
409
    {
410
        PHPUnit::assertThat($values, new SeeInOrder($this->getContent()));
411
412
        return $this;
413
    }
414
415
    /**
416
     * Assert that the given string is contained within the response text.
417
     *
418
     * @param  string  $value
419
     * @return $this
420
     */
421
    public function assertSeeText($value)
422
    {
423
        PHPUnit::assertStringContainsString((string) $value, strip_tags($this->getContent()));
424
425
        return $this;
426
    }
427
428
    /**
429
     * Assert that the given strings are contained in order within the response text.
430
     *
431
     * @param  array  $values
432
     * @return $this
433
     */
434
    public function assertSeeTextInOrder(array $values)
435
    {
436
        PHPUnit::assertThat($values, new SeeInOrder(strip_tags($this->getContent())));
437
438
        return $this;
439
    }
440
441
    /**
442
     * Assert that the given string is not contained within the response.
443
     *
444
     * @param  string  $value
445
     * @return $this
446
     */
447
    public function assertDontSee($value)
448
    {
449
        PHPUnit::assertStringNotContainsString((string) $value, $this->getContent());
450
451
        return $this;
452
    }
453
454
    /**
455
     * Assert that the given string is not contained within the response text.
456
     *
457
     * @param  string  $value
458
     * @return $this
459
     */
460
    public function assertDontSeeText($value)
461
    {
462
        PHPUnit::assertStringNotContainsString((string) $value, strip_tags($this->getContent()));
463
464
        return $this;
465
    }
466
467
    /**
468
     * Assert that the response is a superset of the given JSON.
469
     *
470
     * @param  array  $data
471
     * @param  bool  $strict
472
     * @return $this
473
     */
474
    public function assertJson(array $data, $strict = false)
475
    {
476
        PHPUnit::assertArraySubset(
477
            $data, $this->decodeResponseJson(), $strict, $this->assertJsonMessage($data)
478
        );
479
480
        return $this;
481
    }
482
483
    /**
484
     * Get the assertion message for assertJson.
485
     *
486
     * @param  array  $data
487
     * @return string
488
     */
489
    protected function assertJsonMessage(array $data)
490
    {
491
        $expected = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
492
493
        $actual = json_encode($this->decodeResponseJson(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
494
495
        return 'Unable to find JSON: '.PHP_EOL.PHP_EOL.
496
            "[{$expected}]".PHP_EOL.PHP_EOL.
497
            'within response JSON:'.PHP_EOL.PHP_EOL.
498
            "[{$actual}].".PHP_EOL.PHP_EOL;
499
    }
500
501
    /**
502
     * Assert that the expected value exists at the given path in the response.
503
     *
504
     * @param  string  $path
505
     * @param  mixed  $expect
506
     * @param  bool  $strict
507
     * @return $this
508
     */
509
    public function assertJsonPath($path, $expect, $strict = false)
510
    {
511
        if ($strict) {
512
            PHPUnit::assertSame($expect, $this->json($path));
513
        } else {
514
            PHPUnit::assertEquals($expect, $this->json($path));
515
        }
516
517
        return $this;
518
    }
519
520
    /**
521
     * Assert that the response has the exact given JSON.
522
     *
523
     * @param  array  $data
524
     * @return $this
525
     */
526
    public function assertExactJson(array $data)
527
    {
528
        $actual = json_encode(Arr::sortRecursive(
529
            (array) $this->decodeResponseJson()
530
        ));
531
532
        PHPUnit::assertEquals(json_encode(Arr::sortRecursive($data)), $actual);
533
534
        return $this;
535
    }
536
537
    /**
538
     * Assert that the response contains the given JSON fragment.
539
     *
540
     * @param  array  $data
541
     * @return $this
542
     */
543
    public function assertJsonFragment(array $data)
544
    {
545
        $actual = json_encode(Arr::sortRecursive(
546
            (array) $this->decodeResponseJson()
547
        ));
548
549
        foreach (Arr::sortRecursive($data) as $key => $value) {
550
            $expected = $this->jsonSearchStrings($key, $value);
551
552
            PHPUnit::assertTrue(
553
                Str::contains($actual, $expected),
554
                'Unable to find JSON fragment: '.PHP_EOL.PHP_EOL.
555
                '['.json_encode([$key => $value]).']'.PHP_EOL.PHP_EOL.
556
                'within'.PHP_EOL.PHP_EOL.
557
                "[{$actual}]."
558
            );
559
        }
560
561
        return $this;
562
    }
563
564
    /**
565
     * Assert that the response does not contain the given JSON fragment.
566
     *
567
     * @param  array  $data
568
     * @param  bool  $exact
569
     * @return $this
570
     */
571
    public function assertJsonMissing(array $data, $exact = false)
572
    {
573
        if ($exact) {
574
            return $this->assertJsonMissingExact($data);
575
        }
576
577
        $actual = json_encode(Arr::sortRecursive(
578
            (array) $this->decodeResponseJson()
579
        ));
580
581
        foreach (Arr::sortRecursive($data) as $key => $value) {
582
            $unexpected = $this->jsonSearchStrings($key, $value);
583
584
            PHPUnit::assertFalse(
585
                Str::contains($actual, $unexpected),
586
                'Found unexpected JSON fragment: '.PHP_EOL.PHP_EOL.
587
                '['.json_encode([$key => $value]).']'.PHP_EOL.PHP_EOL.
588
                'within'.PHP_EOL.PHP_EOL.
589
                "[{$actual}]."
590
            );
591
        }
592
593
        return $this;
594
    }
595
596
    /**
597
     * Assert that the response does not contain the exact JSON fragment.
598
     *
599
     * @param  array  $data
600
     * @return $this
601
     */
602
    public function assertJsonMissingExact(array $data)
603
    {
604
        $actual = json_encode(Arr::sortRecursive(
605
            (array) $this->decodeResponseJson()
606
        ));
607
608
        foreach (Arr::sortRecursive($data) as $key => $value) {
609
            $unexpected = $this->jsonSearchStrings($key, $value);
610
611
            if (! Str::contains($actual, $unexpected)) {
612
                return $this;
613
            }
614
        }
615
616
        PHPUnit::fail(
617
            'Found unexpected JSON fragment: '.PHP_EOL.PHP_EOL.
618
            '['.json_encode($data).']'.PHP_EOL.PHP_EOL.
619
            'within'.PHP_EOL.PHP_EOL.
620
            "[{$actual}]."
621
        );
622
    }
623
624
    /**
625
     * Get the strings we need to search for when examining the JSON.
626
     *
627
     * @param  string  $key
628
     * @param  string  $value
629
     * @return array
630
     */
631
    protected function jsonSearchStrings($key, $value)
632
    {
633
        $needle = substr(json_encode([$key => $value]), 1, -1);
634
635
        return [
636
            $needle.']',
637
            $needle.'}',
638
            $needle.',',
639
        ];
640
    }
641
642
    /**
643
     * Assert that the response has a given JSON structure.
644
     *
645
     * @param  array|null  $structure
646
     * @param  array|null  $responseData
647
     * @return $this
648
     */
649
    public function assertJsonStructure(array $structure = null, $responseData = null)
650
    {
651
        if (is_null($structure)) {
652
            return $this->assertExactJson($this->json());
653
        }
654
655
        if (is_null($responseData)) {
656
            $responseData = $this->decodeResponseJson();
657
        }
658
659
        foreach ($structure as $key => $value) {
660
            if (is_array($value) && $key === '*') {
661
                PHPUnit::assertIsArray($responseData);
662
663
                foreach ($responseData as $responseDataItem) {
664
                    $this->assertJsonStructure($structure['*'], $responseDataItem);
665
                }
666
            } elseif (is_array($value)) {
667
                PHPUnit::assertArrayHasKey($key, $responseData);
668
669
                $this->assertJsonStructure($structure[$key], $responseData[$key]);
670
            } else {
671
                PHPUnit::assertArrayHasKey($value, $responseData);
672
            }
673
        }
674
675
        return $this;
676
    }
677
678
    /**
679
     * Assert that the response JSON has the expected count of items at the given key.
680
     *
681
     * @param  int  $count
682
     * @param  string|null  $key
683
     * @return $this
684
     */
685
    public function assertJsonCount(int $count, $key = null)
686
    {
687
        if ($key) {
688
            PHPUnit::assertCount(
689
                $count, data_get($this->json(), $key),
690
                "Failed to assert that the response count matched the expected {$count}"
691
            );
692
693
            return $this;
694
        }
695
696
        PHPUnit::assertCount($count,
697
            $this->json(),
698
            "Failed to assert that the response count matched the expected {$count}"
699
        );
700
701
        return $this;
702
    }
703
704
    /**
705
     * Assert that the response has the given JSON validation errors.
706
     *
707
     * @param  string|array  $errors
708
     * @param  string  $responseKey
709
     * @return $this
710
     */
711
    public function assertJsonValidationErrors($errors, $responseKey = 'errors')
712
    {
713
        $errors = Arr::wrap($errors);
714
715
        PHPUnit::assertNotEmpty($errors, 'No validation errors were provided.');
716
717
        $jsonErrors = $this->json()[$responseKey] ?? [];
718
719
        $errorMessage = $jsonErrors
720
                ? 'Response has the following JSON validation errors:'.
721
                        PHP_EOL.PHP_EOL.json_encode($jsonErrors, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE).PHP_EOL
722
                : 'Response does not have JSON validation errors.';
723
724
        foreach ($errors as $key => $value) {
725
            PHPUnit::assertArrayHasKey(
726
                (is_int($key)) ? $value : $key,
727
                $jsonErrors,
728
                "Failed to find a validation error in the response for key: '{$value}'".PHP_EOL.PHP_EOL.$errorMessage
729
            );
730
731
            if (! is_int($key)) {
732
                $hasError = false;
733
734
                foreach (Arr::wrap($jsonErrors[$key]) as $jsonErrorMessage) {
735
                    if (Str::contains($jsonErrorMessage, $value)) {
736
                        $hasError = true;
737
738
                        break;
739
                    }
740
                }
741
742
                if (! $hasError) {
743
                    PHPUnit::fail(
744
                        "Failed to find a validation error in the response for key and message: '$key' => '$value'".PHP_EOL.PHP_EOL.$errorMessage
745
                    );
746
                }
747
            }
748
        }
749
750
        return $this;
751
    }
752
753
    /**
754
     * Assert that the response has no JSON validation errors for the given keys.
755
     *
756
     * @param  string|array|null  $keys
757
     * @param  string  $responseKey
758
     * @return $this
759
     */
760
    public function assertJsonMissingValidationErrors($keys = null, $responseKey = 'errors')
761
    {
762
        if ($this->getContent() === '') {
763
            PHPUnit::assertTrue(true);
764
765
            return $this;
766
        }
767
768
        $json = $this->json();
769
770
        if (! array_key_exists($responseKey, $json)) {
771
            PHPUnit::assertArrayNotHasKey($responseKey, $json);
772
773
            return $this;
774
        }
775
776
        $errors = $json[$responseKey];
777
778
        if (is_null($keys) && count($errors) > 0) {
779
            PHPUnit::fail(
780
                'Response has unexpected validation errors: '.PHP_EOL.PHP_EOL.
781
                json_encode($errors, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
782
            );
783
        }
784
785
        foreach (Arr::wrap($keys) as $key) {
786
            PHPUnit::assertFalse(
787
                isset($errors[$key]),
788
                "Found unexpected validation error for key: '{$key}'"
789
            );
790
        }
791
792
        return $this;
793
    }
794
795
    /**
796
     * Validate and return the decoded response JSON.
797
     *
798
     * @param  string|null  $key
799
     * @return mixed
800
     */
801
    public function decodeResponseJson($key = null)
802
    {
803
        $decodedResponse = json_decode($this->getContent(), true);
804
805
        if (is_null($decodedResponse) || $decodedResponse === false) {
806
            if ($this->exception) {
807
                throw $this->exception;
808
            } else {
809
                PHPUnit::fail('Invalid JSON was returned from the route.');
810
            }
811
        }
812
813
        return data_get($decodedResponse, $key);
814
    }
815
816
    /**
817
     * Validate and return the decoded response JSON.
818
     *
819
     * @param  string|null  $key
820
     * @return mixed
821
     */
822
    public function json($key = null)
823
    {
824
        return $this->decodeResponseJson($key);
825
    }
826
827
    /**
828
     * Assert that the response view equals the given value.
829
     *
830
     * @param  string  $value
831
     * @return $this
832
     */
833
    public function assertViewIs($value)
834
    {
835
        $this->ensureResponseHasView();
836
837
        PHPUnit::assertEquals($value, $this->original->name());
838
839
        return $this;
840
    }
841
842
    /**
843
     * Assert that the response view has a given piece of bound data.
844
     *
845
     * @param  string|array  $key
846
     * @param  mixed  $value
847
     * @return $this
848
     */
849
    public function assertViewHas($key, $value = null)
850
    {
851
        if (is_array($key)) {
852
            return $this->assertViewHasAll($key);
853
        }
854
855
        $this->ensureResponseHasView();
856
857
        if (is_null($value)) {
858
            PHPUnit::assertArrayHasKey($key, $this->original->gatherData());
859
        } elseif ($value instanceof Closure) {
860
            PHPUnit::assertTrue($value(Arr::get($this->original->gatherData(), $key)));
861
        } elseif ($value instanceof Model) {
862
            PHPUnit::assertTrue($value->is(Arr::get($this->original->gatherData(), $key)));
863
        } else {
864
            PHPUnit::assertEquals($value, Arr::get($this->original->gatherData(), $key));
865
        }
866
867
        return $this;
868
    }
869
870
    /**
871
     * Assert that the response view has a given list of bound data.
872
     *
873
     * @param  array  $bindings
874
     * @return $this
875
     */
876
    public function assertViewHasAll(array $bindings)
877
    {
878
        foreach ($bindings as $key => $value) {
879
            if (is_int($key)) {
880
                $this->assertViewHas($value);
881
            } else {
882
                $this->assertViewHas($key, $value);
883
            }
884
        }
885
886
        return $this;
887
    }
888
889
    /**
890
     * Get a piece of data from the original view.
891
     *
892
     * @param  string  $key
893
     * @return mixed
894
     */
895
    public function viewData($key)
896
    {
897
        $this->ensureResponseHasView();
898
899
        return $this->original->gatherData()[$key];
900
    }
901
902
    /**
903
     * Assert that the response view is missing a piece of bound data.
904
     *
905
     * @param  string  $key
906
     * @return $this
907
     */
908
    public function assertViewMissing($key)
909
    {
910
        $this->ensureResponseHasView();
911
912
        PHPUnit::assertArrayNotHasKey($key, $this->original->gatherData());
913
914
        return $this;
915
    }
916
917
    /**
918
     * Ensure that the response has a view as its original content.
919
     *
920
     * @return $this
921
     */
922
    protected function ensureResponseHasView()
923
    {
924
        if (! isset($this->original) || ! $this->original instanceof View) {
925
            return PHPUnit::fail('The response is not a view.');
926
        }
927
928
        return $this;
929
    }
930
931
    /**
932
     * Assert that the session has a given value.
933
     *
934
     * @param  string|array  $key
935
     * @param  mixed  $value
936
     * @return $this
937
     */
938
    public function assertSessionHas($key, $value = null)
939
    {
940
        if (is_array($key)) {
941
            return $this->assertSessionHasAll($key);
942
        }
943
944
        if (is_null($value)) {
945
            PHPUnit::assertTrue(
946
                $this->session()->has($key),
947
                "Session is missing expected key [{$key}]."
948
            );
949
        } elseif ($value instanceof Closure) {
950
            PHPUnit::assertTrue($value($this->session()->get($key)));
951
        } else {
952
            PHPUnit::assertEquals($value, $this->session()->get($key));
953
        }
954
955
        return $this;
956
    }
957
958
    /**
959
     * Assert that the session has a given list of values.
960
     *
961
     * @param  array  $bindings
962
     * @return $this
963
     */
964
    public function assertSessionHasAll(array $bindings)
965
    {
966
        foreach ($bindings as $key => $value) {
967
            if (is_int($key)) {
968
                $this->assertSessionHas($value);
969
            } else {
970
                $this->assertSessionHas($key, $value);
971
            }
972
        }
973
974
        return $this;
975
    }
976
977
    /**
978
     * Assert that the session has a given value in the flashed input array.
979
     *
980
     * @param  string|array  $key
981
     * @param  mixed  $value
982
     * @return $this
983
     */
984
    public function assertSessionHasInput($key, $value = null)
985
    {
986
        if (is_array($key)) {
987
            foreach ($key as $k => $v) {
988
                if (is_int($k)) {
989
                    $this->assertSessionHasInput($v);
990
                } else {
991
                    $this->assertSessionHasInput($k, $v);
992
                }
993
            }
994
995
            return $this;
996
        }
997
998
        if (is_null($value)) {
999
            PHPUnit::assertTrue(
1000
                $this->session()->getOldInput($key),
1001
                "Session is missing expected key [{$key}]."
1002
            );
1003
        } elseif ($value instanceof Closure) {
1004
            PHPUnit::assertTrue($value($this->session()->getOldInput($key)));
1005
        } else {
1006
            PHPUnit::assertEquals($value, $this->session()->getOldInput($key));
1007
        }
1008
1009
        return $this;
1010
    }
1011
1012
    /**
1013
     * Assert that the session has the given errors.
1014
     *
1015
     * @param  string|array  $keys
1016
     * @param  mixed  $format
1017
     * @param  string  $errorBag
1018
     * @return $this
1019
     */
1020
    public function assertSessionHasErrors($keys = [], $format = null, $errorBag = 'default')
1021
    {
1022
        $this->assertSessionHas('errors');
1023
1024
        $keys = (array) $keys;
1025
1026
        $errors = $this->session()->get('errors')->getBag($errorBag);
1027
1028
        foreach ($keys as $key => $value) {
1029
            if (is_int($key)) {
1030
                PHPUnit::assertTrue($errors->has($value), "Session missing error: $value");
1031
            } else {
1032
                PHPUnit::assertContains($value, $errors->get($key, $format));
1033
            }
1034
        }
1035
1036
        return $this;
1037
    }
1038
1039
    /**
1040
     * Assert that the session is missing the given errors.
1041
     *
1042
     * @param  string|array  $keys
1043
     * @param  string|null  $format
1044
     * @param  string  $errorBag
1045
     * @return $this
1046
     */
1047
    public function assertSessionDoesntHaveErrors($keys = [], $format = null, $errorBag = 'default')
1048
    {
1049
        $keys = (array) $keys;
1050
1051
        if (empty($keys)) {
1052
            return $this->assertSessionHasNoErrors();
1053
        }
1054
1055
        if (is_null($this->session()->get('errors'))) {
1056
            PHPUnit::assertTrue(true);
1057
1058
            return $this;
1059
        }
1060
1061
        $errors = $this->session()->get('errors')->getBag($errorBag);
1062
1063
        foreach ($keys as $key => $value) {
1064
            if (is_int($key)) {
1065
                PHPUnit::assertFalse($errors->has($value), "Session has unexpected error: $value");
1066
            } else {
1067
                PHPUnit::assertNotContains($value, $errors->get($key, $format));
1068
            }
1069
        }
1070
1071
        return $this;
1072
    }
1073
1074
    /**
1075
     * Assert that the session has no errors.
1076
     *
1077
     * @return $this
1078
     */
1079
    public function assertSessionHasNoErrors()
1080
    {
1081
        $hasErrors = $this->session()->has('errors');
1082
1083
        $errors = $hasErrors ? $this->session()->get('errors')->all() : [];
1084
1085
        PHPUnit::assertFalse(
1086
            $hasErrors,
1087
            'Session has unexpected errors: '.PHP_EOL.PHP_EOL.
1088
            json_encode($errors, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
1089
        );
1090
1091
        return $this;
1092
    }
1093
1094
    /**
1095
     * Assert that the session has the given errors.
1096
     *
1097
     * @param  string  $errorBag
1098
     * @param  string|array  $keys
1099
     * @param  mixed  $format
1100
     * @return $this
1101
     */
1102
    public function assertSessionHasErrorsIn($errorBag, $keys = [], $format = null)
1103
    {
1104
        return $this->assertSessionHasErrors($keys, $format, $errorBag);
1105
    }
1106
1107
    /**
1108
     * Assert that the session does not have a given key.
1109
     *
1110
     * @param  string|array  $key
1111
     * @return $this
1112
     */
1113
    public function assertSessionMissing($key)
1114
    {
1115
        if (is_array($key)) {
1116
            foreach ($key as $value) {
1117
                $this->assertSessionMissing($value);
1118
            }
1119
        } else {
1120
            PHPUnit::assertFalse(
1121
                $this->session()->has($key),
1122
                "Session has unexpected key [{$key}]."
1123
            );
1124
        }
1125
1126
        return $this;
1127
    }
1128
1129
    /**
1130
     * Get the current session store.
1131
     *
1132
     * @return \Illuminate\Session\Store
1133
     */
1134
    protected function session()
1135
    {
1136
        return app('session.store');
1137
    }
1138
1139
    /**
1140
     * Dump the content from the response.
1141
     *
1142
     * @return $this
1143
     */
1144
    public function dump()
1145
    {
1146
        $content = $this->getContent();
1147
1148
        $json = json_decode($content);
1149
1150
        if (json_last_error() === JSON_ERROR_NONE) {
1151
            $content = $json;
1152
        }
1153
1154
        dump($content);
1155
1156
        return $this;
1157
    }
1158
1159
    /**
1160
     * Dump the headers from the response.
1161
     *
1162
     * @return $this
1163
     */
1164
    public function dumpHeaders()
1165
    {
1166
        dump($this->headers->all());
1167
1168
        return $this;
1169
    }
1170
1171
    /**
1172
     * Dump the session from the response.
1173
     *
1174
     * @param  string|array  $keys
1175
     * @return $this
1176
     */
1177
    public function dumpSession($keys = [])
1178
    {
1179
        $keys = (array) $keys;
1180
1181
        if (empty($keys)) {
1182
            dump($this->session()->all());
1183
        } else {
1184
            dump($this->session()->only($keys));
1185
        }
1186
1187
        return $this;
1188
    }
1189
1190
    /**
1191
     * Get the streamed content from the response.
1192
     *
1193
     * @return string
1194
     */
1195
    public function streamedContent()
1196
    {
1197
        if (! is_null($this->streamedContent)) {
1198
            return $this->streamedContent;
1199
        }
1200
1201
        if (! $this->baseResponse instanceof StreamedResponse) {
1202
            PHPUnit::fail('The response is not a streamed response.');
1203
        }
1204
1205
        ob_start();
1206
1207
        $this->sendContent();
1208
1209
        return $this->streamedContent = ob_get_clean();
1210
    }
1211
1212
    /**
1213
     * Dynamically access base response parameters.
1214
     *
1215
     * @param  string  $key
1216
     * @return mixed
1217
     */
1218
    public function __get($key)
1219
    {
1220
        return $this->baseResponse->{$key};
1221
    }
1222
1223
    /**
1224
     * Proxy isset() checks to the underlying base response.
1225
     *
1226
     * @param  string  $key
1227
     * @return mixed
1228
     */
1229
    public function __isset($key)
1230
    {
1231
        return isset($this->baseResponse->{$key});
1232
    }
1233
1234
    /**
1235
     * Determine if the given offset exists.
1236
     *
1237
     * @param  string  $offset
1238
     * @return bool
1239
     */
1240
    public function offsetExists($offset)
1241
    {
1242
        return isset($this->json()[$offset]);
1243
    }
1244
1245
    /**
1246
     * Get the value for a given offset.
1247
     *
1248
     * @param  string  $offset
1249
     * @return mixed
1250
     */
1251
    public function offsetGet($offset)
1252
    {
1253
        return $this->json()[$offset];
1254
    }
1255
1256
    /**
1257
     * Set the value at the given offset.
1258
     *
1259
     * @param  string  $offset
1260
     * @param  mixed  $value
1261
     * @return void
1262
     *
1263
     * @throws \LogicException
1264
     */
1265
    public function offsetSet($offset, $value)
1266
    {
1267
        throw new LogicException('Response data may not be mutated using array access.');
1268
    }
1269
1270
    /**
1271
     * Unset the value at the given offset.
1272
     *
1273
     * @param  string  $offset
1274
     * @return void
1275
     *
1276
     * @throws \LogicException
1277
     */
1278
    public function offsetUnset($offset)
1279
    {
1280
        throw new LogicException('Response data may not be mutated using array access.');
1281
    }
1282
1283
    /**
1284
     * Handle dynamic calls into macros or pass missing methods to the base response.
1285
     *
1286
     * @param  string  $method
1287
     * @param  array  $args
1288
     * @return mixed
1289
     */
1290
    public function __call($method, $args)
1291
    {
1292
        if (static::hasMacro($method)) {
1293
            return $this->macroCall($method, $args);
1294
        }
1295
1296
        return $this->baseResponse->{$method}(...$args);
1297
    }
1298
}
1299