1fca8179a8327601bb650bd6a76e8583a4f59c58
[yaffs-website] / 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     $expected_when_empty_metadata = [
167       '#cache' => [
168         'contexts' => [],
169         'tags' => [],
170         'max-age' => Cache::PERMANENT,
171       ],
172       '#attached' => [],
173     ];
174     $data[] = [$empty_metadata, $empty_render_array, $expected_when_empty_metadata];
175     $data[] = [$empty_metadata, $nonempty_render_array, $expected_when_empty_metadata];
176     $expected_when_nonempty_metadata = [
177       '#cache' => [
178         'contexts' => ['qux'],
179         'tags' => ['foo:bar'],
180         'max-age' => Cache::PERMANENT,
181       ],
182       '#attached' => [
183         'settings' => [
184           'foo' => 'bar',
185         ],
186       ],
187     ];
188     $data[] = [$nonempty_metadata, $empty_render_array, $expected_when_nonempty_metadata];
189     $data[] = [$nonempty_metadata, $nonempty_render_array, $expected_when_nonempty_metadata];
190
191     return $data;
192   }
193
194   /**
195    * @covers ::createFromRenderArray
196    * @dataProvider providerTestCreateFromRenderArray
197    */
198   public function testCreateFromRenderArray(array $render_array, BubbleableMetadata $expected) {
199     $this->assertEquals($expected, BubbleableMetadata::createFromRenderArray($render_array));
200   }
201
202   /**
203    * Provides test data for createFromRenderArray().
204    *
205    * @return array
206    */
207   public function providerTestCreateFromRenderArray() {
208     $data = [];
209
210     $empty_metadata = new BubbleableMetadata();
211     $nonempty_metadata = new BubbleableMetadata();
212     $nonempty_metadata->setCacheContexts(['qux'])
213       ->setCacheTags(['foo:bar'])
214       ->setAttachments(['settings' => ['foo' => 'bar']]);
215
216     $empty_render_array = [];
217     $nonempty_render_array = [
218       '#cache' => [
219         'contexts' => ['qux'],
220         'tags' => ['foo:bar'],
221         'max-age' => Cache::PERMANENT,
222       ],
223       '#attached' => [
224         'settings' => [
225           'foo' => 'bar',
226         ],
227       ],
228     ];
229
230     $data[] = [$empty_render_array, $empty_metadata];
231     $data[] = [$nonempty_render_array, $nonempty_metadata];
232
233     return $data;
234   }
235
236   /**
237    * Tests library asset merging.
238    *
239    * @covers ::mergeAttachments
240    */
241   public function testMergeAttachmentsLibraryMerging() {
242     $a['#attached'] = [
243       'library' => [
244         'core/drupal',
245         'core/drupalSettings',
246       ],
247       'drupalSettings' => [
248         'foo' => ['d'],
249       ],
250     ];
251     $b['#attached'] = [
252       'library' => [
253         'core/jquery',
254       ],
255       'drupalSettings' => [
256         'bar' => ['a', 'b', 'c'],
257       ],
258     ];
259     $expected['#attached'] = [
260       'library' => [
261         'core/drupal',
262         'core/drupalSettings',
263         'core/jquery',
264       ],
265       'drupalSettings' => [
266         'foo' => ['d'],
267         'bar' => ['a', 'b', 'c'],
268       ],
269     ];
270     $this->assertSame($expected['#attached'], BubbleableMetadata::mergeAttachments($a['#attached'], $b['#attached']), 'Attachments merged correctly.');
271
272     // Merging in the opposite direction yields the opposite library order.
273     $expected['#attached'] = [
274       'library' => [
275         'core/jquery',
276         'core/drupal',
277         'core/drupalSettings',
278       ],
279       'drupalSettings' => [
280         'bar' => ['a', 'b', 'c'],
281         'foo' => ['d'],
282       ],
283     ];
284     $this->assertSame($expected['#attached'], BubbleableMetadata::mergeAttachments($b['#attached'], $a['#attached']), 'Attachments merged correctly; opposite merging yields opposite order.');
285
286     // Merging with duplicates: duplicates are simply retained, it's up to the
287     // rest of the system to handle duplicates.
288     $b['#attached']['library'][] = 'core/drupalSettings';
289     $expected['#attached'] = [
290       'library' => [
291         'core/drupal',
292         'core/drupalSettings',
293         'core/jquery',
294         'core/drupalSettings',
295       ],
296       'drupalSettings' => [
297         'foo' => ['d'],
298         'bar' => ['a', 'b', 'c'],
299       ],
300     ];
301     $this->assertSame($expected['#attached'], BubbleableMetadata::mergeAttachments($a['#attached'], $b['#attached']), 'Attachments merged correctly; duplicates are retained.');
302
303     // Merging with duplicates (simple case).
304     $b['#attached']['drupalSettings']['foo'] = ['a', 'b', 'c'];
305     $expected['#attached'] = [
306       'library' => [
307         'core/drupal',
308         'core/drupalSettings',
309         'core/jquery',
310         'core/drupalSettings',
311       ],
312       'drupalSettings' => [
313         'foo' => ['a', 'b', 'c'],
314         'bar' => ['a', 'b', 'c'],
315       ],
316     ];
317     $this->assertSame($expected['#attached'], BubbleableMetadata::mergeAttachments($a['#attached'], $b['#attached']));
318
319     // Merging with duplicates (simple case) in the opposite direction yields
320     // the opposite JS setting asset order, but also opposite overriding order.
321     $expected['#attached'] = [
322       'library' => [
323         'core/jquery',
324         'core/drupalSettings',
325         'core/drupal',
326         'core/drupalSettings',
327       ],
328       'drupalSettings' => [
329         'bar' => ['a', 'b', 'c'],
330         'foo' => ['d', 'b', 'c'],
331       ],
332     ];
333     $this->assertSame($expected['#attached'], BubbleableMetadata::mergeAttachments($b['#attached'], $a['#attached']));
334
335     // Merging with duplicates: complex case.
336     // Only the second of these two entries should appear in drupalSettings.
337     $build = [];
338     $build['a']['#attached']['drupalSettings']['commonTest'] = 'firstValue';
339     $build['b']['#attached']['drupalSettings']['commonTest'] = 'secondValue';
340     // Only the second of these entries should appear in drupalSettings.
341     $build['a']['#attached']['drupalSettings']['commonTestJsArrayLiteral'] = ['firstValue'];
342     $build['b']['#attached']['drupalSettings']['commonTestJsArrayLiteral'] = ['secondValue'];
343     // Only the second of these two entries should appear in drupalSettings.
344     $build['a']['#attached']['drupalSettings']['commonTestJsObjectLiteral'] = ['key' => 'firstValue'];
345     $build['b']['#attached']['drupalSettings']['commonTestJsObjectLiteral'] = ['key' => 'secondValue'];
346     // Real world test case: multiple elements in a render array are adding the
347     // same (or nearly the same) JavaScript settings. When merged, they should
348     // contain all settings and not duplicate some settings.
349     $settings_one = ['moduleName' => ['ui' => ['button A', 'button B'], 'magical flag' => 3.14159265359]];
350     $build['a']['#attached']['drupalSettings']['commonTestRealWorldIdentical'] = $settings_one;
351     $build['b']['#attached']['drupalSettings']['commonTestRealWorldIdentical'] = $settings_one;
352     $settings_two_a = ['moduleName' => ['ui' => ['button A', 'button B', 'button C'], 'magical flag' => 3.14159265359, 'thingiesOnPage' => ['id1' => []]]];
353     $build['a']['#attached']['drupalSettings']['commonTestRealWorldAlmostIdentical'] = $settings_two_a;
354     $settings_two_b = ['moduleName' => ['ui' => ['button D', 'button E'], 'magical flag' => 3.14, 'thingiesOnPage' => ['id2' => []]]];
355     $build['b']['#attached']['drupalSettings']['commonTestRealWorldAlmostIdentical'] = $settings_two_b;
356
357     $merged = BubbleableMetadata::mergeAttachments($build['a']['#attached'], $build['b']['#attached']);
358
359     // Test whether #attached can be used to override a previous setting.
360     $this->assertSame('secondValue', $merged['drupalSettings']['commonTest']);
361
362     // Test whether #attached can be used to add and override a JavaScript
363     // array literal (an indexed PHP array) values.
364     $this->assertSame('secondValue', $merged['drupalSettings']['commonTestJsArrayLiteral'][0]);
365
366     // Test whether #attached can be used to add and override a JavaScript
367     // object literal (an associate PHP array) values.
368     $this->assertSame('secondValue', $merged['drupalSettings']['commonTestJsObjectLiteral']['key']);
369
370     // Test whether the two real world cases are handled correctly: the first
371     // adds the exact same settings twice and hence tests idempotency, the
372     // second adds *almost* the same settings twice: the second time, some
373     // values are altered, and some key-value pairs are added.
374     $settings_two['moduleName']['thingiesOnPage']['id1'] = [];
375     $this->assertSame($settings_one, $merged['drupalSettings']['commonTestRealWorldIdentical']);
376     $expected_settings_two = $settings_two_a;
377     $expected_settings_two['moduleName']['ui'][0] = 'button D';
378     $expected_settings_two['moduleName']['ui'][1] = 'button E';
379     $expected_settings_two['moduleName']['ui'][2] = 'button C';
380     $expected_settings_two['moduleName']['magical flag'] = 3.14;
381     $expected_settings_two['moduleName']['thingiesOnPage']['id2'] = [];
382     $this->assertSame($expected_settings_two, $merged['drupalSettings']['commonTestRealWorldAlmostIdentical']);
383   }
384
385   /**
386    * Tests feed asset merging.
387    *
388    * @covers ::mergeAttachments
389    *
390    * @dataProvider providerTestMergeAttachmentsFeedMerging
391    */
392   public function testMergeAttachmentsFeedMerging($a, $b, $expected) {
393     $this->assertSame($expected, BubbleableMetadata::mergeAttachments($a, $b));
394   }
395
396   /**
397    * Data provider for testMergeAttachmentsFeedMerging
398    *
399    * @return array
400    */
401   public function providerTestMergeAttachmentsFeedMerging() {
402     $feed_a = [
403       'aggregator/rss',
404       'Feed title',
405     ];
406
407     $feed_b = [
408       'taxonomy/term/1/feed',
409       'RSS - foo',
410     ];
411
412     $a = [
413       'feed' => [
414         $feed_a,
415       ],
416     ];
417     $b = [
418       'feed' => [
419         $feed_b,
420       ],
421     ];
422
423     $expected_a = [
424       'feed' => [
425         $feed_a,
426         $feed_b,
427       ],
428     ];
429
430     // Merging in the opposite direction yields the opposite library order.
431     $expected_b = [
432       'feed' => [
433         $feed_b,
434         $feed_a,
435       ],
436     ];
437
438     return [
439       [$a, $b, $expected_a],
440       [$b, $a, $expected_b],
441     ];
442   }
443
444   /**
445    * Tests html_head asset merging.
446    *
447    * @covers ::mergeAttachments
448    *
449    * @dataProvider providerTestMergeAttachmentsHtmlHeadMerging
450    */
451   public function testMergeAttachmentsHtmlHeadMerging($a, $b, $expected) {
452     $this->assertSame($expected, BubbleableMetadata::mergeAttachments($a, $b));
453   }
454
455   /**
456    * Data provider for testMergeAttachmentsHtmlHeadMerging
457    *
458    * @return array
459    */
460   public function providerTestMergeAttachmentsHtmlHeadMerging() {
461     $meta = [
462       '#tag' => 'meta',
463       '#attributes' => [
464         'charset' => 'utf-8',
465       ],
466       '#weight' => -1000,
467     ];
468
469     $html_tag = [
470       '#type' => 'html_tag',
471       '#tag' => 'meta',
472       '#attributes' => [
473         'name' => 'Generator',
474         'content' => 'Kitten 1.0 (https://www.drupal.org/project/kitten)',
475       ],
476     ];
477
478     $a = [
479       'html_head' => [
480         $meta,
481         'system_meta_content_type',
482       ],
483     ];
484
485     $b = [
486       'html_head' => [
487         $html_tag,
488         'system_meta_generator',
489       ],
490     ];
491
492     $expected_a = [
493       'html_head' => [
494         $meta,
495         'system_meta_content_type',
496         $html_tag,
497         'system_meta_generator',
498       ],
499     ];
500
501     // Merging in the opposite direction yields the opposite library order.
502     $expected_b = [
503       'html_head' => [
504         $html_tag,
505         'system_meta_generator',
506         $meta,
507         'system_meta_content_type',
508       ],
509     ];
510
511     return [
512       [$a, $b, $expected_a],
513       [$b, $a, $expected_b],
514     ];
515   }
516
517   /**
518    * Tests html_head_link asset merging.
519    *
520    * @covers ::mergeAttachments
521    *
522    * @dataProvider providerTestMergeAttachmentsHtmlHeadLinkMerging
523    */
524   public function testMergeAttachmentsHtmlHeadLinkMerging($a, $b, $expected) {
525     $this->assertSame($expected, BubbleableMetadata::mergeAttachments($a, $b));
526   }
527
528   /**
529    * Data provider for testMergeAttachmentsHtmlHeadLinkMerging
530    *
531    * @return array
532    */
533   public function providerTestMergeAttachmentsHtmlHeadLinkMerging() {
534     $rel = [
535       'rel' => 'rel',
536       'href' => 'http://rel.example.com',
537     ];
538
539     $shortlink = [
540       'rel' => 'shortlink',
541       'href' => 'http://shortlink.example.com',
542     ];
543
544     $a = [
545       'html_head_link' => [
546         $rel,
547         TRUE,
548       ],
549     ];
550
551     $b = [
552       'html_head_link' => [
553         $shortlink,
554         FALSE,
555       ],
556     ];
557
558     $expected_a = [
559       'html_head_link' => [
560         $rel,
561         TRUE,
562         $shortlink,
563         FALSE,
564       ],
565     ];
566
567     // Merging in the opposite direction yields the opposite library order.
568     $expected_b = [
569       'html_head_link' => [
570         $shortlink,
571         FALSE,
572         $rel,
573         TRUE,
574       ],
575     ];
576
577     return [
578       [$a, $b, $expected_a],
579       [$b, $a, $expected_b],
580     ];
581   }
582
583   /**
584    * Tests http_header asset merging.
585    *
586    * @covers ::mergeAttachments
587    *
588    * @dataProvider providerTestMergeAttachmentsHttpHeaderMerging
589    */
590   public function testMergeAttachmentsHttpHeaderMerging($a, $b, $expected) {
591     $this->assertSame($expected, BubbleableMetadata::mergeAttachments($a, $b));
592   }
593
594   /**
595    * Data provider for testMergeAttachmentsHttpHeaderMerging
596    *
597    * @return array
598    */
599   public function providerTestMergeAttachmentsHttpHeaderMerging() {
600     $content_type = [
601       'Content-Type',
602       'application/rss+xml; charset=utf-8',
603     ];
604
605     $expires = [
606       'Expires',
607       'Sun, 19 Nov 1978 05:00:00 GMT',
608     ];
609
610     $a = [
611       'http_header' => [
612         $content_type,
613       ],
614     ];
615
616     $b = [
617       'http_header' => [
618         $expires,
619       ],
620     ];
621
622     $expected_a = [
623       'http_header' => [
624         $content_type,
625         $expires,
626       ],
627     ];
628
629     // Merging in the opposite direction yields the opposite library order.
630     $expected_b = [
631       'http_header' => [
632         $expires,
633         $content_type,
634       ],
635     ];
636
637     return [
638       [$a, $b, $expected_a],
639       [$b, $a, $expected_b],
640     ];
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 }