Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
58 / 58
100.00% covered (success)
100.00%
1 / 1
CRAP
n/a
0 / 0
getConcreteApiController
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3// ╔════════════════════════════════════════════════════════════╗
4// ║ MIT Licence (#Expat) - https://opensource.org/licenses/MIT ║
5// ║ Copyright 2026 Frederic Poeydomenge <dyno@phexium.com>     ║
6// ╚════════════════════════════════════════════════════════════╝
7
8declare(strict_types=1);
9
10pest()->group('unit');
11
12use Nyholm\Psr7\Response;
13use Phexium\Presentation\AbstractApiController;
14use Phexium\Presentation\ResponseBuilder;
15use Phexium\Presentation\ResponseBuilderInterface;
16use Psr\Http\Message\ResponseInterface;
17
18function getConcreteApiController(ResponseBuilderInterface $responseBuilder): AbstractApiController
19{
20    return new readonly class($responseBuilder) extends AbstractApiController {
21        public function __construct(ResponseBuilderInterface $responseBuilder)
22        {
23            $this->responseBuilder = $responseBuilder;
24        }
25
26        public function exposeJsonSuccess(ResponseInterface $response, array $payload, int $statusCode = 200): ResponseInterface
27        {
28            return $this->jsonSuccess($response, $payload, $statusCode);
29        }
30
31        public function exposeJsonCreated(ResponseInterface $response): ResponseInterface
32        {
33            return $this->jsonCreated($response);
34        }
35
36        public function exposeJsonError(ResponseInterface $response, int $statusCode, string $message): ResponseInterface
37        {
38            return $this->jsonError($response, $statusCode, $message);
39        }
40    };
41}
42
43describe('Response building', function (): void {
44    it('returns JSON response with payload and default status 200', function (): void {
45        $response = new Response();
46        $responseBuilder = new ResponseBuilder($response);
47        $controller = getConcreteApiController($responseBuilder);
48
49        $result = $controller->exposeJsonSuccess($response, ['data' => 'test']);
50
51        expect($result->getStatusCode())->toBe(200)
52            ->and($result->getHeaderLine('Content-Type'))->toBe('application/json; charset=utf-8')
53            ->and((string) $result->getBody())->toContain('"data": "test"')
54        ;
55    });
56
57    it('returns JSON response with custom status code', function (): void {
58        $response = new Response();
59        $responseBuilder = new ResponseBuilder($response);
60        $controller = getConcreteApiController($responseBuilder);
61
62        $result = $controller->exposeJsonSuccess($response, ['accepted' => true], 202);
63
64        expect($result->getStatusCode())->toBe(202)
65            ->and($result->getHeaderLine('Content-Type'))->toBe('application/json; charset=utf-8')
66            ->and((string) $result->getBody())->toContain('"accepted": true')
67        ;
68    });
69
70    it('returns response with status 201 for jsonCreated', function (): void {
71        $response = new Response();
72        $responseBuilder = new ResponseBuilder($response);
73        $controller = getConcreteApiController($responseBuilder);
74
75        $result = $controller->exposeJsonCreated($response);
76
77        expect($result->getStatusCode())->toBe(201);
78    });
79});
80
81describe('Error handling', function (): void {
82    it('returns JSON error response with 400 status', function (): void {
83        $response = new Response();
84        $responseBuilder = new ResponseBuilder($response);
85        $controller = getConcreteApiController($responseBuilder);
86
87        $result = $controller->exposeJsonError($response, 400, 'Invalid input');
88
89        expect($result->getStatusCode())->toBe(400)
90            ->and($result->getHeaderLine('Content-Type'))->toBe('application/json; charset=utf-8')
91            ->and((string) $result->getBody())->toContain('"error": "Invalid input"')
92        ;
93    });
94
95    it('returns JSON error response with 404 status', function (): void {
96        $response = new Response();
97        $responseBuilder = new ResponseBuilder($response);
98        $controller = getConcreteApiController($responseBuilder);
99
100        $result = $controller->exposeJsonError($response, 404, 'Not found');
101
102        expect($result->getStatusCode())->toBe(404)
103            ->and($result->getHeaderLine('Content-Type'))->toBe('application/json; charset=utf-8')
104            ->and((string) $result->getBody())->toContain('"error": "Not found"')
105        ;
106    });
107});