Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
n/a
0 / 0
n/a
0 / 0
CRAP
n/a
0 / 0
AbstractRenderTestCase
n/a
0 / 0
n/a
0 / 0
5
n/a
0 / 0
 getRenderer
n/a
0 / 0
n/a
0 / 0
0
 getFixturesPath
n/a
0 / 0
n/a
0 / 0
0
 createTwigRuntimeForTests
n/a
0 / 0
n/a
0 / 0
1
 shouldOverwriteFixture
n/a
0 / 0
n/a
0 / 0
1
 testRender
n/a
0 / 0
n/a
0 / 0
2
 provideComponents
n/a
0 / 0
n/a
0 / 0
1
1<?php
2namespace Apie\HtmlBuilders\TestHelpers;
3
4use Apie\Common\ActionDefinitions\CreateResourceActionDefinition;
5use Apie\Common\MenuStructure\MenuBuilder;
6use Apie\Common\MenuStructure\MenuNode;
7use Apie\Core\Attributes\CmsSingleInput;
8use Apie\Core\BoundedContext\BoundedContextId;
9use Apie\Core\Context\ApieContext;
10use Apie\Core\Dto\CmsInputOption;
11use Apie\Core\Enums\RequestMethod;
12use Apie\Core\Lists\StringSet;
13use Apie\Core\Translator\ApieTranslator;
14use Apie\Core\Translator\ApieTranslatorInterface;
15use Apie\Core\Translator\Lists\TranslationStringSet;
16use Apie\Core\Translator\ValueObjects\DummyTranslation;
17use Apie\Core\Translator\ValueObjects\MenuHeader;
18use Apie\Core\ValueObjects\DatabaseText;
19use Apie\Fixtures\BoundedContextFactory;
20use Apie\Fixtures\Entities\Order;
21use Apie\Fixtures\Entities\Polymorphic\Animal;
22use Apie\Fixtures\Entities\UserWithAddress;
23use Apie\Fixtures\Entities\UserWithAutoincrementKey;
24use Apie\Fixtures\Identifiers\OrderIdentifier;
25use Apie\Fixtures\Identifiers\UserWithAddressIdentifier;
26use Apie\Fixtures\Lists\OrderLineList;
27use Apie\Fixtures\ValueObjects\AddressWithZipcodeCheck;
28use Apie\HtmlBuilders\Components\Dashboard\RawContents;
29use Apie\HtmlBuilders\Components\Forms\Csrf;
30use Apie\HtmlBuilders\Components\Forms\Form;
31use Apie\HtmlBuilders\Components\Forms\FormGroup;
32use Apie\HtmlBuilders\Components\Forms\FormPrototypeHashmap;
33use Apie\HtmlBuilders\Components\Forms\FormPrototypeList;
34use Apie\HtmlBuilders\Components\Forms\FormSplit;
35use Apie\HtmlBuilders\Components\Forms\PolymorphicForm;
36use Apie\HtmlBuilders\Components\Forms\RemoveConfirm;
37use Apie\HtmlBuilders\Components\Forms\SingleInput;
38use Apie\HtmlBuilders\Components\Layout;
39use Apie\HtmlBuilders\Components\Layout\BoundedContextSelect;
40use Apie\HtmlBuilders\Components\Layout\LoginSelect;
41use Apie\HtmlBuilders\Components\Layout\Logo;
42use Apie\HtmlBuilders\Components\Layout\MenuItem;
43use Apie\HtmlBuilders\Components\Layout\ShowProfile;
44use Apie\HtmlBuilders\Components\Resource\Detail;
45use Apie\HtmlBuilders\Components\Resource\FieldDisplay\BooleanDisplay;
46use Apie\HtmlBuilders\Components\Resource\FieldDisplay\LinkDisplay;
47use Apie\HtmlBuilders\Components\Resource\FieldDisplay\ListDisplay;
48use Apie\HtmlBuilders\Components\Resource\FieldDisplay\NullDisplay;
49use Apie\HtmlBuilders\Components\Resource\FieldDisplay\SegmentDisplay;
50use Apie\HtmlBuilders\Components\Resource\FilterColumns;
51use Apie\HtmlBuilders\Components\Resource\Overview;
52use Apie\HtmlBuilders\Components\Resource\ResourceActionList;
53use Apie\HtmlBuilders\Components\Resource\SingleResourceActionList;
54use Apie\HtmlBuilders\Configuration\CurrentConfiguration;
55use Apie\HtmlBuilders\Interfaces\ComponentInterface;
56use Apie\HtmlBuilders\Interfaces\ComponentRendererInterface;
57use Apie\HtmlBuilders\Lists\ActionList;
58use Apie\HtmlBuilders\Lists\ComponentHashmap;
59use Apie\HtmlBuilders\ResourceActions\CreateResourceAction;
60use Apie\HtmlBuilders\ValueObjects\FormName;
61use Apie\TypeConverter\ReflectionTypeFactory;
62use Generator;
63use PHPUnit\Framework\TestCase;
64use ReflectionClass;
65use Symfony\UX\Icons\IconRenderer;
66use Symfony\UX\Icons\Registry\ChainIconRegistry;
67use Symfony\UX\Icons\Twig\UXIconRuntime;
68
69/**
70 * @codeCoverageIgnore
71 */
72abstract class AbstractRenderTestCase extends TestCase
73{
74    abstract public function getRenderer(): ComponentRendererInterface;
75
76    abstract public function getFixturesPath(): string;
77
78    public static function createTwigRuntimeForTests(): UXIconRuntime
79    {
80        return new UXIconRuntime(
81            new IconRenderer(
82                new ChainIconRegistry([]),
83            ),
84            true,
85            new \Psr\Log\NullLogger()
86        );
87    }
88
89    /**
90     * Overwriting this method to return true means the fixtures will be overwritten to ease big refactorings.
91     */
92    protected function shouldOverwriteFixture(): bool
93    {
94        return true;//false;
95    }
96
97    #[\PHPUnit\Framework\Attributes\DataProvider('provideComponents')]
98    public function testRender(string $expectedFixtureFile, ComponentInterface $component): void
99    {
100        $renderer = $this->getRenderer();
101        $context = new ApieContext([
102            ApieTranslatorInterface::class => new ApieTranslator(),
103        ]);
104        $actual = $renderer->render($component, $context);
105        $fixtureFile = $this->getFixturesPath() . DIRECTORY_SEPARATOR . $expectedFixtureFile;
106        if ($this->shouldOverwriteFixture()) {
107            file_put_contents($fixtureFile, $actual);
108        }
109        $expected = file_get_contents($fixtureFile);
110        $this->assertEquals($expected, $actual);
111    }
112
113    public static function provideComponents(): Generator
114    {
115        $rawContents = new RawContents('<marquee>Hello world</marquee>');
116        $defaultConfiguration = new CurrentConfiguration([], new ApieContext(), BoundedContextFactory::createHashmap(), new BoundedContextId('default'));
117        $menuBuilder = new MenuBuilder();
118        $menuBuilder->addLeaf('test', new MenuNode(MenuHeader::fromNative('apie.menu.test.header'), '/test'));
119        $menuBuilder->addLeaf('test2', new MenuNode(MenuHeader::fromNative('apie.menu.test2.header'), '/test2'));
120        $menuBuilder->addLeaf('test3/test4', new MenuNode(MenuHeader::fromNative('apie.menu.test3.header'), '/test3'));
121       
122        
123        yield 'Raw HTML concents' => [
124            'expected-raw-contents.html',
125            $rawContents,
126        ];
127
128        
129        yield 'Simple layout' => [
130            'expected-simple-layout.html',
131            new Layout(
132                'Title',
133                $defaultConfiguration,
134                $rawContents,
135                new MenuItem($menuBuilder->getRoot())
136            )
137        ];
138         
139        yield 'Simple layout, new menu' => [
140            'expected-with-menu.html',
141            new Layout(
142                'Title',
143                $defaultConfiguration,
144                $rawContents,
145                new MenuItem($menuBuilder->getRoot()),
146            )
147        ];
148        yield 'Bounded context select => nothing selected' => [
149            'expected-bounded-context-select-nothing.html',
150            new BoundedContextSelect(
151                new CurrentConfiguration([], new ApieContext(), BoundedContextFactory::createHashmap(), null)
152            )
153        ];
154        yield 'Bounded context select => unknown selection' => [
155            'expected-bounded-context-select-unknown.html',
156            new BoundedContextSelect(
157                new CurrentConfiguration([], new ApieContext(), BoundedContextFactory::createHashmap(), new BoundedContextId('unknown'))
158            )
159        ];
160        yield 'Bounded context select => single bounded context' => [
161            'expected-bounded-context-select.html',
162            new BoundedContextSelect(
163                $defaultConfiguration
164            )
165        ];
166        yield 'Bounded context select => multiple bounded context' => [
167            'expected-bounded-context-select-multiple.html',
168            new BoundedContextSelect(
169                new CurrentConfiguration([], new ApieContext(), BoundedContextFactory::createHashmapWithMultipleContexts(), new BoundedContextId('default'))
170            )
171        ];
172        yield 'Logo' => [
173            'expected-logo.html',
174            new Logo($defaultConfiguration),
175        ];
176        yield 'Login select' => [
177            'expected-login-select.html',
178            new LoginSelect(
179                $defaultConfiguration
180            )
181        ];
182
183        yield 'Profile' => [
184            'expected-profile.html',
185            new ShowProfile(
186                $defaultConfiguration,
187                new UserWithAddress(
188                    new AddressWithZipcodeCheck(
189                        new DatabaseText('Evergreen Terrace'),
190                        new DatabaseText('742'),
191                        new DatabaseText('11111'),
192                        new DatabaseText('Springfield'),
193                    ),
194                    new UserWithAddressIdentifier('d788c9f5-6493-4386-89f4-374be3b28764'),
195                )
196            )
197        ];
198
199        yield 'Simple Menu' => [
200            'expected-menu.html',
201            new Layout\MenuItem($menuBuilder->getRoot()),
202        ];
203
204        yield 'Resource overview filters' => [
205            'expected-resource-overview-filters.html',
206            new FilterColumns(
207                new StringSet(['id', 'description']),
208                'text search',
209                ['description' => 'test'],
210            )
211            ];
212        
213        yield 'Resource overview' => [
214            'expected-resource-overview.html',
215            new Overview(
216                [['id' => 12, 'name' => 'Pizza']],
217                ['id', 'name'],
218                new ResourceActionList(
219                    $defaultConfiguration,
220                    new ActionList([]),
221                    new FilterColumns(new StringSet(), '', []),
222                )
223            )
224        ];
225
226        $createResourceAction = new CreateResourceAction(
227            new ReflectionClass(UserWithAutoincrementKey::class),
228            new CreateResourceActionDefinition(
229                new ReflectionClass(UserWithAutoincrementKey::class),
230                new BoundedContextId('default')
231            )
232        );
233        $resourceActionList = new ResourceActionList(
234            $defaultConfiguration,
235            new ActionList([$createResourceAction]),
236            new FilterColumns(new StringSet(), '', []),
237        );
238        yield 'Resource action list' => [
239            'expected-resource-action-list.html',
240            $resourceActionList
241        ];
242
243        yield 'Resource overview large list' => [
244            'expected-resource-overview-large-list.html',
245            new Overview(
246                array_fill(0, 100, ['id' => 12, 'name' => 'Pizza']),
247                ['id', 'name'],
248                $resourceActionList
249            )
250        ];
251
252        yield 'Form' => [
253            'expected-form.html',
254            new Form(RequestMethod::POST, null, [], [], false, new RawContents('test'), new RawContents('test2')),
255        ];
256        yield 'Form-Upload' => [
257            'expected-form-with-upload.html',
258            new Form(RequestMethod::POST, null, [], [], true, new RawContents('test'), new RawContents('test2')),
259        ];
260        yield 'Polymorphic Form' => [
261            'expected-polymorphic-form.html',
262            new PolymorphicForm(
263                RequestMethod::POST,
264                new ReflectionClass(Animal::class),
265                null,
266                [],
267                [],
268                false,
269                new Csrf('temp'),
270                new ComponentHashmap([
271                    'test1' => new RawContents('test3'),
272                    'test2' => new RawContents('test4'),
273                ])
274            ),
275        ];
276        yield 'Polymorphic Form-Upload' => [
277            'expected-polymorphic-form-with-upload.html',
278            new PolymorphicForm(
279                RequestMethod::POST,
280                new ReflectionClass(Animal::class),
281                null,
282                [],
283                [],
284                true,
285                new Csrf('temp'),
286                new ComponentHashmap([
287                    'test1' => new RawContents('test3'),
288                    'test2' => new RawContents('test4'),
289                ])
290            ),
291        ];
292        yield 'Form with validation errors' => [
293            'expected-form-with-unknown-validation-error.html',
294            new Form(RequestMethod::POST, null, ['id' => 'unknown field'], [], false, new RawContents('test')),
295        ];
296
297        yield 'Form group with validation errors' => [
298            'expected-form-group-with-validation-error.html',
299            new FormGroup(new FormName('test'), null, ['id' => 'unknown field'], new RawContents('test')),
300        ];
301
302        yield 'Form with validation error' => [
303            'expected-form-with-validation-error.html',
304            new Form(RequestMethod::POST, 'validation error', [], [], false, new RawContents('test'), new RawContents('test2')),
305        ];
306
307        yield 'Configured input' => [
308            'expected-single-input.html',
309            new SingleInput(
310                new FormName('name'),
311                42,
312                new TranslationStringSet([DummyTranslation::fromNative('apie.mid-section.parent')]),
313                false,
314                ReflectionTypeFactory::createReflectionType('string'),
315                new CmsSingleInput(['datetimetz', 'text'], new CmsInputOption())
316            )
317        ];
318        $type = ReflectionTypeFactory::createReflectionType('string');
319        yield 'Union type' => [
320            'expected-type-split.html',
321            new FormSplit(
322                new FormName('name'),
323                false,
324                false,
325                '42',
326                new ComponentHashmap([
327                    'input' => new SingleInput(new FormName('input'), null, new TranslationStringSet([]), false, $type, new CmsSingleInput(['text'])),
328                    'password' => new SingleInput(new FormName('password'), null, new TranslationStringSet([]), false, $type, new CmsSingleInput(['text'])),
329                ])
330            )
331        ];
332
333        yield 'Form list' => [
334            'expected-form-list.html',
335            new FormPrototypeList(
336                new FormName('name'),
337                [],
338                '__NAME__',
339                new RawContents('<div>Row</div>')
340            )
341        ];
342
343        yield 'Form list with values' => [
344            'expected-form-list-with-values.html',
345            new FormPrototypeList(
346                new FormName('name'),
347                [
348                    '0611223344',
349                    '0123456789',
350                ],
351                '__NAME__',
352                new RawContents('<div>Row</div>')
353            )
354        ];
355
356        yield 'Form hashmap' => [
357            'expected-form-hashmap.html',
358            new FormPrototypeHashmap(
359                new FormName('name'),
360                [],
361                '__NAME__',
362                new RawContents('<div>Row</div>')
363            )
364        ];
365
366        yield 'Form hashmap with values' => [
367            'expected-form-hashmap-with-values.html',
368            new FormPrototypeHashmap(
369                new FormName('name'),
370                [
371                    'first' => '0611223344',
372                    'second' => '0123456789',
373                ],
374                '__NAME__',
375                new RawContents('<div>Row</div>')
376            )
377        ];
378
379        yield 'CSRF token' => [
380            'expected-csrf-token.html',
381            new Csrf('token-123')
382        ];
383        yield 'List display' => [
384            'expected-list-display.html',
385            new ListDisplay(
386                [
387                    [
388                        'id' => 1,
389                        'description' => 'Description of 1',
390                    ],
391                    [
392                        'id' => 2,
393                        'description' => 'Description of 2',
394                        'extra' => 'extra field',
395                    ]
396                ],
397                ['id', 'description', 'extra'],
398            )
399        ];
400        yield 'Empty list display' => [
401            'expected-empty-list-display.html',
402            new ListDisplay(
403                [],
404                ['id', 'description', 'extra'],
405            )
406        ];
407        yield 'Segment display' => [
408            'expected-segment-display.html',
409            new SegmentDisplay([
410                'test' => new RawContents('value1'),
411                'test2' => new RawContents('value2'),
412            ]),
413        ];
414        yield 'Segment display, hide keys' => [
415            'expected-segment-display-no-keys.html',
416            new SegmentDisplay(
417                [
418                    new RawContents('value1'),
419                    new RawContents('value2'),
420                ],
421                showKeys: false,
422            ),
423        ];
424        yield 'Empty segment display' => [
425            'expected-empty-segment-display.html',
426            new SegmentDisplay([
427            ]),
428        ];
429        yield 'Link display' => [
430            'expected-link-display.html',
431            new LinkDisplay('this is a link', 'https://apie-lib.github.io/projectCoverage/index.html')
432        ];
433        yield 'Display true' => [
434            'expected-true-display.html',
435            new BooleanDisplay(true)
436        ];
437        yield 'Display false' => [
438            'expected-false-display.html',
439            new BooleanDisplay(false)
440        ];
441        yield 'Display null' => [
442             'expected-null-display.html',
443             new NullDisplay()
444        ];
445        $entity = new Order(OrderIdentifier::fromNative('35eadea7-b93b-4031-acaf-c9759886627d'), new OrderLineList());
446        $singleResourceActionList = new SingleResourceActionList($defaultConfiguration, new ActionList([]), $entity->getId());
447        yield 'Single resource action list' => [
448            'expected-single-resource-action-list.html',
449            $singleResourceActionList,
450        ];
451        
452        yield 'Resource details' => [
453            'expected-resource-details.html',
454            new Detail(
455                $entity,
456                $singleResourceActionList,
457                new SegmentDisplay([
458                    'test' => new RawContents('value1'),
459                    'test2' => new RawContents('value2'),
460                ]),
461            )
462        ];
463
464        yield 'Remove confirmation text' => [
465            'expected-remove-confirm.html',
466            new RemoveConfirm(new ReflectionClass(Order::class))
467        ];
468    }
469}