ldc-mesbr-app/tests/Unit/Application/UseCases/CampaignRequest/Find/FindCampaignRequestTest.php

224 lines
9.1 KiB
PHP
Raw Normal View History

2026-09-23 09:29:22 +02:00
<?php
declare(strict_types=1);
namespace Tests\Unit\Application\UseCases\CampaignRequest\Find;
use Application\UseCases\CampaignRequest\Find\FindCampaignRequest;
use Application\UseCases\CampaignRequest\Find\Input;
use Application\UseCases\CampaignRequest\Find\Output\CampaignRequestFound;
use Application\UseCases\CampaignRequest\Find\Output\CampaignRequestNotFound;
use Application\UseCases\CampaignRequest\Find\Output\Output;
use Domain\Enums\BarcodeFormat;
use Domain\Enums\Country;
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestStatus;
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestType;
2026-09-23 09:29:22 +02:00
use Domain\Exceptions\BrandNotFoundException;
use Domain\Models\Entities\Brand;
use Domain\Models\Entities\CampaignRequest;
use Domain\Models\Entities\RequestedCoupon;
use Domain\Models\ValueObjects\Brand\BrandCode;
use Domain\Models\ValueObjects\Brand\BrandId;
use Domain\Models\ValueObjects\Brand\BrandName;
use Domain\Models\ValueObjects\CampaignRequest\Applicant;
use Domain\Models\ValueObjects\CampaignRequest\CampaignRequestId;
use Domain\Models\ValueObjects\CampaignRequest\RejectionReason;
use Domain\Models\ValueObjects\CountryAuthorized;
2026-09-23 09:29:22 +02:00
use Domain\Models\ValueObjects\Coupon\CouponValidity;
use Domain\Models\ValueObjects\CouponName;
use Domain\Models\ValueObjects\CouponPicture;
use Domain\Models\ValueObjects\CouponProductName;
use Domain\Models\ValueObjects\GS1;
use Domain\Models\ValueObjects\MoneyAmount;
use Domain\Models\ValueObjects\Period;
use Domain\Models\ValueObjects\PicturePath;
use Domain\Models\ValueObjects\PrintRules;
use Domain\Models\ValueObjects\ProcessingCode;
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponId;
use Domain\Models\ValueObjects\RequestedCoupon\RequestedCouponQuantity;
use Domain\Models\ValueObjects\WarningThresholdQuantity;
2026-09-23 09:29:22 +02:00
use Domain\Ports\Repositories\BrandRepository;
use Domain\Ports\Repositories\CampaignRequestRepository;
use Shared\DDD\UseCases\Input as BaseInput;
use Shared\Enums\Currency;
use DateTime;
2026-09-23 09:29:22 +02:00
use Shared\ValueObjects\Email;
use Shared\ValueObjects\Money;
use Shared\ValueObjects\Rcs;
covers(FindCampaignRequest::class, Input::class, CampaignRequestFound::class, CampaignRequestNotFound::class);
describe('find campaign request use case', function (): void {
2026-09-23 09:40:47 +02:00
beforeEach(function (): void {
$this->requestedCoupon = RequestedCoupon::hydrate(
RequestedCouponId::generate(),
new CouponName('Coupon A'),
new CouponProductName('Product A'),
new RequestedCouponQuantity(100),
new WarningThresholdQuantity(10),
2026-09-23 09:40:47 +02:00
new Period(new DateTime('2026-01-01'), new DateTime('2026-02-01')),
new MoneyAmount(new Money(Currency::EUR, 300)),
new ProcessingCode('PC1'),
new CouponPicture(new PicturePath('coupons/product.jpg'), new PicturePath('coupons/thumbnail.jpg')),
new GS1('01234567890128', BarcodeFormat::EAN13),
new CouponValidity(30, new DateTime()),
2026-09-23 09:40:47 +02:00
);
});
it('finds a campaign request by its id, along with its brand', function (): void {
// GIVEN
$id = CampaignRequestId::generate();
$code = new BrandCode('AAA01');
$campaignRequest = CampaignRequest::hydrate(
$id,
$code,
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
new CountryAuthorized(Country::FRANCE),
CampaignRequestType::CLUB,
2026-09-23 09:40:47 +02:00
new PrintRules(maxPerCustomer: 3),
$this->requestedCoupon,
CampaignRequestStatus::CREATED,
2026-09-23 09:40:47 +02:00
);
$brand = Brand::hydrate(
BrandId::generate(),
$code,
new BrandName('Brand A'),
new PicturePath('brands/logo.jpg'),
new Rcs('RCS PARIS 111 222 333'),
new Email('contact@example.com'),
);
$repository = \Mockery::mock(CampaignRequestRepository::class);
$repository->shouldReceive('findById')->once()->with($id)->andReturn($campaignRequest);
$brandRepository = \Mockery::mock(BrandRepository::class);
$brandRepository->shouldReceive('findByCode')->once()->with($code)->andReturn($brand);
$useCase = new FindCampaignRequest($repository, $brandRepository);
// WHEN
$result = $useCase->execute(new Input(id: $id));
// THEN
expect($result)->toBeInstanceOf(CampaignRequestFound::class)
->and($result->brand)->toBe($brand)
->and($result->applicant)->toBe($campaignRequest->applicant)
->and($result->country)->toBe($campaignRequest->country)
->and($result->campaignType)->toBe($campaignRequest->campaignType)
->and($result->printRules)->toBe($campaignRequest->printRules)
->and($result->requestedCoupon)->toBe($campaignRequest->requestedCoupon)
->and($result->status)->toBe($campaignRequest->status)
->and($result->rejectionReason)->toBeNull();
});
it('finds a rejected campaign request with its rejection reason', function (): void {
// GIVEN
$id = CampaignRequestId::generate();
$code = new BrandCode('AAA01');
$rejectionReason = new RejectionReason('Missing legal documents.');
$campaignRequest = CampaignRequest::hydrate(
$id,
$code,
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
new CountryAuthorized(Country::FRANCE),
CampaignRequestType::CLUB,
2026-09-23 09:40:47 +02:00
new PrintRules(maxPerCustomer: 3),
$this->requestedCoupon,
CampaignRequestStatus::REJECTED,
2026-09-23 09:40:47 +02:00
$rejectionReason,
);
$repository = \Mockery::mock(CampaignRequestRepository::class);
$repository->shouldReceive('findById')->once()->with($id)->andReturn($campaignRequest);
$brandRepository = \Mockery::mock(BrandRepository::class);
$brandRepository->shouldReceive('findByCode')->once()->with($code)->andReturn(
Brand::hydrate(
BrandId::generate(),
$code,
new BrandName('Brand A'),
new PicturePath('brands/logo.jpg'),
new Rcs('RCS PARIS 111 222 333'),
new Email('contact@example.com'),
)
);
$useCase = new FindCampaignRequest($repository, $brandRepository);
// WHEN
$result = $useCase->execute(new Input(id: $id));
// THEN
expect($result)->toBeInstanceOf(CampaignRequestFound::class)
->and($result->status)->toBe(CampaignRequestStatus::REJECTED)
2026-09-23 09:40:47 +02:00
->and($result->rejectionReason)->toBe($rejectionReason);
});
2026-09-23 09:29:22 +02:00
it('returns CampaignRequestNotFound when the id is not found', function (): void {
// GIVEN
$id = CampaignRequestId::generate();
$repository = \Mockery::mock(CampaignRequestRepository::class);
$repository->shouldReceive('findById')->once()->with($id)->andReturn(null);
$brandRepository = \Mockery::mock(BrandRepository::class);
$brandRepository->shouldNotReceive('findByCode');
$useCase = new FindCampaignRequest($repository, $brandRepository);
// WHEN
$result = $useCase->execute(new Input(id: $id));
// THEN
expect($result)->toBeInstanceOf(CampaignRequestNotFound::class);
});
it('throws when the campaign request references a brand that no longer exists', function (): void {
// GIVEN
$id = CampaignRequestId::generate();
$code = new BrandCode('AAA01');
$campaignRequest = CampaignRequest::hydrate(
$id,
$code,
new Applicant('John', 'Doe', new Email('john.doe@example.com')),
new CountryAuthorized(Country::FRANCE),
CampaignRequestType::CLUB,
2026-09-23 09:29:22 +02:00
new PrintRules(maxPerCustomer: 3),
2026-09-23 09:40:47 +02:00
$this->requestedCoupon,
CampaignRequestStatus::CREATED,
2026-09-23 09:29:22 +02:00
);
$repository = \Mockery::mock(CampaignRequestRepository::class);
$repository->shouldReceive('findById')->once()->with($id)->andReturn($campaignRequest);
$brandRepository = \Mockery::mock(BrandRepository::class);
$brandRepository->shouldReceive('findByCode')->once()->with($code)->andReturn(null);
$useCase = new FindCampaignRequest($repository, $brandRepository);
// WHEN
$action = fn (): Output => $useCase->execute(new Input(id: $id));
// THEN
expect($action)->toThrow(BrandNotFoundException::class);
});
});
describe('find campaign request use case assertions', function (): void {
2026-09-23 09:40:47 +02:00
it('rejects an input of the wrong type', function (): void {
2026-09-23 09:29:22 +02:00
// GIVEN
$repository = \Mockery::mock(CampaignRequestRepository::class);
$brandRepository = \Mockery::mock(BrandRepository::class);
$useCase = new FindCampaignRequest($repository, $brandRepository);
$invalidInput = new class () implements BaseInput
{
};
// WHEN
$action = fn (): Output => $useCase->execute($invalidInput);
// THEN
expect($action)->toThrow(\InvalidArgumentException::class);
});
});