Chris@0: adminUser = $this->drupalCreateUser($perms); Chris@0: $this->adminUser2 = $this->drupalCreateUser($perms); Chris@0: Chris@0: $this->drupalLogin($this->adminUser); Chris@0: Chris@0: $this->drupalGet('test-page'); Chris@0: $this->assertResponse(200); Chris@0: Chris@0: // Assert that the toolbar is present in the HTML. Chris@0: $this->assertRaw('id="toolbar-administration"'); Chris@0: Chris@0: // Store the adminUser admin menu subtrees hash for comparison later. Chris@0: $this->hash = $this->getSubtreesHash(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the toolbar_modules_installed() and toolbar_modules_uninstalled() hook Chris@0: * implementations. Chris@0: */ Chris@0: public function testModuleStatusChangeSubtreesHashCacheClear() { Chris@0: // Uninstall a module. Chris@0: $edit = []; Chris@0: $edit['uninstall[taxonomy]'] = TRUE; Chris@0: $this->drupalPostForm('admin/modules/uninstall', $edit, t('Uninstall')); Chris@0: // Confirm the uninstall form. Chris@0: $this->drupalPostForm(NULL, [], t('Uninstall')); Chris@0: $this->rebuildContainer(); Chris@0: Chris@0: // Assert that the subtrees hash has been altered because the subtrees Chris@0: // structure changed. Chris@0: $this->assertDifferentHash(); Chris@0: Chris@0: // Enable a module. Chris@0: $edit = []; Chris@0: $edit['modules[taxonomy][enable]'] = TRUE; Chris@0: $this->drupalPostForm('admin/modules', $edit, t('Install')); Chris@0: $this->rebuildContainer(); Chris@0: Chris@0: // Assert that the subtrees hash has been altered because the subtrees Chris@0: // structure changed. Chris@0: $this->assertDifferentHash(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests toolbar cache tags implementation. Chris@0: */ Chris@0: public function testMenuLinkUpdateSubtreesHashCacheClear() { Chris@0: // The ID of a (any) admin menu link. Chris@0: $admin_menu_link_id = 'system.admin_config_development'; Chris@0: Chris@0: // Disable the link. Chris@0: $edit = []; Chris@0: $edit['enabled'] = FALSE; Chris@0: $this->drupalPostForm("admin/structure/menu/link/" . $admin_menu_link_id . "/edit", $edit, t('Save')); Chris@0: $this->assertResponse(200); Chris@0: $this->assertText('The menu link has been saved.'); Chris@0: Chris@0: // Assert that the subtrees hash has been altered because the subtrees Chris@0: // structure changed. Chris@0: $this->assertDifferentHash(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Exercises the toolbar_user_role_update() and toolbar_user_update() hook Chris@0: * implementations. Chris@0: */ Chris@0: public function testUserRoleUpdateSubtreesHashCacheClear() { Chris@0: // Find the new role ID. Chris@0: $all_rids = $this->adminUser->getRoles(); Chris@0: unset($all_rids[array_search(RoleInterface::AUTHENTICATED_ID, $all_rids)]); Chris@0: $rid = reset($all_rids); Chris@0: Chris@0: $edit = []; Chris@0: $edit[$rid . '[administer taxonomy]'] = FALSE; Chris@0: $this->drupalPostForm('admin/people/permissions', $edit, t('Save permissions')); Chris@0: Chris@0: // Assert that the subtrees hash has been altered because the subtrees Chris@0: // structure changed. Chris@0: $this->assertDifferentHash(); Chris@0: Chris@0: // Test that assigning a user an extra role only affects that single user. Chris@0: // Get the hash for a second user. Chris@0: $this->drupalLogin($this->adminUser2); Chris@0: $this->drupalGet('test-page'); Chris@0: $this->assertResponse(200); Chris@0: Chris@0: // Assert that the toolbar is present in the HTML. Chris@0: $this->assertRaw('id="toolbar-administration"'); Chris@0: Chris@0: $admin_user_2_hash = $this->getSubtreesHash(); Chris@0: Chris@0: // Log in the first admin user again. Chris@0: $this->drupalLogin($this->adminUser); Chris@0: $this->drupalGet('test-page'); Chris@0: $this->assertResponse(200); Chris@0: Chris@0: // Assert that the toolbar is present in the HTML. Chris@0: $this->assertRaw('id="toolbar-administration"'); Chris@0: Chris@0: $this->hash = $this->getSubtreesHash(); Chris@0: Chris@0: $rid = $this->drupalCreateRole(['administer content types']); Chris@0: Chris@0: // Assign the role to the user. Chris@0: $this->drupalPostForm('user/' . $this->adminUser->id() . '/edit', ["roles[$rid]" => $rid], t('Save')); Chris@0: $this->assertText(t('The changes have been saved.')); Chris@0: Chris@0: // Assert that the subtrees hash has been altered because the subtrees Chris@0: // structure changed. Chris@0: $this->assertDifferentHash(); Chris@0: Chris@0: // Log in the second user again and assert that their subtrees hash did not Chris@0: // change. Chris@0: $this->drupalLogin($this->adminUser2); Chris@0: Chris@0: // Request a new page to refresh the drupalSettings object. Chris@0: $this->drupalGet('test-page'); Chris@0: $this->assertResponse(200); Chris@0: $new_subtree_hash = $this->getSubtreesHash(); Chris@0: Chris@0: // Assert that the old admin menu subtree hash and the new admin menu Chris@0: // subtree hash are the same. Chris@0: $this->assertTrue($new_subtree_hash, 'A valid hash value for the admin menu subtrees was created.'); Chris@0: $this->assertEqual($admin_user_2_hash, $new_subtree_hash, 'The user-specific subtree menu hash has not been updated.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that changes to a user account by another user clears the changed Chris@0: * account's toolbar cached, not the user's who took the action. Chris@0: */ Chris@0: public function testNonCurrentUserAccountUpdates() { Chris@0: $admin_user_id = $this->adminUser->id(); Chris@0: $this->hash = $this->getSubtreesHash(); Chris@0: Chris@0: // adminUser2 will add a role to adminUser. Chris@0: $this->drupalLogin($this->adminUser2); Chris@0: $rid = $this->drupalCreateRole(['administer content types']); Chris@0: Chris@0: // Get the subtree hash for adminUser2 to check later that it has not Chris@0: // changed. Request a new page to refresh the drupalSettings object. Chris@0: $this->drupalGet('test-page'); Chris@0: $this->assertResponse(200); Chris@0: $admin_user_2_hash = $this->getSubtreesHash(); Chris@0: Chris@0: // Assign the role to the user. Chris@0: $this->drupalPostForm('user/' . $admin_user_id . '/edit', ["roles[$rid]" => $rid], t('Save')); Chris@0: $this->assertText(t('The changes have been saved.')); Chris@0: Chris@0: // Log in adminUser and assert that the subtrees hash has changed. Chris@0: $this->drupalLogin($this->adminUser); Chris@0: $this->assertDifferentHash(); Chris@0: Chris@0: // Log in adminUser2 to check that its subtrees hash has not changed. Chris@0: $this->drupalLogin($this->adminUser2); Chris@0: $new_subtree_hash = $this->getSubtreesHash(); Chris@0: Chris@0: // Assert that the old adminUser subtree hash and the new adminUser Chris@0: // subtree hash are the same. Chris@0: $this->assertTrue($new_subtree_hash, 'A valid hash value for the admin menu subtrees was created.'); Chris@0: $this->assertEqual($admin_user_2_hash, $new_subtree_hash, 'The user-specific subtree menu hash has not been updated.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that toolbar cache is cleared when string translations are made. Chris@0: */ Chris@0: public function testLocaleTranslationSubtreesHashCacheClear() { Chris@0: $admin_user = $this->adminUser; Chris@0: // User to translate and delete string. Chris@0: $translate_user = $this->drupalCreateUser(['translate interface', 'access administration pages']); Chris@0: Chris@0: // Create a new language with the langcode 'xx'. Chris@0: $langcode = 'xx'; Chris@0: // The English name for the language. This will be translated. Chris@0: $name = $this->randomMachineName(16); Chris@0: // This will be the translation of $name. Chris@0: $translation = $this->randomMachineName(16); Chris@0: Chris@0: // Add custom language. Chris@0: $this->drupalLogin($admin_user); Chris@0: $edit = [ Chris@0: 'predefined_langcode' => 'custom', Chris@0: 'langcode' => $langcode, Chris@0: 'label' => $name, Chris@0: 'direction' => LanguageInterface::DIRECTION_LTR, Chris@0: ]; Chris@0: $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language')); Chris@0: t($name, [], ['langcode' => $langcode]); Chris@0: // Reset locale cache. Chris@0: $this->container->get('string_translation')->reset(); Chris@0: $this->assertRaw('"edit-languages-' . $langcode . '-weight"', 'Language code found.'); Chris@0: $this->assertText(t($name), 'Test language added.'); Chris@0: Chris@0: // Have the adminUser request a page in the new language. Chris@0: $this->drupalGet($langcode . '/test-page'); Chris@0: $this->assertResponse(200); Chris@0: Chris@0: // Get a baseline hash for the admin menu subtrees before translating one Chris@0: // of the menu link items. Chris@0: $original_subtree_hash = $this->getSubtreesHash(); Chris@0: $this->assertTrue($original_subtree_hash, 'A valid hash value for the admin menu subtrees was created.'); Chris@0: $this->drupalLogout(); Chris@0: Chris@0: // Translate the string 'Search and metadata' in the xx language. This Chris@0: // string appears in a link in the admin menu subtrees. Changing the string Chris@0: // should create a new menu hash if the toolbar subtrees cache is correctly Chris@0: // invalidated. Chris@0: $this->drupalLogin($translate_user); Chris@0: $search = [ Chris@0: 'string' => 'Search and metadata', Chris@0: 'langcode' => $langcode, Chris@0: 'translation' => 'untranslated', Chris@0: ]; Chris@0: $this->drupalPostForm('admin/config/regional/translate', $search, t('Filter')); Chris@0: $this->assertNoText(t('No strings available')); Chris@0: $this->assertText($name, 'Search found the string as untranslated.'); Chris@0: Chris@0: // Assume this is the only result. Chris@0: // Translate the string to a random string. Chris@0: $textarea = current($this->xpath('//textarea')); Chris@0: $lid = (string) $textarea->getAttribute('name'); Chris@0: $edit = [ Chris@0: $lid => $translation, Chris@0: ]; Chris@0: $this->drupalPostForm('admin/config/regional/translate', $edit, t('Save translations')); Chris@0: $this->assertText(t('The strings have been saved.'), 'The strings have been saved.'); Chris@18: $this->assertUrl(Url::fromRoute('locale.translate_page', [], ['absolute' => TRUE])->toString(), [], 'Correct page redirection.'); Chris@0: $this->drupalLogout(); Chris@0: Chris@0: // Log in the adminUser. Check the admin menu subtrees hash now that one Chris@0: // of the link items in the Structure tree (Menus) has had its text Chris@0: // translated. Chris@0: $this->drupalLogin($admin_user); Chris@0: // Have the adminUser request a page in the new language. Chris@0: $this->drupalGet($langcode . '/test-page'); Chris@0: $this->assertResponse(200); Chris@0: $new_subtree_hash = $this->getSubtreesHash(); Chris@0: Chris@0: // Assert that the old admin menu subtrees hash and the new admin menu Chris@0: // subtrees hash are different. Chris@0: $this->assertTrue($new_subtree_hash, 'A valid hash value for the admin menu subtrees was created.'); Chris@0: $this->assertNotEqual($original_subtree_hash, $new_subtree_hash, 'The user-specific subtree menu hash has been updated.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that the 'toolbar/subtrees/{hash}' is reachable and correct. Chris@0: */ Chris@0: public function testSubtreesJsonRequest() { Chris@0: $admin_user = $this->adminUser; Chris@0: $this->drupalLogin($admin_user); Chris@0: // Request a new page to refresh the drupalSettings object. Chris@0: $subtrees_hash = $this->getSubtreesHash(); Chris@0: Chris@0: $this->drupalGet('toolbar/subtrees/' . $subtrees_hash, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']], ['X-Requested-With: XMLHttpRequest']); Chris@0: $ajax_result = json_decode($this->getSession()->getPage()->getContent(), TRUE); Chris@0: $this->assertEqual($ajax_result[0]['command'], 'setToolbarSubtrees', 'Subtrees response uses the correct command.'); Chris@0: $this->assertEqual(array_keys($ajax_result[0]['subtrees']), ['system-admin_content', 'system-admin_structure', 'system-themes_page', 'system-modules_list', 'system-admin_config', 'entity-user-collection', 'front'], 'Correct subtrees returned.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Test that subtrees hashes vary by the language of the page. Chris@0: */ Chris@0: public function testLanguageSwitching() { Chris@0: // Create a new language with the langcode 'xx'. Chris@0: $langcode = 'xx'; Chris@0: $language = ConfigurableLanguage::createFromLangcode($langcode); Chris@0: $language->save(); Chris@0: // The language path processor is just registered for more than one Chris@0: // configured language, so rebuild the container now that we are Chris@0: // multilingual. Chris@0: $this->rebuildContainer(); Chris@0: Chris@0: // Get a page with the new language langcode in the URL. Chris@0: $this->drupalGet('test-page', ['language' => $language]); Chris@0: // Assert different hash. Chris@0: $new_subtree_hash = $this->getSubtreesHash(); Chris@0: Chris@0: // Assert that the old admin menu subtree hash and the new admin menu Chris@0: // subtree hash are different. Chris@0: $this->assertTrue($new_subtree_hash, 'A valid hash value for the admin menu subtrees was created.'); Chris@0: $this->assertNotEqual($this->hash, $new_subtree_hash, 'The user-specific subtree menu hash has been updated.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Test that back to site link exists on admin pages, not on content pages. Chris@0: */ Chris@0: public function testBackToSiteLink() { Chris@0: // Back to site link should exist in the markup. Chris@0: $this->drupalGet('test-page'); Chris@0: $back_link = $this->cssSelect('.home-toolbar-tab'); Chris@0: $this->assertTrue($back_link); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that external links added to the menu appear in the toolbar. Chris@0: */ Chris@0: public function testExternalLink() { Chris@0: $edit = [ Chris@0: 'title[0][value]' => 'External URL', Chris@0: 'link[0][uri]' => 'http://example.org', Chris@0: 'menu_parent' => 'admin:system.admin', Chris@0: 'description[0][value]' => 'External URL & escaped', Chris@0: ]; Chris@0: $this->drupalPostForm('admin/structure/menu/manage/admin/add', $edit, 'Save'); Chris@0: Chris@0: // Assert that the new menu link is shown on the menu link listing. Chris@0: $this->drupalGet('admin/structure/menu/manage/admin'); Chris@0: $this->assertText('External URL'); Chris@0: Chris@0: // Assert that the new menu link is shown in the toolbar on a regular page. Chris@0: $this->drupalGet(Url::fromRoute('')); Chris@0: $this->assertText('External URL'); Chris@0: // Ensure the description is escaped as expected. Chris@0: $this->assertRaw('title="External URL & escaped"'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the hash value from the admin menu subtrees route path. Chris@0: * Chris@0: * @return string Chris@0: * The hash value from the admin menu subtrees route path. Chris@0: */ Chris@0: private function getSubtreesHash() { Chris@0: $settings = $this->getDrupalSettings(); Chris@0: // The toolbar module defines a route '/toolbar/subtrees/{hash}' that Chris@0: // returns JSON for the rendered subtrees. This hash is provided to the Chris@0: // client in drupalSettings. Chris@0: return $settings['toolbar']['subtreesHash']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Asserts the subtrees hash on a fresh page GET is different from the hash Chris@0: * from the previous page GET. Chris@0: */ Chris@0: private function assertDifferentHash() { Chris@0: // Request a new page to refresh the drupalSettings object. Chris@0: $this->drupalGet('test-page'); Chris@0: $this->assertResponse(200); Chris@0: $new_subtree_hash = $this->getSubtreesHash(); Chris@0: Chris@0: // Assert that the old admin menu subtree hash and the new admin menu Chris@0: // subtree hash are different. Chris@0: $this->assertTrue($new_subtree_hash, 'A valid hash value for the admin menu subtrees was created.'); Chris@0: $this->assertNotEqual($this->hash, $new_subtree_hash, 'The user-specific subtree menu hash has been updated.'); Chris@0: Chris@0: // Save the new subtree hash as the original. Chris@0: $this->hash = $new_subtree_hash; Chris@0: } Chris@0: Chris@0: }