dispatchedEvents[] = $event; } } describe('Notification System', function () { beforeEach(function () { // Setup test dependencies $this->queue = new InMemoryQueue(); $this->eventBus = new MockEventBus(); }); it('can create a notification with required fields', function () { $notification = Notification::create( 'user-123', NotificationType::system(), 'System Update', 'Your system has been updated', NotificationChannel::DATABASE, NotificationChannel::EMAIL ); expect($notification->recipientId)->toBe('user-123'); expect($notification->title)->toBe('System Update'); expect($notification->body)->toBe('Your system has been updated'); expect($notification->channels)->toHaveCount(2); expect($notification->priority)->toBe(NotificationPriority::NORMAL); }); it('can add action to notification', function () { $notification = Notification::create( 'user-123', NotificationType::system(), 'Action Required', 'Please review your settings', NotificationChannel::DATABASE )->withAction('/settings', 'Review Settings'); expect($notification->hasAction())->toBeTrue(); expect($notification->actionUrl)->toBe('/settings'); expect($notification->actionLabel)->toBe('Review Settings'); }); it('can set priority on notification', function () { $notification = Notification::create( 'user-123', NotificationType::security(), 'Security Alert', 'Unusual login detected', NotificationChannel::DATABASE, NotificationChannel::EMAIL )->withPriority(NotificationPriority::URGENT); expect($notification->priority)->toBe(NotificationPriority::URGENT); expect($notification->priority->shouldInterruptUser())->toBeTrue(); }); it('can add custom data to notification', function () { $notification = Notification::create( 'user-123', NotificationType::social(), 'New Follower', 'John Doe started following you', NotificationChannel::DATABASE )->withData([ 'follower_id' => 'user-456', 'follower_name' => 'John Doe', 'follower_avatar' => '/avatars/456.jpg', ]); expect($notification->data)->toHaveKey('follower_id'); expect($notification->data['follower_name'])->toBe('John Doe'); }); it('validates required fields', function () { try { Notification::create( '', NotificationType::system(), 'Test', 'Test body', NotificationChannel::DATABASE ); expect(true)->toBeFalse('Should have thrown exception'); } catch (\InvalidArgumentException $e) { expect($e->getMessage())->toContain('Recipient ID'); } }); it('requires at least one channel', function () { try { new Notification( id: \App\Framework\Notification\ValueObjects\NotificationId::generate(), recipientId: 'user-123', type: NotificationType::system(), title: 'Test', body: 'Test body', data: [], channels: [], // Empty channels priority: NotificationPriority::NORMAL, status: \App\Framework\Notification\ValueObjects\NotificationStatus::PENDING, createdAt: \App\Framework\Core\ValueObjects\Timestamp::now() ); expect(true)->toBeFalse('Should have thrown exception'); } catch (\InvalidArgumentException $e) { expect($e->getMessage())->toContain('channel'); } }); it('can mark notification as read', function () { $notification = Notification::create( 'user-123', NotificationType::system(), 'Test', 'Test body', NotificationChannel::DATABASE ); expect($notification->isRead())->toBeFalse(); $readNotification = $notification->markAsRead(); expect($readNotification->isRead())->toBeTrue(); expect($readNotification->readAt)->toBeInstanceOf(\App\Framework\Core\ValueObjects\Timestamp::class); }); it('can convert notification to array', function () { $notification = Notification::create( 'user-123', NotificationType::transactional(), 'Payment Received', 'Your payment of $50 was processed', NotificationChannel::DATABASE, NotificationChannel::EMAIL )->withData(['amount' => 50, 'currency' => 'USD']); $array = $notification->toArray(); expect($array)->toHaveKey('id'); expect($array)->toHaveKey('recipient_id'); expect($array['title'])->toBe('Payment Received'); expect($array['data']['amount'])->toBe(50); expect($array['channels'])->toContain('database'); expect($array['channels'])->toContain('email'); }); }); describe('Notification Dispatcher', function () { it('can queue notification for async delivery', function () { $queue = new InMemoryQueue(); $eventBus = new MockEventBus(); $dispatcher = new NotificationDispatcher( channels: [], queue: $queue, eventBus: $eventBus ); $notification = Notification::create( 'user-123', NotificationType::system(), 'Test', 'Test body', NotificationChannel::DATABASE ); expect($queue->size())->toBe(0); $dispatcher->sendLater($notification); expect($queue->size())->toBe(1); }); });