registry = new SubscriptionRegistry(); // Create mock WebSocket connection using Mockery $this->connection = Mockery::mock(WebSocketConnectionInterface::class); $this->connection->shouldReceive('getId')->andReturn('test-connection-1'); $this->connection->shouldReceive('isConnected')->andReturn(true); $this->connection->shouldReceive('sendJson')->andReturnTrue(); $this->connection->shouldReceive('setAttribute')->andReturnNull(); $this->connection->shouldReceive('getAttribute')->andReturn(null); $this->sentMessages = []; }); it('can register and retrieve subscriptions', function () { $id = SubscriptionId::generate(); $this->registry->register( $id, $this->connection, 'notificationReceived', ['userId' => '123'] ); $subscriptions = $this->registry->getByName('notificationReceived'); expect($subscriptions)->toHaveCount(1); expect($subscriptions[0]['id']->toString())->toBe($id->toString()); expect($subscriptions[0]['variables']['userId'])->toBe('123'); }); it('can unregister subscriptions', function () { $id = SubscriptionId::generate(); $this->registry->register( $id, $this->connection, 'notificationReceived', ['userId' => '123'] ); expect($this->registry->getByName('notificationReceived'))->toHaveCount(1); $this->registry->unregister($id); expect($this->registry->getByName('notificationReceived'))->toHaveCount(0); }); it('can cleanup subscriptions by connection', function () { $id1 = SubscriptionId::generate(); $id2 = SubscriptionId::generate(); $this->registry->register( $id1, $this->connection, 'notificationReceived', ['userId' => '123'] ); $this->registry->register( $id2, $this->connection, 'orderStatusChanged', ['orderId' => 'order-1'] ); expect($this->registry->getByName('notificationReceived'))->toHaveCount(1); expect($this->registry->getByName('orderStatusChanged'))->toHaveCount(1); $this->registry->removeByConnection($this->connection); expect($this->registry->getByName('notificationReceived'))->toHaveCount(0); expect($this->registry->getByName('orderStatusChanged'))->toHaveCount(0); }); it('provides subscription statistics', function () { $this->registry->register( SubscriptionId::generate(), $this->connection, 'notificationReceived', ['userId' => '123'] ); $this->registry->register( SubscriptionId::generate(), $this->connection, 'orderStatusChanged', ['orderId' => 'order-1'] ); $stats = $this->registry->getStats(); expect($stats['total_subscriptions'])->toBe(2); expect($stats['unique_connections'])->toBe(1); expect($stats['subscriptions_by_type']['notificationReceived'])->toBe(1); expect($stats['subscriptions_by_type']['orderStatusChanged'])->toBe(1); }); it('discovers GraphQLSubscription classes', function () { $reflection = new ReflectionClass(NotificationSubscriptions::class); $attribute = $reflection->getAttributes(GraphQLSubscription::class)[0] ?? null; expect($attribute)->not->toBeNull(); $instance = $attribute->newInstance(); expect($instance->description)->toBe('Real-time notification subscriptions'); }); it('builds subscription fields in schema', function () { // Create simple container for testing $container = new \App\Framework\DI\DefaultContainer(); $typeResolver = new \App\Framework\GraphQL\Schema\TypeResolver(); $schemaBuilder = new SchemaBuilder($container, $typeResolver); $schema = $schemaBuilder->build([ NotificationSubscriptions::class, ]); expect($schema->subscriptions)->toHaveCount(3); expect($schema->getSubscription('notificationReceived'))->not->toBeNull(); expect($schema->getSubscription('orderStatusChanged'))->not->toBeNull(); expect($schema->getSubscription('systemAnnouncement'))->not->toBeNull(); }); it('generates correct SDL for subscriptions', function () { // Create simple container for testing $container = new \App\Framework\DI\DefaultContainer(); $typeResolver = new \App\Framework\GraphQL\Schema\TypeResolver(); $schemaBuilder = new SchemaBuilder($container, $typeResolver); $schema = $schemaBuilder->build([ NotificationSubscriptions::class, ]); $sdl = $schema->toSDL(); expect($sdl)->toContain('type Subscription {'); expect($sdl)->toContain('notificationReceived'); expect($sdl)->toContain('orderStatusChanged'); expect($sdl)->toContain('systemAnnouncement'); }); });