d5246a0c2cd0342e65a1211f6f067b45f091009f
[yaffs-website] / web / core / modules / layout_builder / tests / src / Kernel / FieldBlockTest.php
1 <?php
2
3 namespace Drupal\Tests\layout_builder\Kernel;
4
5 use Drupal\Core\Access\AccessResult;
6 use Drupal\Core\Entity\EntityFieldManagerInterface;
7 use Drupal\Core\Entity\EntityInterface;
8 use Drupal\Core\Entity\FieldableEntityInterface;
9 use Drupal\Core\Extension\ModuleHandlerInterface;
10 use Drupal\Core\Field\FieldDefinitionInterface;
11 use Drupal\Core\Field\FieldItemListInterface;
12 use Drupal\Core\Field\FormatterPluginManager;
13 use Drupal\Core\Plugin\Context\EntityContextDefinition;
14 use Drupal\Core\Session\AccountInterface;
15 use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
16 use Drupal\layout_builder\Plugin\Block\FieldBlock;
17 use Prophecy\Argument;
18 use Prophecy\Promise\PromiseInterface;
19 use Prophecy\Promise\ReturnPromise;
20 use Prophecy\Promise\ThrowPromise;
21 use Prophecy\Prophecy\ProphecyInterface;
22 use Psr\Log\LoggerInterface;
23
24 /**
25  * @coversDefaultClass \Drupal\layout_builder\Plugin\Block\FieldBlock
26  * @group Field
27  */
28 class FieldBlockTest extends EntityKernelTestBase {
29
30   /**
31    * The entity field manager.
32    *
33    * @var \Drupal\Core\Entity\EntityFieldManagerInterface
34    */
35   protected $entityFieldManager;
36
37   /**
38    * The logger.
39    *
40    * @var \Psr\Log\LoggerInterface
41    */
42   protected $logger;
43
44   /**
45    * {@inheritdoc}
46    */
47   protected function setUp() {
48     parent::setUp();
49
50     $this->entityFieldManager = $this->prophesize(EntityFieldManagerInterface::class);
51     $this->logger = $this->prophesize(LoggerInterface::class);
52   }
53
54   /**
55    * Tests entity access.
56    *
57    * @covers ::blockAccess
58    * @dataProvider providerTestBlockAccessNotAllowed
59    */
60   public function testBlockAccessEntityNotAllowed($expected, $entity_access) {
61     $entity = $this->prophesize(FieldableEntityInterface::class);
62     $block = $this->getTestBlock($entity);
63
64     $account = $this->prophesize(AccountInterface::class);
65     $entity->access('view', $account->reveal(), TRUE)->willReturn($entity_access);
66     $entity->hasField()->shouldNotBeCalled();
67
68     $access = $block->access($account->reveal(), TRUE);
69     $this->assertSame($expected, $access->isAllowed());
70   }
71
72   /**
73    * Provides test data for ::testBlockAccessEntityNotAllowed().
74    */
75   public function providerTestBlockAccessNotAllowed() {
76     $data = [];
77     $data['entity_forbidden'] = [
78       FALSE,
79       AccessResult::forbidden(),
80     ];
81     $data['entity_neutral'] = [
82       FALSE,
83       AccessResult::neutral(),
84     ];
85     return $data;
86   }
87
88   /**
89    * Tests unfieldable entity.
90    *
91    * @covers ::blockAccess
92    */
93   public function testBlockAccessEntityAllowedNotFieldable() {
94     $entity = $this->prophesize(EntityInterface::class);
95     $block = $this->getTestBlock($entity);
96
97     $account = $this->prophesize(AccountInterface::class);
98     $entity->access('view', $account->reveal(), TRUE)->willReturn(AccessResult::allowed());
99
100     $access = $block->access($account->reveal(), TRUE);
101     $this->assertSame(FALSE, $access->isAllowed());
102   }
103
104   /**
105    * Tests fieldable entity without a particular field.
106    *
107    * @covers ::blockAccess
108    */
109   public function testBlockAccessEntityAllowedNoField() {
110     $entity = $this->prophesize(FieldableEntityInterface::class);
111     $block = $this->getTestBlock($entity);
112
113     $account = $this->prophesize(AccountInterface::class);
114     $entity->access('view', $account->reveal(), TRUE)->willReturn(AccessResult::allowed());
115     $entity->hasField('the_field_name')->willReturn(FALSE);
116     $entity->get('the_field_name')->shouldNotBeCalled();
117
118     $access = $block->access($account->reveal(), TRUE);
119     $this->assertSame(FALSE, $access->isAllowed());
120   }
121
122   /**
123    * Tests field access.
124    *
125    * @covers ::blockAccess
126    * @dataProvider providerTestBlockAccessNotAllowed
127    */
128   public function testBlockAccessEntityAllowedFieldNotAllowed($expected, $field_access) {
129     $entity = $this->prophesize(FieldableEntityInterface::class);
130     $block = $this->getTestBlock($entity);
131
132     $account = $this->prophesize(AccountInterface::class);
133     $entity->access('view', $account->reveal(), TRUE)->willReturn(AccessResult::allowed());
134     $entity->hasField('the_field_name')->willReturn(TRUE);
135     $field = $this->prophesize(FieldItemListInterface::class);
136     $entity->get('the_field_name')->willReturn($field->reveal());
137
138     $field->access('view', $account->reveal(), TRUE)->willReturn($field_access);
139     $field->isEmpty()->shouldNotBeCalled();
140
141     $access = $block->access($account->reveal(), TRUE);
142     $this->assertSame($expected, $access->isAllowed());
143   }
144
145   /**
146    * Tests populated vs empty build.
147    *
148    * @covers ::blockAccess
149    * @covers ::build
150    * @dataProvider providerTestBlockAccessEntityAllowedFieldHasValue
151    */
152   public function testBlockAccessEntityAllowedFieldHasValue($expected, $is_empty) {
153     $entity = $this->prophesize(FieldableEntityInterface::class);
154     $block = $this->getTestBlock($entity);
155
156     $account = $this->prophesize(AccountInterface::class);
157     $entity->access('view', $account->reveal(), TRUE)->willReturn(AccessResult::allowed());
158     $entity->hasField('the_field_name')->willReturn(TRUE);
159     $field = $this->prophesize(FieldItemListInterface::class);
160     $entity->get('the_field_name')->willReturn($field->reveal());
161
162     $field->access('view', $account->reveal(), TRUE)->willReturn(AccessResult::allowed());
163     $field->isEmpty()->willReturn($is_empty)->shouldBeCalled();
164
165     $access = $block->access($account->reveal(), TRUE);
166     $this->assertSame($expected, $access->isAllowed());
167   }
168
169   /**
170    * Provides test data for ::testBlockAccessEntityAllowedFieldHasValue().
171    */
172   public function providerTestBlockAccessEntityAllowedFieldHasValue() {
173     $data = [];
174     $data['empty'] = [
175       FALSE,
176       TRUE,
177     ];
178     $data['populated'] = [
179       TRUE,
180       FALSE,
181     ];
182     return $data;
183   }
184
185   /**
186    * Instantiates a block for testing.
187    *
188    * @param \Prophecy\Prophecy\ProphecyInterface $entity_prophecy
189    *   An entity prophecy for use as an entity context value.
190    * @param array $configuration
191    *   A configuration array containing information about the plugin instance.
192    * @param array $plugin_definition
193    *   The plugin implementation definition.
194    *
195    * @return \Drupal\layout_builder\Plugin\Block\FieldBlock
196    *   The block to test.
197    */
198   protected function getTestBlock(ProphecyInterface $entity_prophecy, array $configuration = [], array $plugin_definition = []) {
199     $entity_prophecy->getCacheContexts()->willReturn([]);
200     $entity_prophecy->getCacheTags()->willReturn([]);
201     $entity_prophecy->getCacheMaxAge()->willReturn(0);
202
203     $plugin_definition += [
204       'provider' => 'test',
205       'default_formatter' => '',
206       'category' => 'Test',
207       'admin_label' => 'Test Block',
208       'bundles' => ['entity_test'],
209       'context' => [
210         'entity' => EntityContextDefinition::fromEntityTypeId('entity_test')->setLabel('Test'),
211       ],
212     ];
213     $formatter_manager = $this->prophesize(FormatterPluginManager::class);
214     $module_handler = $this->prophesize(ModuleHandlerInterface::class);
215
216     $block = new FieldBlock(
217       $configuration,
218       'field_block:entity_test:entity_test:the_field_name',
219       $plugin_definition,
220       $this->entityFieldManager->reveal(),
221       $formatter_manager->reveal(),
222       $module_handler->reveal(),
223       $this->logger->reveal()
224     );
225     $block->setContextValue('entity', $entity_prophecy->reveal());
226     return $block;
227   }
228
229   /**
230    * @covers ::build
231    * @dataProvider providerTestBuild
232    */
233   public function testBuild(PromiseInterface $promise, $in_preview, $expected_markup, $log_message = '', $log_arguments = []) {
234     $entity = $this->prophesize(FieldableEntityInterface::class);
235     $field = $this->prophesize(FieldItemListInterface::class);
236     $entity->get('the_field_name')->willReturn($field->reveal());
237     $entity->in_preview = $in_preview;
238     $field->view(Argument::type('array'))->will($promise);
239
240     $field_definition = $this->prophesize(FieldDefinitionInterface::class);
241     $field_definition->getLabel()->willReturn('The Field Label');
242     $this->entityFieldManager->getFieldDefinitions('entity_test', 'entity_test')->willReturn(['the_field_name' => $field_definition]);
243
244     if ($log_message) {
245       $this->logger->warning($log_message, $log_arguments)->shouldBeCalled();
246     }
247     else {
248       $this->logger->warning(Argument::cetera())->shouldNotBeCalled();
249     }
250
251     $block = $this->getTestBlock($entity);
252     $expected = [
253       '#cache' => [
254         'contexts' => [],
255         'tags' => [],
256         'max-age' => 0,
257       ],
258     ];
259     if ($expected_markup) {
260       $expected['content']['#markup'] = $expected_markup;
261     }
262
263     $actual = $block->build();
264     $this->assertEquals($expected, $actual);
265   }
266
267   /**
268    * Provides test data for ::testBuild().
269    */
270   public function providerTestBuild() {
271     $data = [];
272     $data['array, no preview'] = [
273       new ReturnPromise([['content' => ['#markup' => 'The field value']]]),
274       FALSE,
275       'The field value',
276     ];
277     $data['array, preview'] = [
278       new ReturnPromise([['content' => ['#markup' => 'The field value']]]),
279       TRUE,
280       'The field value',
281     ];
282     $data['empty array, no preview'] = [
283       new ReturnPromise([[]]),
284       FALSE,
285       '',
286     ];
287     $data['empty array, preview'] = [
288       new ReturnPromise([[]]),
289       TRUE,
290       'Placeholder for the "The Field Label" field',
291     ];
292     $data['exception, no preview'] = [
293       new ThrowPromise(new \Exception('The exception message')),
294       FALSE,
295       '',
296       'The field "%field" failed to render with the error of "%error".',
297       ['%field' => 'the_field_name', '%error' => 'The exception message'],
298     ];
299     $data['exception, preview'] = [
300       new ThrowPromise(new \Exception('The exception message')),
301       TRUE,
302       'Placeholder for the "The Field Label" field',
303       'The field "%field" failed to render with the error of "%error".',
304       ['%field' => 'the_field_name', '%error' => 'The exception message'],
305     ];
306     return $data;
307   }
308
309 }