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