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