5 * Contains \Drupal\Tests\Core\Menu\LocalActionManagerTest.
8 namespace Drupal\Tests\Core\Menu;
10 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
11 use Drupal\Component\Plugin\Factory\FactoryInterface;
12 use Drupal\Core\Access\AccessManagerInterface;
13 use Drupal\Core\Access\AccessResult;
14 use Drupal\Core\Access\AccessResultForbidden;
15 use Drupal\Core\Cache\CacheBackendInterface;
16 use Drupal\Core\Cache\Context\CacheContextsManager;
17 use Drupal\Core\Controller\ControllerResolver;
18 use Drupal\Core\DependencyInjection\Container;
19 use Drupal\Core\Extension\ModuleHandlerInterface;
20 use Drupal\Core\Language\Language;
21 use Drupal\Core\Menu\LocalActionManager;
22 use Drupal\Core\Menu\LocalTaskManager;
23 use Drupal\Core\Routing\RouteMatchInterface;
24 use Drupal\Core\Routing\RouteProviderInterface;
25 use Drupal\Core\Session\AccountInterface;
27 use Drupal\Tests\UnitTestCase;
28 use Prophecy\Argument;
29 use Symfony\Component\HttpFoundation\Request;
30 use Symfony\Component\HttpFoundation\RequestStack;
31 use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
34 * @coversDefaultClass \Drupal\Core\Menu\LocalActionManager
37 class LocalActionManagerTest extends UnitTestCase {
40 * The mocked argument resolver.
42 * @var \Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface|\PHPUnit_Framework_MockObject_MockObject
44 protected $argumentResolver;
49 * @var \Symfony\Component\HttpFoundation\Request|\PHPUnit_Framework_MockObject_MockObject
54 * The mocked module handler.
56 * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
58 protected $moduleHandler;
61 * The mocked router provider.
63 * @var \Drupal\Core\Routing\RouteProviderInterface|\PHPUnit_Framework_MockObject_MockObject
65 protected $routeProvider;
68 * The mocked cache backend.
70 * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
72 protected $cacheBackend;
75 * The mocked access manager.
77 * @var \Drupal\Core\Access\AccessManagerInterface|\PHPUnit_Framework_MockObject_MockObject
79 protected $accessManager;
84 * @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
91 * @var \Drupal\Component\Plugin\Factory\FactoryInterface|\PHPUnit_Framework_MockObject_MockObject
96 * The mocked plugin discovery.
98 * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface|\PHPUnit_Framework_MockObject_MockObject
100 protected $discovery;
103 * The tested local action manager
105 * @var \Drupal\Tests\Core\Menu\TestLocalActionManager
107 protected $localActionManager;
112 protected function setUp() {
113 $this->argumentResolver = $this->getMock('\Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface');
114 $this->request = $this->getMock('Symfony\Component\HttpFoundation\Request');
115 $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
116 $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
117 $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
119 $cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
120 $cache_contexts_manager->assertValidTokens(Argument::any())
123 $container = new Container();
124 $container->set('cache_contexts_manager', $cache_contexts_manager->reveal());
125 \Drupal::setContainer($container);
127 $access_result = (new AccessResultForbidden())->cachePerPermissions();
128 $this->accessManager = $this->getMock('Drupal\Core\Access\AccessManagerInterface');
129 $this->accessManager->expects($this->any())
130 ->method('checkNamedRoute')
131 ->willReturn($access_result);
132 $this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
133 $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
134 $this->factory = $this->getMock('Drupal\Component\Plugin\Factory\FactoryInterface');
135 $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
137 $this->localActionManager = new TestLocalActionManager($this->argumentResolver, $this->request, $route_match, $this->routeProvider, $this->moduleHandler, $this->cacheBackend, $this->accessManager, $this->account, $this->discovery, $this->factory);
143 public function testGetTitle() {
144 $local_action = $this->getMock('Drupal\Core\Menu\LocalActionInterface');
145 $local_action->expects($this->once())
149 $this->argumentResolver->expects($this->once())
150 ->method('getArguments')
151 ->with($this->request, [$local_action, 'getTitle'])
152 ->will($this->returnValue(['test']));
154 $this->localActionManager->getTitle($local_action);
158 * @covers ::getActionsForRoute
160 * @dataProvider getActionsForRouteProvider
162 public function testGetActionsForRoute($route_appears, array $plugin_definitions, array $expected_actions) {
163 $this->discovery->expects($this->any())
164 ->method('getDefinitions')
165 ->will($this->returnValue($plugin_definitions));
167 foreach ($plugin_definitions as $plugin_id => $plugin_definition) {
168 $plugin = $this->getMock('Drupal\Core\Menu\LocalActionInterface');
169 $plugin->expects($this->any())
170 ->method('getRouteName')
171 ->will($this->returnValue($plugin_definition['route_name']));
172 $plugin->expects($this->any())
173 ->method('getRouteParameters')
174 ->will($this->returnValue(isset($plugin_definition['route_parameters']) ? $plugin_definition['route_parameters'] : []));
175 $plugin->expects($this->any())
177 ->will($this->returnValue($plugin_definition['title']));
178 $this->argumentResolver->expects($this->any())
179 ->method('getArguments')
180 ->with($this->request, [$plugin, 'getTitle'])
181 ->will($this->returnValue([]));
183 $plugin->expects($this->any())
184 ->method('getWeight')
185 ->will($this->returnValue($plugin_definition['weight']));
186 $this->argumentResolver->expects($this->any())
187 ->method('getArguments')
188 ->with($this->request, [$plugin, 'getTitle'])
189 ->will($this->returnValue([]));
190 $map[] = [$plugin_id, [], $plugin];
192 $this->factory->expects($this->any())
193 ->method('createInstance')
194 ->will($this->returnValueMap($map));
196 $this->assertEquals($expected_actions, $this->localActionManager->getActionsForRoute($route_appears));
199 public function getActionsForRouteProvider() {
200 $cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
201 $cache_contexts_manager->assertValidTokens(Argument::any())
204 $container = new Container();
205 $container->set('cache_contexts_manager', $cache_contexts_manager->reveal());
206 \Drupal::setContainer($container);
208 // Single available and single expected plugins.
216 'route_name' => 'test_route_2',
217 'title' => 'Plugin ID 1',
224 'contexts' => ['route', 'user.permissions'],
228 '#theme' => 'menu_local_action',
230 'title' => 'Plugin ID 1',
231 'url' => Url::fromRoute('test_route_2'),
232 'localized_options' => '',
234 '#access' => AccessResult::forbidden()->cachePerPermissions(),
239 // Multiple available and single expected plugins.
247 'route_name' => 'test_route_2',
248 'title' => 'Plugin ID 1',
255 'route_name' => 'test_route_3',
256 'title' => 'Plugin ID 2',
263 'contexts' => ['route', 'user.permissions'],
267 '#theme' => 'menu_local_action',
269 'title' => 'Plugin ID 1',
270 'url' => Url::fromRoute('test_route_2'),
271 'localized_options' => '',
273 '#access' => AccessResult::forbidden()->cachePerPermissions(),
279 // Multiple available and multiple expected plugins and specified weight.
287 'route_name' => 'test_route_2',
288 'title' => 'Plugin ID 1',
295 'route_name' => 'test_route_3',
296 'title' => 'Plugin ID 2',
302 'contexts' => ['route', 'user.permissions'],
307 '#theme' => 'menu_local_action',
309 'title' => 'Plugin ID 1',
310 'url' => Url::fromRoute('test_route_2'),
311 'localized_options' => '',
313 '#access' => AccessResult::forbidden()->cachePerPermissions(),
317 '#theme' => 'menu_local_action',
319 'title' => 'Plugin ID 2',
320 'url' => Url::fromRoute('test_route_3'),
321 'localized_options' => '',
323 '#access' => AccessResult::forbidden()->cachePerPermissions(),
329 // Two plugins with the same route name but different route parameters.
337 'route_name' => 'test_route_2',
338 'route_parameters' => ['test1'],
339 'title' => 'Plugin ID 1',
346 'route_name' => 'test_route_2',
347 'route_parameters' => ['test2'],
348 'title' => 'Plugin ID 2',
354 'contexts' => ['route', 'user.permissions'],
359 '#theme' => 'menu_local_action',
361 'title' => 'Plugin ID 1',
362 'url' => Url::fromRoute('test_route_2', ['test1']),
363 'localized_options' => '',
365 '#access' => AccessResult::forbidden()->cachePerPermissions(),
369 '#theme' => 'menu_local_action',
371 'title' => 'Plugin ID 2',
372 'url' => Url::fromRoute('test_route_2', ['test2']),
373 'localized_options' => '',
375 '#access' => AccessResult::forbidden()->cachePerPermissions(),
385 * @expectedDeprecation Using the 'controller_resolver' service as the first argument is deprecated, use the 'http_kernel.controller.argument_resolver' instead. If your subclass requires the 'controller_resolver' service add it as an additional argument. See https://www.drupal.org/node/2959408.
388 public function testControllerResolverDeprecation() {
389 $controller_resolver = $this->getMockBuilder(ControllerResolver::class)->disableOriginalConstructor()->getMock();
390 $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
391 $request_stack = new RequestStack();
392 $request_stack->push($this->request);
393 $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
394 $module_handler->expects($this->any())
395 ->method('getModuleDirectories')
397 $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
398 $language_manager->expects($this->any())
399 ->method('getCurrentLanguage')
400 ->will($this->returnValue(new Language(['id' => 'en'])));
401 new LocalTaskManager($controller_resolver, $request_stack, $route_match, $this->routeProvider, $this->moduleHandler, $this->cacheBackend, $language_manager, $this->accessManager, $this->account);
406 class TestLocalActionManager extends LocalActionManager {
408 public function __construct(ArgumentResolverInterface $argument_resolver, Request $request, RouteMatchInterface $route_match, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, AccessManagerInterface $access_manager, AccountInterface $account, DiscoveryInterface $discovery, FactoryInterface $factory) {
409 $this->discovery = $discovery;
410 $this->factory = $factory;
411 $this->routeProvider = $route_provider;
412 $this->accessManager = $access_manager;
413 $this->account = $account;
414 $this->argumentResolver = $argument_resolver;
415 $this->requestStack = new RequestStack();
416 $this->requestStack->push($request);
417 $this->routeMatch = $route_match;
418 $this->moduleHandler = $module_handler;
419 $this->alterInfo('menu_local_actions');
420 $this->setCacheBackend($cache_backend, 'local_action_plugins', ['local_action']);