3 namespace Drupal\Tests\menu_link_content\Kernel;
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Core\Language\LanguageInterface;
7 use Drupal\Core\Menu\MenuTreeParameters;
8 use Drupal\Core\Render\BubbleableMetadata;
9 use Drupal\menu_link_content\Entity\MenuLinkContent;
10 use Drupal\KernelTests\KernelTestBase;
11 use Drupal\user\Entity\User;
12 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
13 use Symfony\Component\HttpFoundation\Request;
14 use Symfony\Component\Routing\Route;
17 * Ensures that rendered menu links bubble the necessary bubbleable metadata
18 * for outbound path/route processing.
20 * @group menu_link_content
22 class MenuLinkContentCacheabilityBubblingTest extends KernelTestBase {
27 public static $modules = ['menu_link_content', 'system', 'link', 'outbound_processing_test', 'url_alter_test', 'user'];
32 protected function setUp() {
35 $this->installEntitySchema('menu_link_content');
36 $this->installEntitySchema('user');
38 // Ensure that the weight of module_link_content is higher than system.
39 // @see menu_link_content_install()
40 module_set_weight('menu_link_content', 1);
44 * Tests bubbleable metadata of menu links' outbound route/path processing.
46 public function testOutboundPathAndRouteProcessing() {
47 \Drupal::service('router.builder')->rebuild();
49 $request_stack = \Drupal::requestStack();
50 /** @var \Symfony\Component\Routing\RequestContext $request_context */
51 $request_context = \Drupal::service('router.request_context');
53 $request = Request::create('/');
54 $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<front>');
55 $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/'));
56 $request_stack->push($request);
57 $request_context->fromRequest($request);
59 $menu_tree = \Drupal::menuTree();
60 $renderer = \Drupal::service('renderer');
63 $default_menu_cacheability = (new BubbleableMetadata())
64 ->setCacheMaxAge(Cache::PERMANENT)
65 ->setCacheTags(['config:system.menu.tools'])
66 ->setCacheContexts(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions']);
68 User::create(['uid' => 1, 'name' => $this->randomString()])->save();
69 User::create(['uid' => 2, 'name' => $this->randomString()])->save();
71 // Five test cases, four asserting one outbound path/route processor, and
72 // together covering one of each:
73 // - no cacheability metadata,
77 // Plus an additional test case to verify that multiple links adding
78 // cacheability metadata of the same type is working (two links with cache
81 // \Drupal\Core\RouteProcessor\RouteProcessorCurrent: 'route' cache context.
83 'uri' => 'route:<current>',
84 'cacheability' => (new BubbleableMetadata())->setCacheContexts(['route']),
86 // \Drupal\Core\Access\RouteProcessorCsrf: placeholder.
88 'uri' => 'route:outbound_processing_test.route.csrf',
89 'cacheability' => (new BubbleableMetadata())->setCacheContexts(['session'])->setAttachments(['placeholders' => []]),
91 // \Drupal\Core\PathProcessor\PathProcessorFront: permanently cacheable.
93 'uri' => 'internal:/',
94 'cacheability' => (new BubbleableMetadata()),
96 // \Drupal\url_alter_test\PathProcessorTest: user entity's cache tags.
98 'uri' => 'internal:/user/1',
99 'cacheability' => (new BubbleableMetadata())->setCacheTags(User::load(1)->getCacheTags()),
102 'uri' => 'internal:/user/2',
103 'cacheability' => (new BubbleableMetadata())->setCacheTags(User::load(2)->getCacheTags()),
107 // Test each expectation individually.
108 foreach ($test_cases as $expectation) {
109 $menu_link_content = MenuLinkContent::create([
110 'link' => ['uri' => $expectation['uri']],
111 'menu_name' => 'tools',
113 $menu_link_content->save();
114 $tree = $menu_tree->load('tools', new MenuTreeParameters());
115 $build = $menu_tree->build($tree);
116 $renderer->renderRoot($build);
118 $expected_cacheability = $default_menu_cacheability->merge($expectation['cacheability']);
119 $this->assertEqual($expected_cacheability, BubbleableMetadata::createFromRenderArray($build));
121 $menu_link_content->delete();
124 // Now test them all together in one menu: the rendered menu's cacheability
125 // metadata should be the combination of the cacheability of all links, and
126 // thus of all tested outbound path & route processors.
127 $expected_cacheability = new BubbleableMetadata();
128 foreach ($test_cases as $expectation) {
129 $menu_link_content = MenuLinkContent::create([
130 'link' => ['uri' => $expectation['uri']],
131 'menu_name' => 'tools',
133 $menu_link_content->save();
134 $expected_cacheability = $expected_cacheability->merge($expectation['cacheability']);
136 $tree = $menu_tree->load('tools', new MenuTreeParameters());
137 $build = $menu_tree->build($tree);
138 $renderer->renderRoot($build);
139 $expected_cacheability = $expected_cacheability->merge($default_menu_cacheability);
140 $this->assertEqual($expected_cacheability, BubbleableMetadata::createFromRenderArray($build));