Mercurial > hg > cmmr2012-drupal-site
comparison core/modules/block/tests/src/Kernel/BlockViewBuilderTest.php @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c75dbcec494b |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Tests\block\Kernel; | |
4 | |
5 use Drupal\Component\Utility\Html; | |
6 use Drupal\Core\Cache\Cache; | |
7 use Drupal\Core\Language\LanguageInterface; | |
8 use Drupal\KernelTests\KernelTestBase; | |
9 use Drupal\block\Entity\Block; | |
10 | |
11 /** | |
12 * Tests the block view builder. | |
13 * | |
14 * @group block | |
15 */ | |
16 class BlockViewBuilderTest extends KernelTestBase { | |
17 | |
18 /** | |
19 * Modules to install. | |
20 * | |
21 * @var array | |
22 */ | |
23 public static $modules = ['block', 'block_test', 'system', 'user']; | |
24 | |
25 /** | |
26 * The block being tested. | |
27 * | |
28 * @var \Drupal\block\Entity\BlockInterface | |
29 */ | |
30 protected $block; | |
31 | |
32 /** | |
33 * The block storage. | |
34 * | |
35 * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface | |
36 */ | |
37 protected $controller; | |
38 | |
39 /** | |
40 * The renderer. | |
41 * | |
42 * @var \Drupal\Core\Render\RendererInterface | |
43 */ | |
44 protected $renderer; | |
45 | |
46 /** | |
47 * {@inheritdoc} | |
48 */ | |
49 protected function setUp() { | |
50 parent::setUp(); | |
51 | |
52 $this->controller = $this->container | |
53 ->get('entity_type.manager') | |
54 ->getStorage('block'); | |
55 | |
56 \Drupal::state()->set('block_test.content', 'Llamas > unicorns!'); | |
57 | |
58 // Create a block with only required values. | |
59 $this->block = $this->controller->create([ | |
60 'id' => 'test_block', | |
61 'theme' => 'stark', | |
62 'plugin' => 'test_cache', | |
63 ]); | |
64 $this->block->save(); | |
65 | |
66 $this->container->get('cache.render')->deleteAll(); | |
67 | |
68 $this->renderer = $this->container->get('renderer'); | |
69 } | |
70 | |
71 /** | |
72 * Tests the rendering of blocks. | |
73 */ | |
74 public function testBasicRendering() { | |
75 \Drupal::state()->set('block_test.content', ''); | |
76 | |
77 $entity = $this->controller->create([ | |
78 'id' => 'test_block1', | |
79 'theme' => 'stark', | |
80 'plugin' => 'test_html', | |
81 ]); | |
82 $entity->save(); | |
83 | |
84 // Test the rendering of a block. | |
85 $entity = Block::load('test_block1'); | |
86 $output = entity_view($entity, 'block'); | |
87 $expected = []; | |
88 $expected[] = '<div id="block-test-block1">'; | |
89 $expected[] = ' '; | |
90 $expected[] = ' '; | |
91 $expected[] = ' '; | |
92 $expected[] = ' </div>'; | |
93 $expected[] = ''; | |
94 $expected_output = implode("\n", $expected); | |
95 $this->assertEqual($this->renderer->renderRoot($output), $expected_output); | |
96 | |
97 // Reset the HTML IDs so that the next render is not affected. | |
98 Html::resetSeenIds(); | |
99 | |
100 // Test the rendering of a block with a given title. | |
101 $entity = $this->controller->create([ | |
102 'id' => 'test_block2', | |
103 'theme' => 'stark', | |
104 'plugin' => 'test_html', | |
105 'settings' => [ | |
106 'label' => 'Powered by Bananas', | |
107 ], | |
108 ]); | |
109 $entity->save(); | |
110 $output = entity_view($entity, 'block'); | |
111 $expected = []; | |
112 $expected[] = '<div id="block-test-block2">'; | |
113 $expected[] = ' '; | |
114 $expected[] = ' <h2>Powered by Bananas</h2>'; | |
115 $expected[] = ' '; | |
116 $expected[] = ' '; | |
117 $expected[] = ' </div>'; | |
118 $expected[] = ''; | |
119 $expected_output = implode("\n", $expected); | |
120 $this->assertEqual($this->renderer->renderRoot($output), $expected_output); | |
121 } | |
122 | |
123 /** | |
124 * Tests block render cache handling. | |
125 */ | |
126 public function testBlockViewBuilderCache() { | |
127 // Verify cache handling for a non-empty block. | |
128 $this->verifyRenderCacheHandling(); | |
129 | |
130 // Create an empty block. | |
131 $this->block = $this->controller->create([ | |
132 'id' => 'test_block', | |
133 'theme' => 'stark', | |
134 'plugin' => 'test_cache', | |
135 ]); | |
136 $this->block->save(); | |
137 \Drupal::state()->set('block_test.content', NULL); | |
138 | |
139 // Verify cache handling for an empty block. | |
140 $this->verifyRenderCacheHandling(); | |
141 } | |
142 | |
143 /** | |
144 * Verifies render cache handling of the block being tested. | |
145 * | |
146 * @see ::testBlockViewBuilderCache() | |
147 */ | |
148 protected function verifyRenderCacheHandling() { | |
149 // Force a request via GET so we can test the render cache. | |
150 $request = \Drupal::request(); | |
151 $request_method = $request->server->get('REQUEST_METHOD'); | |
152 $request->setMethod('GET'); | |
153 | |
154 // Test that a cache entry is created. | |
155 $build = $this->getBlockRenderArray(); | |
156 $cid = 'entity_view:block:test_block:' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'])->getKeys()); | |
157 $this->renderer->renderRoot($build); | |
158 $this->assertTrue($this->container->get('cache.render')->get($cid), 'The block render element has been cached.'); | |
159 | |
160 // Re-save the block and check that the cache entry has been deleted. | |
161 $this->block->save(); | |
162 $this->assertFalse($this->container->get('cache.render')->get($cid), 'The block render cache entry has been cleared when the block was saved.'); | |
163 | |
164 // Rebuild the render array (creating a new cache entry in the process) and | |
165 // delete the block to check the cache entry is deleted. | |
166 unset($build['#printed']); | |
167 // Re-add the block because \Drupal\block\BlockViewBuilder::buildBlock() | |
168 // removes it. | |
169 $build['#block'] = $this->block; | |
170 | |
171 $this->renderer->renderRoot($build); | |
172 $this->assertTrue($this->container->get('cache.render')->get($cid), 'The block render element has been cached.'); | |
173 $this->block->delete(); | |
174 $this->assertFalse($this->container->get('cache.render')->get($cid), 'The block render cache entry has been cleared when the block was deleted.'); | |
175 | |
176 // Restore the previous request method. | |
177 $request->setMethod($request_method); | |
178 } | |
179 | |
180 /** | |
181 * Tests block view altering. | |
182 * | |
183 * @see hook_block_view_alter() | |
184 * @see hook_block_view_BASE_BLOCK_ID_alter() | |
185 */ | |
186 public function testBlockViewBuilderViewAlter() { | |
187 // Establish baseline. | |
188 $build = $this->getBlockRenderArray(); | |
189 $this->setRawContent((string) $this->renderer->renderRoot($build)); | |
190 $this->assertIdentical(trim((string) $this->cssSelect('div')[0]), 'Llamas > unicorns!'); | |
191 | |
192 // Enable the block view alter hook that adds a foo=bar attribute. | |
193 \Drupal::state()->set('block_test_view_alter_suffix', TRUE); | |
194 Cache::invalidateTags($this->block->getCacheTagsToInvalidate()); | |
195 $build = $this->getBlockRenderArray(); | |
196 $this->setRawContent((string) $this->renderer->renderRoot($build)); | |
197 $this->assertIdentical(trim((string) $this->cssSelect('[foo=bar]')[0]), 'Llamas > unicorns!'); | |
198 \Drupal::state()->set('block_test_view_alter_suffix', FALSE); | |
199 | |
200 \Drupal::state()->set('block_test.content', NULL); | |
201 Cache::invalidateTags($this->block->getCacheTagsToInvalidate()); | |
202 | |
203 // Advanced: cached block, but an alter hook adds a #pre_render callback to | |
204 // alter the eventual content. | |
205 \Drupal::state()->set('block_test_view_alter_append_pre_render_prefix', TRUE); | |
206 $build = $this->getBlockRenderArray(); | |
207 $this->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before rendering.'); | |
208 $this->assertIdentical((string) $this->renderer->renderRoot($build), 'Hiya!<br>'); | |
209 $this->assertTrue(isset($build['#prefix']) && $build['#prefix'] === 'Hiya!<br>', 'A cached block without content is altered.'); | |
210 } | |
211 | |
212 /** | |
213 * Tests block build altering. | |
214 * | |
215 * @see hook_block_build_alter() | |
216 * @see hook_block_build_BASE_BLOCK_ID_alter() | |
217 */ | |
218 public function testBlockViewBuilderBuildAlter() { | |
219 // Force a request via GET so we can test the render cache. | |
220 $request = \Drupal::request(); | |
221 $request_method = $request->server->get('REQUEST_METHOD'); | |
222 $request->setMethod('GET'); | |
223 | |
224 $default_keys = ['entity_view', 'block', 'test_block']; | |
225 $default_contexts = []; | |
226 $default_tags = ['block_view', 'config:block.block.test_block']; | |
227 $default_max_age = Cache::PERMANENT; | |
228 | |
229 // hook_block_build_alter() adds an additional cache key. | |
230 $alter_add_key = $this->randomMachineName(); | |
231 \Drupal::state()->set('block_test_block_alter_cache_key', $alter_add_key); | |
232 $this->assertBlockRenderedWithExpectedCacheability(array_merge($default_keys, [$alter_add_key]), $default_contexts, $default_tags, $default_max_age); | |
233 \Drupal::state()->set('block_test_block_alter_cache_key', NULL); | |
234 | |
235 // hook_block_build_alter() adds an additional cache context. | |
236 $alter_add_context = 'url.query_args:' . $this->randomMachineName(); | |
237 \Drupal::state()->set('block_test_block_alter_cache_context', $alter_add_context); | |
238 $this->assertBlockRenderedWithExpectedCacheability($default_keys, Cache::mergeContexts($default_contexts, [$alter_add_context]), $default_tags, $default_max_age); | |
239 \Drupal::state()->set('block_test_block_alter_cache_context', NULL); | |
240 | |
241 // hook_block_build_alter() adds an additional cache tag. | |
242 $alter_add_tag = $this->randomMachineName(); | |
243 \Drupal::state()->set('block_test_block_alter_cache_tag', $alter_add_tag); | |
244 $this->assertBlockRenderedWithExpectedCacheability($default_keys, $default_contexts, Cache::mergeTags($default_tags, [$alter_add_tag]), $default_max_age); | |
245 \Drupal::state()->set('block_test_block_alter_cache_tag', NULL); | |
246 | |
247 // hook_block_build_alter() alters the max-age. | |
248 $alter_max_age = 300; | |
249 \Drupal::state()->set('block_test_block_alter_cache_max_age', $alter_max_age); | |
250 $this->assertBlockRenderedWithExpectedCacheability($default_keys, $default_contexts, $default_tags, $alter_max_age); | |
251 \Drupal::state()->set('block_test_block_alter_cache_max_age', NULL); | |
252 | |
253 // hook_block_build_alter() alters cache keys, contexts, tags and max-age. | |
254 \Drupal::state()->set('block_test_block_alter_cache_key', $alter_add_key); | |
255 \Drupal::state()->set('block_test_block_alter_cache_context', $alter_add_context); | |
256 \Drupal::state()->set('block_test_block_alter_cache_tag', $alter_add_tag); | |
257 \Drupal::state()->set('block_test_block_alter_cache_max_age', $alter_max_age); | |
258 $this->assertBlockRenderedWithExpectedCacheability(array_merge($default_keys, [$alter_add_key]), Cache::mergeContexts($default_contexts, [$alter_add_context]), Cache::mergeTags($default_tags, [$alter_add_tag]), $alter_max_age); | |
259 \Drupal::state()->set('block_test_block_alter_cache_key', NULL); | |
260 \Drupal::state()->set('block_test_block_alter_cache_context', NULL); | |
261 \Drupal::state()->set('block_test_block_alter_cache_tag', NULL); | |
262 \Drupal::state()->set('block_test_block_alter_cache_max_age', NULL); | |
263 | |
264 // hook_block_build_alter() sets #create_placeholder. | |
265 foreach ([TRUE, FALSE] as $value) { | |
266 \Drupal::state()->set('block_test_block_alter_create_placeholder', $value); | |
267 $build = $this->getBlockRenderArray(); | |
268 $this->assertTrue(isset($build['#create_placeholder'])); | |
269 $this->assertIdentical($value, $build['#create_placeholder']); | |
270 } | |
271 \Drupal::state()->set('block_test_block_alter_create_placeholder', NULL); | |
272 | |
273 // Restore the previous request method. | |
274 $request->setMethod($request_method); | |
275 } | |
276 | |
277 /** | |
278 * Asserts that a block is built/rendered/cached with expected cacheability. | |
279 * | |
280 * @param string[] $expected_keys | |
281 * The expected cache keys. | |
282 * @param string[] $expected_contexts | |
283 * The expected cache contexts. | |
284 * @param string[] $expected_tags | |
285 * The expected cache tags. | |
286 * @param int $expected_max_age | |
287 * The expected max-age. | |
288 */ | |
289 protected function assertBlockRenderedWithExpectedCacheability(array $expected_keys, array $expected_contexts, array $expected_tags, $expected_max_age) { | |
290 $required_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions']; | |
291 | |
292 // Check that the expected cacheability metadata is present in: | |
293 // - the built render array; | |
294 $this->pass('Built render array'); | |
295 $build = $this->getBlockRenderArray(); | |
296 $this->assertIdentical($expected_keys, $build['#cache']['keys']); | |
297 $this->assertIdentical($expected_contexts, $build['#cache']['contexts']); | |
298 $this->assertIdentical($expected_tags, $build['#cache']['tags']); | |
299 $this->assertIdentical($expected_max_age, $build['#cache']['max-age']); | |
300 $this->assertFalse(isset($build['#create_placeholder'])); | |
301 // - the rendered render array; | |
302 $this->pass('Rendered render array'); | |
303 $this->renderer->renderRoot($build); | |
304 // - the render cache item. | |
305 $this->pass('Render cache item'); | |
306 $final_cache_contexts = Cache::mergeContexts($expected_contexts, $required_cache_contexts); | |
307 $cid = implode(':', $expected_keys) . ':' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys($final_cache_contexts)->getKeys()); | |
308 $cache_item = $this->container->get('cache.render')->get($cid); | |
309 $this->assertTrue($cache_item, 'The block render element has been cached with the expected cache ID.'); | |
310 $this->assertIdentical(Cache::mergeTags($expected_tags, ['rendered']), $cache_item->tags); | |
311 $this->assertIdentical($final_cache_contexts, $cache_item->data['#cache']['contexts']); | |
312 $this->assertIdentical($expected_tags, $cache_item->data['#cache']['tags']); | |
313 $this->assertIdentical($expected_max_age, $cache_item->data['#cache']['max-age']); | |
314 | |
315 $this->container->get('cache.render')->delete($cid); | |
316 } | |
317 | |
318 /** | |
319 * Get a fully built render array for a block. | |
320 * | |
321 * @return array | |
322 * The render array. | |
323 */ | |
324 protected function getBlockRenderArray() { | |
325 return $this->container->get('entity_type.manager')->getViewBuilder('block')->view($this->block, 'block'); | |
326 } | |
327 | |
328 } |