171 lines
7.2 KiB
PHP
171 lines
7.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Application\UseCases\Campaign\Update;
|
|
|
|
use Application\UseCases\Campaign\Outputs\CampaignNotFound;
|
|
use Application\UseCases\Campaign\Update\AutoUnpublishCampaign;
|
|
use Application\UseCases\Campaign\Update\Inputs\AutoUnpublishCampaignInput;
|
|
use Application\UseCases\Campaign\Update\Outputs\CampaignStatusUpdated;
|
|
use Application\UseCases\Campaign\Update\Outputs\CampaignUnpublicationSkipped;
|
|
use Domain\Models\Entities\Campaign;
|
|
use Domain\Models\ValueObjects\Campaign\CampaignCode;
|
|
use Domain\Models\ValueObjects\Coupon\CouponCode;
|
|
use Domain\Ports\Repositories\CampaignRepository;
|
|
use Domain\Ports\Repositories\CouponRepository;
|
|
use Domain\Services\Campaign\CampaignAvailabilityChecker;
|
|
use Tests\Fixtures\Campaign\CampaignFactory;
|
|
use Tests\Fixtures\Coupon\CouponFactory;
|
|
|
|
covers(
|
|
AutoUnpublishCampaign::class,
|
|
AutoUnpublishCampaignInput::class,
|
|
CampaignStatusUpdated::class,
|
|
CampaignUnpublicationSkipped::class,
|
|
CampaignNotFound::class,
|
|
);
|
|
|
|
describe('auto unpublish campaign use case', function (): void {
|
|
it('returns CampaignNotFound when the campaign does not exist', function (): void {
|
|
// GIVEN
|
|
$code = CampaignCode::generate();
|
|
|
|
$repository = \Mockery::mock(CampaignRepository::class);
|
|
$repository->shouldReceive('findByCode')->once()->with($code)->andReturn(null);
|
|
$repository->shouldNotReceive('save');
|
|
|
|
$couponRepository = \Mockery::mock(CouponRepository::class);
|
|
$couponRepository->shouldNotReceive('findByCodes');
|
|
|
|
$useCase = new AutoUnpublishCampaign($repository, new CampaignAvailabilityChecker($couponRepository));
|
|
|
|
// WHEN
|
|
$result = $useCase->execute(new AutoUnpublishCampaignInput($code));
|
|
|
|
// THEN
|
|
expect($result)->toBeInstanceOf(CampaignNotFound::class);
|
|
});
|
|
|
|
it('skips an already unpublished campaign without querying coupons', function (): void {
|
|
// GIVEN
|
|
$campaign = CampaignFactory::hydrated(published: false);
|
|
|
|
$repository = \Mockery::mock(CampaignRepository::class);
|
|
$repository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
|
$repository->shouldNotReceive('save');
|
|
|
|
$couponRepository = \Mockery::mock(CouponRepository::class);
|
|
$couponRepository->shouldNotReceive('findByCodes');
|
|
|
|
$useCase = new AutoUnpublishCampaign($repository, new CampaignAvailabilityChecker($couponRepository));
|
|
|
|
// WHEN
|
|
$result = $useCase->execute(new AutoUnpublishCampaignInput($campaign->code));
|
|
|
|
// THEN
|
|
expect($result)->toBeInstanceOf(CampaignUnpublicationSkipped::class);
|
|
});
|
|
|
|
it('skips a published campaign that still has an active coupon', function (): void {
|
|
// GIVEN
|
|
$couponCode = CouponCode::generate();
|
|
$campaign = CampaignFactory::hydrated(published: true, couponCodes: [$couponCode]);
|
|
|
|
$repository = \Mockery::mock(CampaignRepository::class);
|
|
$repository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
|
$repository->shouldNotReceive('save');
|
|
|
|
$couponRepository = \Mockery::mock(CouponRepository::class);
|
|
$couponRepository->shouldReceive('findByCodes')->once()->andReturn([CouponFactory::make()]);
|
|
|
|
$useCase = new AutoUnpublishCampaign($repository, new CampaignAvailabilityChecker($couponRepository));
|
|
|
|
// WHEN
|
|
$result = $useCase->execute(new AutoUnpublishCampaignInput($campaign->code));
|
|
|
|
// THEN
|
|
expect($result)->toBeInstanceOf(CampaignUnpublicationSkipped::class);
|
|
});
|
|
|
|
it('skips a published campaign with one active and one expired coupon', function (): void {
|
|
// GIVEN
|
|
$campaign = CampaignFactory::hydrated(published: true, couponCodes: [CouponCode::generate(), CouponCode::generate()]);
|
|
|
|
$repository = \Mockery::mock(CampaignRepository::class);
|
|
$repository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
|
$repository->shouldNotReceive('save');
|
|
|
|
$couponRepository = \Mockery::mock(CouponRepository::class);
|
|
$couponRepository->shouldReceive('findByCodes')->once()->andReturn([
|
|
CouponFactory::expired(),
|
|
CouponFactory::make(),
|
|
]);
|
|
|
|
$useCase = new AutoUnpublishCampaign($repository, new CampaignAvailabilityChecker($couponRepository));
|
|
|
|
// WHEN
|
|
$result = $useCase->execute(new AutoUnpublishCampaignInput($campaign->code));
|
|
|
|
// THEN
|
|
expect($result)->toBeInstanceOf(CampaignUnpublicationSkipped::class);
|
|
});
|
|
|
|
it('unpublishes a published campaign when every coupon is not available', function (): void {
|
|
// GIVEN
|
|
$couponCode1 = CouponCode::generate();
|
|
$couponCode2 = CouponCode::generate();
|
|
$campaign = CampaignFactory::hydrated(published: true, couponCodes: [$couponCode1->value, $couponCode2->value]);
|
|
|
|
$repository = \Mockery::mock(CampaignRepository::class);
|
|
$repository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
|
$repository->shouldReceive('save')->once()->with(\Mockery::on(
|
|
static fn (Campaign $saved): bool => $saved->publication === false
|
|
&& $saved->code === $campaign->code
|
|
&& $saved->updatedAt() instanceof \DateTimeInterface,
|
|
));
|
|
|
|
$couponRepository = \Mockery::mock(CouponRepository::class);
|
|
$couponRepository->shouldReceive('findByCodes')->once()->andReturn([
|
|
CouponFactory::expired(),
|
|
CouponFactory::upcoming(),
|
|
]);
|
|
|
|
$useCase = new AutoUnpublishCampaign($repository, new CampaignAvailabilityChecker($couponRepository));
|
|
|
|
// WHEN
|
|
$result = $useCase->execute(new AutoUnpublishCampaignInput($campaign->code));
|
|
|
|
// THEN
|
|
expect($result)->toBeInstanceOf(CampaignStatusUpdated::class)
|
|
->and($result->publication)->toBeFalse()
|
|
->and($result->code)->toBe($campaign->code)
|
|
->and($result->name)->toBe($campaign->name)
|
|
->and($result->brandCode)->toBe($campaign->brandCode)
|
|
->and($result->coupons)->toBe($campaign->coupons);
|
|
});
|
|
|
|
it('unpublishes a published campaign when no coupon is found', function (): void {
|
|
// GIVEN
|
|
$couponCode = CouponCode::generate();
|
|
$campaign = CampaignFactory::hydrated(published: true, couponCodes: [$couponCode]);
|
|
|
|
$repository = \Mockery::mock(CampaignRepository::class);
|
|
$repository->shouldReceive('findByCode')->once()->with($campaign->code)->andReturn($campaign);
|
|
$repository->shouldReceive('save')->once()->with(\Mockery::on(
|
|
static fn (Campaign $saved): bool => $saved->publication === false,
|
|
));
|
|
|
|
$couponRepository = \Mockery::mock(CouponRepository::class);
|
|
$couponRepository->shouldReceive('findByCodes')->once()->andReturn([]);
|
|
|
|
$useCase = new AutoUnpublishCampaign($repository, new CampaignAvailabilityChecker($couponRepository));
|
|
|
|
// WHEN
|
|
$result = $useCase->execute(new AutoUnpublishCampaignInput($campaign->code));
|
|
|
|
// THEN
|
|
expect($result)->toBeInstanceOf(CampaignStatusUpdated::class)
|
|
->and($result->publication)->toBeFalse();
|
|
});
|
|
});
|