• 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/Resolver/Factory/CollectionResolverFactoryTest.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\Resolver\Factory;
15

16
use ApiPlatform\GraphQl\Resolver\Factory\CollectionResolverFactory;
17
use ApiPlatform\GraphQl\Resolver\Stage\ReadStageInterface;
18
use ApiPlatform\GraphQl\Resolver\Stage\SecurityPostDenormalizeStageInterface;
19
use ApiPlatform\GraphQl\Resolver\Stage\SecurityStageInterface;
20
use ApiPlatform\GraphQl\Resolver\Stage\SerializeStageInterface;
21
use ApiPlatform\GraphQl\Tests\Fixtures\Enum\GenderTypeEnum;
22
use ApiPlatform\Metadata\GraphQl\QueryCollection;
23
use GraphQL\Type\Definition\ResolveInfo;
24
use PHPUnit\Framework\TestCase;
25
use Prophecy\PhpUnit\ProphecyTrait;
26
use Prophecy\Prophecy\ObjectProphecy;
27
use Psr\Container\ContainerInterface;
28

29
/**
30
 * @author Alan Poulain <contact@alanpoulain.eu>
31
 * @author Kévin Dunglas <dunglas@gmail.com>
32
 */
33
class CollectionResolverFactoryTest extends TestCase
34
{
35
    use ProphecyTrait;
36

37
    private CollectionResolverFactory $collectionResolverFactory;
38
    private ObjectProphecy $readStageProphecy;
39
    private ObjectProphecy $securityStageProphecy;
40
    private ObjectProphecy $securityPostDenormalizeStageProphecy;
41
    private ObjectProphecy $serializeStageProphecy;
42
    private ObjectProphecy $queryResolverLocatorProphecy;
43

44
    /**
45
     * {@inheritdoc}
46
     */
47
    protected function setUp(): void
48
    {
49
        $this->readStageProphecy = $this->prophesize(ReadStageInterface::class);
×
50
        $this->securityStageProphecy = $this->prophesize(SecurityStageInterface::class);
×
51
        $this->securityPostDenormalizeStageProphecy = $this->prophesize(SecurityPostDenormalizeStageInterface::class);
×
52
        $this->serializeStageProphecy = $this->prophesize(SerializeStageInterface::class);
×
53
        $this->queryResolverLocatorProphecy = $this->prophesize(ContainerInterface::class);
×
54

55
        $this->collectionResolverFactory = new CollectionResolverFactory(
×
56
            $this->readStageProphecy->reveal(),
×
57
            $this->securityStageProphecy->reveal(),
×
58
            $this->securityPostDenormalizeStageProphecy->reveal(),
×
59
            $this->serializeStageProphecy->reveal(),
×
60
            $this->queryResolverLocatorProphecy->reveal(),
×
61
        );
×
62
    }
63

64
    public function testResolve(): void
65
    {
66
        $resourceClass = \stdClass::class;
×
67
        $rootClass = 'rootClass';
×
68
        $operationName = 'collection_query';
×
69
        $operation = (new QueryCollection())->withName($operationName);
×
70
        $source = ['testField' => 0];
×
71
        $args = ['args'];
×
72
        $info = $this->prophesize(ResolveInfo::class)->reveal();
×
73
        $info->fieldName = 'testField';
×
74
        $resolverContext = ['source' => $source, 'args' => $args, 'info' => $info, 'is_collection' => true, 'is_mutation' => false, 'is_subscription' => false];
×
75

76
        $readStageCollection = [new \stdClass()];
×
77
        $this->readStageProphecy->__invoke($resourceClass, $rootClass, $operation, $resolverContext)->shouldBeCalled()->willReturn($readStageCollection);
×
78

79
        $this->securityStageProphecy->__invoke($resourceClass, $operation, $resolverContext + [
×
80
            'extra_variables' => [
×
81
                'object' => $readStageCollection,
×
82
            ],
×
83
        ])->shouldNotBeCalled();
×
84
        $this->securityPostDenormalizeStageProphecy->__invoke($resourceClass, $operation, $resolverContext + [
×
85
            'extra_variables' => [
×
86
                'object' => $readStageCollection,
×
87
                'previous_object' => $readStageCollection,
×
88
            ],
×
89
        ])->shouldNotBeCalled();
×
90

91
        $serializeStageData = ['serialized'];
×
92
        $this->serializeStageProphecy->__invoke($readStageCollection, $resourceClass, $operation, $resolverContext)->shouldBeCalled()->willReturn($serializeStageData);
×
93

94
        $this->assertSame($serializeStageData, ($this->collectionResolverFactory)($resourceClass, $rootClass, $operation)($source, $args, null, $info));
×
95
    }
96

97
    public function testResolveEnumFieldFromSource(): void
98
    {
NEW
99
        $resourceClass = GenderTypeEnum::class;
×
NEW
100
        $rootClass = 'rootClass';
×
NEW
101
        $operationName = 'collection_query';
×
NEW
102
        $operation = (new QueryCollection())->withName($operationName);
×
NEW
103
        $source = ['genders' => [GenderTypeEnum::MALE, GenderTypeEnum::FEMALE]];
×
NEW
104
        $args = ['args'];
×
NEW
105
        $info = $this->prophesize(ResolveInfo::class)->reveal();
×
NEW
106
        $info->fieldName = 'genders';
×
107

NEW
108
        $this->assertSame([GenderTypeEnum::MALE, GenderTypeEnum::FEMALE], ($this->collectionResolverFactory)($resourceClass, $rootClass, $operation)($source, $args, null, $info));
×
109
    }
110

111
    public function testResolveFieldNotInSource(): void
112
    {
113
        $resourceClass = \stdClass::class;
×
114
        $rootClass = 'rootClass';
×
115
        $operationName = 'collection_query';
×
116
        $operation = (new QueryCollection())->withName($operationName);
×
117
        $source = ['source'];
×
118
        $args = ['args'];
×
119
        $info = $this->prophesize(ResolveInfo::class)->reveal();
×
120
        $info->fieldName = 'testField';
×
121
        $resolverContext = ['source' => $source, 'args' => $args, 'info' => $info, 'is_collection' => true, 'is_mutation' => false, 'is_subscription' => false];
×
122

123
        $readStageCollection = [new \stdClass()];
×
124
        $this->readStageProphecy->__invoke($resourceClass, $rootClass, $operation, $resolverContext)->shouldNotBeCalled();
×
125

126
        $this->securityStageProphecy->__invoke($resourceClass, $operation, $resolverContext + [
×
127
            'extra_variables' => [
×
128
                'object' => $readStageCollection,
×
129
            ],
×
130
        ])->shouldNotBeCalled();
×
131
        $this->securityPostDenormalizeStageProphecy->__invoke($resourceClass, $operation, $resolverContext + [
×
132
            'extra_variables' => [
×
133
                'object' => $readStageCollection,
×
134
                'previous_object' => $readStageCollection,
×
135
            ],
×
136
        ])->shouldNotBeCalled();
×
137

138
        // Null should be returned if the field isn't in the source - as its lack of presence will be due to @ApiProperty security stripping unauthorized fields
139
        $this->assertNull(($this->collectionResolverFactory)($resourceClass, $rootClass, $operation)($source, $args, null, $info));
×
140
    }
141

142
    public function testResolveNullSource(): void
143
    {
144
        $resourceClass = \stdClass::class;
×
145
        $rootClass = 'rootClass';
×
146
        $operationName = 'collection_query';
×
147
        $operation = (new QueryCollection())->withName($operationName);
×
148
        $source = null;
×
149
        $args = ['args'];
×
150
        $info = $this->prophesize(ResolveInfo::class)->reveal();
×
151
        $resolverContext = ['source' => $source, 'args' => $args, 'info' => $info, 'is_collection' => true, 'is_mutation' => false, 'is_subscription' => false];
×
152

153
        $readStageCollection = [new \stdClass()];
×
154
        $this->readStageProphecy->__invoke($resourceClass, $rootClass, $operation, $resolverContext)->shouldBeCalled()->willReturn($readStageCollection);
×
155

156
        $this->securityStageProphecy->__invoke($resourceClass, $operation, $resolverContext + [
×
157
            'extra_variables' => [
×
158
                'object' => $readStageCollection,
×
159
            ],
×
160
        ])->shouldBeCalled();
×
161
        $this->securityPostDenormalizeStageProphecy->__invoke($resourceClass, $operation, $resolverContext + [
×
162
            'extra_variables' => [
×
163
                'object' => $readStageCollection,
×
164
                'previous_object' => $readStageCollection,
×
165
            ],
×
166
        ])->shouldBeCalled();
×
167

168
        $serializeStageData = ['serialized'];
×
169
        $this->serializeStageProphecy->__invoke($readStageCollection, $resourceClass, $operation, $resolverContext)->shouldBeCalled()->willReturn($serializeStageData);
×
170

171
        $this->assertSame($serializeStageData, ($this->collectionResolverFactory)($resourceClass, $rootClass, $operation)($source, $args, null, $info));
×
172
    }
173

174
    public function testResolveNullResourceClass(): void
175
    {
176
        $resourceClass = null;
×
177
        $rootClass = 'rootClass';
×
178
        $operationName = 'collection_query';
×
179
        $operation = (new QueryCollection())->withName($operationName);
×
180
        $source = ['source'];
×
181
        $args = ['args'];
×
182
        $info = $this->prophesize(ResolveInfo::class)->reveal();
×
183

184
        $this->assertNull(($this->collectionResolverFactory)($resourceClass, $rootClass, $operation)($source, $args, null, $info));
×
185
    }
186

187
    public function testResolveNullRootClass(): void
188
    {
189
        $resourceClass = \stdClass::class;
×
190
        $rootClass = null;
×
191
        $operationName = 'collection_query';
×
192
        $operation = (new QueryCollection())->withName($operationName);
×
193
        $source = ['source'];
×
194
        $args = ['args'];
×
195
        $info = $this->prophesize(ResolveInfo::class)->reveal();
×
196

197
        $this->assertNull(($this->collectionResolverFactory)($resourceClass, $rootClass, $operation)($source, $args, null, $info));
×
198
    }
199

200
    public function testResolveBadReadStageCollection(): void
201
    {
202
        $resourceClass = \stdClass::class;
×
203
        $rootClass = 'rootClass';
×
204
        $operationName = 'collection_query';
×
205
        $operation = (new QueryCollection())->withName($operationName);
×
206
        $source = null;
×
207
        $args = ['args'];
×
208
        $info = $this->prophesize(ResolveInfo::class)->reveal();
×
209
        $resolverContext = ['source' => $source, 'args' => $args, 'info' => $info, 'is_collection' => true, 'is_mutation' => false, 'is_subscription' => false];
×
210

211
        $readStageCollection = new \stdClass();
×
212
        $this->readStageProphecy->__invoke($resourceClass, $rootClass, $operation, $resolverContext)->shouldBeCalled()->willReturn($readStageCollection);
×
213

214
        $this->expectException(\LogicException::class);
×
215
        $this->expectExceptionMessage('Collection from read stage should be iterable.');
×
216

217
        ($this->collectionResolverFactory)($resourceClass, $rootClass, $operation)($source, $args, null, $info);
×
218
    }
219

220
    public function testResolveCustom(): void
221
    {
222
        $resourceClass = \stdClass::class;
×
223
        $rootClass = 'rootClass';
×
224
        $operationName = 'collection_query';
×
225
        $operation = (new QueryCollection())->withResolver('query_resolver_id')->withName($operationName);
×
226
        $source = null;
×
227
        $args = ['args'];
×
228
        $info = $this->prophesize(ResolveInfo::class)->reveal();
×
229
        $resolverContext = ['source' => $source, 'args' => $args, 'info' => $info, 'is_collection' => true, 'is_mutation' => false, 'is_subscription' => false];
×
230

231
        $readStageCollection = [new \stdClass()];
×
232
        $this->readStageProphecy->__invoke($resourceClass, $rootClass, $operation, $resolverContext)->shouldBeCalled()->willReturn($readStageCollection);
×
233

234
        $customCollection = [new \stdClass()];
×
235
        $customCollection[0]->field = 'foo';
×
236
        $this->queryResolverLocatorProphecy->get('query_resolver_id')->shouldBeCalled()->willReturn(fn (): array => $customCollection);
×
237

238
        $this->securityStageProphecy->__invoke($resourceClass, $operation, $resolverContext + [
×
239
            'extra_variables' => [
×
240
                'object' => $customCollection,
×
241
            ],
×
242
        ])->shouldBeCalled();
×
243
        $this->securityPostDenormalizeStageProphecy->__invoke($resourceClass, $operation, $resolverContext + [
×
244
            'extra_variables' => [
×
245
                'object' => $customCollection,
×
246
                'previous_object' => $customCollection,
×
247
            ],
×
248
        ])->shouldBeCalled();
×
249

250
        $serializeStageData = ['serialized'];
×
251
        $this->serializeStageProphecy->__invoke($customCollection, $resourceClass, $operation, $resolverContext)->shouldBeCalled()->willReturn($serializeStageData);
×
252

253
        $this->assertSame($serializeStageData, ($this->collectionResolverFactory)($resourceClass, $rootClass, $operation)($source, $args, null, $info));
×
254
    }
255
}
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

© 2025 Coveralls, Inc