• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 6981542872

24 Nov 2023 01:48PM UTC coverage: 37.261% (-0.02%) from 37.284%
6981542872

push

github

web-flow
feat(graphql): support enum collection as property (#5955)

Co-authored-by: josef.wagner <josef.wagner@hf-solutions.co>

0 of 40 new or added lines in 6 files covered. (0.0%)

2 existing lines in 2 files now uncovered.

10287 of 27608 relevant lines covered (37.26%)

20.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/GraphQl/Tests/Type/TypeConverterTest.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace ApiPlatform\GraphQl\Tests\Type;
15

16
use ApiPlatform\GraphQl\Tests\Fixtures\Enum\GenderTypeEnum;
17
use ApiPlatform\GraphQl\Tests\Fixtures\Type\Definition\DateTimeType;
18
use ApiPlatform\GraphQl\Type\TypeBuilderEnumInterface;
19
use ApiPlatform\GraphQl\Type\TypeConverter;
20
use ApiPlatform\GraphQl\Type\TypesContainerInterface;
21
use ApiPlatform\Metadata\ApiProperty;
22
use ApiPlatform\Metadata\ApiResource;
23
use ApiPlatform\Metadata\Exception\ResourceClassNotFoundException;
24
use ApiPlatform\Metadata\GraphQl\Operation;
25
use ApiPlatform\Metadata\GraphQl\Query;
26
use ApiPlatform\Metadata\GraphQl\QueryCollection;
27
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
28
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
29
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
30
use GraphQL\Type\Definition\EnumType;
31
use GraphQL\Type\Definition\ObjectType;
32
use GraphQL\Type\Definition\Type as GraphQLType;
33
use PHPUnit\Framework\TestCase;
34
use Prophecy\Argument;
35
use Prophecy\PhpUnit\ProphecyTrait;
36
use Prophecy\Prophecy\ObjectProphecy;
37
use Symfony\Component\PropertyInfo\Type;
38

39
/**
40
 * @author Alan Poulain <contact@alanpoulain.eu>
41
 */
42
class TypeConverterTest extends TestCase
43
{
44
    use ProphecyTrait;
45

46
    private ObjectProphecy $typeBuilderProphecy;
47
    private ObjectProphecy $typesContainerProphecy;
48
    private ObjectProphecy $resourceMetadataCollectionFactoryProphecy;
49
    private ObjectProphecy $propertyMetadataFactoryProphecy;
50
    private TypeConverter $typeConverter;
51

52
    /**
53
     * {@inheritdoc}
54
     */
55
    protected function setUp(): void
56
    {
57
        $this->typeBuilderProphecy = $this->prophesize(TypeBuilderEnumInterface::class);
×
58
        $this->typesContainerProphecy = $this->prophesize(TypesContainerInterface::class);
×
59
        $this->resourceMetadataCollectionFactoryProphecy = $this->prophesize(ResourceMetadataCollectionFactoryInterface::class);
×
60
        $this->propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
61
        $this->typeConverter = new TypeConverter($this->typeBuilderProphecy->reveal(), $this->typesContainerProphecy->reveal(), $this->resourceMetadataCollectionFactoryProphecy->reveal(), $this->propertyMetadataFactoryProphecy->reveal());
×
62
    }
63

64
    /**
65
     * @dataProvider convertTypeProvider
66
     */
67
    public function testConvertType(Type $type, bool $input, int $depth, GraphQLType|string|null $expectedGraphqlType): void
68
    {
69
        $this->typeBuilderProphecy->isCollection($type)->willReturn(false);
×
NEW
70
        $this->resourceMetadataCollectionFactoryProphecy->create(Argument::type('string'))->willReturn(new ResourceMetadataCollection('resourceClass'));
×
71
        $this->typeBuilderProphecy->getEnumType(Argument::type(Operation::class))->willReturn($expectedGraphqlType);
×
72

73
        /** @var Operation $operation */
74
        $operation = (new Query())->withName('test');
×
75
        $graphqlType = $this->typeConverter->convertType($type, $input, $operation, 'resourceClass', 'rootClass', null, $depth);
×
76
        $this->assertSame($expectedGraphqlType, $graphqlType);
×
77
    }
78

79
    public static function convertTypeProvider(): array
80
    {
81
        return [
×
82
            [new Type(Type::BUILTIN_TYPE_BOOL), false, 0, GraphQLType::boolean()],
×
83
            [new Type(Type::BUILTIN_TYPE_INT), false, 0, GraphQLType::int()],
×
84
            [new Type(Type::BUILTIN_TYPE_FLOAT), false, 0, GraphQLType::float()],
×
85
            [new Type(Type::BUILTIN_TYPE_STRING), false, 0, GraphQLType::string()],
×
86
            [new Type(Type::BUILTIN_TYPE_ARRAY), false, 0, 'Iterable'],
×
87
            [new Type(Type::BUILTIN_TYPE_ITERABLE), false, 0, 'Iterable'],
×
88
            [new Type(Type::BUILTIN_TYPE_OBJECT, false, \DateTimeInterface::class), false, 0, GraphQLType::string()],
×
89
            [new Type(Type::BUILTIN_TYPE_OBJECT, false, GenderTypeEnum::class), false, 0, new EnumType(['name' => 'GenderTypeEnum', 'values' => []])],
×
90
            [new Type(Type::BUILTIN_TYPE_OBJECT), false, 0, null],
×
91
            [new Type(Type::BUILTIN_TYPE_CALLABLE), false, 0, null],
×
92
            [new Type(Type::BUILTIN_TYPE_NULL), false, 0, null],
×
93
            [new Type(Type::BUILTIN_TYPE_RESOURCE), false, 0, null],
×
94
        ];
×
95
    }
96

97
    public function testConvertTypeNoGraphQlResourceMetadata(): void
98
    {
99
        $type = new Type(Type::BUILTIN_TYPE_OBJECT, false, 'dummy');
×
100

101
        $this->typeBuilderProphecy->isCollection($type)->shouldBeCalled()->willReturn(false);
×
102
        $this->resourceMetadataCollectionFactoryProphecy->create('dummy')->shouldBeCalled()->willReturn(new ResourceMetadataCollection('dummy', [new ApiResource()]));
×
103

104
        /** @var Operation $operation */
105
        $operation = (new Query())->withName('test');
×
106
        $graphqlType = $this->typeConverter->convertType($type, false, $operation, 'resourceClass', 'rootClass', null, 0);
×
107
        $this->assertNull($graphqlType);
×
108
    }
109

110
    public function testConvertTypeNodeResource(): void
111
    {
112
        $type = new Type(Type::BUILTIN_TYPE_OBJECT, false, 'node');
×
113

114
        $this->typeBuilderProphecy->isCollection($type)->shouldBeCalled()->willReturn(false);
×
115
        $this->resourceMetadataCollectionFactoryProphecy->create('node')->shouldBeCalled()->willReturn(new ResourceMetadataCollection('node', [(new ApiResource())->withShortName('Node')->withGraphQlOperations(['test' => new Query()])]));
×
116

117
        $this->expectException(\UnexpectedValueException::class);
×
118
        $this->expectExceptionMessage('A "Node" resource cannot be used with GraphQL because the type is already used by the Relay specification.');
×
119

120
        /** @var Operation $operation */
121
        $operation = (new Query())->withName('test');
×
122
        $this->typeConverter->convertType($type, false, $operation, 'resourceClass', 'rootClass', null, 0);
×
123
    }
124

125
    public function testConvertTypeResourceClassNotFound(): void
126
    {
127
        $type = new Type(Type::BUILTIN_TYPE_OBJECT, false, 'dummy');
×
128

129
        $this->typeBuilderProphecy->isCollection($type)->shouldBeCalled()->willReturn(false);
×
130
        $this->resourceMetadataCollectionFactoryProphecy->create('dummy')->shouldBeCalled()->willThrow(new ResourceClassNotFoundException());
×
131

132
        /** @var Operation $operation */
133
        $operation = (new Query())->withName('test');
×
134
        $graphqlType = $this->typeConverter->convertType($type, false, $operation, 'resourceClass', 'rootClass', null, 0);
×
135
        $this->assertNull($graphqlType);
×
136
    }
137

138
    public function testConvertTypeResourceIri(): void
139
    {
140
        $type = new Type(Type::BUILTIN_TYPE_OBJECT, false, 'dummy');
×
141

142
        $graphqlResourceMetadata = new ResourceMetadataCollection('dummy', [(new ApiResource())->withGraphQlOperations(['test' => new Query()])]);
×
143
        $this->resourceMetadataCollectionFactoryProphecy->create('dummy')->willReturn($graphqlResourceMetadata);
×
144
        $this->typeBuilderProphecy->isCollection($type)->willReturn(false);
×
145
        $this->propertyMetadataFactoryProphecy->create('rootClass', 'dummyProperty', Argument::type('array'))->shouldBeCalled()->willReturn((new ApiProperty())->withWritableLink(false));
×
146

147
        /** @var Operation $operation */
148
        $operation = (new Query())->withName('test');
×
149
        $graphqlType = $this->typeConverter->convertType($type, true, $operation, 'dummy', 'rootClass', 'dummyProperty', 1);
×
150
        $this->assertSame(GraphQLType::string(), $graphqlType);
×
151
    }
152

153
    public function testConvertTypeInputResource(): void
154
    {
155
        $type = new Type(Type::BUILTIN_TYPE_OBJECT, false, 'dummy');
×
156
        /** @var Operation $operation */
157
        $operation = new Query();
×
158
        $graphqlResourceMetadata = new ResourceMetadataCollection('dummy', [(new ApiResource())->withGraphQlOperations(['item_query' => $operation])]);
×
159
        $expectedGraphqlType = new ObjectType(['name' => 'resourceObjectType', 'fields' => []]);
×
160

161
        $this->resourceMetadataCollectionFactoryProphecy->create('dummy')->willReturn($graphqlResourceMetadata);
×
162
        $this->typeBuilderProphecy->isCollection($type)->willReturn(false);
×
163
        $this->propertyMetadataFactoryProphecy->create('rootClass', 'dummyProperty', Argument::type('array'))->shouldBeCalled()->willReturn((new ApiProperty())->withWritableLink(true));
×
164
        $this->typeBuilderProphecy->getResourceObjectType('dummy', $graphqlResourceMetadata, $operation, true, false, 1)->shouldBeCalled()->willReturn($expectedGraphqlType);
×
165

166
        $graphqlType = $this->typeConverter->convertType($type, true, $operation, 'dummy', 'rootClass', 'dummyProperty', 1);
×
167
        $this->assertSame($expectedGraphqlType, $graphqlType);
×
168
    }
169

170
    /**
171
     * @dataProvider convertTypeResourceProvider
172
     */
173
    public function testConvertTypeCollectionResource(Type $type, ObjectType $expectedGraphqlType): void
174
    {
175
        $collectionOperation = new QueryCollection();
×
176
        $graphqlResourceMetadata = new ResourceMetadataCollection('dummyValue', [
×
177
            (new ApiResource())->withShortName('DummyValue')->withGraphQlOperations(['collection_query' => $collectionOperation]),
×
178
        ]);
×
179

180
        $this->typeBuilderProphecy->isCollection($type)->shouldBeCalled()->willReturn(true);
×
181
        $this->resourceMetadataCollectionFactoryProphecy->create('dummyValue')->shouldBeCalled()->willReturn($graphqlResourceMetadata);
×
182
        $this->typeBuilderProphecy->getResourceObjectType('dummyValue', $graphqlResourceMetadata, $collectionOperation, false, false, 0)->shouldBeCalled()->willReturn($expectedGraphqlType);
×
183

184
        /** @var Operation $rootOperation */
185
        $rootOperation = (new Query())->withName('test');
×
186
        $graphqlType = $this->typeConverter->convertType($type, false, $rootOperation, 'resourceClass', 'rootClass', null, 0);
×
187
        $this->assertSame($expectedGraphqlType, $graphqlType);
×
188
    }
189

190
    public static function convertTypeResourceProvider(): array
191
    {
192
        return [
×
193
            [new Type(Type::BUILTIN_TYPE_OBJECT, false, null, true, null, new Type(Type::BUILTIN_TYPE_OBJECT, false, 'dummyValue')), new ObjectType(['name' => 'resourceObjectType', 'fields' => []])],
×
194
            [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, null, new Type(Type::BUILTIN_TYPE_OBJECT, false, 'dummyValue')), new ObjectType(['name' => 'resourceObjectType', 'fields' => []])],
×
195
        ];
×
196
    }
197

198
    public function testConvertTypeCollectionEnum(): void
199
    {
NEW
200
        $type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, null, new Type(Type::BUILTIN_TYPE_OBJECT, false, GenderTypeEnum::class));
×
NEW
201
        $expectedGraphqlType = new EnumType(['name' => 'GenderTypeEnum', 'values' => []]);
×
NEW
202
        $this->typeBuilderProphecy->isCollection($type)->shouldBeCalled()->willReturn(true);
×
NEW
203
        $this->resourceMetadataCollectionFactoryProphecy->create(GenderTypeEnum::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(GenderTypeEnum::class, []));
×
NEW
204
        $this->typeBuilderProphecy->getEnumType(Argument::type(Operation::class))->willReturn($expectedGraphqlType);
×
205

206
        /** @var Operation $rootOperation */
NEW
207
        $rootOperation = (new Query())->withName('test');
×
NEW
208
        $graphqlType = $this->typeConverter->convertType($type, false, $rootOperation, 'resourceClass', 'rootClass', null, 0);
×
NEW
209
        $this->assertSame($expectedGraphqlType, $graphqlType);
×
210
    }
