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); }); });