Skip to content

Commit

Permalink
Test RootTypeResolver
Browse files Browse the repository at this point in the history
  • Loading branch information
jerowork committed Jan 3, 2025
1 parent 0c6f6f5 commit be4e26a
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 4 deletions.
8 changes: 8 additions & 0 deletions src/TypeResolver/ResolveException.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@ public static function logicError(string $error): self
{
return new self(sprintf('Logic error: %s', $error));
}

/**
* @param class-string $typeId
*/
public static function nodeTypeIdNotInContainer(string $typeId): self
{
return new self(sprintf('Node type ID %s is not in a container (or not publicly accessible)', $typeId));
}
}
7 changes: 7 additions & 0 deletions src/TypeResolver/RootTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@ public function __construct(
private ContainerInterface $container,
) {}

/**
* @throws ResolveException
*/
public function resolve(MutationNode|QueryNode $node, Ast $ast): callable
{
if (!$this->container->has($node->typeId)) {
throw ResolveException::nodeTypeIdNotInContainer($node->typeId);
}

return function ($rootValue, array $args) use ($node, $ast) {
/** @var array<string, mixed> $args */
return $this->container->get($node->typeId)->{$node->methodName}(
Expand Down
9 changes: 7 additions & 2 deletions tests/Doubles/Container/TestContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@
final class TestContainer implements ContainerInterface
{
/**
* @var array<string, mixed>
* @var array<string, object>
*/
public array $services = [];

public function get(string $id): mixed
public function set(string $id, object $service): void
{
$this->services[$id] = $service;
}

public function get(string $id): ?object
{
return $this->services[$id] ?? null;
}
Expand Down
17 changes: 17 additions & 0 deletions tests/Doubles/InputType/TestResolvableInputType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Jerowork\GraphqlAttributeSchema\Test\Doubles\InputType;

use Jerowork\GraphqlAttributeSchema\Attribute\Field;
use Jerowork\GraphqlAttributeSchema\Attribute\InputType;

#[InputType]
final readonly class TestResolvableInputType
{
public function __construct(
#[Field]
public string $name,
) {}
}
7 changes: 6 additions & 1 deletion tests/Doubles/Mutation/TestMutation.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Jerowork\GraphqlAttributeSchema\Attribute\Arg;
use Jerowork\GraphqlAttributeSchema\Attribute\Mutation;
use DateTimeImmutable;
use DateTimeInterface;

#[Mutation(description: 'Test mutation')]
final readonly class TestMutation
Expand All @@ -18,6 +19,10 @@ public function __invoke(
#[Arg(name: 'mutationId', description: 'Mutation ID')]
?string $id,
): string {
return '';
return sprintf(
'Mutation has been called with date %s and id %s',
$date->format(DateTimeInterface::RFC3339_EXTENDED),
$id,
);
}
}
21 changes: 21 additions & 0 deletions tests/Doubles/Mutation/TestResolvableMutation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Jerowork\GraphqlAttributeSchema\Test\Doubles\Mutation;

use Jerowork\GraphqlAttributeSchema\Attribute\Mutation;
use Jerowork\GraphqlAttributeSchema\Test\Doubles\InputType\TestResolvableInputType;

#[Mutation]
final readonly class TestResolvableMutation
{
public function __invoke(string $id, TestResolvableInputType $input): string
{
return sprintf(
'Mutation has been called with id %s and input with name %s',
$id,
$input->name,
);
}
}
7 changes: 6 additions & 1 deletion tests/TypeBuilder/RootTypeBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/
final class RootTypeBuilderTest extends TestCase
{
private TestContainer $container;
private RootTypeBuilder $builder;

#[Override]
Expand All @@ -31,13 +32,17 @@ protected function setUp(): void

$this->builder = new RootTypeBuilder(
new TypeBuilder([]),
new RootTypeResolver(new TestContainer()),
new RootTypeResolver(
$this->container = new TestContainer(),
),
);
}

#[Test]
public function itShouldBuildRootNode(): void
{
$this->container->set(TestMutation::class, new TestMutation());

$type = $this->builder->build(
new MutationNode(
TestMutation::class,
Expand Down
173 changes: 173 additions & 0 deletions tests/TypeResolver/RootTypeResolverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?php

declare(strict_types=1);

namespace Jerowork\GraphqlAttributeSchema\Test\TypeResolver;

use Jerowork\GraphqlAttributeSchema\Parser\Ast;
use Jerowork\GraphqlAttributeSchema\Parser\Node\ArgNode;
use Jerowork\GraphqlAttributeSchema\Parser\Node\FieldNode;
use Jerowork\GraphqlAttributeSchema\Parser\Node\FieldNodeType;
use Jerowork\GraphqlAttributeSchema\Parser\Node\InputTypeNode;
use Jerowork\GraphqlAttributeSchema\Parser\Node\MutationNode;
use Jerowork\GraphqlAttributeSchema\Test\Doubles\Container\TestContainer;
use Jerowork\GraphqlAttributeSchema\Test\Doubles\InputType\TestResolvableInputType;
use Jerowork\GraphqlAttributeSchema\Test\Doubles\Mutation\TestResolvableMutation;
use Jerowork\GraphqlAttributeSchema\TypeResolver\ResolveException;
use Jerowork\GraphqlAttributeSchema\TypeResolver\RootTypeResolver;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Override;

/**
* @internal
*/
final class RootTypeResolverTest extends TestCase
{
private TestContainer $container;
private RootTypeResolver $rootTypeResolver;

#[Override]
protected function setUp(): void
{
parent::setUp();

$this->rootTypeResolver = new RootTypeResolver(
$this->container = new TestContainer(),
);
}

#[Test]
public function itShouldGuardIfNodeTypeIdIsInContainer(): void
{
self::expectException(ResolveException::class);
self::expectExceptionMessage('Node type ID ' . TestResolvableMutation::class . ' is not in a container');

$this->rootTypeResolver->resolve(
new MutationNode(
TestResolvableMutation::class,
'Test',
null,
[],
null,
'string',
true,
'__invoke',
),
new Ast(),
);
}

#[Test]
public function itShouldGuardIfNodeIsInAst(): void
{
$this->container->set(TestResolvableMutation::class, new TestResolvableMutation());

self::expectException(ResolveException::class);
self::expectExceptionMessage('Node ' . TestResolvableInputType::class . ' not found for typeId');

$type = $this->rootTypeResolver->resolve(
new MutationNode(
TestResolvableMutation::class,
'Test',
null,
[
new ArgNode(
null,
'string',
'id',
null,
true,
'id',
),
new ArgNode(
TestResolvableInputType::class,
null,
'input',
null,
true,
'input',
),
],
null,
'string',
true,
'__invoke',
),
new Ast(),
);

$type('rootValue', [
'id' => '45963d07-796c-44d5-8f1b-5e92ae6225a9',
'input' => [
'name' => 'Foobar',
],
]);
}

#[Test]
public function itShouldResolve(): void
{
$this->container->set(TestResolvableMutation::class, new TestResolvableMutation());

$type = $this->rootTypeResolver->resolve(
new MutationNode(
TestResolvableMutation::class,
'Test',
null,
[
new ArgNode(
null,
'string',
'id',
null,
true,
'id',
),
new ArgNode(
TestResolvableInputType::class,
null,
'input',
null,
true,
'input',
),
],
null,
'string',
true,
'__invoke',
),
new Ast(
new InputTypeNode(
TestResolvableInputType::class,
'TestResolvableInput',
null,
[
new FieldNode(
null,
'string',
'name',
null,
true,
[],
FieldNodeType::Property,
null,
'name',
),
],
),
),
);

self::assertSame(
'Mutation has been called with id 45963d07-796c-44d5-8f1b-5e92ae6225a9 and input with name Foobar',
$type('rootValue', [
'id' => '45963d07-796c-44d5-8f1b-5e92ae6225a9',
'input' => [
'name' => 'Foobar',
],
]),
);
}
}

0 comments on commit be4e26a

Please sign in to comment.