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\Factory\Psr17Factory;
13use Nyholm\Psr7\Response;
14use Phexium\Presentation\AbstractApiController;
15use Phexium\Presentation\ResponseBuilder;
16use Phexium\Presentation\ResponseBuilderInterface;
17use Psr\Http\Message\ResponseInterface;
18
19function getConcreteApiController(ResponseBuilderInterface $responseBuilder): AbstractApiController
20{
21    return new readonly class($responseBuilder) extends AbstractApiController {
22        public function __construct(ResponseBuilderInterface $responseBuilder)
23        {
24            $this->responseBuilder = $responseBuilder;
25        }
26
27        public function exposeJsonSuccess(ResponseInterface $response, array $payload, int $statusCode = 200): ResponseInterface
28        {
29            return $this->jsonSuccess($response, $payload, $statusCode);
30        }
31
32        public function exposeJsonCreated(ResponseInterface $response): ResponseInterface
33        {
34            return $this->jsonCreated($response);
35        }
36
37        public function exposeJsonError(ResponseInterface $response, int $statusCode, string $message): ResponseInterface
38        {
39            return $this->jsonError($response, $statusCode, $message);
40        }
41    };
42}
43
44describe('Response building', function (): void {
45    it('returns JSON response with payload and default status 200', function (): void {
46        $response = new Response();
47        $responseBuilder = new ResponseBuilder(new Psr17Factory());
48        $controller = getConcreteApiController($responseBuilder);
49
50        $result = $controller->exposeJsonSuccess($response, ['data' => 'test']);
51
52        expect($result->getStatusCode())->toBe(200)
53            ->and($result->getHeaderLine('Content-Type'))->toBe('application/json; charset=utf-8')
54            ->and((string) $result->getBody())->toContain('"data": "test"')
55        ;
56    });
57
58    it('returns JSON response with custom status code', function (): void {
59        $response = new Response();
60        $responseBuilder = new ResponseBuilder(new Psr17Factory());
61        $controller = getConcreteApiController($responseBuilder);
62
63        $result = $controller->exposeJsonSuccess($response, ['accepted' => true], 202);
64
65        expect($result->getStatusCode())->toBe(202)
66            ->and($result->getHeaderLine('Content-Type'))->toBe('application/json; charset=utf-8')
67            ->and((string) $result->getBody())->toContain('"accepted": true')
68        ;
69    });
70
71    it('returns response with status 201 for jsonCreated', function (): void {
72        $response = new Response();
73        $responseBuilder = new ResponseBuilder(new Psr17Factory());
74        $controller = getConcreteApiController($responseBuilder);
75
76        $result = $controller->exposeJsonCreated($response);
77
78        expect($result->getStatusCode())->toBe(201);
79    });
80});
81
82describe('Error handling', function (): void {
83    it('returns JSON error response with 400 status', function (): void {
84        $response = new Response();
85        $responseBuilder = new ResponseBuilder(new Psr17Factory());
86        $controller = getConcreteApiController($responseBuilder);
87
88        $result = $controller->exposeJsonError($response, 400, 'Invalid input');
89
90        expect($result->getStatusCode())->toBe(400)
91            ->and($result->getHeaderLine('Content-Type'))->toBe('application/json; charset=utf-8')
92            ->and((string) $result->getBody())->toContain('"error": "Invalid input"')
93        ;
94    });
95
96    it('returns JSON error response with 404 status', function (): void {
97        $response = new Response();
98        $responseBuilder = new ResponseBuilder(new Psr17Factory());
99        $controller = getConcreteApiController($responseBuilder);
100
101        $result = $controller->exposeJsonError($response, 404, 'Not found');
102
103        expect($result->getStatusCode())->toBe(404)
104            ->and($result->getHeaderLine('Content-Type'))->toBe('application/json; charset=utf-8')
105            ->and((string) $result->getBody())->toContain('"error": "Not found"')
106        ;
107    });
108});