214 lines
8.5 KiB
PHP
214 lines
8.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Domain\Services;
|
|
|
|
use Domain\Enums\ProductBrand;
|
|
use Domain\Enums\TaxRate;
|
|
use Domain\Enums\Units\OrderUnit;
|
|
use Domain\Models\Entities\Basket;
|
|
use Domain\Models\ValueObjects\BasketProduct;
|
|
use Domain\Models\ValueObjects\DiscountRate;
|
|
use Domain\Models\ValueObjects\Entities\BasketId;
|
|
use Domain\Models\ValueObjects\Entities\ProductId;
|
|
use Domain\Models\ValueObjects\IncoId;
|
|
use Domain\Models\ValueObjects\SessionId;
|
|
use Domain\Ports\Repositories\BasketRepository;
|
|
use Domain\Ports\Repositories\ProductRepository;
|
|
use Domain\Ports\Services\SessionService;
|
|
use Domain\Services\BasketService;
|
|
use Mockery;
|
|
use Money\Money;
|
|
use Ramsey\Uuid\Uuid;
|
|
|
|
function makeBasketProduct(array $overrides = []): BasketProduct
|
|
{
|
|
$data = array_merge([
|
|
'id' => new ProductId(Uuid::fromString('019e9e37-f2a1-74ef-b9c2-66d222470128')),
|
|
'name' => 'Poulet Rôti',
|
|
'qty' => 1,
|
|
'unitPriceHt' => Money::EUR(1000),
|
|
'unitDiscount' => Money::EUR(0),
|
|
'taxRate' => TaxRate::TVA_5_5,
|
|
'weightGrams' => 1200,
|
|
'brand' => ProductBrand::marie,
|
|
'incoId' => new IncoId(45),
|
|
'orderUnit' => OrderUnit::PCE,
|
|
'slug' => 'poulet-roti',
|
|
'picture' => 'images/poulet.jpg',
|
|
'description' => 'Un bon poulet',
|
|
'weightVariable' => false,
|
|
'discountRate' => DiscountRate::fromRatio(0.0),
|
|
'priceKgTtc' => Money::EUR(1500),
|
|
], $overrides);
|
|
|
|
return new BasketProduct(...$data);
|
|
}
|
|
|
|
describe('BasketService', function (): void {
|
|
|
|
it('adds a new product to the basket and saves it', function (): void {
|
|
// GIVEN
|
|
$productId = new ProductId(Uuid::uuid7());
|
|
$qty = 2;
|
|
$basket = new Basket(new BasketId(Uuid::uuid7()));
|
|
$basketProduct = makeBasketProduct(['id' => $productId, 'qty' => $qty]);
|
|
|
|
$basketRepository = Mockery::mock(BasketRepository::class);
|
|
$sessionService = Mockery::mock(SessionService::class);
|
|
$sessionService->shouldReceive('get')->andReturn(new SessionId(Uuid::uuid7()))->byDefault();
|
|
$basketRepository->shouldReceive('find')->once()->andReturn($basket);
|
|
$basketRepository->shouldReceive('persist')->once()->with(Mockery::on(function (Basket $b) use ($productId) {
|
|
return $b->has($productId) && $b->countItems() === 2;
|
|
}));
|
|
|
|
$productRepository = Mockery::mock(ProductRepository::class);
|
|
$productRepository->shouldReceive('getBasketProduct')->once()->with($productId, $qty)->andReturn($basketProduct);
|
|
|
|
$service = new BasketService($basketRepository, $productRepository, $sessionService);
|
|
|
|
// WHEN
|
|
$service->add($productId, $qty);
|
|
|
|
// THEN
|
|
expect($basket->has($productId))->toBeTrue();
|
|
});
|
|
|
|
it('removes a quantity from the basket', function (): void {
|
|
// GIVEN
|
|
$productId = new ProductId(Uuid::uuid7());
|
|
$basket = new Basket(new BasketId(Uuid::uuid7()));
|
|
$basket->addOrUpdate(makeBasketProduct(['id' => $productId, 'qty' => 3]));
|
|
|
|
$basketRepository = Mockery::mock(BasketRepository::class);
|
|
$sessionService = Mockery::mock(SessionService::class);
|
|
$sessionService->shouldReceive('get')->andReturn(new SessionId(Uuid::uuid7()))->byDefault();
|
|
$basketRepository->shouldReceive('find')->once()->andReturn($basket);
|
|
$basketRepository->shouldReceive('persist')->once()->with(Mockery::on(function (Basket $b) use ($productId) {
|
|
$items = $b->items();
|
|
|
|
return $items[(string) $productId->value]->qty === 1;
|
|
}));
|
|
|
|
$productRepository = Mockery::mock(ProductRepository::class);
|
|
|
|
$service = new BasketService($basketRepository, $productRepository, $sessionService);
|
|
|
|
// WHEN
|
|
$service->remove($productId, 2);
|
|
|
|
// THEN
|
|
$items = $basket->items();
|
|
expect($items[(string) $productId->value]->qty)->toBe(1);
|
|
});
|
|
|
|
it('removes the entire line when quantity to remove equals current quantity', function (): void {
|
|
// GIVEN
|
|
$productId = new ProductId(Uuid::uuid7());
|
|
$basket = new Basket(new BasketId(Uuid::uuid7()));
|
|
$basket->addOrUpdate(makeBasketProduct(['id' => $productId, 'qty' => 3]));
|
|
|
|
$basketRepository = Mockery::mock(BasketRepository::class);
|
|
$sessionService = Mockery::mock(SessionService::class);
|
|
$sessionService->shouldReceive('get')->andReturn(new SessionId(Uuid::uuid7()))->byDefault();
|
|
$basketRepository->shouldReceive('find')->once()->andReturn($basket);
|
|
$basketRepository->shouldReceive('persist')->once()->with(Mockery::on(function (Basket $b) use ($productId) {
|
|
return ! $b->has($productId);
|
|
}));
|
|
|
|
$productRepository = Mockery::mock(ProductRepository::class);
|
|
|
|
$service = new BasketService($basketRepository, $productRepository, $sessionService);
|
|
|
|
// WHEN
|
|
$service->remove($productId, 3);
|
|
|
|
// THEN
|
|
expect($basket->has($productId))->toBeFalse();
|
|
});
|
|
|
|
it('removes an entire line directly via removeLine', function (): void {
|
|
// GIVEN
|
|
$productId = new ProductId(Uuid::uuid7());
|
|
$basket = new Basket(new BasketId(Uuid::uuid7()));
|
|
$basket->addOrUpdate(makeBasketProduct(['id' => $productId, 'qty' => 5]));
|
|
|
|
$basketRepository = Mockery::mock(BasketRepository::class);
|
|
$sessionService = Mockery::mock(SessionService::class);
|
|
$sessionService->shouldReceive('get')->andReturn(new SessionId(Uuid::uuid7()))->byDefault();
|
|
$basketRepository->shouldReceive('find')->once()->andReturn($basket);
|
|
$basketRepository->shouldReceive('persist')->once()->with(Mockery::on(function (Basket $b) use ($productId) {
|
|
return ! $b->has($productId);
|
|
}));
|
|
|
|
$productRepository = Mockery::mock(ProductRepository::class);
|
|
|
|
$service = new BasketService($basketRepository, $productRepository, $sessionService);
|
|
|
|
// WHEN
|
|
$service->removeLine($productId);
|
|
|
|
// THEN
|
|
expect($basket->has($productId))->toBeFalse();
|
|
});
|
|
|
|
it('empties the basket by destroying it from repository', function (): void {
|
|
// GIVEN
|
|
$basketRepository = Mockery::mock(BasketRepository::class);
|
|
$sessionService = Mockery::mock(SessionService::class);
|
|
$sessionService->shouldReceive('get')->andReturn(new SessionId(Uuid::uuid7()))->byDefault();
|
|
$basketRepository->shouldReceive('find')->once()->andReturn(new Basket(new BasketId(Uuid::uuid7())));
|
|
$basketRepository->shouldReceive('delete')->once();
|
|
|
|
$productRepository = Mockery::mock(ProductRepository::class);
|
|
|
|
$service = new BasketService($basketRepository, $productRepository, $sessionService);
|
|
|
|
// WHEN
|
|
$service->empty();
|
|
|
|
// THEN
|
|
expect(true)->toBeTrue();
|
|
});
|
|
|
|
it('gets the basket from repository', function (): void {
|
|
// GIVEN
|
|
$basket = new Basket(new BasketId(Uuid::uuid7()));
|
|
$basketRepository = Mockery::mock(BasketRepository::class);
|
|
$sessionService = Mockery::mock(SessionService::class);
|
|
$sessionService->shouldReceive('get')->andReturn(new SessionId(Uuid::uuid7()))->byDefault();
|
|
$basketRepository->shouldReceive('find')->once()->andReturn($basket);
|
|
|
|
$productRepository = Mockery::mock(ProductRepository::class);
|
|
|
|
$service = new BasketService($basketRepository, $productRepository, $sessionService);
|
|
|
|
// WHEN
|
|
$returnedBasket = $service->getBasket();
|
|
|
|
// THEN
|
|
expect($returnedBasket)->toBe($basket);
|
|
});
|
|
|
|
it('returns a new basket if not found in repository', function (): void {
|
|
// GIVEN
|
|
$sessionId = new SessionId(Uuid::uuid7());
|
|
$basketRepository = Mockery::mock(BasketRepository::class);
|
|
$sessionService = Mockery::mock(SessionService::class);
|
|
$sessionService->shouldReceive('get')->andReturn($sessionId)->byDefault();
|
|
$basketRepository->shouldReceive('find')->once()->andReturn(null);
|
|
|
|
$productRepository = Mockery::mock(ProductRepository::class);
|
|
|
|
$service = new BasketService($basketRepository, $productRepository, $sessionService);
|
|
|
|
// WHEN
|
|
$returnedBasket = $service->getBasket();
|
|
|
|
// THEN
|
|
expect($returnedBasket)->toBeInstanceOf(Basket::class)
|
|
->and($returnedBasket->id->value)->toBe($sessionId->value)
|
|
->and($returnedBasket->countItems())->toBe(0);
|
|
});
|
|
});
|