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        yield 'Raw HTML concents' => [
118            'expected-raw-contents.html',
119            $rawContents,
120        ];
121        yield 'Simple layout' => [
122            'expected-simple-layout.html',
123            new Layout(
124                'Title',
125                $defaultConfiguration,
126                $rawContents
127            )
128        ];
129        $menuBuilder = new MenuBuilder();
130        $menuBuilder->addLeaf('test', new MenuNode(MenuHeader::fromNative('apie.menu.test.header'), '/test'));
131        $menuBuilder->addLeaf('test2', new MenuNode(MenuHeader::fromNative('apie.menu.test2.header'), '/test2'));
132        $menuBuilder->addLeaf('test3/test4', new MenuNode(MenuHeader::fromNative('apie.menu.test3.header'), '/test3'));
133        
134        yield 'Simple layout, new menu' => [
135            'expected-with-menu.html',
136            new Layout(
137                'Title',
138                $defaultConfiguration,
139                $rawContents,
140                new MenuItem($menuBuilder->getRoot()),
141            )
142        ];
143        yield 'Bounded context select => nothing selected' => [
144            'expected-bounded-context-select-nothing.html',
145            new BoundedContextSelect(
146                new CurrentConfiguration([], new ApieContext(), BoundedContextFactory::createHashmap(), null)
147            )
148        ];
149        yield 'Bounded context select => unknown selection' => [
150            'expected-bounded-context-select-unknown.html',
151            new BoundedContextSelect(
152                new CurrentConfiguration([], new ApieContext(), BoundedContextFactory::createHashmap(), new BoundedContextId('unknown'))
153            )
154        ];
155        yield 'Bounded context select => single bounded context' => [
156            'expected-bounded-context-select.html',
157            new BoundedContextSelect(
158                $defaultConfiguration
159            )
160        ];
161        yield 'Bounded context select => multiple bounded context' => [
162            'expected-bounded-context-select-multiple.html',
163            new BoundedContextSelect(
164                new CurrentConfiguration([], new ApieContext(), BoundedContextFactory::createHashmapWithMultipleContexts(), new BoundedContextId('default'))
165            )
166        ];
167        yield 'Logo' => [
168            'expected-logo.html',
169            new Logo($defaultConfiguration),
170        ];
171        yield 'Login select' => [
172            'expected-login-select.html',
173            new LoginSelect(
174                $defaultConfiguration
175            )
176        ];
177
178        yield 'Profile' => [
179            'expected-profile.html',
180            new ShowProfile(
181                $defaultConfiguration,
182                new UserWithAddress(
183                    new AddressWithZipcodeCheck(
184                        new DatabaseText('Evergreen Terrace'),
185                        new DatabaseText('742'),
186                        new DatabaseText('11111'),
187                        new DatabaseText('Springfield'),
188                    ),
189                    new UserWithAddressIdentifier('d788c9f5-6493-4386-89f4-374be3b28764'),
190                )
191            )
192        ];
193
194        yield 'Simple Menu' => [
195            'expected-menu.html',
196            new Layout\Menu($defaultConfiguration),
197        ];
198
199        yield 'Resource overview filters' => [
200            'expected-resource-overview-filters.html',
201            new FilterColumns(
202                new StringSet(['id', 'description']),
203                'text search',
204                ['description' => 'test'],
205            )
206            ];
207        
208        yield 'Resource overview' => [
209            'expected-resource-overview.html',
210            new Overview(
211                [['id' => 12, 'name' => 'Pizza']],
212                ['id', 'name'],
213                new ResourceActionList(
214                    $defaultConfiguration,
215                    new ActionList([]),
216                    new FilterColumns(new StringSet(), '', []),
217                )
218            )
219        ];
220
221        $createResourceAction = new CreateResourceAction(
222            new ReflectionClass(UserWithAutoincrementKey::class),
223            new CreateResourceActionDefinition(
224                new ReflectionClass(UserWithAutoincrementKey::class),
225                new BoundedContextId('default')
226            )
227        );
228        $resourceActionList = new ResourceActionList(
229            $defaultConfiguration,
230            new ActionList([$createResourceAction]),
231            new FilterColumns(new StringSet(), '', []),
232        );
233        yield 'Resource action list' => [
234            'expected-resource-action-list.html',
235            $resourceActionList
236        ];
237
238        yield 'Resource overview large list' => [
239            'expected-resource-overview-large-list.html',
240            new Overview(
241                array_fill(0, 100, ['id' => 12, 'name' => 'Pizza']),
242                ['id', 'name'],
243                $resourceActionList
244            )
245        ];
246
247        yield 'Form' => [
248            'expected-form.html',
249            new Form(RequestMethod::POST, null, [], [], false, new RawContents('test'), new RawContents('test2')),
250        ];
251        yield 'Form-Upload' => [
252            'expected-form-with-upload.html',
253            new Form(RequestMethod::POST, null, [], [], true, new RawContents('test'), new RawContents('test2')),
254        ];
255        yield 'Polymorphic Form' => [
256            'expected-polymorphic-form.html',
257            new PolymorphicForm(
258                RequestMethod::POST,
259                new ReflectionClass(Animal::class),
260                null,
261                [],
262                [],
263                false,
264                new Csrf('temp'),
265                new ComponentHashmap([
266                    'test1' => new RawContents('test3'),
267                    'test2' => new RawContents('test4'),
268                ])
269            ),
270        ];
271        yield 'Polymorphic Form-Upload' => [
272            'expected-polymorphic-form-with-upload.html',
273            new PolymorphicForm(
274                RequestMethod::POST,
275                new ReflectionClass(Animal::class),
276                null,
277                [],
278                [],
279                true,
280                new Csrf('temp'),
281                new ComponentHashmap([
282                    'test1' => new RawContents('test3'),
283                    'test2' => new RawContents('test4'),
284                ])
285            ),
286        ];
287        yield 'Form with validation errors' => [
288            'expected-form-with-unknown-validation-error.html',
289            new Form(RequestMethod::POST, null, ['id' => 'unknown field'], [], false, new RawContents('test')),
290        ];
291
292        yield 'Form group with validation errors' => [
293            'expected-form-group-with-validation-error.html',
294            new FormGroup(new FormName('test'), null, ['id' => 'unknown field'], new RawContents('test')),
295        ];
296
297        yield 'Form with validation error' => [
298            'expected-form-with-validation-error.html',
299            new Form(RequestMethod::POST, 'validation error', [], [], false, new RawContents('test'), new RawContents('test2')),
300        ];
301
302        yield 'Configured input' => [
303            'expected-single-input.html',
304            new SingleInput(
305                new FormName('name'),
306                42,
307                new TranslationStringSet([DummyTranslation::fromNative('apie.mid-section.parent')]),
308                false,
309                ReflectionTypeFactory::createReflectionType('string'),
310                new CmsSingleInput(['datetimetz', 'text'], new CmsInputOption())
311            )
312        ];
313        $type = ReflectionTypeFactory::createReflectionType('string');
314        yield 'Union type' => [
315            'expected-type-split.html',
316            new FormSplit(
317                new FormName('name'),
318                false,
319                false,
320                '42',
321                new ComponentHashmap([
322                    'input' => new SingleInput(new FormName('input'), null, new TranslationStringSet([]), false, $type, new CmsSingleInput(['text'])),
323                    'password' => new SingleInput(new FormName('password'), null, new TranslationStringSet([]), false, $type, new CmsSingleInput(['text'])),
324                ])
325            )
326        ];
327
328        yield 'Form list' => [
329            'expected-form-list.html',
330            new FormPrototypeList(
331                new FormName('name'),
332                [],
333                '__NAME__',
334                new RawContents('<div>Row</div>')
335            )
336        ];
337
338        yield 'Form list with values' => [
339            'expected-form-list-with-values.html',
340            new FormPrototypeList(
341                new FormName('name'),
342                [
343                    '0611223344',
344                    '0123456789',
345                ],
346                '__NAME__',
347                new RawContents('<div>Row</div>')
348            )
349        ];
350
351        yield 'Form hashmap' => [
352            'expected-form-hashmap.html',
353            new FormPrototypeHashmap(
354                new FormName('name'),
355                [],
356                '__NAME__',
357                new RawContents('<div>Row</div>')
358            )
359        ];
360
361        yield 'Form hashmap with values' => [
362            'expected-form-hashmap-with-values.html',
363            new FormPrototypeHashmap(
364                new FormName('name'),
365                [
366                    'first' => '0611223344',
367                    'second' => '0123456789',
368                ],
369                '__NAME__',
370                new RawContents('<div>Row</div>')
371            )
372        ];
373
374        yield 'CSRF token' => [
375            'expected-csrf-token.html',
376            new Csrf('token-123')
377        ];
378        yield 'List display' => [
379            'expected-list-display.html',
380            new ListDisplay(
381                [
382                    [
383                        'id' => 1,
384                        'description' => 'Description of 1',
385                    ],
386                    [
387                        'id' => 2,
388                        'description' => 'Description of 2',
389                        'extra' => 'extra field',
390                    ]
391                ],
392                ['id', 'description', 'extra'],
393            )
394        ];
395        yield 'Empty list display' => [
396            'expected-empty-list-display.html',
397            new ListDisplay(
398                [],
399                ['id', 'description', 'extra'],
400            )
401        ];
402        yield 'Segment display' => [
403            'expected-segment-display.html',
404            new SegmentDisplay([
405                'test' => new RawContents('value1'),
406                'test2' => new RawContents('value2'),
407            ]),
408        ];
409        yield 'Segment display, hide keys' => [
410            'expected-segment-display-no-keys.html',
411            new SegmentDisplay(
412                [
413                    new RawContents('value1'),
414                    new RawContents('value2'),
415                ],
416                showKeys: false,
417            ),
418        ];
419        yield 'Empty segment display' => [
420            'expected-empty-segment-display.html',
421            new SegmentDisplay([
422            ]),
423        ];
424        yield 'Link display' => [
425            'expected-link-display.html',
426            new LinkDisplay('this is a link', 'https://apie-lib.github.io/projectCoverage/index.html')
427        ];
428        yield 'Display true' => [
429            'expected-true-display.html',
430            new BooleanDisplay(true)
431        ];
432        yield 'Display false' => [
433            'expected-false-display.html',
434            new BooleanDisplay(false)
435        ];
436        yield 'Display null' => [
437             'expected-null-display.html',
438             new NullDisplay()
439        ];
440        $entity = new Order(OrderIdentifier::fromNative('35eadea7-b93b-4031-acaf-c9759886627d'), new OrderLineList());
441        $singleResourceActionList = new SingleResourceActionList($defaultConfiguration, new ActionList([]), $entity->getId());
442        yield 'Single resource action list' => [
443            'expected-single-resource-action-list.html',
444            $singleResourceActionList,
445        ];
446        
447        yield 'Resource details' => [
448            'expected-resource-details.html',
449            new Detail(
450                $entity,
451                $singleResourceActionList,
452                new SegmentDisplay([
453                    'test' => new RawContents('value1'),
454                    'test2' => new RawContents('value2'),
455                ]),
456            )
457        ];
458
459        yield 'Remove confirmation text' => [
460            'expected-remove-confirm.html',
461            new RemoveConfirm(new ReflectionClass(Order::class))
462        ];
463    }
464}