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

api-platform / core / 18089937549

29 Sep 2025 07:56AM UTC coverage: 21.764% (-0.3%) from 22.093%
18089937549

Pull #7416

github

web-flow
Merge 061bcc790 into abe0438be
Pull Request #7416: fix(laravel): serializer attributes on Eloquent methods

0 of 151 new or added lines in 11 files covered. (0.0%)

5028 existing lines in 173 files now uncovered.

11889 of 54626 relevant lines covered (21.76%)

25.32 hits per line

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

0.0
/src/GraphQl/Tests/Serializer/SerializerContextBuilderTest.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\Serializer;
15

16
use ApiPlatform\GraphQl\Serializer\SerializerContextBuilder;
17
use ApiPlatform\GraphQl\Tests\Fixtures\Serializer\NameConverter\CustomConverter;
18
use ApiPlatform\Metadata\GraphQl\Mutation;
19
use ApiPlatform\Metadata\GraphQl\Operation;
20
use ApiPlatform\Metadata\GraphQl\Query;
21
use ApiPlatform\Metadata\GraphQl\Subscription;
22
use GraphQL\Type\Definition\ResolveInfo;
23
use PHPUnit\Framework\TestCase;
24
use Prophecy\Argument;
25
use Prophecy\PhpUnit\ProphecyTrait;
26
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;
27

28
/**
29
 * @author Alan Poulain <contact@alanpoulain.eu>
30
 */
