Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Render / BubbleableMetadataTest.php
1 <?php
2
3 namespace Drupal\Tests\Core\Render;
4
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Core\Cache\CacheableMetadata;
7 use Drupal\Core\Render\BubbleableMetadata;
8 use Drupal\Tests\UnitTestCase;
9 use Symfony\Component\DependencyInjection\ContainerBuilder;
10
11 /**
12  * @coversDefaultClass \Drupal\Core\Render\BubbleableMetadata
13  * @group Render
14  */
15 class BubbleableMetadataTest extends UnitTestCase {
16
17   /**
18    * @covers ::merge
19    * @dataProvider providerTestMerge
20    *
21    * This only tests at a high level, because it reuses existing logic. Detailed
22    * tests exist for the existing logic:
23    *
24    * @see \Drupal\Tests\Core\Cache\CacheTest::testMergeTags()
25    * @see \Drupal\Tests\Core\Cache\CacheTest::testMergeMaxAges()
26    * @see \Drupal\Tests\Core\Cache\CacheContextsTest
27    * @see \Drupal\Tests\Core\Render\RendererPlaceholdersTest
28    * @see testMergeAttachmentsLibraryMerging()
29    * @see testMergeAttachmentsFeedMerging()
30    * @see testMergeAttachmentsHtmlHeadMerging()
31    * @see testMergeAttachmentsHtmlHeadLinkMerging()
32    * @see testMergeAttachmentsHttpHeaderMerging()
33    */
34   public function testMerge(BubbleableMetadata $a, CacheableMetadata $b, BubbleableMetadata $expected) {
35     // Verify that if the second operand is a CacheableMetadata object, not a
36     // BubbleableMetadata object, that BubbleableMetadata::merge() doesn't
37     // attempt to merge assets.
38     if (!$b instanceof BubbleableMetadata) {
39       $renderer = $this->getMockBuilder('Drupal\Core\Render\Renderer')
40         ->disableOriginalConstructor()
41         ->setMethods(['mergeAttachments'])
42         ->getMock();
43       $renderer->expects($this->never())
44         ->method('mergeAttachments');
45     }
46     // Otherwise, let the original ::mergeAttachments() method be executed.
47     else {
48       $renderer = $this->getMockBuilder('Drupal\Core\Render\Renderer')
49         ->disableOriginalConstructor()
50         ->setMethods(NULL)
51         ->getMock();
52     }
53
54     $cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
55       ->disableOriginalConstructor()
56       ->getMock();
57     $cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
58     $container = new ContainerBuilder();
59     $container->set('cache_contexts_manager', $cache_contexts_manager);
60     $container->set('renderer', $renderer);
61     \Drupal::setContainer($container);
62
63     $this->assertEquals($expected, $a->merge($b));
64   }
65
66   /**
67    * Provides test data for testMerge().
68    *
69    * @return array
70    */
71   public function providerTestMerge() {
72     return [
73       // Second operand is a BubbleableMetadata object.
74       // All empty.
75       [(new BubbleableMetadata()), (new BubbleableMetadata()), (new BubbleableMetadata())],
76       // Cache contexts.
77       [(new BubbleableMetadata())->setCacheContexts(['foo']), (new BubbleableMetadata())->setCacheContexts(['bar']), (new BubbleableMetadata())->setCacheContexts(['bar', 'foo'])],
78       // Cache tags.
79       [(new BubbleableMetadata())->setCacheTags(['foo']), (new BubbleableMetadata())->setCacheTags(['bar']), (new BubbleableMetadata())->setCacheTags(['bar', 'foo'])],
80       // Cache max-ages.
81       [(new BubbleableMetadata())->setCacheMaxAge(60), (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT), (new BubbleableMetadata())->setCacheMaxAge(60)],
82       // Assets.
83       [(new BubbleableMetadata())->setAttachments(['library' => ['core/foo']]), (new BubbleableMetadata())->setAttachments(['library' => ['core/bar']]), (new BubbleableMetadata())->setAttachments(['library' => ['core/foo', 'core/bar']])],
84       // Placeholders.
85       [(new BubbleableMetadata())->setAttachments(['placeholders' => ['<my-placeholder>' => ['callback', ['A']]]]), (new BubbleableMetadata())->setAttachments(['placeholders' => ['<my-placeholder>' => ['callback', ['A']]]]), (new BubbleableMetadata())->setAttachments(['placeholders' => ['<my-placeholder>' => ['callback', ['A']]]])],
86
87       // Second operand is a CacheableMetadata object.
88       // All empty.
89       [(new BubbleableMetadata()), (new CacheableMetadata()), (new BubbleableMetadata())],
90       // Cache contexts.
91       [(new BubbleableMetadata())->setCacheContexts(['foo']), (new CacheableMetadata())->setCacheContexts(['bar']), (new BubbleableMetadata())->setCacheContexts(['bar', 'foo'])],
92       // Cache tags.
93       [(new BubbleableMetadata())->setCacheTags(['foo']), (new CacheableMetadata())->setCacheTags(['bar']), (new BubbleableMetadata())->setCacheTags(['bar', 'foo'])],
94       // Cache max-ages.
95       [(new BubbleableMetadata())->setCacheMaxAge(60), (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT), (new BubbleableMetadata())->setCacheMaxAge(60)],
96     ];
97   }
98
99   /**
100    * @covers ::addAttachments
101    * @covers ::setAttachments
102    * @dataProvider providerTestAddAttachments
103    *
104    * This only tests at a high level, because it reuses existing logic. Detailed
105    * tests exist for the existing logic:
106    *
107    * @see testMergeAttachmentsLibraryMerging()
108    * @see testMergeAttachmentsFeedMerging()
109    * @see testMergeAttachmentsHtmlHeadMerging()
110    * @see testMergeAttachmentsHtmlHeadLinkMerging()
111    * @see testMergeAttachmentsHttpHeaderMerging()
112    */
113   public function testAddAttachments(BubbleableMetadata $initial, $attachments, BubbleableMetadata $expected) {
114     $test = $initial;
115     $test->addAttachments($attachments);
116     $this->assertEquals($expected, $test);
117   }
118
119   /**
120    * Provides test data for testAddAttachments().
121    */
122   public function providerTestAddAttachments() {
123     return [
124       [new BubbleableMetadata(), [], new BubbleableMetadata()],
125       [new BubbleableMetadata(), ['library' => ['core/foo']], (new BubbleableMetadata())->setAttachments(['library' => ['core/foo']])],
126       [(new BubbleableMetadata())->setAttachments(['library' => ['core/foo']]), ['library' => ['core/bar']], (new BubbleableMetadata())->setAttachments(['library' => ['core/foo', 'core/bar']])],
127     ];
128   }
129
130   /**
131    * @covers ::applyTo
132    * @dataProvider providerTestApplyTo
133    */
134   public function testApplyTo(BubbleableMetadata $metadata, array $render_array, array $expected) {
135     $this->assertNull($metadata->applyTo($render_array));
136     $this->assertEquals($expected, $render_array);
137   }
138
139   /**
140    * Provides test data for testApplyTo().
141    *
142    * @return array
143    */
144   public function providerTestApplyTo() {
145     $data = [];
146
147     $empty_metadata = new BubbleableMetadata();
148     $nonempty_metadata = new BubbleableMetadata();
149     $nonempty_metadata->setCacheContexts(['qux'])
150       ->setCacheTags(['foo:bar'])
151       ->setAttachments(['settings' => ['foo' => 'bar']]);
152
153     $empty_render_array = [];
154     $nonempty_render_array = [
155       '#cache' => [
156         'contexts' => ['qux'],
157         'tags' => ['llamas:are:awesome:but:kittens:too'],
158         'max-age' => Cache::PERMANENT,
159       ],
160       '#attached' => [
161         'library' => [
162           'core/jquery',
163         ],
164       ],
165     ];
166
167     $expected_when_empty_metadata = [
168       '#cache' => [
169         'contexts' => [],
170         'tags' => [],
171         'max-age' => Cache::PERMANENT,
172       ],
173       '#attached' => [],
174     ];
175     $data[] = [$empty_metadata, $empty_render_array, $expected_when_empty_metadata];
176     $data[] = [$empty_metadata, $nonempty_render_array, $expected_when_empty_metadata];
177     $expected_when_nonempty_metadata = [
178       '#cache' => [
179         'contexts' => ['qux'],
180         'tags' => ['foo:bar'],
181         'max-age' => Cache::PERMANENT,
182       ],
183       '#attached' => [
184         'settings' => [
185           'foo' => 'bar',
186         ],
187       ],
188     ];
189     $data[] = [$nonempty_metadata, $empty_render_array, $expected_when_nonempty_metadata];
190     $data[] = [$nonempty_metadata, $nonempty_render_array, $expected_when_nonempty_metadata];
191
192     return $data;
193   }
194
195   /**
196    * @covers ::createFromRenderArray
197    * @dataProvider providerTestCreateFromRenderArray
198    */
199   public function testCreateFromRenderArray(array $render_array, BubbleableMetadata $expected) {
200     $this->assertEquals($expected, BubbleableMetadata::createFromRenderArray($render_array));
201   }
202
203   /**
204    * Provides test data for createFromRenderArray().
205    *
206    * @return array
207    */
208   public function providerTestCreateFromRenderArray() {
209     $data = [];
210
211     $empty_metadata = new BubbleableMetadata();
212     $nonempty_metadata = new BubbleableMetadata();
213     $nonempty_metadata->setCacheContexts(['qux'])
214       ->setCacheTags(['foo:bar'])
215       ->setAttachments(['settings' => ['foo' => 'bar']]);
216
217     $empty_render_array = [];
218     $nonempty_render_array = [
219       '#cache' => [
220         'contexts' => ['qux'],
221         'tags' => ['foo:bar'],
222         'max-age' => Cache::PERMANENT,
223       ],
224       '#attached' => [
225         'settings' => [
226           'foo' => 'bar',
227         ],
228       ],
229     ];
230
231     $data[] = [$empty_render_array, $empty_metadata];
232     $data[] = [$nonempty_render_array, $nonempty_metadata];
233
234     return $data;
235   }
236
237   /**
238    * Tests library asset merging.
239    *
240    * @covers ::mergeAttachments
241    */
242   public function testMergeAttachmentsLibraryMerging() {
243     $a['#attached'] = [
244       'library' => [
245         'core/drupal',
246         'core/drupalSettings',
247       ],
248       'drupalSettings' => [
249         'foo' => ['d'],
250       ],
251     ];
252     $b['#attached'] = [
253       'library' => [
254         'core/jquery',
255       ],
256       'drupalSettings' => [
257         'bar' => ['a', 'b', 'c'],
258       ],
259     ];
260     $expected['#attached'] = [
261       'library' => [
262         'core/drupal',
263         'core/drupalSettings',
264         'core/jquery',
265       ],
266       'drupalSettings' => [
267         'foo' => ['d'],
268         'bar' => ['a', 'b', 'c'],
269       ],
270     ];
271     $this->assertSame($expected['#attached'], BubbleableMetadata::mergeAttachments($a['#attached'], $b['#attached']), 'Attachments merged correctly.');
272
273     // Merging in the opposite direction yields the opposite library order.
274     $expected['#attached'] = [
275       'library' => [
276         'core/jquery',
277         'core/drupal',
278         'core/drupalSettings',
279       ],
280       'drupalSettings' => [
281         'bar' => ['a', 'b', 'c'],
282         'foo' => ['d'],
283       ],
284     ];
285     $this->assertSame($expected['#attached'], BubbleableMetadata::mergeAttachments($b['#attached'], $a['#attached']), 'Attachments merged correctly; opposite merging yields opposite order.');
286
287     // Merging with duplicates: duplicates are simply retained, it's up to the
288     // rest of the system to handle duplicates.
289     $b['#attached']['library'][] = 'core/drupalSettings';
290     $expected['#attached'] = [
291       'library' => [
292         'core/drupal',
293         'core/drupalSettings',
294         'core/jquery',
295         'core/drupalSettings',
296       ],
297       'drupalSettings' => [
298         'foo' => ['d'],
299         'bar' => ['a', 'b', 'c'],
300       ],
301     ];
302     $this->assertSame($expected['#attached'], BubbleableMetadata::mergeAttachments($a['#attached'], $b['#attached']), 'Attachments merged correctly; duplicates are retained.');
303
304     // Merging with duplicates (simple case).
305     $b['#attached']['drupalSettings']['foo'] = ['a', 'b', 'c'];
306     $expected['#attached'] = [
307       'library' => [
308         'core/drupal',
309         'core/drupalSettings',
310         'core/jquery',
311         'core/drupalSettings',
312       ],
313       'drupalSettings' => [
314         'foo' => ['a', 'b', 'c'],
315         'bar' => ['a', 'b', 'c'],
316       ],
317     ];
318     $this->assertSame($expected['#attached'], BubbleableMetadata::mergeAttachments($a['#attached'], $b['#attached']));
319
320     // Merging with duplicates (simple case) in the opposite direction yields
321     // the opposite JS setting asset order, but also opposite overriding order.
322     $expected['#attached'] = [
323       'library' => [
324         'core/jquery',
325         'core/drupalSettings',
326         'core/drupal',
327         'core/drupalSettings',
328       ],
329       'drupalSettings' => [
330         'bar' => ['a', 'b', 'c'],
331         'foo' => ['d', 'b', 'c'],
332       ],
333     ];
334     $this->assertSame($expected['#attached'], BubbleableMetadata::mergeAttachments($b['#attached'], $a['#attached']));
335
336     // Merging with duplicates: complex case.
337     // Only the second of these two entries should appear in drupalSettings.
338     $build = [];
339     $build['a']['#attached']['drupalSettings']['commonTest'] = 'firstValue';
340     $build['b']['#attached']['drupalSettings']['commonTest'] = 'secondValue';
341     // Only the second of these entries should appear in drupalSettings.
342     $build['a']['#attached']['drupalSettings']['commonTestJsArrayLiteral'] = ['firstValue'];
343     $build['b']['#attached']['drupalSettings']['commonTestJsArrayLiteral'] = ['secondValue'];
344     // Only the second of these two entries should appear in drupalSettings.
345     $build['a']['#attached']['drupalSettings']['commonTestJsObjectLiteral'] = ['key' => 'firstValue'];
346     $build['b']['#attached']['drupalSettings']['commonTestJsObjectLiteral'] = ['key' => 'secondValue'];
347     // Real world test case: multiple elements in a render array are adding the
348     // same (or nearly the same) JavaScript settings. When merged, they should
349     // contain all settings and not duplicate some settings.
350     $settings_one = ['moduleName' => ['ui' => ['button A', 'button B'], 'magical flag' => 3.14159265359]];
351     $build['a']['#attached']['drupalSettings']['commonTestRealWorldIdentical'] = $settings_one;
352     $build['b']['#attached']['drupalSettings']['commonTestRealWorldIdentical'] = $settings_one;
353     $settings_two_a = ['moduleName' => ['ui' => ['button A', 'button B', 'button C'], 'magical flag' => 3.14159265359, 'thingiesOnPage' => ['id1' => []]]];
354     $build['a']['#attached']['drupalSettings']['commonTestRealWorldAlmostIdentical'] = $settings_two_a;
355     $settings_two_b = ['moduleName' => ['ui' => ['button D', 'button E'], 'magical flag' => 3.14, 'thingiesOnPage' => ['id2' => []]]];
356     $build['b']['#attached']['drupalSettings']['commonTestRealWorldAlmostIdentical'] = $settings_two_b;
357
358     $merged = BubbleableMetadata::mergeAttachments($build['a']['#attached'], $build['b']['#attached']);
359
360     // Test whether #attached can be used to override a previous setting.
361     $this->assertSame('secondValue', $merged['drupalSettings']['commonTest']);
362
363     // Test whether #attached can be used to add and override a JavaScript
364     // array literal (an indexed PHP array) values.
365     $this->assertSame('secondValue', $merged['drupalSettings']['commonTestJsArrayLiteral'][0]);
366
367     // Test whether #attached can be used to add and override a JavaScript
368     // object literal (an associate PHP array) values.
369     $this->assertSame('secondValue', $merged['drupalSettings']['commonTestJsObjectLiteral']['key']);
370
371     // Test whether the two real world cases are handled correctly: the first
372     // adds the exact same settings twice and hence tests idempotency, the
373     // second adds *almost* the same settings twice: the second time, some
374     // values are altered, and some key-value pairs are added.
375     $settings_two['moduleName']['thingiesOnPage']['id1'] = [];
376     $this->assertSame($settings_one, $merged['drupalSettings']['commonTestRealWorldIdentical']);
377     $expected_settings_two = $settings_two_a;
378     $expected_settings_two['moduleName']['ui'][0] = 'button D';
379     $expected_settings_two['moduleName']['ui'][1] = 'button E';
380     $expected_settings_two['moduleName']['ui'][2] = 'button C';
381     $expected_settings_two['moduleName']['magical flag'] = 3.14;
382     $expected_settings_two['moduleName']['thingiesOnPage']['id2'] = [];
383     $this->assertSame($expected_settings_two, $merged['drupalSettings']['commonTestRealWorldAlmostIdentical']);
384   }
385
386   /**
387    * Tests feed asset merging.
388    *
389    * @covers ::mergeAttachments
390    *
391    * @dataProvider providerTestMergeAttachmentsFeedMerging
392    */
393   public function testMergeAttachmentsFeedMerging($a, $b, $expected) {
394     $this->assertSame($expected, BubbleableMetadata::mergeAttachments($a, $b));
395   }
396
397   /**
398    * Data provider for testMergeAttachmentsFeedMerging
399    *
400    * @return array
401    */
402   public function providerTestMergeAttachmentsFeedMerging() {
403     $feed_a = [
404       'aggregator/rss',
405       'Feed title',
406     ];
407
408     $feed_b = [
409       'taxonomy/term/1/feed',
410       'RSS - foo',
411     ];
412
413     $a = [
414       'feed' => [
415         $feed_a,
416       ],
417     ];
418     $b = [
419       'feed' => [
420         $feed_b,
421       ],
422     ];
423
424     $expected_a = [
425       'feed' => [
426         $feed_a,
427         $feed_b,
428       ],
429     ];
430
431     // Merging in the opposite direction yields the opposite library order.
432     $expected_b = [
433       'feed' => [
434         $feed_b,
435         $feed_a,
436       ],
437     ];
438
439     return [
440       [$a, $b, $expected_a],
441       [$b, $a, $expected_b],
442     ];
443   }
444
445   /**
446    * Tests html_head asset merging.
447    *
448    * @covers ::mergeAttachments
449    *
450    * @dataProvider providerTestMergeAttachmentsHtmlHeadMerging
451    */
452   public function testMergeAttachmentsHtmlHeadMerging($a, $b, $expected) {
453     $this->assertSame($expected, BubbleableMetadata::mergeAttachments($a, $b));
454   }
455
456   /**
457    * Data provider for testMergeAttachmentsHtmlHeadMerging
458    *
459    * @return array
460    */
461   public function providerTestMergeAttachmentsHtmlHeadMerging() {
462     $meta = [
463       '#tag' => 'meta',
464       '#attributes' => [
465         'charset' => 'utf-8',
466       ],
467       '#weight' => -1000,
468     ];
469
470     $html_tag = [
471       '#type' => 'html_tag',
472       '#tag' => 'meta',
473       '#attributes' => [
474         'name' => 'Generator',
475         'content' => 'Kitten 1.0 (https://www.drupal.org/project/kitten)',
476       ],
477     ];
478
479     $a = [
480       'html_head' => [
481         $meta,
482         'system_meta_content_type',
483       ],
484     ];
485
486     $b = [
487       'html_head' => [
488         $html_tag,
489         'system_meta_generator',
490       ],
491     ];
492
493     $expected_a = [
494       'html_head' => [
495         $meta,
496         'system_meta_content_type',
497         $html_tag,
498         'system_meta_generator',
499       ],
500     ];
501
502     // Merging in the opposite direction yields the opposite library order.
503     $expected_b = [
504       'html_head' => [
505         $html_tag,
506         'system_meta_generator',
507         $meta,
508         'system_meta_content_type',
509       ],
510     ];
511
512     return [
513       [$a, $b, $expected_a],
514       [$b, $a, $expected_b],
515     ];
516   }
517
518   /**
519    * Tests html_head_link asset merging.
520    *
521    * @covers ::mergeAttachments
522    *
523    * @dataProvider providerTestMergeAttachmentsHtmlHeadLinkMerging
524    */
525   public function testMergeAttachmentsHtmlHeadLinkMerging($a, $b, $expected) {
526     $this->assertSame($expected, BubbleableMetadata::mergeAttachments($a, $b));
527   }
528
529   /**
530    * Data provider for testMergeAttachmentsHtmlHeadLinkMerging
531    *
532    * @return array
533    */
534   public function providerTestMergeAttachmentsHtmlHeadLinkMerging() {
535     $rel = [
536       'rel' => 'rel',
537       'href' => 'http://rel.example.com',
538     ];
539
540     $shortlink = [
541       'rel' => 'shortlink',
542       'href' => 'http://shortlink.example.com',
543     ];
544
545     $a = [
546       'html_head_link' => [
547         $rel,
548         TRUE,
549       ],
550     ];
551
552     $b = [
553       'html_head_link' => [
554         $shortlink,
555         FALSE,
556       ],
557     ];
558
559     $expected_a = [
560       'html_head_link' => [
561         $rel,
562         TRUE,
563         $shortlink,
564         FALSE,
565       ],
566     ];
567
568     // Merging in the opposite direction yields the opposite library order.
569     $expected_b = [
570       'html_head_link' => [
571         $shortlink,
572         FALSE,
573         $rel,
574         TRUE,
575       ],
576     ];
577
578     return [
579       [$a, $b, $expected_a],
580       [$b, $a, $expected_b],
581     ];
582   }
583
584   /**
585    * Tests http_header asset merging.
586    *
587    * @covers ::mergeAttachments
588    *
589    * @dataProvider providerTestMergeAttachmentsHttpHeaderMerging
590    */
591   public function testMergeAttachmentsHttpHeaderMerging($a, $b, $expected) {
592     $this->assertSame($expected, BubbleableMetadata::mergeAttachments($a, $b));
593   }
594
595   /**
596    * Data provider for testMergeAttachmentsHttpHeaderMerging
597    *
598    * @return array
599    */
600   public function providerTestMergeAttachmentsHttpHeaderMerging() {
601     $content_type = [
602       'Content-Type',
603       'application/rss+xml; charset=utf-8',
604     ];
605
606     $expires = [
607       'Expires',
608       'Sun, 19 Nov 1978 05:00:00 GMT',
609     ];
610
611     $a = [
612       'http_header' => [
613         $content_type,
614       ],
615     ];
616
617     $b = [
618       'http_header' => [
619         $expires,
620       ],
621     ];
622
623     $expected_a = [
624       'http_header' => [
625         $content_type,
626         $expires,
627       ],
628     ];
629
630     // Merging in the opposite direction yields the opposite library order.
631     $expected_b = [
632       'http_header' => [
633         $expires,
634         $content_type,
635       ],
636     ];
637
638     return [
639       [$a, $b, $expected_a],
640       [$b, $a, $expected_b],
641     ];
642   }
643
644   /**
645    * @covers ::addCacheableDependency
646    * @dataProvider providerTestMerge
647    *
648    * This only tests at a high level, because it reuses existing logic. Detailed
649    * tests exist for the existing logic:
650    *
651    * @see \Drupal\Tests\Core\Cache\CacheTest::testMergeTags()
652    * @see \Drupal\Tests\Core\Cache\CacheTest::testMergeMaxAges()
653    * @see \Drupal\Tests\Core\Cache\CacheContextsTest
654    */
655   public function testAddCacheableDependency(BubbleableMetadata $a, $b, BubbleableMetadata $expected) {
656     $cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
657       ->disableOriginalConstructor()
658       ->getMock();
659     $cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
660     $container = new ContainerBuilder();
661     $container->set('cache_contexts_manager', $cache_contexts_manager);
662     \Drupal::setContainer($container);
663
664     $this->assertEquals($expected, $a->addCacheableDependency($b));
665   }
666
667   /**
668    * Provides test data for testMerge().
669    *
670    * @return array
671    */
672   public function providerTestAddCacheableDependency() {
673     return [
674       // Merge in a cacheable metadata.
675       'merge-cacheable-metadata' => [
676         (new BubbleableMetadata())->setCacheContexts(['foo'])->setCacheTags(['foo'])->setCacheMaxAge(20),
677         (new CacheableMetadata())->setCacheContexts(['bar'])->setCacheTags(['bar'])->setCacheMaxAge(60),
678         (new BubbleableMetadata())->setCacheContexts(['foo', 'bar'])->setCacheTags(['foo', 'bar'])->setCacheMaxAge(20),
679       ],
680       'merge-bubbleable-metadata' => [
681         (new BubbleableMetadata())->setCacheContexts(['foo'])->setCacheTags(['foo'])->setCacheMaxAge(20)->setAttachments(['foo' => []]),
682         (new BubbleableMetadata())->setCacheContexts(['bar'])->setCacheTags(['bar'])->setCacheMaxAge(60)->setAttachments(['bar' => []]),
683         (new BubbleableMetadata())->setCacheContexts(['foo', 'bar'])->setCacheTags(['foo', 'bar'])->setCacheMaxAge(20)->setAttachments(['foo' => [], 'bar' => []]),
684       ],
685       'merge-attachments-metadata' => [
686         (new BubbleableMetadata())->setAttachments(['foo' => []]),
687         (new BubbleableMetadata())->setAttachments(['baro' => []]),
688         (new BubbleableMetadata())->setAttachments(['foo' => [], 'bar' => []]),
689       ],
690     ];
691   }
692
693 }