reference_table_formatter-2.0.x-dev/tests/src/Kernel/EntityToTableRendererTest.php
tests/src/Kernel/EntityToTableRendererTest.php
<?php
namespace Drupal\Tests\reference_table_formatter\Kernel;
use Drupal\Core\Entity\Entity\EntityViewMode;
use Drupal\Core\Render\RenderContext;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\reference_table_formatter\EntityToTableRenderer;
/**
* Tests reference table formatter entity to table renderer.
*
* @group reference_table_formatter
*/
class EntityToTableRendererTest extends EntityKernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'reference_table_formatter'];
/**
* Node entities to test with.
*
* @var \Drupal\node\NodeInterface[]
*/
protected $nodes;
/**
* The display repository.
*
* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
*/
protected $displayRepository;
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* The entity table renderer undertest.
*
* @var \Drupal\reference_table_formatter\EntityToTableRendererInterface
*/
protected $tableRenderer;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installConfig(['system']);
$this->installSchema('node', ['node_access']);
NodeType::create(['type' => 't_shirt'])->save();
$fields = [
[
['type' => 'string', 'field_name' => 'field_color'],
['label' => 'Color'],
],
[
['type' => 'float', 'field_name' => 'field_price'],
['label' => 'Price', 'settings' => ['prefix' => '$']],
],
[
['type' => 'string', 'field_name' => 'field_size'],
['label' => 'Size'],
],
];
foreach ($fields as $parameters) {
list($storage, $instance) = $parameters;
$this->createField($storage, $instance + ['bundle' => 't_shirt']);
}
EntityViewMode::create([
'id' => 'node.teaser',
'targetEntityType' => 'node',
])->save();
$this->displayRepository = $this->container->get('entity_display.repository');
$this->displayRepository
->getViewDisplay('node', 't_shirt', 'teaser')
->setComponent('title', ['weight' => -5])
->setComponent('field_color', ['weight' => 3])
->setComponent('field_price', ['weight' => 1])
->setComponent('field_size', ['weight' => 2])
->save();
$node_0 = Node::create([
'title' => 'Red Medium T',
'type' => 't_shirt',
'field_color' => 'Red',
'field_price' => 1.00,
'field_size' => 'M',
]);
$node_0->save();
$node_1 = Node::create([
'title' => 'Green Large T',
'type' => 't_shirt',
'field_color' => 'Green',
'field_price' => 2.00,
'field_size' => 'L',
]);
$node_1->save();
$this->nodes = [$node_0, $node_1];
$entity_manager = $this->container->get('entity_type.manager');
$this->renderer = $this->container->get('renderer');
$this->tableRenderer = new EntityToTableRenderer($entity_manager, $this->renderer, $this->displayRepository);
}
/**
* Test standard table rendering.
*
* @dataProvider tableRenderingDataProvider
*/
public function testRendering($settings, $expected_header, $expected_rows, $empty_field = FALSE) {
if ($empty_field) {
$this->nodes[0]->field_size = [];
$this->nodes[0]->save();
}
$table = $this->renderer->executeInRenderContext(new RenderContext(), function () use ($settings) {
return $this->tableRenderer->getTable('node', 't_shirt', $this->nodes, $settings);
});
$this->assertEquals('table', $table['#theme']);
$this->assertEquals($expected_header, $table['#header'], 'Assert table headers are correct.');
foreach ($table['#rows'] as $i => $row) {
foreach ($row as $j => $field) {
$this->assertEquals($expected_rows[$i][$j], trim(strip_tags($field)));
}
}
$this->assertCount(2, array_intersect(['node:1', 'node:2'], $table['#cache']['tags']), 'Cache metadata of rendered referenced entities are added to the table.');
}
/**
* Data provider for testing the table builder.
*/
public static function tableRenderingDataProvider() {
return [
'Standard table' => [
[
'show_entity_label' => TRUE,
'view_mode' => 'teaser',
'empty_cell_value' => '',
'hide_header' => FALSE,
],
[
'title' => 'Title',
'field_price' => 'Price',
'field_size' => 'Size',
'field_color' => 'Color',
],
[
['Red Medium T', '$1.00', 'M', 'Red'],
['Green Large T', '$2.00', 'L', 'Green'],
],
],
'No entity label' => [
[
'show_entity_label' => FALSE,
'view_mode' => 'teaser',
'empty_cell_value' => '',
'hide_header' => FALSE,
],
[
'field_price' => 'Price',
'field_size' => 'Size',
'field_color' => 'Color',
],
[
['$1.00', 'M', 'Red'],
['$2.00', 'L', 'Green'],
],
],
'Incomplete rows' => [
[
'show_entity_label' => FALSE,
'view_mode' => 'teaser',
'empty_cell_value' => '',
'hide_header' => FALSE,
],
[
'field_price' => 'Price',
'field_size' => 'Size',
'field_color' => 'Color',
],
[
['$1.00', '', 'Red'],
['$2.00', 'L', 'Green'],
],
TRUE,
],
'Empty cell' => [
[
'show_entity_label' => FALSE,
'view_mode' => 'teaser',
'empty_cell_value' => 'N/A',
'hide_header' => FALSE,
],
[
'field_price' => 'Price',
'field_size' => 'Size',
'field_color' => 'Color',
],
[
['$1.00', 'N/A', 'Red'],
['$2.00', 'L', 'Green'],
],
TRUE,
],
];
}
/**
* Tests interactions with view modes and displays of referenced entities.
*/
public function testViewDisplays() {
$this->displayRepository
->getViewDisplay('node', 't_shirt', 'default')
->setComponent('field_color')
->save();
$base_settings = [
'show_entity_label' => FALSE,
'empty_cell_value' => '',
'hide_header' => FALSE,
];
$table = $this->renderer->executeInRenderContext(new RenderContext(), function () use ($base_settings) {
return $this->tableRenderer->getTable('node', 't_shirt', $this->nodes, [
'view_mode' => 'does_not_exist',
] + $base_settings);
});
$this->assertArrayHasKey('field_color', $table['#header'], 'Use default view mode as fallback.');
$this->displayRepository->getViewDisplay('node', 't_shirt', 'default')->delete();
// Check that no error is raised even if there is no default view mode.
$this->renderer->executeInRenderContext(new RenderContext(), function () use ($base_settings) {
return $this->tableRenderer->getTable('node', 't_shirt', $this->nodes, [
'view_mode' => 'does_not_exist',
] + $base_settings);
});
}
/**
* Tests handling of empty fields.
*/
public function testEmptyFields() {
$this->createField(['type' => 'string', 'field_name' => 'field_test'], ['bundle' => 't_shirt']);
// Create a field which will be empty across all referenced entities to test
// it gets filtered out.
$this->createField(['type' => 'string', 'field_name' => 'field_empty'], ['bundle' => 't_shirt']);
$this->displayRepository
->getViewDisplay('node', 't_shirt', 'teaser')
->setComponent('field_test')
->setComponent('field_empty')
->save();
$node_0 = Node::create([
'title' => $this->randomMachineName(),
'type' => 't_shirt',
// Tests entity with less field values still has field present in table.
'field_color' => 'Red',
// Tests overlapping field value with other entity.
'field_test' => $this->randomMachineName(),
]);
$node_0->save();
$node_1 = Node::create([
'title' => $this->randomMachineName(),
'type' => 't_shirt',
'field_size' => 'L',
'field_price' => 15.00,
'field_test' => $this->randomMachineName(),
]);
$node_1->save();
$nodes = [$node_0, $node_1];
$table = $this->renderer->executeInRenderContext(new RenderContext(), function () use ($nodes) {
return $this->tableRenderer->getTable('node', 't_shirt', $nodes, [
'show_entity_label' => FALSE,
'view_mode' => 'teaser',
'empty_cell_value' => '',
'hide_header' => FALSE,
]);
});
$expected = [
'field_price' => 'Price',
'field_size' => 'Size',
'field_color' => 'Color',
'field_test' => 'field_test',
];
$this->assertEquals($expected, $table['#header'], 'All non-empty fields across displayed entities are present.');
}
/**
* Creates a field on the node entity type.
*
* @param array $storage_settings
* Settings to create the field storage with.
* @param array $field_settings
* Settings to create the field instance with.
*/
public function createField(array $storage_settings, array $field_settings) {
$field_storage = FieldStorageConfig::create($storage_settings + ['entity_type' => 'node']);
$field_storage->save();
FieldConfig::create($field_settings + ['field_storage' => $field_storage])->save();
}
}
