7669e1875af72d97579d32d8f6863e69844f4659
[yaffs-website] / web / core / modules / system / tests / src / Functional / Menu / MenuRouterTest.php
1 <?php
2
3 namespace Drupal\Tests\system\Functional\Menu;
4
5 use Drupal\Core\Url;
6 use Drupal\Tests\BrowserTestBase;
7
8 /**
9  * Tests menu router and default menu link functionality.
10  *
11  * @group Menu
12  */
13 class MenuRouterTest extends BrowserTestBase {
14
15   /**
16    * Modules to enable.
17    *
18    * @var array
19    */
20   public static $modules = ['block', 'menu_test', 'test_page_test'];
21
22   /**
23    * Name of the administrative theme to use for tests.
24    *
25    * @var string
26    */
27   protected $adminTheme;
28
29   /**
30    * Name of the default theme to use for tests.
31    *
32    * @var string
33    */
34   protected $defaultTheme;
35
36   protected function setUp() {
37     // Enable dummy module that implements hook_menu.
38     parent::setUp();
39
40     $this->drupalPlaceBlock('system_menu_block:tools');
41     $this->drupalPlaceBlock('local_tasks_block');
42     $this->drupalPlaceBlock('page_title_block');
43   }
44
45   /**
46    * Tests menu integration.
47    */
48   public function testMenuIntegration() {
49     $this->doTestTitleMenuCallback();
50     $this->doTestMenuOptionalPlaceholders();
51     $this->doTestMenuHierarchy();
52     $this->doTestMenuOnRoute();
53     $this->doTestMenuName();
54     $this->doTestMenuLinksDiscoveredAlter();
55     $this->doTestHookMenuIntegration();
56     $this->doTestExoticPath();
57   }
58
59   /**
60    * Test local tasks with route placeholders.
61    */
62   protected function doTestHookMenuIntegration() {
63     // Generate base path with random argument.
64     $machine_name = $this->randomMachineName(8);
65     $base_path = 'foo/' . $machine_name;
66     $this->drupalGet($base_path);
67     // Confirm correct controller activated.
68     $this->assertText('test1');
69     // Confirm local task links are displayed.
70     $this->assertLink('Local task A');
71     $this->assertLink('Local task B');
72     $this->assertNoLink('Local task C');
73     $this->assertEscaped("<script>alert('Welcome to the jungle!')</script>", ENT_QUOTES, 'UTF-8');
74     // Confirm correct local task href.
75     $this->assertLinkByHref(Url::fromRoute('menu_test.router_test1', ['bar' => $machine_name])->toString());
76     $this->assertLinkByHref(Url::fromRoute('menu_test.router_test2', ['bar' => $machine_name])->toString());
77   }
78
79   /**
80    * Test title callback set to FALSE.
81    */
82   protected function doTestTitleCallbackFalse() {
83     $this->drupalGet('test-page');
84     $this->assertText('A title with @placeholder', 'Raw text found on the page');
85     $this->assertNoText(t('A title with @placeholder', ['@placeholder' => 'some other text']), 'Text with placeholder substitutions not found.');
86   }
87
88   /**
89    * Tests page title of MENU_CALLBACKs.
90    */
91   protected function doTestTitleMenuCallback() {
92     // Verify that the menu router item title is not visible.
93     $this->drupalGet('');
94     $this->assertNoText(t('Menu Callback Title'));
95     // Verify that the menu router item title is output as page title.
96     $this->drupalGet('menu_callback_title');
97     $this->assertText(t('Menu Callback Title'));
98   }
99
100   /**
101    * Tests menu item descriptions.
102    */
103   protected function doTestDescriptionMenuItems() {
104     // Verify that the menu router item title is output as page title.
105     $this->drupalGet('menu_callback_description');
106     $this->assertText(t('Menu item description text'));
107   }
108
109   /**
110    * Tests for menu_name parameter for default menu links.
111    */
112   protected function doTestMenuName() {
113     $admin_user = $this->drupalCreateUser(['administer site configuration']);
114     $this->drupalLogin($admin_user);
115     /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
116     $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
117     $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.menu_name_test');
118     $menu_link = reset($menu_links);
119     $this->assertEqual($menu_link->getMenuName(), 'original', 'Menu name is "original".');
120
121     // Change the menu_name parameter in menu_test.module, then force a menu
122     // rebuild.
123     menu_test_menu_name('changed');
124     $menu_link_manager->rebuild();
125
126     $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.menu_name_test');
127     $menu_link = reset($menu_links);
128     $this->assertEqual($menu_link->getMenuName(), 'changed', 'Menu name was successfully changed after rebuild.');
129   }
130
131   /**
132    * Tests menu links added in hook_menu_links_discovered_alter().
133    */
134   protected function doTestMenuLinksDiscoveredAlter() {
135     // Check that machine name does not need to be defined since it is already
136     // set as the key of each menu link.
137     /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
138     $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
139     $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.custom');
140     $menu_link = reset($menu_links);
141     $this->assertEqual($menu_link->getPluginId(), 'menu_test.custom', 'Menu links added at hook_menu_links_discovered_alter() obtain the machine name from the $links key.');
142     // Make sure that rebuilding the menu tree does not produce duplicates of
143     // links added by hook_menu_links_discovered_alter().
144     \Drupal::service('router.builder')->rebuild();
145     $this->drupalGet('menu-test');
146     $this->assertUniqueText('Custom link', 'Menu links added by hook_menu_links_discovered_alter() do not duplicate after a menu rebuild.');
147   }
148
149   /**
150    * Tests for menu hierarchy.
151    */
152   protected function doTestMenuHierarchy() {
153     /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
154     $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
155     $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.hierarchy_parent');
156     $parent_link = reset($menu_links);
157     $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.hierarchy_parent_child');
158     $child_link = reset($menu_links);
159     $menu_links = $menu_link_manager->loadLinksByRoute('menu_test.hierarchy_parent_child2');
160     $unattached_child_link = reset($menu_links);
161     $this->assertEqual($child_link->getParent(), $parent_link->getPluginId(), 'The parent of a directly attached child is correct.');
162     $this->assertEqual($unattached_child_link->getParent(), $child_link->getPluginId(), 'The parent of a non-directly attached child is correct.');
163   }
164
165   /**
166    * Test menu links that have optional placeholders.
167    */
168   protected function doTestMenuOptionalPlaceholders() {
169     $this->drupalGet('menu-test/optional');
170     $this->assertResponse(200);
171     $this->assertText('Sometimes there is no placeholder.');
172
173     $this->drupalGet('menu-test/optional/foobar');
174     $this->assertResponse(200);
175     $this->assertText("Sometimes there is a placeholder: 'foobar'.");
176   }
177
178   /**
179    * Tests a menu on a router page.
180    */
181   protected function doTestMenuOnRoute() {
182     \Drupal::service('module_installer')->install(['router_test']);
183     \Drupal::service('router.builder')->rebuild();
184     $this->resetAll();
185
186     $this->drupalGet('router_test/test2');
187     $this->assertLinkByHref('menu_no_title_callback');
188     $this->assertLinkByHref('menu-title-test/case1');
189     $this->assertLinkByHref('menu-title-test/case2');
190     $this->assertLinkByHref('menu-title-test/case3');
191   }
192
193   /**
194    * Test path containing "exotic" characters.
195    */
196   protected function doTestExoticPath() {
197     // "Special" ASCII characters.
198     $path =
199       "menu-test/ -._~!$'\"()*@[]?&+%#,;=:" .
200       // Characters that look like a percent-escaped string.
201       "%23%25%26%2B%2F%3F" .
202       // Characters from various non-ASCII alphabets.
203       "éøïвβ中國書۞";
204     $this->drupalGet($path);
205     $this->assertRaw('This is the menuTestCallback content.');
206     $this->assertNoText(t('The website encountered an unexpected error. Please try again later.'));
207   }
208
209   /**
210    * Make sure the maintenance mode can be bypassed using an EventSubscriber.
211    *
212    * @see \Drupal\menu_test\EventSubscriber\MaintenanceModeSubscriber::onKernelRequestMaintenance()
213    */
214   public function testMaintenanceModeLoginPaths() {
215     $this->container->get('state')->set('system.maintenance_mode', TRUE);
216
217     $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', ['@site' => $this->config('system.site')->get('name')]);
218     $this->drupalGet('test-page');
219     $this->assertText($offline_message);
220     $this->drupalGet('menu_login_callback');
221     $this->assertText('This is TestControllers::testLogin.', 'Maintenance mode can be bypassed using an event subscriber.');
222
223     $this->container->get('state')->set('system.maintenance_mode', FALSE);
224   }
225
226   /**
227    * Test that an authenticated user hitting 'user/login' gets redirected to
228    * 'user' and 'user/register' gets redirected to the user edit page.
229    */
230   public function testAuthUserUserLogin() {
231     $web_user = $this->drupalCreateUser([]);
232     $this->drupalLogin($web_user);
233
234     $this->drupalGet('user/login');
235     // Check that we got to 'user'.
236     $this->assertUrl($this->loggedInUser->url('canonical', ['absolute' => TRUE]));
237
238     // user/register should redirect to user/UID/edit.
239     $this->drupalGet('user/register');
240     $this->assertUrl($this->loggedInUser->url('edit-form', ['absolute' => TRUE]));
241   }
242
243   /**
244    * Tests theme integration.
245    */
246   public function testThemeIntegration() {
247     $this->defaultTheme = 'bartik';
248     $this->adminTheme = 'seven';
249
250     $theme_handler = $this->container->get('theme_handler');
251     $theme_handler->install([$this->defaultTheme, $this->adminTheme]);
252     $this->config('system.theme')
253       ->set('default', $this->defaultTheme)
254       ->set('admin', $this->adminTheme)
255       ->save();
256
257     $this->doTestThemeCallbackMaintenanceMode();
258
259     $this->doTestThemeCallbackFakeTheme();
260
261     $this->doTestThemeCallbackAdministrative();
262
263     $this->doTestThemeCallbackNoThemeRequested();
264
265     $this->doTestThemeCallbackOptionalTheme();
266   }
267
268   /**
269    * Test the theme negotiation when it is set to use an administrative theme.
270    */
271   protected function doTestThemeCallbackAdministrative() {
272     $this->drupalGet('menu-test/theme-callback/use-admin-theme');
273     $this->assertText('Active theme: seven. Actual theme: seven.', 'The administrative theme can be correctly set in a theme negotiation.');
274     $this->assertRaw('seven/css/base/elements.css', "The administrative theme's CSS appears on the page.");
275   }
276
277   /**
278    * Test the theme negotiation when the site is in maintenance mode.
279    */
280   protected function doTestThemeCallbackMaintenanceMode() {
281     $this->container->get('state')->set('system.maintenance_mode', TRUE);
282
283     // For a regular user, the fact that the site is in maintenance mode means
284     // we expect the theme callback system to be bypassed entirely.
285     $this->drupalGet('menu-test/theme-callback/use-admin-theme');
286     $this->assertRaw('bartik/css/base/elements.css', "The maintenance theme's CSS appears on the page.");
287
288     // An administrator, however, should continue to see the requested theme.
289     $admin_user = $this->drupalCreateUser(['access site in maintenance mode']);
290     $this->drupalLogin($admin_user);
291     $this->drupalGet('menu-test/theme-callback/use-admin-theme');
292     $this->assertText('Active theme: seven. Actual theme: seven.', 'The theme negotiation system is correctly triggered for an administrator when the site is in maintenance mode.');
293     $this->assertRaw('seven/css/base/elements.css', "The administrative theme's CSS appears on the page.");
294
295     $this->container->get('state')->set('system.maintenance_mode', FALSE);
296   }
297
298   /**
299    * Test the theme negotiation when it is set to use an optional theme.
300    */
301   protected function doTestThemeCallbackOptionalTheme() {
302     // Request a theme that is not installed.
303     $this->drupalGet('menu-test/theme-callback/use-test-theme');
304     $this->assertText('Active theme: bartik. Actual theme: bartik.', 'The theme negotiation system falls back on the default theme when a theme that is not installed is requested.');
305     $this->assertRaw('bartik/css/base/elements.css', "The default theme's CSS appears on the page.");
306
307     // Now install the theme and request it again.
308     $theme_handler = $this->container->get('theme_handler');
309     $theme_handler->install(['test_theme']);
310
311     $this->drupalGet('menu-test/theme-callback/use-test-theme');
312     $this->assertText('Active theme: test_theme. Actual theme: test_theme.', 'The theme negotiation system uses an optional theme once it has been installed.');
313     $this->assertRaw('test_theme/kitten.css', "The optional theme's CSS appears on the page.");
314
315     $theme_handler->uninstall(['test_theme']);
316   }
317
318   /**
319    * Test the theme negotiation when it is set to use a theme that does not exist.
320    */
321   protected function doTestThemeCallbackFakeTheme() {
322     $this->drupalGet('menu-test/theme-callback/use-fake-theme');
323     $this->assertText('Active theme: bartik. Actual theme: bartik.', 'The theme negotiation system falls back on the default theme when a theme that does not exist is requested.');
324     $this->assertRaw('bartik/css/base/elements.css', "The default theme's CSS appears on the page.");
325   }
326
327   /**
328    * Test the theme negotiation when no theme is requested.
329    */
330   protected function doTestThemeCallbackNoThemeRequested() {
331     $this->drupalGet('menu-test/theme-callback/no-theme-requested');
332     $this->assertText('Active theme: bartik. Actual theme: bartik.', 'The theme negotiation system falls back on the default theme when no theme is requested.');
333     $this->assertRaw('bartik/css/base/elements.css', "The default theme's CSS appears on the page.");
334   }
335
336 }