Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
BrowsePageTrait
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
4 / 4
7
100.00% covered (success)
100.00%
1 / 1
 givenIAmNotAuthenticated
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 givenIAmAuthenticatedAs
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 whenIBrowseThePage
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
2
 whenIBrowse
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
3
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
10namespace Tests\AppDemo\Acceptance\Trait;
11
12use AppDemo\Homepage\Application\Http\HomeController;
13use AppDemo\Library\Application\Http\CreateBookController;
14use AppDemo\Library\Application\Http\DetailBookController;
15use AppDemo\Library\Application\Http\ListBooksController;
16use AppDemo\Library\Application\Http\UpdateBookController;
17use AppDemo\Loan\Application\Http\BorrowBookController;
18use AppDemo\Loan\Application\Http\ListLoansController;
19use AppDemo\Loan\Application\Http\MyLoansController;
20use AppDemo\Shared\Application\Middleware\UserContextMiddleware;
21use AppDemo\Shared\Domain\Interface\SessionServiceInterface;
22use AppDemo\User\Domain\Email;
23use AppDemo\User\Domain\User;
24use AppDemo\User\Domain\UserRepository;
25use Assert\Assert;
26use Behat\Step\Given;
27use Behat\Step\When;
28use Exception;
29use Nyholm\Psr7\Response;
30use Nyholm\Psr7\ServerRequest as Request;
31use Psr\Http\Message\ServerRequestInterface;
32use Psr\Http\Server\RequestHandlerInterface;
33
34trait BrowsePageTrait
35{
36    public User $user;
37
38    #[Given('/I am not authenticated/')]
39    public function givenIAmNotAuthenticated(): void
40    {
41        $sessionService = self::$container->get(SessionServiceInterface::class);
42        $sessionService->clearUserSession();
43    }
44
45    #[Given('/I am authenticated as (.+)/')]
46    public function givenIAmAuthenticatedAs(string $email): void
47    {
48        $userRepository = self::$container->get(UserRepository::class);
49        $this->user = $userRepository->findByEmail(Email::fromString($email));
50        Assert::that($this->user)->notNull('User not found in test fixtures');
51
52        $sessionService = self::$container->get(SessionServiceInterface::class);
53        $sessionService->setUserAuthenticated(
54            $this->user->getId(),
55            $this->user->getEmail()
56        );
57    }
58
59    #[When('/I browse the (.*) page(?: for book ID (\d+))?/')]
60    public function whenIBrowseThePage(string $page, ?int $id = null): void
61    {
62        $urls = [
63            'Home' => ['/', HomeController::class, 'index'],
64            'List Books' => ['/books', ListBooksController::class, 'index'],
65            'Detail Book' => ['/books/'.$id, DetailBookController::class, 'index'],
66            'Create new Book' => ['/books/create', CreateBookController::class, 'showCreateForm'],
67            'Edit Book' => ['/books/'.$id.'/edit', UpdateBookController::class, 'showEditForm'],
68            'List Loans' => ['/loans', ListLoansController::class, 'index'],
69            'My Loans' => ['/loans/my', MyLoansController::class, 'index'],
70            'Borrow Book' => ['/loans/borrow', BorrowBookController::class, 'showBorrowForm'],
71        ];
72
73        if ([$url, $controller, $method] = $urls[$page]) {
74            $this->whenIBrowse($url, $controller, $method, $id);
75        }
76    }
77
78    private function whenIBrowse(string $pageUrl, string $controllerClass, string $methodName, ?int $id = null): void
79    {
80        $controller = self::$container->get($controllerClass);
81        $idParameter = $id === null ? [] : ['id' => $id];
82
83        // Create a mock request handler that does nothing but allows the middleware to pass the request through
84        $mockHandler = new class implements RequestHandlerInterface {
85            public ServerRequestInterface $request;
86
87            public function handle(ServerRequestInterface $request): Response
88            {
89                $this->request = $request;
90
91                return new Response();
92            }
93        };
94
95        // Process the initial request through the middleware
96        $middleware = self::$container->get(UserContextMiddleware::class);
97        $middleware->process(new Request('GET', $pageUrl), $mockHandler);
98
99        // The processed request now contains the user context attributes
100        $processedRequest = $mockHandler->request;
101
102        try {
103            $this->response = $controller->{$methodName}($processedRequest, new Response(), $idParameter);
104        } catch (Exception $exception) {
105            $this->exception = $exception;
106        }
107    }
108}