Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
93 / 93
n/a
0 / 0
CRAP
n/a
0 / 0
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 AppDemo\Shared\Application\Service\SessionService;
13use AppDemo\User\Domain\Email;
14use Odan\Session\MemorySession;
15use Phexium\Domain\Id\IdInterface;
16use Phexium\Plugin\IdGenerator\Adapter\TimestampIdGenerator;
17use Phexium\Plugin\Session\Adapter\OdanSession;
18use Phexium\Plugin\Session\Port\FlashInterface;
19use Tests\Phexium\Fake\Plugin\Logger\Logger as FakeLogger;
20
21beforeEach(function (): void {
22    $this->session = new OdanSession(new MemorySession());
23    $this->session->start();
24
25    $this->logger = new FakeLogger();
26
27    $this->sessionService = new SessionService(
28        $this->session,
29        $this->logger,
30        new TimestampIdGenerator()
31    );
32});
33
34describe('Authentication', function (): void {
35    it('gets session object', function (): void {
36        expect($this->sessionService->getSession())->toBe($this->session);
37    });
38
39    it('sets user data in session', function (): void {
40        $idGenerator = new TimestampIdGenerator();
41        $userId = $idGenerator->from(123);
42        $email = Email::fromString('test@example.com');
43
44        $this->sessionService->setUserAuthenticated($userId, $email);
45
46        expect($this->session->get('user_id'))->toBe(123)
47            ->and($this->session->get('user_email'))->toBe('test@example.com')
48        ;
49
50        expect($this->logger->hasLogWithContext('info', 'User authenticated in session', [
51            'userId' => 123,
52            'email' => 'test@example.com',
53        ]))->toBeTrue();
54    });
55
56    it('returns true when user ID is in session', function (): void {
57        $this->session->set('user_id', 123);
58
59        expect($this->sessionService->isUserAuthenticated())->toBeTrue();
60    });
61
62    it('returns false when user ID is not in session', function (): void {
63        expect($this->sessionService->isUserAuthenticated())->toBeFalse();
64    });
65
66    it('returns user ID when it exists in session', function (): void {
67        $userId = 123;
68        $this->session->set('user_id', $userId);
69
70        $result = $this->sessionService->getUserId();
71
72        expect($result)->toBeInstanceOf(IdInterface::class)
73            ->and($result->getValue())->toBe($userId)
74        ;
75    });
76
77    it('returns null user ID when it does not exist in session', function (): void {
78        expect($this->sessionService->getUserId())->toBeNull();
79    });
80
81    it('returns user email when it exists in session', function (): void {
82        $email = 'user@example.com';
83        $this->session->set('user_email', $email);
84
85        $result = $this->sessionService->getUserEmail();
86
87        expect($result)->toBeInstanceOf(Email::class)
88            ->and($result->getValue())->toBe($email)
89        ;
90    });
91
92    it('returns null user email when it does not exist in session', function (): void {
93        expect($this->sessionService->getUserEmail())->toBeNull();
94    });
95});
96
97describe('Flash messages', function (): void {
98    it('adds a flash message to the session', function (): void {
99        $flash = $this->session->getFlash();
100        $messages = $flash->all();
101        expect($messages)->toBeEmpty();
102
103        $this->sessionService->addFlashMessage('success', 'Operation successful');
104
105        $flash = $this->session->getFlash();
106        $messages = $flash->get('success');
107        expect($messages)->toBeArray()
108            ->and($messages)->toContain('Operation successful')
109        ;
110    });
111
112    it('returns the flash interface from the session', function (): void {
113        $flash = $this->sessionService->getFlash();
114
115        expect($flash)->toBeInstanceOf(FlashInterface::class);
116    });
117});
118
119describe('Session lifecycle', function (): void {
120    it('clears the session', function (): void {
121        $this->session->set('key', 'value');
122
123        expect($this->session->all())->not->toBeEmpty();
124
125        $this->sessionService->clearUserSession();
126
127        expect($this->session->all())->toBeEmpty()
128            ->and($this->logger->hasLogContaining('info', 'User session cleared'))->toBeTrue()
129        ;
130    });
131
132    it('regenerates the session ID', function (): void {
133        $oldSessionId = $this->session->getId();
134        $this->sessionService->regenerateSession();
135        $newSessionId = $this->session->getId();
136
137        expect($newSessionId)->not->toBe($oldSessionId)
138            ->and($this->logger->hasLogContaining('info', 'Session regeneration requested'))->toBeTrue()
139        ;
140    });
141});