Upgraded drupal core with security updates
[yaffs-website] / web / core / modules / system / src / Tests / Menu / MenuRouterTest.php
1 <?php
2
3 namespace Drupal\system\Tests\Menu;
4
5 use Drupal\Core\Url;
6 use Drupal\simpletest\WebTestBase;
7
8 /**
9  * Tests menu router and default menu link functionality.
10  *
11  * @group Menu
12  */
13 class MenuRouterTest extends WebTestBase {
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     $path = "menu-test/ -._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters.
198       "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
199       "éøïвβ中國書۞"; // Characters from various non-ASCII alphabets.
200     $this->drupalGet($path);
201     $this->assertRaw('This is the menuTestCallback content.');
202     $this->assertNoText(t('The website encountered an unexpected error. Please try again later.'));
203   }
204
205   /**
206    * Make sure the maintenance mode can be bypassed using an EventSubscriber.
207    *
208    * @see \Drupal\menu_test\EventSubscriber\MaintenanceModeSubscriber::onKernelRequestMaintenance()
209    */
210   public function testMaintenanceModeLoginPaths() {
211     $this->container->get('state')->set('system.maintenance_mode', TRUE);
212
213     $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')]);
214     $this->drupalGet('test-page');
215     $this->assertText($offline_message);
216     $this->drupalGet('menu_login_callback');
217     $this->assertText('This is TestControllers::testLogin.', 'Maintenance mode can be bypassed using an event subscriber.');
218
219     $this->container->get('state')->set('system.maintenance_mode', FALSE);
220   }
221
222   /**
223    * Test that an authenticated user hitting 'user/login' gets redirected to
224    * 'user' and 'user/register' gets redirected to the user edit page.
225    */
226   public function testAuthUserUserLogin() {
227     $web_user = $this->drupalCreateUser([]);
228     $this->drupalLogin($web_user);
229
230     $this->drupalGet('user/login');
231     // Check that we got to 'user'.
232     $this->assertUrl($this->loggedInUser->url('canonical', ['absolute' => TRUE]));
233
234     // user/register should redirect to user/UID/edit.
235     $this->drupalGet('user/register');
236     $this->assertUrl($this->loggedInUser->url('edit-form', ['absolute' => TRUE]));
237   }
238
239   /**
240    * Tests theme integration.
241    */
242   public function testThemeIntegration() {
243     $this->defaultTheme = 'bartik';
244     $this->adminTheme = 'seven';
245
246     $theme_handler = $this->container->get('theme_handler');
247     $theme_handler->install([$this->defaultTheme, $this->adminTheme]);
248     $this->config('system.theme')
249       ->set('default', $this->defaultTheme)
250       ->set('admin', $this->adminTheme)
251       ->save();
252
253     $this->doTestThemeCallbackMaintenanceMode();
254
255     $this->doTestThemeCallbackFakeTheme();
256
257     $this->doTestThemeCallbackAdministrative();
258
259     $this->doTestThemeCallbackNoThemeRequested();
260
261     $this->doTestThemeCallbackOptionalTheme();
262   }
263
264   /**
265    * Test the theme negotiation when it is set to use an administrative theme.
266    */
267   protected function doTestThemeCallbackAdministrative() {
268     $this->drupalGet('menu-test/theme-callback/use-admin-theme');
269     $this->assertText('Active theme: seven. Actual theme: seven.', 'The administrative theme can be correctly set in a theme negotiation.');
270     $this->assertRaw('seven/css/base/elements.css', "The administrative theme's CSS appears on the page.");
271   }
272
273   /**
274    * Test the theme negotiation when the site is in maintenance mode.
275    */
276   protected function doTestThemeCallbackMaintenanceMode() {
277     $this->container->get('state')->set('system.maintenance_mode', TRUE);
278
279     // For a regular user, the fact that the site is in maintenance mode means
280     // we expect the theme callback system to be bypassed entirely.
281     $this->drupalGet('menu-test/theme-callback/use-admin-theme');
282     $this->assertRaw('bartik/css/base/elements.css', "The maintenance theme's CSS appears on the page.");
283
284     // An administrator, however, should continue to see the requested theme.
285     $admin_user = $this->drupalCreateUser(['access site in maintenance mode']);
286     $this->drupalLogin($admin_user);
287     $this->drupalGet('menu-test/theme-callback/use-admin-theme');
288     $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.');
289     $this->assertRaw('seven/css/base/elements.css', "The administrative theme's CSS appears on the page.");
290
291     $this->container->get('state')->set('system.maintenance_mode', FALSE);
292   }
293
294   /**
295    * Test the theme negotiation when it is set to use an optional theme.
296    */
297   protected function doTestThemeCallbackOptionalTheme() {
298     // Request a theme that is not installed.
299     $this->drupalGet('menu-test/theme-callback/use-test-theme');
300     $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.');
301     $this->assertRaw('bartik/css/base/elements.css', "The default theme's CSS appears on the page.");
302
303     // Now install the theme and request it again.
304     $theme_handler = $this->container->get('theme_handler');
305     $theme_handler->install(['test_theme']);
306
307     $this->drupalGet('menu-test/theme-callback/use-test-theme');
308     $this->assertText('Active theme: test_theme. Actual theme: test_theme.', 'The theme negotiation system uses an optional theme once it has been installed.');
309     $this->assertRaw('test_theme/kitten.css', "The optional theme's CSS appears on the page.");
310
311     $theme_handler->uninstall(['test_theme']);
312   }
313
314   /**
315    * Test the theme negotiation when it is set to use a theme that does not exist.
316    */
317   protected function doTestThemeCallbackFakeTheme() {
318     $this->drupalGet('menu-test/theme-callback/use-fake-theme');
319     $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.');
320     $this->assertRaw('bartik/css/base/elements.css', "The default theme's CSS appears on the page.");
321   }
322
323   /**
324    * Test the theme negotiation when no theme is requested.
325    */
326   protected function doTestThemeCallbackNoThemeRequested() {
327     $this->drupalGet('menu-test/theme-callback/no-theme-requested');
328     $this->assertText('Active theme: bartik. Actual theme: bartik.', 'The theme negotiation system falls back on the default theme when no theme is requested.');
329     $this->assertRaw('bartik/css/base/elements.css', "The default theme's CSS appears on the page.");
330   }
331
332 }