toBase58() ), employee: $overrides['employee'] ?? new OrderEmployee( matricule: new Matricule('1234567'), firstname: 'Jean', lastname: 'Dupont', facility: new ShopperEstablishmentCode('ETAB01'), site: new ShopperSiteCode('SITEA'), service: new ShopperServiceCode('101'), ), deliveryAddress: $overrides['deliveryAddress'] ?? new DeliveryAddress( name: 'Cocotte Lyon', address: '12 rue de la Paix', postcode: '69001', city: 'Lyon', ), pickupTimeSlot: $overrides['pickupTimeSlot'] ?? new PickupTimeSlot( new \DateTimeImmutable('+1 day 10:00'), new \DateInterval('PT10M'), ), status: $overrides['status'] ?? OrderStatus::VALIDATED, total: $overrides['total'] ?? Money::EUR(3798), lines: $overrides['lines'] ?? [makeOrderLine()], ); } describe('Order - Instantiation', function (): void { it('can instantiate a valid order', function (): void { // GIVEN $line = makeOrderLine(); // WHEN $order = makeOrder(['lines' => [$line]]); // THEN expect($order)->toBeInstanceOf(Order::class) ->and($order->status)->toBe(OrderStatus::VALIDATED) ->and($order->getTotal()->getAmount())->toBe('3798') ->and($order->getLines())->toHaveCount(1); }); it('throws if total is zero or negative', function (): void { // GIVEN $total = Money::EUR(0); // WHEN $action = fn () => makeOrder(['total' => $total]); // THEN expect($action)->toThrow(\DomainException::class, 'Total amount must be greater than zero'); }); it('throws if lines contain non-OrderLine instances', function (): void { // GIVEN $lines = ['not-an-order-line']; // WHEN $action = fn () => makeOrder(['lines' => $lines]); // THEN expect($action)->toThrow(\DomainException::class, 'All lines must be instances of OrderLine'); }); }); describe('Order - Cancellation', function (): void { it('cancels a validated order', function (): void { // GIVEN $order = makeOrder(['status' => OrderStatus::VALIDATED]); // WHEN $order->cancel(); // THEN expect($order->status)->toBe(OrderStatus::CANCELED); }); it('cancels a waiting order', function (): void { // GIVEN $order = makeOrder(['status' => OrderStatus::WAITING]); // WHEN $order->cancel(); // THEN expect($order->status)->toBe(OrderStatus::CANCELED); }); it('is idempotent when cancelling an already cancelled order', function (): void { // GIVEN $order = makeOrder(['status' => OrderStatus::CANCELED]); // WHEN $order->cancel(); // THEN expect($order->status)->toBe(OrderStatus::CANCELED); }); }); describe('Order - Getters immutability', function (): void { it('returns a clone of total', function (): void { // GIVEN $order = makeOrder(['total' => Money::EUR(5000)]); // WHEN $total1 = $order->getTotal(); $total2 = $order->getTotal(); // THEN expect($total1)->toEqual($total2); }); it('returns clones of lines', function (): void { // GIVEN $order = makeOrder(); // WHEN $lines1 = $order->getLines(); $lines2 = $order->getLines(); // THEN expect($lines1[0])->toEqual($lines2[0]); }); }); describe('Order - id', function (): void { it('returns id', function (): void { // GIVEN $order = makeOrder(); // WHEN $id = $order->id(); // THEN expect($id)->toBeInstanceOf(OrderId::class); }); });