admin_menu.test 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. <?php
  2. /**
  3. * @file
  4. * Tests for the Administration menu module.
  5. */
  6. /**
  7. * Base class for all administration menu web test cases.
  8. */
  9. class AdminMenuWebTestCase extends DrupalWebTestCase {
  10. protected $profile = 'testing';
  11. protected $basePermissions = array(
  12. 'system' => 'access administration pages',
  13. 'admin_menu' => 'access administration menu',
  14. );
  15. function setUp() {
  16. // Enable admin menu module and any other modules.
  17. $modules = func_get_args();
  18. $modules = isset($modules[0]) ? $modules[0] : $modules;
  19. $modules[] = 'admin_menu';
  20. parent::setUp($modules);
  21. // Disable client-side caching.
  22. variable_set('admin_menu_cache_client', FALSE);
  23. // Disable Clean URLs to ensure drupal.org testbot compatibility.
  24. variable_set('clean_url', 0);
  25. }
  26. /**
  27. * Check that an element exists in HTML markup.
  28. *
  29. * @param $xpath
  30. * An XPath expression.
  31. * @param array $arguments
  32. * (optional) An associative array of XPath replacement tokens to pass to
  33. * DrupalWebTestCase::buildXPathQuery().
  34. * @param $message
  35. * The message to display along with the assertion.
  36. * @param $group
  37. * The type of assertion - examples are "Browser", "PHP".
  38. *
  39. * @return
  40. * TRUE if the assertion succeeded, FALSE otherwise.
  41. */
  42. protected function assertElementByXPath($xpath, array $arguments = array(), $message, $group = 'Other') {
  43. $elements = $this->xpath($xpath, $arguments);
  44. return $this->assertTrue(!empty($elements[0]), $message, $group);
  45. }
  46. /**
  47. * Check that an element does not exist in HTML markup.
  48. *
  49. * @param $xpath
  50. * An XPath expression.
  51. * @param array $arguments
  52. * (optional) An associative array of XPath replacement tokens to pass to
  53. * DrupalWebTestCase::buildXPathQuery().
  54. * @param $message
  55. * The message to display along with the assertion.
  56. * @param $group
  57. * The type of assertion - examples are "Browser", "PHP".
  58. *
  59. * @return
  60. * TRUE if the assertion succeeded, FALSE otherwise.
  61. */
  62. protected function assertNoElementByXPath($xpath, array $arguments = array(), $message, $group = 'Other') {
  63. $elements = $this->xpath($xpath, $arguments);
  64. return $this->assertTrue(empty($elements), $message, $group);
  65. }
  66. /**
  67. * Asserts that links appear in the menu in a specified trail.
  68. *
  69. * @param array $trail
  70. * A list of menu link titles to assert in the menu.
  71. */
  72. protected function assertLinkTrailByTitle(array $trail) {
  73. $xpath = array();
  74. $args = array();
  75. $message = '';
  76. foreach ($trail as $i => $title) {
  77. $xpath[] = '/li/a[text()=:title' . $i . ']';
  78. $args[':title' . $i] = $title;
  79. $message .= ($i ? ' » ' : '') . check_plain($title);
  80. }
  81. $xpath = '//div[@id="admin-menu"]/div/ul' . implode('/parent::li/ul', $xpath);
  82. $this->assertElementByXPath($xpath, $args, $message . ' link found.');
  83. }
  84. /**
  85. * Asserts that no link appears in the menu for a specified trail.
  86. *
  87. * @param array $trail
  88. * A list of menu link titles to assert in the menu.
  89. */
  90. protected function assertNoLinkTrailByTitle(array $trail) {
  91. $xpath = array();
  92. $args = array();
  93. $message = '';
  94. foreach ($trail as $i => $title) {
  95. $xpath[] = '/li/a[text()=:title' . $i . ']';
  96. $args[':title' . $i] = $title;
  97. $message .= ($i ? ' » ' : '') . check_plain($title);
  98. }
  99. $xpath = '//div[@id="admin-menu"]/div/ul' . implode('/parent::li/ul', $xpath);
  100. $this->assertNoElementByXPath($xpath, $args, $message . ' link not found.');
  101. }
  102. }
  103. /**
  104. * Tests menu links depending on user permissions.
  105. */
  106. class AdminMenuPermissionsTestCase extends AdminMenuWebTestCase {
  107. public static function getInfo() {
  108. return array(
  109. 'name' => 'Menu link access permissions',
  110. 'description' => 'Tests appearance of menu links depending on user permissions.',
  111. 'group' => 'Administration menu',
  112. );
  113. }
  114. function setUp() {
  115. parent::setUp(array('node'));
  116. }
  117. /**
  118. * Test that the links are added to the page (no JS testing).
  119. */
  120. function testPermissions() {
  121. module_enable(array('contact'));
  122. $this->resetAll();
  123. // Anonymous users should not see the menu.
  124. $this->drupalGet('');
  125. $this->assertNoElementByXPath('//div[@id="admin-menu"]', array(), t('Administration menu not found.'));
  126. // Create a user who
  127. // - can access content overview
  128. // - cannot access drupal.org links
  129. // - cannot administer Contact module
  130. $permissions = $this->basePermissions + array(
  131. 'access content overview',
  132. );
  133. $admin_user = $this->drupalCreateUser($permissions);
  134. $this->drupalLogin($admin_user);
  135. // Check that the user can see the admin links, but not the drupal links.
  136. $this->assertElementByXPath('//div[@id="admin-menu"]', array(), 'Administration menu found.');
  137. $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/content'), 'Content link found.');
  138. $this->assertNoElementByXPath('//div[@id="admin-menu"]//a[@href=:path]', array(':path' => 'http://drupal.org'), 'Icon » Drupal.org link not found.');
  139. $this->assertNoElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/structure/contact'), 'Structure » Contact link not found.');
  140. // Create a user "reversed" to the above; i.e., who
  141. // - cannot access content overview
  142. // - can access drupal.org links
  143. // - can administer Contact module
  144. $permissions = $this->basePermissions + array(
  145. 'display drupal links',
  146. 'administer contact forms',
  147. );
  148. $admin_user2 = $this->drupalCreateUser($permissions);
  149. $this->drupalLogin($admin_user2);
  150. $this->assertElementByXPath('//div[@id="admin-menu"]', array(), 'Administration menu found.');
  151. $this->assertNoElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/content'), 'Content link not found.');
  152. $this->assertElementByXPath('//div[@id="admin-menu"]//a[@href=:path]', array(':path' => 'http://drupal.org'), 'Icon » Drupal.org link found.');
  153. $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/structure/contact'), 'Structure » Contact link found.');
  154. }
  155. /**
  156. * Tests handling of links pointing to category/overview pages.
  157. */
  158. function testCategories() {
  159. // Create a user with minimum permissions.
  160. $admin_user = $this->drupalCreateUser($this->basePermissions);
  161. $this->drupalLogin($admin_user);
  162. // Verify that no category links appear.
  163. $this->assertNoLinkTrailByTitle(array(t('Structure')));
  164. $this->assertNoLinkTrailByTitle(array(t('Configuration')));
  165. // Create a user with access to one configuration category.
  166. $permissions = $this->basePermissions + array(
  167. 'administer users',
  168. );
  169. $admin_user = $this->drupalCreateUser($permissions);
  170. $this->drupalLogin($admin_user);
  171. // Verify that only expected category links appear.
  172. $this->assertNoLinkTrailByTitle(array(t('Structure')));
  173. $this->assertLinkTrailByTitle(array(t('People')));
  174. $this->assertLinkTrailByTitle(array(t('Configuration')));
  175. $this->assertLinkTrailByTitle(array(t('Configuration'), t('People')));
  176. // Random picks are sufficient.
  177. $this->assertNoLinkTrailByTitle(array(t('Configuration'), t('Media')));
  178. $this->assertNoLinkTrailByTitle(array(t('Configuration'), t('System')));
  179. }
  180. /**
  181. * Tests that user role and permission changes are properly taken up.
  182. */
  183. function testPermissionChanges() {
  184. // Create a user who is able to change permissions.
  185. $permissions = $this->basePermissions + array(
  186. 'administer permissions',
  187. );
  188. $admin_user = $this->drupalCreateUser($permissions);
  189. $this->drupalLogin($admin_user);
  190. // Extract the user role ID that was created for above permissions.
  191. $rid = key(array_diff_key($admin_user->roles, array(DRUPAL_AUTHENTICATED_RID => 0)));
  192. // Verify that Configuration does not appear.
  193. $this->assertNoLinkTrailByTitle(array(t('Configuration')));
  194. // Grant the 'administer site configuration' permission to ourselves.
  195. $edit = array(
  196. $rid . '[administer site configuration]' => TRUE,
  197. );
  198. $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
  199. // Verify that Configuration appears.
  200. $this->assertLinkTrailByTitle(array(t('Configuration')));
  201. // Verify that Structure » Content types does not appear.
  202. $this->assertNoLinkTrailByTitle(array(t('Structure'), t('Content types')));
  203. // Create a new role.
  204. $edit = array(
  205. 'name' => 'test',
  206. );
  207. $this->drupalPost('admin/people/permissions/roles', $edit, t('Add role'));
  208. // It should be safe to assume that the new role gets the next ID.
  209. $test_rid = $rid + 1;
  210. // Grant the 'administer content types' permission for the role.
  211. $edit = array(
  212. $test_rid . '[administer content types]' => TRUE,
  213. );
  214. $this->drupalPost('admin/people/permissions/' . $test_rid, $edit, t('Save permissions'));
  215. // Verify that Structure » Content types does not appear.
  216. $this->assertNoLinkTrailByTitle(array(t('Structure'), t('Content types')));
  217. // Assign the role to ourselves.
  218. $edit = array(
  219. 'roles[' . $test_rid . ']' => TRUE,
  220. );
  221. $this->drupalPost('user/' . $admin_user->uid . '/edit', $edit, t('Save'));
  222. // Verify that Structure » Content types appears.
  223. $this->assertLinkTrailByTitle(array(t('Structure'), t('Content types')));
  224. // Delete the role.
  225. $this->drupalPost('admin/people/permissions/roles/edit/' . $test_rid, array(), t('Delete role'));
  226. $this->drupalPost(NULL, array(), t('Delete'));
  227. // Verify that Structure » Content types does not appear.
  228. $this->assertNoLinkTrailByTitle(array(t('Structure'), t('Content types')));
  229. }
  230. }
  231. /**
  232. * Tests appearance, localization, and escaping of dynamic links.
  233. */
  234. class AdminMenuDynamicLinksTestCase extends AdminMenuWebTestCase {
  235. public static function getInfo() {
  236. return array(
  237. 'name' => 'Dynamic links',
  238. 'description' => 'Tests appearance, localization, and escaping of dynamic links.',
  239. 'group' => 'Administration menu',
  240. );
  241. }
  242. function setUp() {
  243. parent::setUp(array('node'));
  244. }
  245. /**
  246. * Tests node type links.
  247. */
  248. function testNode() {
  249. $type = $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
  250. // Create a content-type with special characters.
  251. $type = $this->drupalCreateContentType(array('type' => 'special', 'name' => 'Cool & Special'));
  252. $permissions = $this->basePermissions + array(
  253. 'administer content types',
  254. 'create article content',
  255. 'create special content',
  256. );
  257. $this->admin_user = $this->drupalCreateUser($permissions);
  258. $this->drupalLogin($this->admin_user);
  259. // Verify that dynamic links are displayed.
  260. $this->drupalGet('');
  261. $this->assertElementByXPath('//div[@id="admin-menu"]', array(), t('Administration menu found.'));
  262. $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/structure/types'), "Structure » Content types link found.");
  263. // Verify link title output escaping.
  264. $this->assertNoRaw('Cool & Special');
  265. $this->assertRaw(check_plain('Cool & Special'));
  266. // Verify Manage content type links.
  267. $links = array(
  268. 'admin/structure/types/manage/article' => 'Article',
  269. 'admin/structure/types/manage/special' => 'Cool & Special',
  270. );
  271. foreach ($links as $path => $title) {
  272. $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path) and text()=:title]', array(
  273. ':path' => $path,
  274. ':title' => $title,
  275. ), "Structure » Content types » $title link found.");
  276. }
  277. // Verify Add content links.
  278. $links = array(
  279. 'node/add/article' => 'Article',
  280. 'node/add/special' => 'Cool & Special',
  281. );
  282. foreach ($links as $path => $title) {
  283. $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path) and text()=:title]', array(
  284. ':path' => $path,
  285. ':title' => $title,
  286. ), "Add content » $title link found.");
  287. }
  288. }
  289. /**
  290. * Tests Add content links.
  291. */
  292. function testNodeAdd() {
  293. $type = $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
  294. // Verify that "Add content" does not appear for unprivileged users.
  295. $permissions = $this->basePermissions + array(
  296. 'access content',
  297. );
  298. $this->web_user = $this->drupalCreateUser($permissions);
  299. $this->drupalLogin($this->web_user);
  300. $this->assertNoText(t('Add content'));
  301. // Verify "Add content" appears below "Content" for administrative users.
  302. $permissions = $this->basePermissions + array(
  303. 'access content overview',
  304. 'access content',
  305. 'create article content',
  306. );
  307. $this->admin_user = $this->drupalCreateUser($permissions);
  308. $this->drupalLogin($this->admin_user);
  309. $this->assertLinkTrailByTitle(array(
  310. t('Content'),
  311. t('Add content'),
  312. ));
  313. // Verify "Add content" appears on the top-level for regular users.
  314. $permissions = $this->basePermissions + array(
  315. 'access content',
  316. 'create article content',
  317. );
  318. $this->web_user = $this->drupalCreateUser($permissions);
  319. $this->drupalLogin($this->web_user);
  320. $this->assertLinkTrailByTitle(array(
  321. t('Add content'),
  322. ));
  323. }
  324. }
  325. /**
  326. * Tests appearance of different types of links.
  327. */
  328. class AdminMenuLinkTypesTestCase extends AdminMenuWebTestCase {
  329. public static function getInfo() {
  330. return array(
  331. 'name' => 'Link types',
  332. 'description' => 'Tests appearance of different types of links.',
  333. 'group' => 'Administration menu',
  334. );
  335. }
  336. function setUp() {
  337. parent::setUp(array('help'));
  338. $permissions = module_invoke_all('permission');
  339. $permissions = array_keys($permissions);
  340. $this->admin_user = $this->drupalCreateUser($permissions);
  341. $this->drupalLogin($this->admin_user);
  342. }
  343. /**
  344. * Tests appearance of different router item link types.
  345. */
  346. function testLinkTypes() {
  347. // Verify that MENU_NORMAL_ITEMs appear.
  348. $this->assertLinkTrailByTitle(array(
  349. t('Configuration'),
  350. t('System'),
  351. t('Site information'),
  352. ));
  353. // Verify that MENU_LOCAL_TASKs appear.
  354. $this->assertLinkTrailByTitle(array(t('People'), t('Permissions')));
  355. $this->assertLinkTrailByTitle(array(t('Appearance'), t('Settings')));
  356. $this->assertLinkTrailByTitle(array(t('Modules'), t('Uninstall')));
  357. // Verify that MENU_LOCAL_ACTIONs appear.
  358. $this->assertLinkTrailByTitle(array(
  359. t('People'),
  360. t('Add user'),
  361. ));
  362. // Verify that MENU_DEFAULT_LOCAL_TASKs do NOT appear.
  363. $this->assertNoLinkTrailByTitle(array(t('Modules'), t('List')));
  364. $this->assertNoLinkTrailByTitle(array(t('People'), t('List')));
  365. $this->assertNoLinkTrailByTitle(array(t('People'), t('Permissions'), t('Permissions')));
  366. $this->assertNoLinkTrailByTitle(array(t('Appearance'), t('List')));
  367. // Verify that MENU_VISIBLE_IN_BREADCRUMB items (exact type) do NOT appear.
  368. $this->assertNoLinkTrailByTitle(array(t('Modules'), t('Uninstall'), t('Uninstall')));
  369. $this->assertNoLinkTrailByTitle(array(t('Help'), 'admin_menu'));
  370. // Verify that special "Index" link appears below icon.
  371. $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path) and text()=:title]', array(
  372. ':path' => 'admin/index',
  373. ':title' => t('Index'),
  374. ), "Icon » Index link found.");
  375. }
  376. }
  377. /**
  378. * Tests customized menu links.
  379. */
  380. class AdminMenuCustomizedTestCase extends AdminMenuWebTestCase {
  381. public static function getInfo() {
  382. return array(
  383. 'name' => 'Customized links',
  384. 'description' => 'Tests customized menu links.',
  385. 'group' => 'Administration menu',
  386. );
  387. }
  388. function setUp() {
  389. parent::setUp(array('menu'));
  390. $this->admin_user = $this->drupalCreateUser($this->basePermissions + array(
  391. 'administer menu',
  392. ));
  393. $this->drupalLogin($this->admin_user);
  394. }
  395. /**
  396. * Test disabled custom links.
  397. */
  398. function testCustomDisabled() {
  399. $type = $this->drupalCreateContentType();
  400. $node = $this->drupalCreateNode(array('type' => $type->type));
  401. $text = $this->randomName();
  402. $xpath = $this->buildXPathQuery('//div[@id=:id]//a[contains(text(), :text)]', array(
  403. ':id' => 'admin-menu',
  404. ':text' => $text,
  405. ));
  406. // Verify that the link does not appear in the menu.
  407. $this->drupalGet('node');
  408. $elements = $this->xpath($xpath);
  409. $this->assertFalse($elements, 'Custom link not found.');
  410. // Add a custom link to the node to the menu.
  411. $edit = array(
  412. 'link_path' => 'node/' . $node->nid,
  413. 'link_title' => $text,
  414. 'parent' => 'management:' . $this->queryMlidByPath('admin'),
  415. );
  416. $this->drupalPost('admin/structure/menu/manage/management/add', $edit, t('Save'));
  417. // Verify that the link appears in the menu.
  418. $this->drupalGet('node');
  419. $elements = $this->xpath($xpath);
  420. $this->assertTrue($elements, 'Custom link found.');
  421. // Disable the link.
  422. $edit = array(
  423. 'enabled' => FALSE,
  424. );
  425. $this->drupalPost('admin/structure/menu/item/' . $this->queryMlidByPath('node/' . $node->nid) . '/edit', $edit, t('Save'));
  426. // Verify that the disabled link does not appear in the menu.
  427. $this->drupalGet('node');
  428. $elements = $this->xpath($xpath);
  429. $this->assertFalse($elements, 'Disabled custom link not found.');
  430. }
  431. /**
  432. * Tests external links.
  433. */
  434. function testCustomExternal() {
  435. // Add a custom link to the node to the menu.
  436. $edit = array(
  437. 'link_path' => 'http://example.com',
  438. 'link_title' => 'Example',
  439. 'parent' => 'management:' . $this->queryMlidByPath('admin'),
  440. );
  441. $this->drupalPost('admin/structure/menu/manage/management/add', $edit, t('Save'));
  442. // Verify that the link appears in the menu.
  443. $this->drupalGet('');
  444. $elements = $this->xpath('//div[@id=:id]//a[@href=:href and contains(text(), :text)]', array(
  445. ':id' => 'admin-menu',
  446. ':href' => $edit['link_path'],
  447. ':text' => $edit['link_title'],
  448. ));
  449. $this->assertTrue($elements, 'External link found.');
  450. }
  451. /**
  452. * Returns the menu link ID for a given link path in the management menu.
  453. */
  454. protected function queryMlidByPath($path) {
  455. return db_query('SELECT mlid FROM {menu_links} WHERE menu_name = :menu AND link_path = :path', array(
  456. ':menu' => 'management',
  457. ':path' => $path,
  458. ))->fetchField();
  459. }
  460. }