ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
DataRendererTest.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
21require_once("vendor/composer/vendor/autoload.php");
22require_once(__DIR__ . "/TableRendererTestBase.php");
23
26use ILIAS\Data;
28
32class DTRenderer extends I\Table\Renderer
33{
34 public function p_getMultiActionHandler(I\Signal $signal)
35 {
36 return $this->getMultiActionHandler($signal);
37 }
38
39 public function p_getActionRegistration(string $action_id, I\Table\Action\Action $action)
40 {
41 return $this->getActionRegistration($action_id, $action);
42 }
43
45 array $actions,
46 I\Signal $action_signal,
47 I\Signal $modal_signal
48 ) {
49 return $this->buildMultiActionsDropdown($actions, $action_signal, $modal_signal);
50 }
51
52 public function p_getSingleActionsForRow(string $row_id, array $actions)
53 {
54 return $this->getSingleActionsForRow($row_id, $actions);
55 }
56
57 public function p_renderTableHeader(
58 TestDefaultRenderer $default_renderer,
59 I\Table\Data $component,
60 $tpl,
61 ?I\Signal $sortation_signal
62 ) {
63 $this->renderTableHeader($default_renderer, $component, $tpl, $sortation_signal, 1);
64 }
65 public function p_renderActionsHeader(
66 TestDefaultRenderer $default_renderer,
67 I\Table\Data $component,
68 $tpl
69 ) {
70 $this->renderActionsHeader($default_renderer, $component, $tpl, 1);
71 }
72}
73
78{
79 private function getRenderer()
80 {
81 return new DTRenderer(
82 $this->getUIFactory(),
83 $this->getTemplateFactory(),
84 $this->getLanguage(),
85 $this->getJavaScriptBinding(),
87 new \ILIAS\Data\Factory(),
88 new \ILIAS\UI\Help\TextRetriever\Echoing(),
89 $this->getUploadLimitResolver()
90 );
91 }
92
94 {
95 $renderer = $this->getRenderer();
96 $signal = new I\Signal('signal_id');
97 $closure = $renderer->p_getMultiActionHandler($signal);
98 $actual = $this->brutallyTrimHTML($closure('component_id'));
99 $expected = $this->brutallyTrimHTML(
100 "$(document).on('signal_id', function(event, signal_data) {
101 il.UI.table.data.get('component_id').doMultiAction(signal_data);
102 return false;
103 });"
104 );
105 $this->assertEquals($expected, $actual);
106 }
107
109 {
110 $renderer = $this->getRenderer();
111 $f = $this->getActionFactory();
112 $url = $this->getDataFactory()->uri('http://wwww.ilias.de?ref_id=1');
113 $url_builder = new URLBuilder($url);
114 list($builder, $token) = $url_builder->acquireParameter(['namespace'], 'param');
115
116 $action = $f->standard('label', $builder, $token);
117 $closure = $renderer->p_getActionRegistration('action_id', $action);
118
119 $actual = $this->brutallyTrimHTML($closure('component_id'));
120 $url = $url->__toString();
121 $expected = $this->brutallyTrimHTML(
122 'il.UI.table.data.get(\'component_id\').registerAction(\'action_id\', false, new il.UI.core.URLBuilder(new URL("http://wwww.ilias.de?ref_id=1&namespace_param="), new Map([["namespace_param",new il.UI.core.URLBuilderToken(["namespace"], "param",'
123 );
124 $this->assertStringStartsWith($expected, $actual);
125 }
126
128 {
129 $renderer = $this->getRenderer();
130 $f = $this->getActionFactory();
131 $signal1 = new I\Signal('signal_id');
132 $signal2 = new I\Signal('signal_id2');
133 $url = $this->getDataFactory()->uri('http://wwww.ilias.de?ref_id=1');
134 $url_builder = new URLBuilder($url);
135 list($builder, $token) = $url_builder->acquireParameter(['namespace'], 'param');
136 $actions = [
137 $f->standard('label1', $builder, $token),
138 $f->standard('label2', $builder, $token)
139 ];
140 $this->assertNull(
141 $renderer->p_buildMultiActionsDropdown([], $signal1, $signal2)
142 );
143 $this->assertEquals(
144 4, //2 actions, 1 divider, one all-action
145 count($renderer->p_buildMultiActionsDropdown($actions, $signal1, $signal2)->getItems())
146 );
147 }
149 {
150 $renderer = $this->getRenderer();
151 $f = $this->getActionFactory();
152 $url = $this->getDataFactory()->uri('http://wwww.ilias.de?ref_id=1');
153 $url_builder = new URLBuilder($url);
154 list($builder, $token) = $url_builder->acquireParameter(['namespace'], 'param');
155 $actions = [
156 'a1' => $f->standard('label1', $builder, $token)->withAsync(),
157 'a2' => $f->standard('label2', $builder, $token)
158 ];
159 $this->assertEquals(
160 2,
161 count($renderer->p_getSingleActionsForRow('row_id-1', $actions)->getItems())
162 );
163 }
164
166 {
167 $renderer = $this->getRenderer();
168 $data_factory = new \ILIAS\Data\Factory();
169 $tpl = $this->getTemplateFactory()->getTemplate("components/ILIAS/UI/src/templates/default/Table/tpl.datatable.html", true, true);
170 $f = $this->getColumnFactory();
171 $data = new class () implements ILIAS\UI\Component\Table\DataRetrieval {
172 public function getRows(
173 Component\Table\DataRowBuilder $row_builder,
174 array $visible_column_ids,
176 Data\Order $order,
177 mixed $additional_viewcontrol_data,
178 mixed $filter_data,
179 mixed $additional_parameters
180 ): \Generator {
181 yield $row_builder->buldDataRow('', []);
182 }
183 public function getTotalRowCount(
184 mixed $additional_viewcontrol_data,
185 mixed $filter_data,
186 mixed $additional_parameters
187 ): ?int {
188 return null;
189 }
190 };
191 $columns = [
192 'f1' => $f->text("Field 1")->withIndex(1),
193 'f2' => $f->text("Field 2")->withIndex(2)->withIsSortable(false),
194 'f3' => $f->number("Field 3")->withIndex(3)
195 ];
196 $sortation_signal = new I\Signal('sort_header_signal_id');
197 $sortation_signal->addOption('value', 'f1:ASC');
198 $table = $this->getUIFactory()->table()->data($data, '', $columns)
199 ->withRequest($this->getDummyRequest());
200 $renderer->p_renderTableHeader($this->getDefaultRenderer(), $table, $tpl, $sortation_signal);
201
202 $actual = $this->brutallyTrimHTML($tpl->get());
203 $expected = <<<EOT
204<div class="c-table-data" id="{ID}">
205 <div class="viewcontrols">{VIEW_CONTROLS}</div>
206 <div class="c-table-data__table-wrapper">
207 <table class="c-table-data__table" aria-labelledby="{ID}_label" aria-colcount="{COL_COUNT}" role="grid">
208 <thead>
209 <tr class="c-table-data__header c-table-data__row">
210 <th class="c-table-data__header c-table-data__cell c-table-data__cell--text" tabindex="-1" aria-colindex="1" aria-sort="ascending">
211 <div class="c-table-data__header__resize-wrapper">
212 <a tabindex="0" class="glyph" href="#" aria-label="sort_ascending" id="id_2"><span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span></a>
213 <button class="btn btn-link" id="id_1">Field 1</button>
214 </div>
215 </th>
216 <th class="c-table-data__header c-table-data__cell c-table-data__cell--text" tabindex="-1" aria-colindex="2">
217 <div class="c-table-data__header__resize-wrapper">Field 2</div>
218 </th>
219 <th class="c-table-data__header c-table-data__cell c-table-data__cell--number" tabindex="-1" aria-colindex="3">
220 <div class="c-table-data__header__resize-wrapper">
221 <button class="btn btn-link" id="id_3">Field 3</button>
222 </div>
223 </th>
224 </tr>
225 </thead>
226 <tbody class="c-table-data__body"></tbody>
227 </table>
228 </div>
229 <div class="c-table-data__async_modal_container"></div>
230 <dialog class="c-table-data__async_message c-modal" id="{ID}_msgmodal">
231 <div class="modal-dialog" role="document">
232 <div class="modal-content">
233 <div class="modal-header">
234 <form>
235 <button formmethod="dialog" class="close" aria-label="close">
236 <span aria-hidden="true">&times;</span></button>
237 </form>
238 </div>
239 <div class="c-table-data__async_messageresponse modal-body"></div>
240 </div>
241 </div>
242 </dialog>
243</div>
244EOT;
245 $expected = $this->brutallyTrimHTML($expected);
246 $this->assertEquals($expected, $actual);
247 }
248
249
251 {
252 $renderer = $this->getRenderer();
253 $data_factory = new \ILIAS\Data\Factory();
254 $tpl = $this->getTemplateFactory()->getTemplate("components/ILIAS/UI/src/templates/default/Table/tpl.datatable.html", true, true);
255 $f = $this->getColumnFactory();
256 $data = new class () implements ILIAS\UI\Component\Table\DataRetrieval {
257 public function getRows(
258 Component\Table\DataRowBuilder $row_builder,
259 array $visible_column_ids,
261 Data\Order $order,
262 mixed $additional_viewcontrol_data,
263 mixed $filter_data,
264 mixed $additional_parameters
265 ): \Generator {
266 yield $row_builder->buldDataRow('', []);
267 }
268 public function getTotalRowCount(
269 mixed $additional_viewcontrol_data,
270 mixed $filter_data,
271 mixed $additional_parameters
272 ): ?int {
273 return null;
274 }
275 };
276 $columns = [
277 'f1' => $f->text("Field 1")->withIsSortable(false),
278 'f2' => $f->text("Field 2")->withIsSortable(false)
279 ];
280
281 $sortation_signal = null;
282
283 $table = $this->getUIFactory()->table()->data($data, '', $columns)
284 ->withRequest($this->getDummyRequest());
285 $renderer->p_renderTableHeader($this->getDefaultRenderer(), $table, $tpl, $sortation_signal);
286 $actual = $this->brutallyTrimHTML($tpl->get());
287 $expected = <<<EOT
288<div class="c-table-data" id="{ID}">
289 <div class="viewcontrols">{VIEW_CONTROLS}</div>
290 <div class="c-table-data__table-wrapper">
291 <table class="c-table-data__table" aria-labelledby="{ID}_label" aria-colcount="{COL_COUNT}" role="grid">
292 <thead>
293 <tr class="c-table-data__header c-table-data__row">
294 <th class="c-table-data__header c-table-data__cell c-table-data__cell--text" tabindex="-1" aria-colindex="1">
295 <div class="c-table-data__header__resize-wrapper">Field 1</div>
296 </th>
297 <th class="c-table-data__header c-table-data__cell c-table-data__cell--text" tabindex="-1" aria-colindex="2">
298 <div class="c-table-data__header__resize-wrapper">Field 2</div>
299 </th>
300 </tr>
301 </thead>
302 <tbody class="c-table-data__body"></tbody>
303 </table>
304 </div>
305 <div class="c-table-data__async_modal_container"></div>
306 <dialog class="c-table-data__async_message c-modal" id="{ID}_msgmodal">
307 <div class="modal-dialog" role="document">
308 <div class="modal-content">
309 <div class="modal-header">
310 <form>
311 <button formmethod="dialog" class="close" aria-label="close">
312 <span aria-hidden="true">&times;</span></button>
313 </form>
314 </div>
315 <div class="c-table-data__async_messageresponse modal-body"></div>
316 </div>
317 </div>
318 </dialog>
319</div>
320EOT;
321 $expected = $this->brutallyTrimHTML($expected);
322 $this->assertEquals($expected, $actual);
323 }
324
326 {
327 $renderer = $this->getRenderer();
328 $data_factory = new \ILIAS\Data\Factory();
329 $tpl = $this->getTemplateFactory()->getTemplate("components/ILIAS/UI/src/templates/default/Table/tpl.datatable.html", true, true);
330 $f = $this->getColumnFactory();
331
332 $url = $data_factory->uri('http://wwww.ilias.de?ref_id=1');
333 $url_builder = new URLBuilder($url);
334 list($builder, $token) = $url_builder->acquireParameter(['namespace'], 'param');
335 $actions = [
336 'a2' => $this->getActionFactory()->standard('some action', $builder, $token)
337 ];
338
339 $data = new class () implements ILIAS\UI\Component\Table\DataRetrieval {
340 public function getRows(
341 Component\Table\DataRowBuilder $row_builder,
342 array $visible_column_ids,
344 Data\Order $order,
345 mixed $additional_viewcontrol_data,
346 mixed $filter_data,
347 mixed $additional_parameters
348 ): \Generator {
349 yield $row_builder->buldDataRow('', []);
350 }
351 public function getTotalRowCount(
352 mixed $additional_viewcontrol_data,
353 mixed $filter_data,
354 mixed $additional_parameters
355 ): ?int {
356 return null;
357 }
358 };
359 $columns = [
360 'f1' => $f->text("Field 1")->withIsSortable(false),
361 ];
362
363 $sortation_signal = null;
364
365 $table = $this->getUIFactory()->table()->data($data, '', $columns)
366 ->withActions($actions)
367 ->withRequest($this->getDummyRequest());
368 $renderer->p_renderActionsHeader($this->getDefaultRenderer(), $table, $tpl);
369 $actual = $this->brutallyTrimHTML($tpl->get());
370
371 $expected = '<th class="c-table-data__header c-table-data__cell c-table-data__header__rowaction" aria-colindex="2">actions</th>';
372 $this->assertStringContainsString($expected, $actual);
373 }
374
375 public function testDataTableRowBuilder()
376 {
377 $f = $this->getColumnFactory();
378 $columns = [
379 'f1' => $f->text("Field 1")->withIndex(1),
380 'f2' => $f->text("Field 2")->withIndex(2),
381 'f3' => $f->number("Field 3")->withIndex(3)
382 ];
383 $f = $this->getActionFactory();
384 $url = $this->getDataFactory()->uri('http://wwww.ilias.de?ref_id=1');
385 $url_builder = new URLBuilder($url);
386 list($builder, $token) = $url_builder->acquireParameter(['namespace'], 'param');
387 $actions = [
388 'a1' => $f->standard('label1', $builder, $token)->withAsync(),
389 'a2' => $f->standard('label2', $builder, $token)
390 ];
391
392 $rb = (new I\Table\DataRowBuilder())
393 ->withMultiActionsPresent(true)
394 ->withSingleActions($actions)
395 ->withVisibleColumns($columns);
396
397 $row = $rb->buildDataRow('row_id-1', []);
398 $this->assertInstanceOf(Component\Table\DataRow::class, $row);
399
400 return [$rb, $columns, $actions];
401 }
402
403 #[\PHPUnit\Framework\Attributes\Depends('testDataTableRowBuilder')]
404 public function testDataTableDataRowFromBuilder(array $params): I\Table\DataRow
405 {
406 list($rb, $columns, $actions) = $params;
407 $record = [
408 'f1' => 'v1',
409 'f2' => 'v2',
410 'f3' => 3
411 ];
412 $row = $rb->buildDataRow('row_id-1', $record);
413
414 $this->assertEquals(
415 $columns,
416 $row->getColumns()
417 );
418 $this->assertEquals(
419 $actions,
420 $row->getActions()
421 );
422 $this->assertEquals(
423 $record['f2'],
424 $row->getCellContent('f2')
425 );
426
427 return $row;
428 }
429
430 #[\PHPUnit\Framework\Attributes\Depends('testDataTableDataRowFromBuilder')]
431 public function testDataTableRenderStandardRow(I\Table\DataRow $row)
432 {
433 $actual = $this->brutallyTrimHTML($this->getDefaultRenderer()->render($row));
434 $expected = <<<EOT
435<td class="c-table-data__cell c-table-data__rowselection" tabindex="-1">
436 <input type="checkbox" value="row_id-1" class="c-table-data__row-selector"></td>
437<td class="c-table-data__cell c-table-data__cell--text " tabindex="-1"><span class="c-table-data__cell__col-title">Field 1:</span>v1
438</td>
439<td class="c-table-data__cell c-table-data__cell--text " tabindex="-1"><span class="c-table-data__cell__col-title">Field 2:</span>v2
440</td>
441<td class="c-table-data__cell c-table-data__cell--number " tabindex="-1"><span class="c-table-data__cell__col-title">Field 3:</span>3
442</td>
443<td class="c-table-data__cell c-table-data__rowaction" tabindex="-1">
444 <div class="dropdown" id="id_3">
445 <button class="btn btn-default dropdown-toggle" type="button" aria-label="actions" aria-haspopup="true" aria-expanded="false" aria-controls="id_3_menu">
446 <span class="caret"></span></button>
447 <ul id="id_3_menu" class="dropdown-menu">
448 <li>
449 <button class="btn btn-link" data-action="http://wwww.ilias.de?ref_id=1&namespace_param%5B%5D=row_id-1" id="id_1">label1</button>
450 </li>
451 <li>
452 <button class="btn btn-link" data-action="http://wwww.ilias.de?ref_id=1&namespace_param%5B%5D=row_id-1" id="id_2">label2</button>
453 </li>
454 </ul>
455 </div>
456</td>
457
458EOT;
459 $expected = $this->brutallyTrimHTML($expected);
460 $this->assertEquals($expected, $actual);
461 }
462
463 public function testRenderEmptyDataCell(): void
464 {
465 $data = new class () implements Component\Table\DataRetrieval {
466 public function getRows(
467 Component\Table\DataRowBuilder $row_builder,
468 array $visible_column_ids,
470 Data\Order $order,
471 mixed $additional_viewcontrol_data,
472 mixed $filter_data,
473 mixed $additional_parameters
474 ): Generator {
475 yield from [];
476 }
477
478 public function getTotalRowCount(
479 mixed $additional_viewcontrol_data,
480 mixed $filter_data,
481 mixed $additional_parameters
482 ): ?int {
483 return 0;
484 }
485 };
486
487 $columns = [
488 'f1' => $this->getUIFactory()->table()->column()->text('f1'),
489 'f2' => $this->getUIFactory()->table()->column()->text('f2'),
490 'f3' => $this->getUIFactory()->table()->column()->text('f3'),
491 'f4' => $this->getUIFactory()->table()->column()->text('f4'),
492 'f5' => $this->getUIFactory()->table()->column()->text('f5'),
493 ];
494
495 $table = $this->getTableFactory()->data($data, '', $columns)
496 ->withRequest($this->getDummyRequest());
497
498 $html = $this->getDefaultRenderer()->render($table);
499
500 $translation = $this->getLanguage()->txt('ui_table_no_records');
501 $column_count = count($columns);
502
503 // check that the empty cell is stretched over all columns.
504 $this->assertTrue(str_contains($html, "colspan=\"$column_count\""));
505 // check that the cell contains the default message.
506 $this->assertTrue(str_contains($html, $translation));
507 }
508}
$renderer
wrapper around the renderer to expose protected functions
p_renderTableHeader(TestDefaultRenderer $default_renderer, I\Table\Data $component, $tpl, ?I\Signal $sortation_signal)
p_renderActionsHeader(TestDefaultRenderer $default_renderer, I\Table\Data $component, $tpl)
p_getMultiActionHandler(I\Signal $signal)
p_getSingleActionsForRow(string $row_id, array $actions)
p_getActionRegistration(string $action_id, I\Table\Action\Action $action)
p_buildMultiActionsDropdown(array $actions, I\Signal $action_signal, I\Signal $modal_signal)
Tests for the Renderer of DataTables.
testDataTableDataRowFromBuilder(array $params)
testDataTableRenderStandardRow(I\Table\DataRow $row)
testDataTableRenderHeaderWithoutSortableColums()
Builds data types.
Definition: Factory.php:36
Both the subject and the direction need to be specified when expressing an order.
Definition: Order.php:29
A simple class to express a naive range of whole positive numbers.
Definition: Range.php:29
Definition: UI.php:24
Tests for the Renderer of DataTables.
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:31
button(string $caption, string $cmd)
form(?array $class_path, string $cmd, string $submit_caption="")
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
$url
Definition: shib_logout.php:68
getLanguage()
$token
Definition: xapitoken.php:67