ILIAS  trunk Revision v12.0_alpha-1540-g00f839d5fa1
TreeMultiSelectTest.php
Go to the documentation of this file.
1<?php
2
18declare(strict_types=1);
19
24use PHPUnit\Framework\MockObject\MockObject;
25use PHPUnit\Framework\Attributes\DataProvider;
26
27require_once(__DIR__ . "/../../../../../../../vendor/composer/vendor/autoload.php");
28require_once(__DIR__ . "/../../../Base.php");
29require_once(__DIR__ . "/InputTest.php");
30
35{
36 protected Component\Button\Bulky & MockObject $bulky_stub;
37 protected string $bulky_html;
38 protected Component\Link\Standard & MockObject $link_stub;
39 protected string $link_html;
41 protected string $drilldown_html;
43 protected string $breadcrumbs_html;
44
45 protected Component\SignalGeneratorInterface $signal_generator;
47
48 protected function setUp(): void
49 {
54
55 $this->signal_generator = new IncrementalSignalGenerator();
56
57 $this->menu_factory = $this->createMock(Component\Menu\Factory::class);
58 $this->menu_factory->method('drilldown')->willReturn($this->drilldown_stub);
59
60 parent::setUp();
61 }
62
63 public function getDefaultRenderer(
64 ?JavaScriptBinding $js_binding = null,
65 array $with_stub_renderings = [],
66 array $with_additional_contexts = [],
68 $with_stub_renderings = array_merge($with_stub_renderings, [
69 $this->bulky_stub,
70 $this->drilldown_stub,
71 $this->breadcrumbs_stub,
72 ]);
73
74 return parent::getDefaultRenderer($js_binding, $with_stub_renderings, $with_additional_contexts);
75 }
76
77 public function getUIFactory(): \NoUIFactory
78 {
79 $icon_factory = $this->createMock(Component\Symbol\Icon\Factory::class);
80 $glyph_factory = $this->createMock(Component\Symbol\Glyph\Factory::class);
81 $glyph_mock = $this->createMock(Component\Symbol\Glyph\Glyph::class);
82 $glyph_factory->method($this->anything())->willReturn($glyph_mock);
83 $symbol_factory = $this->createMock(Component\Symbol\Factory::class);
84 $symbol_factory->method('icon')->willReturn($icon_factory);
85
86 $button_factory = $this->createMock(Component\Button\Factory::class);
87 $button_factory->method('bulky')->willReturn($this->bulky_stub);
88
89 $link_factory = $this->createMock(Component\Link\Factory::class);
90 $link_factory->method('standard')->willReturn($this->link_stub);
91
92 $node_factory = $this->createMock(Field\Node\Factory::class);
93 $field_factory = $this->createMock(Field\Factory::class);
94 $field_factory->method('node')->willReturn($node_factory);
95 $input_factory = $this->createMock(Component\Input\Factory::class);
96 $input_factory->method('field')->willReturn($field_factory);
97
98 return new class (
99 $button_factory,
100 $symbol_factory,
101 $link_factory,
102 $input_factory,
103 $this->menu_factory,
104 $this->breadcrumbs_stub,
105 ) extends \NoUIFactory {
106 public function __construct(
107 protected Component\Button\Factory $button_factory,
108 protected Component\Symbol\Factory $symbol_factory,
109 protected Component\Link\Factory $link_factory,
110 protected Component\Input\Factory $input_factory,
111 protected Component\Menu\Factory $menu_factory,
112 protected Component\Breadcrumbs\Breadcrumbs $breadcrumbs,
113 ) {
114 }
115 public function button(): Component\Button\Factory
116 {
117 return $this->button_factory;
118 }
119 public function breadcrumbs(array $crumbs): Component\Breadcrumbs\Breadcrumbs
120 {
121 return $this->breadcrumbs;
122 }
123 public function symbol(): Component\Symbol\Factory
124 {
125 return $this->symbol_factory;
126 }
127 public function link(): Component\Link\Factory
128 {
129 return $this->link_factory;
130 }
131 public function input(): Component\Input\Factory
132 {
133 return $this->input_factory;
134 }
135 public function menu(): Component\Menu\Factory
136 {
137 return $this->menu_factory;
138 }
139 };
140 }
141
142 #[DataProvider('getInvalidArgumentsForWithValue')]
143 public function testWithValueForInvalidArguments(mixed $value): void
144 {
145 $node_retrieval = $this->getNodeRetrieval();
146 $component = $this->getFieldFactory()->treeMultiSelect($node_retrieval, '');
147 $this->expectException(InvalidArgumentException::class);
148 $component = $component->withValue($value);
149 }
150
151 #[DataProvider('getValidArgumentsForWithValue')]
152 public function testWithValueForValidArguments(array $value): void
153 {
154 $node_retrieval = $this->getNodeRetrieval();
155 $component = $this->getFieldFactory()->treeMultiSelect($node_retrieval, '');
156 $component = $component->withValue($value);
157 $this->assertEquals($value, $component->getValue());
158 }
159
160 public function testRenderWithValue(): void
161 {
162 $node_id = 'some-existing-node-id';
163 $node_name = 'some existing node';
164
165 [$leaf_stub,] = $this->getLeafStub($node_id, $node_name);
166
167 $node_retrieval = $this->getNodeRetrieval([], [$leaf_stub]);
168
169 $component = $this->getFieldFactory()->treeMultiSelect($node_retrieval, '');
170 $component = $component->withValue([$node_id]);
171
172 $renderer = $this->getDefaultRenderer(null, [$leaf_stub]);
173
174 $expected_html = <<<HTML
175<li data-node-id="$node_id">
176 <span data-node-name>$node_name</span>
177 <button data-action="remove" type="button" class="close" aria-label="unselect_node">
178 <span aria-hidden="true">&times;</span>
179 </button>
180 <input id="id_2" type="hidden" value="$node_id" />
181</li>
182HTML;
183
184 $actual_html = $renderer->render($component);
185
186 $this->assertTrue(
187 str_contains(
188 $this->brutallyTrimHTML($actual_html),
189 $this->brutallyTrimHTML($expected_html),
190 )
191 );
192 }
193
194 public function testRenderWithDisabled(): void
195 {
196 $node_retrieval = $this->getNodeRetrieval();
197
198 $component = $this->getFieldFactory()->treeMultiSelect($node_retrieval, '');
199 $component = $component->withDisabled(true);
200
201 $renderer = $this->getDefaultRenderer();
202
203 $expected_html = <<<HTML
204<input id="id_2" type="button" aria-label="select" value="select" disabled>
205HTML;
206
207 $actual_html = $renderer->render($component);
208
209 $this->assertTrue(
210 str_contains(
211 $this->brutallyTrimHTML($actual_html),
212 $this->brutallyTrimHTML($expected_html),
213 )
214 );
215 }
216
217 public function testRenderWithRequired(): void
218 {
219 $node_retrieval = $this->getNodeRetrieval();
220
221 $component = $this->getFieldFactory()->treeMultiSelect($node_retrieval, '');
222 $component = $component->withRequired(true);
223
224 $renderer = $this->getDefaultRenderer();
225
226 $expected_html = <<<HTML
227<label for="id_2"><span class="sr-only">required_field</span><span class="asterisk" aria-hidden="true">*</span></label>
228HTML;
229
230 $actual_html = $renderer->render($component);
231
232 $this->assertTrue(
233 str_contains(
234 $this->brutallyTrimHTML($actual_html),
235 $this->brutallyTrimHTML($expected_html),
236 )
237 );
238 }
239
240 public function testRenderDrilldownMenu(): void
241 {
242 $this->menu_factory = $this->getMenuFactory();
243
244 [$leaf_stub, $leaf_html] = $this->getLeafStub();
245
246 $tree_select_label = 'some tree select label';
247
248 $node_retrieval = $this->getNodeRetrieval([$leaf_stub]);
249
250 $component = $this->getFieldFactory()->treeMultiSelect($node_retrieval, $tree_select_label);
251 $component = $component->withNameFrom(new DefNamesource());
252
253 $renderer = $this->getDefaultRenderer(null, [$leaf_stub]);
254
255 $expected_html = <<<HTML
256<fieldset class="c-input" data-il-ui-component="tree-multi-select-field-input" data-il-ui-input-name="name_0">
257 <label for="id_3">some tree select label</label>
258 <div class="c-input__field">
259 <div class="c-input-tree_select">
260 <dialog class="c-modal">
261 <div class="modal-dialog" role="document">
262 <div class="modal-content">
263 <div class="modal-header">
264 <button data-action="close" type="button" class="close" aria-label="close">
265 <span aria-hidden="true">&times;</span>
266 </button>
267 <h1 class="modal-title">$tree_select_label</h1>
268 </div>
269 <div class="modal-body">
270 <template>$this->breadcrumbs_html</template>
271 $this->breadcrumbs_html
272 <section class="c-drilldown" id="id_2">
273 <header class="c-drilldown__header--showbacknav">
274 <div></div>
275 <div></div>
276 <div class="c-drilldown__backnav"> $this->bulky_html</div>
277 </header>
278 <div class="c-drilldown__menu">
279 <ul aria-live="polite" aria-label="$tree_select_label">
280 $leaf_html
281 <li class="c-drilldown__menu--no-items"> drilldown_no_items</li>
282 </ul>
283 </div>
284 </section>
285 </div>
286 <div class="modal-footer">
287 <button data-action="close" type="button" class="btn btn-default" aria-label="close">close</button>
288 <button data-action="close" type="button" class="btn btn-primary" aria-label="select">select</button>
289 </div>
290 </div>
291 </div>
292 </dialog>
293 <ul class="c-input-tree_select__selection">
294 <template>
295 <li data-node-id="">
296 <span data-node-name></span>
297 <button data-action="remove" type="button" class="close" aria-label="">
298 <span aria-hidden="true">&times;</span>
299 </button>
300 <input id="id_1" type="hidden" name="name_0[input_0][]" value="" /></li>
301 </template>
302 </ul>
303 <input id="id_3" type="button" aria-label="select" value="select">
304 </div>
305 </div>
306</fieldset>
307HTML;
308
309 $actual_html = $renderer->render($component);
310
311 $this->assertEquals(
312 $this->brutallyTrimHTML($expected_html),
313 $this->brutallyTrimHTML($actual_html),
314 );
315 }
316
317 public static function getInvalidArgumentsForWithValue(): array
318 {
319 return [
320 [true],
321 [new stdClass()],
322 ['1'],
323 [1.000],
324 [1],
325 ];
326 }
327
328 public static function getValidArgumentsForWithValue(): array
329 {
330 return [
331 [[1, 2, 3]],
332 [[-1]],
333 [['1', '2', '3']],
334 [['1']],
335 [['']],
336 [[' ']],
337 [[]]
338 ];
339 }
340
341 protected function getMenuFactory(): Component\Menu\Factory
342 {
343 return new Component\Menu\Factory($this->signal_generator);
344 }
345
346 protected function getFieldFactory(?Field\Node\Factory $node_factory = null): Field\Factory
347 {
348 return new Field\Factory(
349 ($node_factory) ?: $this->createMock(Field\Node\Factory::class),
350 $this->createMock(Component\Input\UploadLimitResolver::class),
351 $this->signal_generator,
352 $this->getDataFactory(),
353 $this->getRefinery(),
354 $this->getLanguage(),
355 );
356 }
357
362 protected function getNodeRetrieval(array $node_stubs = [], array $leaf_stubs = []): NodeRetrieval & MockObject
363 {
364 $node_retrieval = $this->createMock(NodeRetrieval::class);
365 $node_retrieval->method('getNodes')->willReturnCallback(static fn() => yield from $node_stubs);
366 $node_retrieval->method('getNodesAsLeaf')->willReturnCallback(static fn() => yield from $leaf_stubs);
367 return $node_retrieval;
368 }
369
371 protected function getLeafStub(string|int $id = '', string $name = ''): array
372 {
373 $stub = $this->createMock(Field\Node\Leaf::class);
374 $html = sha1(Field\Node\Leaf::class);
375 $stub->method('getCanonicalName')->willReturn($html);
376 $stub->method('getId')->willReturn($id);
377 $stub->method('getName')->willReturn($name);
378 return [$stub, $html];
379 }
380
382 protected function getBreadcrumbsStub(): array
383 {
384 return $this->createSimpleRenderingStub(Component\Breadcrumbs\Breadcrumbs::class);
385 }
386
388 protected function getDrilldownStub(): array
389 {
390 return $this->createSimpleRenderingStub(Component\Menu\Drilldown::class);
391 }
392
394 protected function getLinkStub(): array
395 {
396 return $this->createSimpleRenderingStub(Component\Link\Standard::class);
397 }
398
400 protected function getBulkyStub(): array
401 {
402 return $this->createSimpleRenderingStub(Component\Button\Bulky::class);
403 }
404
406 protected function createSimpleRenderingStub(string $class_name): array
407 {
408 $stub = $this->createMock($class_name);
409 $html = sha1($class_name);
410 $stub->method('getCanonicalName')->willReturn($html);
411 $stub->method($this->anything())->willReturnSelf();
412 return [$stub, $html];
413 }
414}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$renderer
Builds a Color from either hex- or rgb values.
Definition: Factory.php:31
Factory for Date Formats.
Definition: Factory.php:27
Builds data types.
Definition: Factory.php:36
This implements commonalities between inputs.
Definition: Input.php:43
Provides common functionality for UI tests.
Definition: Base.php:337
static getInvalidArgumentsForWithValue()
getNodeRetrieval(array $node_stubs=[], array $leaf_stubs=[])
Component Button Bulky &MockObject $bulky_stub
getDefaultRenderer(?JavaScriptBinding $js_binding=null, array $with_stub_renderings=[], array $with_additional_contexts=[],)
Component Breadcrumbs Breadcrumbs &MockObject $breadcrumbs_stub
Component Link Standard &MockObject $link_stub
Component Menu Drilldown &MockObject $drilldown_stub
getFieldFactory(?Field\Node\Factory $node_factory=null)
Component Menu Factory $menu_factory
testWithValueForInvalidArguments(mixed $value)
createSimpleRenderingStub(string $class_name)
Component SignalGeneratorInterface $signal_generator
testWithValueForValidArguments(array $value)
getLeafStub(string|int $id='', string $name='')
This is what a factory for input fields looks like.
Definition: Factory.php:31
This describes a symbol.
Definition: Symbol.php:30
Provides methods to interface with javascript.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
button(string $caption, string $cmd)
link(string $caption, string $href, bool $new_viewport=false)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Bulky.php:21
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Checkbox.php:21
getLanguage()