Passed
Push — master ( e63f1d...295fd2 )
by Andrea Marco
03:11 queued 14s
created

TestResponseMixin::assertJsonApiValidationErrors()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 32
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 4

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 4
eloc 16
c 3
b 0
f 0
nc 1
nop 0
dl 0
loc 32
ccs 18
cts 18
cp 1
crap 4
rs 9.7333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cerbero\JsonApiError\Services;
6
7
use Cerbero\JsonApiError\Data\Dot;
8
use Closure;
9
use Illuminate\Testing\Assert;
10
use Illuminate\Testing\TestResponse;
11
use Symfony\Component\HttpFoundation\Response;
12
13
/**
14
 * The mixin to test JSON:API error responses.
15
 */
16
final class TestResponseMixin
17
{
18
    /**
19
     * Assert that the response contains the given JSON:API error.
20
     *
21
     * @return Closure(string, int): TestResponse
22
     */
23 12
    public function assertJsonApiError(): Closure
24
    {
25 12
        return function (string $detail, int $status = Response::HTTP_BAD_REQUEST) {
26
            /**
27
             * @var TestResponse $this
28
             */
29 1
            return $this // @phpstan-ignore-line
30 1
                ->assertJsonApiErrorStructure()
31 1
                ->assertJsonPath('errors.0.status', (string) $status)
32 1
                ->assertJsonPath('errors.0.title', __("json-api-error::statuses.{$status}.title"))
33 1
                ->assertJsonPath('errors.0.detail', $detail);
34 12
        };
35
    }
36
37
    /**
38
     * Assert that the response contains the given JSON:API validation errors.
39
     *
40
     * @return Closure(array<string|int, string>): TestResponse
41
     */
42 12
    public function assertJsonApiValidationErrors(): Closure
43
    {
44 12
        return function (array $expected) {
45
            /**
46
             * @var TestResponse $this
47
             */
48 1
            $this // @phpstan-ignore-line
49 1
                ->assertJsonApiErrorStructure()
50 1
                ->assertJsonPath('errors', fn(array $errors) => collect($errors)->every(function (array $error) {
0 ignored issues
show
Bug introduced by
$errors of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

50
                ->assertJsonPath('errors', fn(array $errors) => collect(/** @scrutinizer ignore-type */ $errors)->every(function (array $error) {
Loading history...
51 1
                    return $error['status'] === '422' && $error['title'] === __('json-api-error::statuses.422.title');
52 1
                }));
53
54 1
            if (array_is_list($expected)) {
0 ignored issues
show
Bug introduced by
The function array_is_list was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

54
            if (/** @scrutinizer ignore-call */ array_is_list($expected)) {
Loading history...
55 1
                Assert::assertEqualsCanonicalizing($expected, $this->json('errors.*.detail'));
56
57 1
                return $this;
58
            }
59
60 1
            $actual = $this->collect('errors')->pluck('detail', 'source.pointer')->all();
61
62 1
            foreach ($expected as $dot => $detail) {
63 1
                $pointer = (new Dot($dot))->toJsonPointer();
64 1
                $message = "The field [{$dot}] does not have the error [{$detail}].";
65
66 1
                Assert::assertSame($detail, $actual[$pointer] ?? null, $message);
67
68 1
                unset($actual[$pointer]);
69
            }
70
71 1
            Assert::assertEmpty($actual, 'Other unexpected validation errors occurred.');
72
73 1
            return $this;
74 12
        };
75
    }
76
77
    /**
78
     * Assert that the response contains the JSON:API error for the given HTTP status.
79
     *
80
     * @return Closure(int): TestResponse
81
     */
82 12
    public function assertJsonApiErrorStatus(): Closure
83
    {
84 12
        return function (int $status) {
85
            /**
86
             * @var TestResponse $this
87
             */
88 7
            return $this // @phpstan-ignore-line
89 7
                ->assertJsonApiErrorStructure()
90 7
                ->assertJsonPath('errors.0.status', (string) $status)
91 7
                ->assertJsonPath('errors.0.title', __("json-api-error::statuses.{$status}.title"))
92 7
                ->assertJsonPath('errors.0.detail', __("json-api-error::statuses.{$status}.detail"));
93 12
        };
94
    }
95
96
    /**
97
     * Assert that the response contains JSON:API compliant errors.
98
     *
99
     * @return Closure(): TestResponse
100
     */
101 12
    public function assertJsonApiErrorStructure(): Closure
102
    {
103 12
        return function () {
104
            /**
105
             * @var TestResponse $this
106
             */
107 9
            return $this->assertJsonStructure([
108 9
                'errors' => [
109 9
                    '*' => [
110 9
                        'status',
111 9
                        'title',
112 9
                        'detail',
113 9
                    ],
114 9
                ],
115 9
            ]);
116 12
        };
117
    }
118
}
119