31
class SerializerContextBuilderTest extends TestCase
32
{
33
    use ProphecyTrait;
34

35
    private SerializerContextBuilder $serializerContextBuilder;
36

37
    /**
38
     * {@inheritdoc}
39
     */
40
    protected function setUp(): void
41
    {
42
        $this->serializerContextBuilder = $this->buildSerializerContextBuilder();
×
43
    }
44

45
    private function buildSerializerContextBuilder(?AdvancedNameConverterInterface $advancedNameConverter = null): SerializerContextBuilder
46
    {
47
        return new SerializerContextBuilder($advancedNameConverter ?? new CustomConverter());
×
48
    }
49

50
    private function buildOperationFromContext(bool $isMutation, bool $isSubscription, array $expectedContext, bool $isNormalization = true, ?string $resourceClass = null): Operation
51
    {
52
        $operation = !$isMutation && !$isSubscription ? new Query() : new Mutation();
×
53
        if ($isSubscription) {
×
54
            $operation = new Subscription();
×
55
        }
56

57
        $operation = $operation->withShortName('shortName');
×
58
        if (isset($expectedContext['operation_name'])) {
×
59
            $operation = $operation->withName($expectedContext['operation_name']);
×
60
        }
61

62
        if ($resourceClass) {
×
63
            if (isset($expectedContext['groups'])) {
×
64
                if ($isNormalization) {
×
65
                    $operation = $operation->withNormalizationContext(['groups' => $expectedContext['groups']]);
×
66
                } else {
67
                    $operation = $operation->withDenormalizationContext(['groups' => $expectedContext['groups']]);
×
68
                }
69
            }
70

71
            if (isset($expectedContext['input'])) {
×
72
                $operation = $operation->withInput($expectedContext['input']);
×
73
            }
74

75
            if (isset($expectedContext['input'])) {
×
76
                $operation = $operation->withOutput($expectedContext['output']);
×
77
            }
78
        }
79

80
        return $operation;
×
81
    }
82

83
    #[\PHPUnit\Framework\Attributes\DataProvider('createNormalizationContextProvider')]
84
    public function testCreateNormalizationContext(?string $resourceClass, string $operationName, array $fields, bool $isMutation, bool $isSubscription, bool $noInfo, array $expectedContext, ?callable $advancedNameConverter = null, ?string $expectedExceptionClass = null, ?string $expectedExceptionMessage = null): void
85
    {
UNCOV
86
        $resolverContext = [];
×
87

88
        $operation = $this->buildOperationFromContext($isMutation, $isSubscription, $expectedContext, true, $resourceClass);
×
UNCOV
89
        if ($noInfo) {
×
90
            $resolverContext['fields'] = $fields;
×
91
        } else {
92
            $resolveInfoProphecy = $this->prophesize(ResolveInfo::class);
×
UNCOV
93
            $resolveInfoProphecy->getFieldSelection(\PHP_INT_MAX)->willReturn($fields);
×
94
            $resolverContext['info'] = $resolveInfoProphecy->reveal();
×
95
        }
96

UNCOV
97
        if ($expectedExceptionClass) {
×
UNCOV
98
            $this->expectException($expectedExceptionClass);
×
99
            $this->expectExceptionMessage($expectedExceptionMessage);
×
100
        }
101

UNCOV
102
        $serializerContextBuilder = $this->serializerContextBuilder;
×
UNCOV
103
        if ($advancedNameConverter) {
×
104
            $serializerContextBuilder = $this->buildSerializerContextBuilder($advancedNameConverter($this));
×
105
        }
106

UNCOV
107
        $context = $serializerContextBuilder->create($resourceClass, $operation, $resolverContext, true);
×
108

109
        unset($context['operation']);
×
UNCOV
110
        $this->assertEquals($expectedContext, $context);
×
111
    }
112

113
    public static function createNormalizationContextProvider(): iterable
114
    {
UNCOV
115
        $advancedNameConverterFactory = function (self $that): AdvancedNameConverterInterface {
×
UNCOV
116
            $advancedNameConverterProphecy = $that->prophesize(AdvancedNameConverterInterface::class);
×
117
            $advancedNameConverterProphecy->denormalize('field', 'myResource', null, Argument::type('array'))->willReturn('denormalizedField');
×
118

119
            return $advancedNameConverterProphecy->reveal();
×
UNCOV
120
        };
×
121

122
        yield 'nominal' => [
×
UNCOV
123
            $resourceClass = 'myResource',
×
124
            $operationName = 'item_query',
×
125
            ['_id' => 3, 'field' => 'foo'],
×
126
            false,
×
127
            false,
×
128
            false,
×
129
            [
×
130
                'groups' => ['normalization_group'],
×
131
                'resource_class' => $resourceClass,
×
132
                'operation_name' => $operationName,
×
133
                'graphql_operation_name' => $operationName,
×
134
                'input' => ['class' => 'inputClass'],
×
135
                'output' => ['class' => 'outputClass'],
×
136
                'attributes' => [
×
137
                    'id' => 3,
×
138
                    'field' => 'foo',
×
139
                ],
×
140
                'exclude_from_cache_key' => [
×
141
                    'root_operation',
×
142
                    'operation',
×
143
                    'object',
×
144
                    'data',
×
145
                    'property_metadata',
×
146
                    'circular_reference_limit_counters',
×
147
                    'debug_trace_id',
×
148
                ],
×
149
            ],
×
150
        ];
×
151
        yield 'nominal with advanced name converter' => [
×
152
            $resourceClass = 'myResource',
×
153
            $operationName = 'item_query',
×
154
            ['_id' => 3, 'field' => 'foo'],
×
155
            false,
×
156
            false,
×
157
            false,
×
158
            [
×
159
                'groups' => ['normalization_group'],
×
160
                'resource_class' => $resourceClass,
×
161
                'operation_name' => $operationName,
×
162
                'graphql_operation_name' => $operationName,
×
163
                'input' => ['class' => 'inputClass'],
×
164
                'output' => ['class' => 'outputClass'],
×
165
                'attributes' => [
×
166
                    'id' => 3,
×
167
                    'denormalizedField' => 'foo',
×
168
                ],
×
169
                'exclude_from_cache_key' => [
×
170
                    'root_operation',
×
171
                    'operation',
×
172
                    'object',
×
173
                    'data',
×
174
                    'property_metadata',
×
175
                    'circular_reference_limit_counters',
×
176
                    'debug_trace_id',
×
177
                ],
×
178
            ],
×
179
            $advancedNameConverterFactory,
×
180
        ];
×
181
        yield 'nominal collection' => [
×
182
            $resourceClass = 'myResource',
×
183
            $operationName = 'collection_query',
×
184
            ['edges' => ['node' => ['nodeField' => 'baz']]],
×
185
            false,
×
186
            false,
×
187
            false,
×
188
            [
×
189
                'groups' => ['normalization_group'],
×
190
                'resource_class' => $resourceClass,
×
191
                'operation_name' => $operationName,
×
192
                'graphql_operation_name' => $operationName,
×
193
                'input' => ['class' => 'inputClass'],
×
194
                'output' => ['class' => 'outputClass'],
×
195
                'attributes' => [
×
196
                    'nodeField' => 'baz',
×
197
                ],
×
198
                'exclude_from_cache_key' => [
×
199
                    'root_operation',
×
200
                    'operation',
×
201
                    'object',
×
202
                    'data',
×
203
                    'property_metadata',
×
204
                    'circular_reference_limit_counters',
×
205
                    'debug_trace_id',
×
206
                ],
×
207
            ],
×
208
        ];
×
209
        yield 'no resource class' => [
×
210
            $resourceClass = null,
×
211
            $operationName = 'item_query',
×
212
            ['related' => ['_id' => 9]],
×
213
            false,
×
214
            false,
×
215
            false,
×
216
            [
×
217
                'resource_class' => $resourceClass,
×
218
                'operation_name' => $operationName,
×
219
                'graphql_operation_name' => $operationName,
×
220
                'attributes' => [
×
221
                    'related' => ['id' => 9],
×
222
                ],
×
223
                'exclude_from_cache_key' => [
×
224
                    'root_operation',
×
225
                    'operation',
×
226
                    'object',
×
227
                    'data',
×
228
                    'property_metadata',
×
229
                    'circular_reference_limit_counters',
×
230
                    'debug_trace_id',
×
231
                ],
×
232
            ],
×
233
        ];
×
234
        yield 'mutation' => [
×
235
            $resourceClass = 'myResource',
×
236
            $operationName = 'create',
×
237
            ['shortName' => ['_id' => 7, 'related' => ['field' => 'bar']]],
×
238
            true,
×
239
            false,
×
240
            false,
×
241
            [
×
242
                'groups' => ['normalization_group'],
×
243
                'resource_class' => $resourceClass,
×
244
                'operation_name' => $operationName,
×
245
                'graphql_operation_name' => $operationName,
×
246
                'input' => ['class' => 'inputClass'],
×
247
                'output' => ['class' => 'outputClass'],
×
248
                'attributes' => [
×
249
                    'id' => 7,
×
250
                    'related' => ['field' => 'bar'],
×
251
                ],
×
252
                'exclude_from_cache_key' => [
×
253
                    'root_operation',
×
254
                    'operation',
×
255
                    'object',
×
256
                    'data',
×
257
                    'property_metadata',
×
258
                    'circular_reference_limit_counters',
×
259
                    'debug_trace_id',
×
260
                ],
×
261
            ],
×
262
        ];
×
263
        yield 'subscription (using fields in context)' => [
×
264
            $resourceClass = 'myResource',
×
265
            $operationName = 'update',
×
266
            ['shortName' => ['_id' => 7, 'related' => ['field' => 'bar']]],
×
267
            false,
×
268
            true,
×
269
            true,
×
270
            [
×
271
                'groups' => ['normalization_group'],
×
272
                'resource_class' => $resourceClass,
×
273
                'operation_name' => $operationName,
×
274
                'graphql_operation_name' => $operationName,
×
275
                'no_resolver_data' => true,
×
276
                'input' => ['class' => 'inputClass'],
×
277
                'output' => ['class' => 'outputClass'],
×
278
                'attributes' => [
×
279
                    'id' => 7,
×
280
                    'related' => ['field' => 'bar'],
×
281
                ],
×
282
                'exclude_from_cache_key' => [
×
283
                    'root_operation',
×
284
                    'operation',
×
285
                    'object',
×
286
                    'data',
×
287
                    'property_metadata',
×
288
                    'circular_reference_limit_counters',
×
289
                    'debug_trace_id',
×
290
                ],
×
291
            ],
×
292
        ];
×
293
    }
294

295
    #[\PHPUnit\Framework\Attributes\DataProvider('createDenormalizationContextProvider')]
296
    public function testCreateDenormalizationContext(?string $resourceClass, string $operationName, array $expectedContext): void
297
    {
UNCOV
298
        $operation = $this->buildOperationFromContext(true, false, $expectedContext, false, $resourceClass);
×
299

300
        $context = $this->serializerContextBuilder->create($resourceClass, $operation, [], false);
×
301

302
        unset($context['operation']);
×
UNCOV
303
        $this->assertEquals($expectedContext, $context);
×
304
    }
305

306
    public static function createDenormalizationContextProvider(): array
307
    {
UNCOV
308
        return [
×
UNCOV
309
            'nominal' => [
×
310
                $resourceClass = 'myResource',
×
311
                $operationName = 'item_query',
×
312
                [
×
313
                    'groups' => ['denormalization_group'],
×
314
                    'resource_class' => $resourceClass,
×
315
                    'operation_name' => $operationName,
×
316
                    'graphql_operation_name' => $operationName,
×
317
                    'input' => ['class' => 'inputClass'],
×
318
                    'output' => ['class' => 'outputClass'],
×
319
                    'exclude_from_cache_key' => [
×
320
                        'root_operation',
×
321
                        'operation',
×
322
                        'object',
×
323
                        'data',
×
324
                        'property_metadata',
×
325
                        'circular_reference_limit_counters',
×
326
                        'debug_trace_id',
×
327
                    ],
×
328
                ],
×
329
            ],
×
330
            'no resource class' => [
×
331
                $resourceClass = null,
×
332
                $operationName = 'item_query',
×
333
                [
×
334
                    'resource_class' => $resourceClass,
×
335
                    'operation_name' => $operationName,
×
336
                    'graphql_operation_name' => $operationName,
×
337
                    'exclude_from_cache_key' => [
×
338
                        'root_operation',
×
339
                        'operation',
×
340
                        'object',
×
341
                        'data',
×
342
                        'property_metadata',
×
343
                        'circular_reference_limit_counters',
×
344
                        'debug_trace_id',
×
345
                    ],
×
346
                ],
×
347
            ],
×
348
        ];
×
349
    }
350
}
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