211

212
    /**
213
     * @dataProvider resolveTypeProvider
214
     */
215
    public function testResolveType(string $type, string|GraphQLType $expectedGraphqlType): void
216
    {
217
        $this->typesContainerProphecy->has(\DateTime::class)->willReturn(true);
×
218
        $this->typesContainerProphecy->get(\DateTime::class)->willReturn(new DateTimeType());
×
219

220
        $this->assertEquals($expectedGraphqlType, $this->typeConverter->resolveType($type));
×
221
    }
222

223
    public static function resolveTypeProvider(): array
224
    {
225
        return [
×
226
            ['String', GraphQLType::string()],
×
227
            ['String!', GraphQLType::nonNull(GraphQLType::string())],
×
228
            ['Boolean', GraphQLType::boolean()],
×
229
            ['[Boolean]', GraphQLType::listOf(GraphQLType::boolean())],
×
230
            ['Int!', GraphQLType::nonNull(GraphQLType::int())],
×
231
            ['[Int!]', GraphQLType::listOf(GraphQLType::nonNull(GraphQLType::int()))],
×
232
            ['Float', GraphQLType::float()],
×
233
            ['[Float]!', GraphQLType::nonNull(GraphQLType::listOf(GraphQLType::float()))],
×
234
            [\DateTime::class, new DateTimeType()],
×
235
            ['[DateTime!]!', GraphQLType::nonNull(GraphQLType::listOf(GraphQLType::nonNull(new DateTimeType())))],
×
236
        ];
×
237
    }
238

239
    /**
240
     * @dataProvider resolveTypeInvalidProvider
241
     */
242
    public function testResolveTypeInvalid(string $type, string $expectedExceptionMessage): void
243
    {
244
        $this->typesContainerProphecy->has('UnknownType')->willReturn(false);
×
245

246
        $this->expectExceptionMessage($expectedExceptionMessage);
×
247

248
        $this->typeConverter->resolveType($type);
×
249
    }
250

251
    public static function resolveTypeInvalidProvider(): array
252
    {
253
        return [
×
254
            ['float?', '"float?" is not a valid GraphQL type.'],
×
255
            ['UnknownType', 'The type "UnknownType" was not resolved.'],
×
256
            ['UnknownType!', 'The type "UnknownType!" was not resolved.'],
×
257
        ];
×
258
    }
259
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc