container = new DefaultContainer(); $this->typeResolver = new TypeResolver(); $this->schemaBuilder = new SchemaBuilder($this->container, $this->typeResolver); }); it('builds schema from GraphQL type classes', function () { $schema = $this->schemaBuilder->build([TestUserType::class]); expect($schema)->toBeInstanceOf(Schema::class); $stats = $schema->getStats(); expect($stats['types_count'])->toBeGreaterThan(0); }); it('parses simple GraphQL query', function () { $parser = new QueryParser(); $query = <<<'GRAPHQL' { user(id: 1) { id name email } } GRAPHQL; $parsed = $parser->parse($query); expect($parsed->fields)->toHaveCount(1); expect($parsed->fields[0]->name)->toBe('user'); expect($parsed->fields[0]->arguments)->toBe(['id' => 1]); expect($parsed->fields[0]->selections)->toHaveCount(3); }); it('parses query with variables', function () { $parser = new QueryParser(); $query = <<<'GRAPHQL' query GetUser($id: Int!) { user(id: $id) { id name } } GRAPHQL; $parsed = $parser->parse($query); expect($parsed->variables)->toHaveKey('id'); expect($parsed->fields[0]->arguments)->toBe(['id' => '$id']); }); it('executes simple query against schema', function () { // Build schema with test query $schema = $this->schemaBuilder->build([ TestUserType::class, TestUserQueries::class, ]); // Register test service $this->container->singleton(TestUserService::class, new TestUserService()); $executor = new QueryExecutor($schema); $parser = new QueryParser(); $query = <<<'GRAPHQL' { user(id: 1) { id name email } } GRAPHQL; $parsed = $parser->parse($query); $result = $executor->execute($parsed); expect($result->isSuccessful())->toBeTrue(); expect($result->data)->toHaveKey('user'); expect($result->data['user']['id'])->toBe(1); expect($result->data['user']['name'])->toBe('Test User'); }); it('handles query with variables', function () { $schema = $this->schemaBuilder->build([ TestUserType::class, TestUserQueries::class, ]); $this->container->singleton(TestUserService::class, new TestUserService()); $executor = new QueryExecutor($schema); $parser = new QueryParser(); $query = <<<'GRAPHQL' query GetUser($userId: Int!) { user(id: $userId) { id name } } GRAPHQL; $parsed = $parser->parse($query); $result = $executor->execute($parsed, ['userId' => 1]); expect($result->isSuccessful())->toBeTrue(); expect($result->data['user']['id'])->toBe(1); }); it('generates correct GraphQL SDL', function () { $schema = $this->schemaBuilder->build([ TestUserType::class, TestUserQueries::class, ]); $sdl = $schema->toSDL(); expect($sdl)->toContain('type TestUser {'); expect($sdl)->toContain('id: Int!'); expect($sdl)->toContain('name: String!'); expect($sdl)->toContain('type Query {'); expect($sdl)->toContain('user(id: Int!): TestUser'); }); it('handles errors gracefully', function () { $schema = $this->schemaBuilder->build([ TestUserType::class, TestUserQueries::class, ]); $this->container->singleton(TestUserService::class, new TestUserService()); $executor = new QueryExecutor($schema); $parser = new QueryParser(); // Query non-existent field $query = '{ nonExistentField }'; $parsed = $parser->parse($query); $result = $executor->execute($parsed); expect($result->isSuccessful())->toBeFalse(); expect($result->errors)->not->toBeNull(); }); }); // Test classes for GraphQL system #[GraphQLType(description: 'Test user type')] final readonly class TestUserType { public function __construct( #[GraphQLField(description: 'User ID')] public int $id, #[GraphQLField(description: 'User name')] public string $name, #[GraphQLField(description: 'User email')] public string $email ) { } } #[GraphQLQuery] final readonly class TestUserQueries { public function __construct( private TestUserService $userService ) { } #[GraphQLField(description: 'Get user by ID')] public function user(int $id): TestUserType { return $this->userService->findById($id); } #[GraphQLField(description: 'Get all users')] public function users(int $limit = 10): array { return $this->userService->findAll($limit); } } final readonly class TestUserService { public function findById(int $id): TestUserType { return new TestUserType( id: $id, name: 'Test User', email: 'test@example.com' ); } public function findAll(int $limit): array { return [ new TestUserType(1, 'User 1', 'user1@example.com'), new TestUserType(2, 'User 2', 'user2@example.com'), ]; } }