test(EloquentEmployeeDirectory): add integration tests for employee retrieval and date conversion

Includes tests for finding employees, handling null values, and date conversion.
This commit is contained in:
Jérémy Munsch 2026-08-13 14:59:21 +02:00
parent 2529118bcc
commit b7f2de4f92
Signed by: forge-joniko
GPG key ID: D7EFE2F5CB6CC0E4
2 changed files with 156 additions and 6 deletions

View file

@ -91,17 +91,13 @@ final class EloquentEmployeeDirectory implements EmployeeDirectory
return new \DateTimeImmutable($value);
}
private function toNullableDateTime(mixed $value): ?\DateTimeInterface
private function toNullableDateTime(\DateTimeInterface | string | null $value): ?\DateTimeInterface
{
if ($value === null) {
return null;
}
if ($value instanceof \DateTimeInterface || is_string($value)) {
return $this->toDateTime($value);
}
throw new \UnexpectedValueException('Invalid datetime value type.');
return $this->toDateTime($value);
}
private function toSqlColumn(EmployeeSortColumn $sortBy): string

View file

@ -0,0 +1,154 @@
<?php
declare(strict_types=1);
namespace Tests\Integration\Infra\Adapters\Directories;
use Domain\Models\Entities\Employee;
use Domain\Models\ValueObjects\Employees\EmployeeSortColumn;
use Domain\Models\ValueObjects\Employees\EmployeeSorter;
use Domain\Models\ValueObjects\Entities\ArcadiaEmployeeId;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Infra\Adapters\Directories\EloquentEmployeeDirectory;
use Infra\Database\Models\Employee as EmployeeModel;
use Shared\Paginated;
use Shared\Pagination;
use Tests\TestCase;
uses(TestCase::class, RefreshDatabase::class);
covers(EloquentEmployeeDirectory::class);
beforeEach(function (): void {
EmployeeModel::query()->delete();
});
describe('EloquentEmployeeDirectory Integration Tests', function (): void {
it('finds an employee by public employee number and maps to domain entity', function (): void {
// GIVEN
$directory = new EloquentEmployeeDirectory();
EmployeeModel::factory()->create([
'public_employee_number' => '1234567',
'last_name' => 'DUPONT',
'first_name' => 'Jean',
'start_date' => '2024-01-01',
'end_date' => '2025-01-01',
'planned_end_date' => '2025-06-01',
'establishment' => '01',
'site' => 'LDCSER',
'service' => '097',
'created_at' => '2024-01-01 10:00:00',
'updated_at' => '2024-01-02 12:00:00',
]);
$employeeId = new ArcadiaEmployeeId('1234567');
// WHEN
$result = $directory->find($employeeId);
// THEN
expect($result)->toBeInstanceOf(Employee::class)
->and($result?->id()->value)->toBe('1234567')
->and($result?->lastName)->toBe('DUPONT')
->and($result?->firstName)->toBe('Jean')
->and($result?->startDate->format('Y-m-d'))->toBe('2024-01-01')
->and($result?->endDate?->format('Y-m-d'))->toBe('2025-01-01')
->and($result?->plannedEndDate?->format('Y-m-d'))->toBe('2025-06-01')
->and($result?->establishment->value)->toBe('01')
->and($result?->site->value)->toBe('LDCSER')
->and($result?->service->value)->toBe('097')
->and($result?->createdAt->format('Y-m-d H:i:s'))->toBe('2024-01-01 10:00:00')
->and($result?->updatedAt?->format('Y-m-d H:i:s'))->toBe('2024-01-02 12:00:00');
});
it('converts string dates to DateTimeInterface using toDateTime helper', function (): void {
// GIVEN
$directory = new EloquentEmployeeDirectory();
$reflection = new \ReflectionMethod(EloquentEmployeeDirectory::class, 'toDateTime');
// WHEN
/** @var \DateTimeInterface $result */
$result = $reflection->invoke($directory, '2024-01-15 14:30:00');
// THEN
expect($result)->toBeInstanceOf(\DateTimeInterface::class)
->and($result->format('Y-m-d H:i:s'))->toBe('2024-01-15 14:30:00');
});
it('returns null when employee is not found', function (): void {
// GIVEN
$directory = new EloquentEmployeeDirectory();
$employeeId = new ArcadiaEmployeeId('9999999');
// WHEN
$result = $directory->find($employeeId);
// THEN
expect($result)->toBeNull();
});
it('throws UnexpectedValueException when created_at is null', function (): void {
// GIVEN
$directory = new EloquentEmployeeDirectory();
EmployeeModel::query()->insert([
'public_employee_number' => '7654321',
'last_name' => 'MARTIN',
'first_name' => 'Alice',
'start_date' => '2024-01-01',
'establishment' => '01',
'site' => 'LDCSER',
'service' => '097',
'created_at' => null,
'updated_at' => null,
]);
$employeeId = new ArcadiaEmployeeId('7654321');
// WHEN & THEN
expect(fn () => $directory->find($employeeId))
->toThrow(\UnexpectedValueException::class, 'Employee created_at cannot be null.');
});
it('returns paginated employees sorted by specified columns', function (EmployeeSortColumn $sortColumn, \SortDirection $direction): void {
// GIVEN
$directory = new EloquentEmployeeDirectory();
EmployeeModel::factory()->create([
'public_employee_number' => '1000001',
'start_date' => '2024-01-01',
'end_date' => '2024-06-01',
'planned_end_date' => '2024-12-01',
'created_at' => '2024-01-01 08:00:00',
'updated_at' => '2024-01-01 09:00:00',
]);
EmployeeModel::factory()->create([
'public_employee_number' => '1000002',
'start_date' => '2024-02-01',
'end_date' => '2024-07-01',
'planned_end_date' => '2024-12-15',
'created_at' => '2024-02-01 08:00:00',
'updated_at' => '2024-02-01 09:00:00',
]);
$pagination = Pagination::ofPage(1, 10);
$sorter = new EmployeeSorter($sortColumn, $direction);
// WHEN
$result = $directory->findAll($pagination, $sorter);
// THEN
expect($result)->toBeInstanceOf(Paginated::class)
->and($result->getTotal())->toBe(2)
->and(count($result->getItems()))->toBe(2);
})->with([
'arcadiaId asc' => [EmployeeSortColumn::arcadiaId, \SortDirection::Ascending],
'arcadiaId desc' => [EmployeeSortColumn::arcadiaId, \SortDirection::Descending],
'startDate asc' => [EmployeeSortColumn::startDate, \SortDirection::Ascending],
'endDate desc' => [EmployeeSortColumn::endDate, \SortDirection::Descending],
'plannedEndDate asc' => [EmployeeSortColumn::plannedEndDate, \SortDirection::Ascending],
'createdAt desc' => [EmployeeSortColumn::createdAt, \SortDirection::Descending],
'updatedAt asc' => [EmployeeSortColumn::updatedAt, \SortDirection::Ascending],
]);
});