Files
michaelschiemer/tests/Framework/GraphQL/GraphQLSystemTest.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

224 lines
6.1 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Core\ValueObjects\EmailAddress;
use App\Framework\DI\DefaultContainer;
use App\Framework\GraphQL\Attributes\GraphQLField;
use App\Framework\GraphQL\Attributes\GraphQLQuery;
use App\Framework\GraphQL\Attributes\GraphQLType;
use App\Framework\GraphQL\Execution\QueryExecutor;
use App\Framework\GraphQL\Execution\QueryParser;
use App\Framework\GraphQL\Schema\Schema;
use App\Framework\GraphQL\Schema\SchemaBuilder;
use App\Framework\GraphQL\Schema\TypeResolver;
describe('GraphQL System', function () {
beforeEach(function () {
$this->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'),
];
}
}