/** * Checks node revision related operations. */ function testRevisions() { $node_storage = $this->container->get('entity.manager')->getStorage('node'); $nodes = $this->nodes; $logs = $this->revisionLogs; // Get last node for simple checks. $node = $nodes[3]; // Confirm the correct revision text appears on "view revisions" page. $this->drupalGet("node/" . $node->id() . "/revisions/" . $node->getRevisionId() . "/view"); $this->assertText($node->body->value, 'Correct text displays for version.'); // Confirm the correct log message appears on "revisions overview" page. $this->drupalGet("node/" . $node->id() . "/revisions"); foreach ($logs as $revision_log) { $this->assertText($revision_log, 'Revision log message found.'); } // Confirm that this is the default revision. $this->assertTrue($node->isDefaultRevision(), 'Third node revision is the default one.'); // Confirm that revisions revert properly. $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionid() . "/revert", array(), t('Revert')); $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.', array('@type' => 'Basic page', '%title' => $nodes[1]->label(), '%revision-date' => format_date($nodes[1]->getRevisionCreationTime()))), 'Revision reverted.'); $node_storage->resetCache(array($node->id())); $reverted_node = $node_storage->load($node->id()); $this->assertTrue($nodes[1]->body->value == $reverted_node->body->value, 'Node reverted correctly.'); // Confirm that this is not the default version. $node = node_revision_load($node->getRevisionId()); $this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the default one.'); // Confirm revisions delete properly. $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/delete", array(), t('Delete')); $this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.', array('%revision-date' => format_date($nodes[1]->getRevisionCreationTime()), '@type' => 'Basic page', '%title' => $nodes[1]->label())), 'Revision deleted.'); $this->assertTrue(db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid and vid = :vid', array(':nid' => $node->id(), ':vid' => $nodes[1]->getRevisionId()))->fetchField() == 0, 'Revision not found.'); // Set the revision timestamp to an older date to make sure that the // confirmation message correctly displays the stored revision date. $old_revision_date = REQUEST_TIME - 86400; db_update('node_revision')->condition('vid', $nodes[2]->getRevisionId())->fields(array('revision_timestamp' => $old_revision_date))->execute(); $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[2]->getRevisionId() . "/revert", array(), t('Revert')); $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.', array('@type' => 'Basic page', '%title' => $nodes[2]->label(), '%revision-date' => format_date($old_revision_date)))); // Make a new revision and set it to not be default. // This will create a new revision that is not "front facing". $new_node_revision = clone $node; $new_body = $this->randomMachineName(); $new_node_revision->body->value = $new_body; // Save this as a non-default revision. $new_node_revision->setNewRevision(); $new_node_revision->isDefaultRevision = FALSE; $new_node_revision->save(); $this->drupalGet('node/' . $node->id()); $this->assertNoText($new_body, 'Revision body text is not present on default version of node.'); // Verify that the new body text is present on the revision. $this->drupalGet("node/" . $node->id() . "/revisions/" . $new_node_revision->getRevisionId() . "/view"); $this->assertText($new_body, 'Revision body text is present when loading specific revision.'); // Verify that the non-default revision vid is greater than the default // revision vid. $default_revision = db_select('node', 'n')->fields('n', array('vid'))->condition('nid', $node->id())->execute()->fetchCol(); $default_revision_vid = $default_revision[0]; $this->assertTrue($new_node_revision->getRevisionId() > $default_revision_vid, 'Revision vid is greater than default revision vid.'); }
/** * Checks node edit functionality. */ function testPageEdit() { $this->drupalLogin($this->web_user); $title_key = 'title[0][value]'; $body_key = 'body[0][value]'; // Create node to edit. $edit = array(); $edit[$title_key] = $this->randomName(8); $edit[$body_key] = $this->randomName(16); $this->drupalPostForm('node/add/page', $edit, t('Save')); // Check that the node exists in the database. $node = $this->drupalGetNodeByTitle($edit[$title_key]); $this->assertTrue($node, 'Node found in database.'); // Check that "edit" link points to correct page. $this->clickLink(t('Edit')); $edit_url = url("node/" . $node->id() . "/edit", array('absolute' => TRUE)); $actual_url = $this->getURL(); $this->assertEqual($edit_url, $actual_url, 'On edit page.'); // Check that the title and body fields are displayed with the correct values. $active = '<span class="visually-hidden">' . t('(active tab)') . '</span>'; $link_text = t('!local-task-title!active', array('!local-task-title' => t('Edit'), '!active' => $active)); $this->assertText(strip_tags($link_text), 0, 'Edit tab found and marked active.'); $this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.'); $this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.'); // Edit the content of the node. $edit = array(); $edit[$title_key] = $this->randomName(8); $edit[$body_key] = $this->randomName(16); // Stay on the current page, without reloading. $this->drupalPostForm(NULL, $edit, t('Save')); // Check that the title and body fields are displayed with the updated values. $this->assertText($edit[$title_key], 'Title displayed.'); $this->assertText($edit[$body_key], 'Body displayed.'); // Login as a second administrator user. $second_web_user = $this->drupalCreateUser(array('administer nodes', 'edit any page content')); $this->drupalLogin($second_web_user); // Edit the same node, creating a new revision. $this->drupalGet("node/" . $node->id() . "/edit"); $edit = array(); $edit['title[0][value]'] = $this->randomName(8); $edit[$body_key] = $this->randomName(16); $edit['revision'] = TRUE; $this->drupalPostForm(NULL, $edit, t('Save and keep published')); // Ensure that the node revision has been created. $revised_node = $this->drupalGetNodeByTitle($edit['title[0][value]'], TRUE); $this->assertNotIdentical($node->getRevisionId(), $revised_node->getRevisionId(), 'A new revision has been created.'); // Ensure that the node author is preserved when it was not changed in the // edit form. $this->assertIdentical($node->getOwnerId(), $revised_node->getOwnerId(), 'The node author has been preserved.'); // Ensure that the revision authors are different since the revisions were // made by different users. $first_node_version = node_revision_load($node->getRevisionId()); $second_node_version = node_revision_load($revised_node->getRevisionId()); $this->assertNotIdentical($first_node_version->getRevisionAuthor()->id(), $second_node_version->getRevisionAuthor()->id(), 'Each revision has a distinct user.'); }
/** * Checks node revision operations. */ function testRevisions() { $node_storage = $this->container->get('entity.manager')->getStorage('node'); $nodes = $this->nodes; $logs = $this->revisionLogs; // Get last node for simple checks. $node = $nodes[3]; // Create and login user. $content_admin = $this->drupalCreateUser(array('view all revisions', 'revert all revisions', 'delete all revisions', 'edit any page content', 'delete any page content')); $this->drupalLogin($content_admin); // Confirm the correct revision text appears on "view revisions" page. $this->drupalGet("node/" . $node->id() . "/revisions/" . $node->getRevisionId() . "/view"); $this->assertText($node->body->value, 'Correct text displays for version.'); // Confirm the correct revision log message appears on the "revisions // overview" page. $this->drupalGet("node/" . $node->id() . "/revisions"); foreach ($logs as $revision_log) { $this->assertText($revision_log, 'Revision log message found.'); } // Confirm that this is the current revision. $this->assertTrue($node->isDefaultRevision(), 'Third node revision is the current one.'); // Confirm that revisions revert properly. $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/revert", array(), t('Revert')); $this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', array('@type' => 'Basic page', '%title' => $nodes[1]->getTitle(), '%revision-date' => format_date($nodes[1]->getRevisionCreationTime()))), 'Revision reverted.'); $node_storage->resetCache(array($node->id())); $reverted_node = $node_storage->load($node->id()); $this->assertTrue($nodes[1]->body->value == $reverted_node->body->value, 'Node reverted correctly.'); // Confirm that this is not the current version. $node = node_revision_load($node->getRevisionId()); $this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the current one.'); // Confirm revisions delete properly. $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/delete", array(), t('Delete')); $this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.', array('%revision-date' => format_date($nodes[1]->getRevisionCreationTime()), '@type' => 'Basic page', '%title' => $nodes[1]->getTitle())), 'Revision deleted.'); $this->assertTrue(db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid and vid = :vid', array(':nid' => $node->id(), ':vid' => $nodes[1]->getRevisionId()))->fetchField() == 0, 'Revision not found.'); // Set the revision timestamp to an older date to make sure that the // confirmation message correctly displays the stored revision date. $old_revision_date = REQUEST_TIME - 86400; db_update('node_revision')->condition('vid', $nodes[2]->getRevisionId())->fields(array('revision_timestamp' => $old_revision_date))->execute(); $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[2]->getRevisionId() . "/revert", array(), t('Revert')); $this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', array('@type' => 'Basic page', '%title' => $nodes[2]->getTitle(), '%revision-date' => format_date($old_revision_date)))); }
/** * Tests creating multiple revisions of a node and managing attached files. * * Expected behaviors: * - Adding a new revision will make another entry in the field table, but * the original file will not be duplicated. * - Deleting a revision should not delete the original file if the file * is in use by another revision. * - When the last revision that uses a file is deleted, the original file * should be deleted also. */ function testRevisions() { $node_storage = $this->container->get('entity.manager')->getStorage('node'); $type_name = 'article'; $field_name = strtolower($this->randomMachineName()); $this->createFileField($field_name, 'node', $type_name); // Create the same fields for users. $this->createFileField($field_name, 'user', 'user'); $test_file = $this->getTestFile('text'); // Create a new node with the uploaded file. $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); // Check that the file exists on disk and in the database. $node_storage->resetCache(array($nid)); $node = $node_storage->load($nid); $node_file_r1 = File::load($node->{$field_name}->target_id); $node_vid_r1 = $node->getRevisionId(); $this->assertFileExists($node_file_r1, 'New file saved to disk on node creation.'); $this->assertFileEntryExists($node_file_r1, 'File entry exists in database on node creation.'); $this->assertFileIsPermanent($node_file_r1, 'File is permanent.'); // Upload another file to the same node in a new revision. $this->replaceNodeFile($test_file, $field_name, $nid); $node_storage->resetCache(array($nid)); $node = $node_storage->load($nid); $node_file_r2 = File::load($node->{$field_name}->target_id); $node_vid_r2 = $node->getRevisionId(); $this->assertFileExists($node_file_r2, 'Replacement file exists on disk after creating new revision.'); $this->assertFileEntryExists($node_file_r2, 'Replacement file entry exists in database after creating new revision.'); $this->assertFileIsPermanent($node_file_r2, 'Replacement file is permanent.'); // Check that the original file is still in place on the first revision. $node = node_revision_load($node_vid_r1); $current_file = File::load($node->{$field_name}->target_id); $this->assertEqual($node_file_r1->id(), $current_file->id(), 'Original file still in place after replacing file in new revision.'); $this->assertFileExists($node_file_r1, 'Original file still in place after replacing file in new revision.'); $this->assertFileEntryExists($node_file_r1, 'Original file entry still in place after replacing file in new revision'); $this->assertFileIsPermanent($node_file_r1, 'Original file is still permanent.'); // Save a new version of the node without any changes. // Check that the file is still the same as the previous revision. $this->drupalPostForm('node/' . $nid . '/edit', array('revision' => '1'), t('Save and keep published')); $node_storage->resetCache(array($nid)); $node = $node_storage->load($nid); $node_file_r3 = File::load($node->{$field_name}->target_id); $node_vid_r3 = $node->getRevisionId(); $this->assertEqual($node_file_r2->id(), $node_file_r3->id(), 'Previous revision file still in place after creating a new revision without a new file.'); $this->assertFileIsPermanent($node_file_r3, 'New revision file is permanent.'); // Revert to the first revision and check that the original file is active. $this->drupalPostForm('node/' . $nid . '/revisions/' . $node_vid_r1 . '/revert', array(), t('Revert')); $node_storage->resetCache(array($nid)); $node = $node_storage->load($nid); $node_file_r4 = File::load($node->{$field_name}->target_id); $this->assertEqual($node_file_r1->id(), $node_file_r4->id(), 'Original revision file still in place after reverting to the original revision.'); $this->assertFileIsPermanent($node_file_r4, 'Original revision file still permanent after reverting to the original revision.'); // Delete the second revision and check that the file is kept (since it is // still being used by the third revision). $this->drupalPostForm('node/' . $nid . '/revisions/' . $node_vid_r2 . '/delete', array(), t('Delete')); $this->assertFileExists($node_file_r3, 'Second file is still available after deleting second revision, since it is being used by the third revision.'); $this->assertFileEntryExists($node_file_r3, 'Second file entry is still available after deleting second revision, since it is being used by the third revision.'); $this->assertFileIsPermanent($node_file_r3, 'Second file entry is still permanent after deleting second revision, since it is being used by the third revision.'); // Attach the second file to a user. $user = $this->drupalCreateUser(); $user->{$field_name}->target_id = $node_file_r3->id(); $user->{$field_name}->display = 1; $user->save(); $this->drupalGet('user/' . $user->id() . '/edit'); // Delete the third revision and check that the file is not deleted yet. $this->drupalPostForm('node/' . $nid . '/revisions/' . $node_vid_r3 . '/delete', array(), t('Delete')); $this->assertFileExists($node_file_r3, 'Second file is still available after deleting third revision, since it is being used by the user.'); $this->assertFileEntryExists($node_file_r3, 'Second file entry is still available after deleting third revision, since it is being used by the user.'); $this->assertFileIsPermanent($node_file_r3, 'Second file entry is still permanent after deleting third revision, since it is being used by the user.'); // Delete the user and check that the file is also deleted. $user->delete(); // TODO: This seems like a bug in File API. Clearing the stat cache should // not be necessary here. The file really is deleted, but stream wrappers // doesn't seem to think so unless we clear the PHP file stat() cache. clearstatcache($node_file_r1->getFileUri()); clearstatcache($node_file_r2->getFileUri()); clearstatcache($node_file_r3->getFileUri()); clearstatcache($node_file_r4->getFileUri()); // Call file_cron() to clean up the file. Make sure the changed timestamp // of the file is older than the system.file.temporary_maximum_age // configuration value. db_update('file_managed')->fields(array('changed' => REQUEST_TIME - ($this->config('system.file')->get('temporary_maximum_age') + 1)))->condition('fid', $node_file_r3->id())->execute(); \Drupal::service('cron')->run(); $this->assertFileNotExists($node_file_r3, 'Second file is now deleted after deleting third revision, since it is no longer being used by any other nodes.'); $this->assertFileEntryNotExists($node_file_r3, 'Second file entry is now deleted after deleting third revision, since it is no longer being used by any other nodes.'); // Delete the entire node and check that the original file is deleted. $this->drupalPostForm('node/' . $nid . '/delete', array(), t('Delete')); // Call file_cron() to clean up the file. Make sure the changed timestamp // of the file is older than the system.file.temporary_maximum_age // configuration value. db_update('file_managed')->fields(array('changed' => REQUEST_TIME - ($this->config('system.file')->get('temporary_maximum_age') + 1)))->condition('fid', $node_file_r1->id())->execute(); \Drupal::service('cron')->run(); $this->assertFileNotExists($node_file_r1, 'Original file is deleted after deleting the entire node with two revisions remaining.'); $this->assertFileEntryNotExists($node_file_r1, 'Original file entry is deleted after deleting the entire node with two revisions remaining.'); }
/** * Checks node revision related operations. */ function testRevisions() { $node_storage = $this->container->get('entity.manager')->getStorage('node'); $nodes = $this->nodes; $logs = $this->revisionLogs; // Get last node for simple checks. $node = $nodes[3]; // Confirm the correct revision text appears on "view revisions" page. $this->drupalGet("node/" . $node->id() . "/revisions/" . $node->getRevisionId() . "/view"); $this->assertText($node->body->value, 'Correct text displays for version.'); // Confirm the correct log message appears on "revisions overview" page. $this->drupalGet("node/" . $node->id() . "/revisions"); foreach ($logs as $revision_log) { $this->assertText($revision_log, 'Revision log message found.'); } // Original author, and editor names should appear on revisions overview. $web_user = $nodes[0]->revision_uid->entity; $this->assertText(t('by @name', ['@name' => $web_user->getAccountName()])); $editor = $nodes[2]->revision_uid->entity; $this->assertText(t('by @name', ['@name' => $editor->getAccountName()])); // Confirm that this is the default revision. $this->assertTrue($node->isDefaultRevision(), 'Third node revision is the default one.'); // Confirm that the "Edit" and "Delete" contextual links appear for the // default revision. $ids = ['node:node=' . $node->id() . ':changed=' . $node->getChangedTime()]; $json = $this->renderContextualLinks($ids, 'node/' . $node->id()); $this->verbose($json[$ids[0]]); $expected = '<li class="entitynodeedit-form"><a href="' . base_path() . 'node/' . $node->id() . '/edit">Edit</a></li>'; $this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Edit" contextual link is shown for the default revision.'); $expected = '<li class="entitynodedelete-form"><a href="' . base_path() . 'node/' . $node->id() . '/delete">Delete</a></li>'; $this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Delete" contextual link is shown for the default revision.'); // Confirm that revisions revert properly. $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionid() . "/revert", array(), t('Revert')); $this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', array('@type' => 'Basic page', '%title' => $nodes[1]->label(), '%revision-date' => format_date($nodes[1]->getRevisionCreationTime()))), 'Revision reverted.'); $node_storage->resetCache(array($node->id())); $reverted_node = $node_storage->load($node->id()); $this->assertTrue($nodes[1]->body->value == $reverted_node->body->value, 'Node reverted correctly.'); // Confirm that this is not the default version. $node = node_revision_load($node->getRevisionId()); $this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the default one.'); // Confirm that "Edit" and "Delete" contextual links don't appear for // non-default revision. $ids = ['node_revision::node=' . $node->id() . '&node_revision=' . $node->getRevisionId() . ':']; $json = $this->renderContextualLinks($ids, 'node/' . $node->id() . '/revisions/' . $node->getRevisionId() . '/view'); $this->verbose($json[$ids[0]]); $this->assertFalse(strstr($json[$ids[0]], '<li class="entitynodeedit-form">'), 'The "Edit" contextual link is not shown for a non-default revision.'); $this->assertFalse(strstr($json[$ids[0]], '<li class="entitynodedelete-form">'), 'The "Delete" contextual link is not shown for a non-default revision.'); // Confirm revisions delete properly. $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/delete", array(), t('Delete')); $this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.', array('%revision-date' => format_date($nodes[1]->getRevisionCreationTime()), '@type' => 'Basic page', '%title' => $nodes[1]->label())), 'Revision deleted.'); $this->assertTrue(db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid and vid = :vid', array(':nid' => $node->id(), ':vid' => $nodes[1]->getRevisionId()))->fetchField() == 0, 'Revision not found.'); // Set the revision timestamp to an older date to make sure that the // confirmation message correctly displays the stored revision date. $old_revision_date = REQUEST_TIME - 86400; db_update('node_revision')->condition('vid', $nodes[2]->getRevisionId())->fields(array('revision_timestamp' => $old_revision_date))->execute(); $this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[2]->getRevisionId() . "/revert", array(), t('Revert')); $this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', array('@type' => 'Basic page', '%title' => $nodes[2]->label(), '%revision-date' => format_date($old_revision_date)))); // Make a new revision and set it to not be default. // This will create a new revision that is not "front facing". $new_node_revision = clone $node; $new_body = $this->randomMachineName(); $new_node_revision->body->value = $new_body; // Save this as a non-default revision. $new_node_revision->setNewRevision(); $new_node_revision->isDefaultRevision = FALSE; $new_node_revision->save(); $this->drupalGet('node/' . $node->id()); $this->assertNoText($new_body, 'Revision body text is not present on default version of node.'); // Verify that the new body text is present on the revision. $this->drupalGet("node/" . $node->id() . "/revisions/" . $new_node_revision->getRevisionId() . "/view"); $this->assertText($new_body, 'Revision body text is present when loading specific revision.'); // Verify that the non-default revision vid is greater than the default // revision vid. $default_revision = db_select('node', 'n')->fields('n', array('vid'))->condition('nid', $node->id())->execute()->fetchCol(); $default_revision_vid = $default_revision[0]; $this->assertTrue($new_node_revision->getRevisionId() > $default_revision_vid, 'Revision vid is greater than default revision vid.'); // Create an 'EN' node with a revision log message. $node = $this->drupalCreateNode(); $node->title = 'Node title in EN'; $node->revision_log = 'Simple revision message (EN)'; $node->save(); $this->drupalGet("node/" . $node->id() . "/revisions"); $this->assertResponse(403); // Create a new revision and new log message. $node = Node::load($node->id()); $node->body->value = 'New text (EN)'; $node->revision_log = 'New revision message (EN)'; $node->setNewRevision(); $node->save(); // Check both revisions are shown on the node revisions overview page. $this->drupalGet("node/" . $node->id() . "/revisions"); $this->assertText('Simple revision message (EN)'); $this->assertText('New revision message (EN)'); // Create an 'EN' node with a revision log message. $node = $this->drupalCreateNode(); $node->langcode = 'en'; $node->title = 'Node title in EN'; $node->revision_log = 'Simple revision message (EN)'; $node->save(); $this->drupalGet("node/" . $node->id() . "/revisions"); $this->assertResponse(403); // Add a translation in 'DE' and create a new revision and new log message. $translation = $node->addTranslation('de'); $translation->title->value = 'Node title in DE'; $translation->body->value = 'New text (DE)'; $translation->revision_log = 'New revision message (DE)'; $translation->setNewRevision(); $translation->save(); // View the revision UI in 'IT', only the original node revision is shown. $this->drupalGet("it/node/" . $node->id() . "/revisions"); $this->assertText('Simple revision message (EN)'); $this->assertNoText('New revision message (DE)'); // View the revision UI in 'DE', only the translated node revision is shown. $this->drupalGet("de/node/" . $node->id() . "/revisions"); $this->assertNoText('Simple revision message (EN)'); $this->assertText('New revision message (DE)'); // View the revision UI in 'EN', only the original node revision is shown. $this->drupalGet("node/" . $node->id() . "/revisions"); $this->assertText('Simple revision message (EN)'); $this->assertNoText('New revision message (DE)'); }
/** * Checks node edit functionality. */ public function testNodeEdit() { $this->drupalLogin($this->webUser); $title_key = 'title[0][value]'; $body_key = 'body[0][value]'; // Create node to edit. $edit = array(); $edit[$title_key] = $this->randomMachineName(8); $edit[$body_key] = $this->randomMachineName(16); $this->drupalPostForm('node/add/page', $edit, t('Save')); // Check that the node exists in the database. $node = $this->drupalGetNodeByTitle($edit[$title_key]); $this->assertTrue($node, 'Node found in database.'); // Check that "edit" link points to correct page. $this->clickLink(t('Edit')); $this->assertUrl($node->url('edit-form', ['absolute' => TRUE])); // Check that the title and body fields are displayed with the correct values. // As you see the expected link text has no HTML, but we are using $link_text = 'Edit<span class="visually-hidden">(active tab)</span>'; // @todo Ideally assertLink would support HTML, but it doesn't. $this->assertRaw($link_text, 'Edit tab found and marked active.'); $this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.'); $this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.'); // Edit the content of the node. $edit = array(); $edit[$title_key] = $this->randomMachineName(8); $edit[$body_key] = $this->randomMachineName(16); // Stay on the current page, without reloading. $this->drupalPostForm(NULL, $edit, t('Save')); // Check that the title and body fields are displayed with the updated values. $this->assertText($edit[$title_key], 'Title displayed.'); $this->assertText($edit[$body_key], 'Body displayed.'); // Login as a second administrator user. $second_web_user = $this->drupalCreateUser(array('administer nodes', 'edit any page content')); $this->drupalLogin($second_web_user); // Edit the same node, creating a new revision. $this->drupalGet("node/" . $node->id() . "/edit"); $edit = array(); $edit['title[0][value]'] = $this->randomMachineName(8); $edit[$body_key] = $this->randomMachineName(16); $edit['revision'] = TRUE; $this->drupalPostForm(NULL, $edit, t('Save and keep published')); // Ensure that the node revision has been created. $revised_node = $this->drupalGetNodeByTitle($edit['title[0][value]'], TRUE); $this->assertNotIdentical($node->getRevisionId(), $revised_node->getRevisionId(), 'A new revision has been created.'); // Ensure that the node author is preserved when it was not changed in the // edit form. $this->assertIdentical($node->getOwnerId(), $revised_node->getOwnerId(), 'The node author has been preserved.'); // Ensure that the revision authors are different since the revisions were // made by different users. $first_node_version = node_revision_load($node->getRevisionId()); $second_node_version = node_revision_load($revised_node->getRevisionId()); $this->assertNotIdentical($first_node_version->getRevisionAuthor()->id(), $second_node_version->getRevisionAuthor()->id(), 'Each revision has a distinct user.'); }
/** * Delete account and remove all content. */ function testUserDelete() { $node_storage = $this->container->get('entity.manager')->getStorage('node'); $this->config('user.settings')->set('cancel_method', 'user_cancel_delete')->save(); \Drupal::service('module_installer')->install(array('comment')); $this->resetAll(); $this->addDefaultCommentField('node', 'page'); $user_storage = $this->container->get('entity.manager')->getStorage('user'); // Create a user. $account = $this->drupalCreateUser(array('cancel account', 'post comments', 'skip comment approval')); $this->drupalLogin($account); // Load a real user object. $user_storage->resetCache(array($account->id())); $account = $user_storage->load($account->id()); // Create a simple node. $node = $this->drupalCreateNode(array('uid' => $account->id())); // Create comment. $edit = array(); $edit['subject[0][value]'] = $this->randomMachineName(8); $edit['comment_body[0][value]'] = $this->randomMachineName(16); $this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit, t('Preview')); $this->drupalPostForm(NULL, array(), t('Save')); $this->assertText(t('Your comment has been posted.')); $comments = entity_load_multiple_by_properties('comment', array('subject' => $edit['subject[0][value]'])); $comment = reset($comments); $this->assertTrue($comment->id(), 'Comment found.'); // Create a node with two revisions, the initial one belonging to the // cancelling user. $revision_node = $this->drupalCreateNode(array('uid' => $account->id())); $revision = $revision_node->getRevisionId(); $settings = get_object_vars($revision_node); $settings['revision'] = 1; $settings['uid'] = 1; // Set new/current revision to someone else. $revision_node = $this->drupalCreateNode($settings); // Attempt to cancel account. $this->drupalGet('user/' . $account->id() . '/edit'); $this->drupalPostForm(NULL, NULL, t('Cancel account')); $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.'); $this->assertText(t('Your account will be removed and all account information deleted. All of your content will also be deleted.'), 'Informs that all content will be deleted.'); // Confirm account cancellation. $timestamp = time(); $this->drupalPostForm(NULL, NULL, t('Cancel account')); $this->assertText(t('A confirmation request to cancel your account has been sent to your email address.'), 'Account cancellation request mailed message displayed.'); // Confirm account cancellation request. $this->drupalGet("user/" . $account->id() . "/cancel/confirm/{$timestamp}/" . user_pass_rehash($account, $timestamp)); $user_storage->resetCache(array($account->id())); $this->assertFalse($user_storage->load($account->id()), 'User is not found in the database.'); // Confirm that user's content has been deleted. $node_storage->resetCache(array($node->id())); $this->assertFalse($node_storage->load($node->id()), 'Node of the user has been deleted.'); $this->assertFalse(node_revision_load($revision), 'Node revision of the user has been deleted.'); $node_storage->resetCache(array($revision_node->id())); $this->assertTrue($node_storage->load($revision_node->id()), "Current revision of the user's node was not deleted."); \Drupal::entityManager()->getStorage('comment')->resetCache(array($comment->id())); $this->assertFalse(Comment::load($comment->id()), 'Comment of the user has been deleted.'); // Confirm that the confirmation message made it through to the end user. $this->assertRaw(t('%name has been deleted.', array('%name' => $account->getUsername())), "Confirmation message displayed to user."); }
/** * Tests the loading of Quick Edit when a user does have access to it. * * Also ensures lazy loading of in-place editors works. */ public function testUserWithPermission() { $this->drupalLogin($this->editorUser); $this->drupalGet('node/1'); // Library and in-place editors. $settings = $this->getDrupalSettings(); $libraries = explode(',', $settings['ajaxPageState']['libraries']); $this->assertTrue(in_array('quickedit/quickedit', $libraries), 'Quick Edit library loaded.'); $this->assertFalse(in_array('quickedit/quickedit.inPlaceEditor.form', $libraries), "'form' in-place editor not loaded."); // HTML annotation must always exist (to not break the render cache). $this->assertRaw('data-quickedit-entity-id="node/1"'); $this->assertRaw('data-quickedit-field-id="node/1/body/en/full"'); // There should be only one revision so far. $node = Node::load(1); $vids = \Drupal::entityManager()->getStorage('node')->revisionIds($node); $this->assertIdentical(1, count($vids), 'The node has only one revision.'); $original_log = $node->revision_log->value; // Retrieving the metadata should result in a 200 JSON response. $htmlPageDrupalSettings = $this->drupalSettings; $post = array('fields[0]' => 'node/1/body/en/full'); $response = $this->drupalPostWithFormat('quickedit/metadata', 'json', $post); $this->assertResponse(200); $expected = array('node/1/body/en/full' => array('label' => 'Body', 'access' => TRUE, 'editor' => 'form')); $this->assertIdentical(Json::decode($response), $expected, 'The metadata HTTP request answers with the correct JSON response.'); // Restore drupalSettings to build the next requests; simpletest wipes them // after a JSON response. $this->drupalSettings = $htmlPageDrupalSettings; // Retrieving the attachments should result in a 200 response, containing: // 1. a settings command with useless metadata: AjaxController is dumb // 2. an insert command that loads the required in-place editors $post = array('editors[0]' => 'form') + $this->getAjaxPageStatePostData(); $response = $this->drupalPost('quickedit/attachments', 'application/vnd.drupal-ajax', $post); $ajax_commands = Json::decode($response); $this->assertIdentical(2, count($ajax_commands), 'The attachments HTTP request results in two AJAX commands.'); // First command: settings. $this->assertIdentical('settings', $ajax_commands[0]['command'], 'The first AJAX command is a settings command.'); // Second command: insert libraries into DOM. $this->assertIdentical('insert', $ajax_commands[1]['command'], 'The second AJAX command is an append command.'); $this->assertTrue(in_array('quickedit/quickedit.inPlaceEditor.form', explode(',', $ajax_commands[0]['settings']['ajaxPageState']['libraries'])), 'The quickedit.inPlaceEditor.form library is loaded.'); // Retrieving the form for this field should result in a 200 response, // containing only a quickeditFieldForm command. $post = array('nocssjs' => 'true', 'reset' => 'true') + $this->getAjaxPageStatePostData(); $response = $this->drupalPost('quickedit/form/' . 'node/1/body/en/full', 'application/vnd.drupal-ajax', $post); $this->assertResponse(200); $ajax_commands = Json::decode($response); $this->assertIdentical(1, count($ajax_commands), 'The field form HTTP request results in one AJAX command.'); $this->assertIdentical('quickeditFieldForm', $ajax_commands[0]['command'], 'The first AJAX command is a quickeditFieldForm command.'); $this->assertIdentical('<form ', Unicode::substr($ajax_commands[0]['data'], 0, 6), 'The quickeditFieldForm command contains a form.'); // Prepare form values for submission. drupalPostAjaxForm() is not suitable // for handling pages with JSON responses, so we need our own solution here. $form_tokens_found = preg_match('/\\sname="form_token" value="([^"]+)"/', $ajax_commands[0]['data'], $token_match) && preg_match('/\\sname="form_build_id" value="([^"]+)"/', $ajax_commands[0]['data'], $build_id_match); $this->assertTrue($form_tokens_found, 'Form tokens found in output.'); if ($form_tokens_found) { $edit = array('body[0][summary]' => '', 'body[0][value]' => '<p>Fine thanks.</p>', 'body[0][format]' => 'filtered_html', 'op' => t('Save')); $post = array('form_id' => 'quickedit_field_form', 'form_token' => $token_match[1], 'form_build_id' => $build_id_match[1]); $post += $edit + $this->getAjaxPageStatePostData(); // Submit field form and check response. This should store the updated // entity in PrivateTempStore on the server. $response = $this->drupalPost('quickedit/form/' . 'node/1/body/en/full', 'application/vnd.drupal-ajax', $post); $this->assertResponse(200); $ajax_commands = Json::decode($response); $this->assertIdentical(1, count($ajax_commands), 'The field form HTTP request results in one AJAX command.'); $this->assertIdentical('quickeditFieldFormSaved', $ajax_commands[0]['command'], 'The first AJAX command is a quickeditFieldFormSaved command.'); $this->assertTrue(strpos($ajax_commands[0]['data'], 'Fine thanks.'), 'Form value saved and printed back.'); $this->assertIdentical($ajax_commands[0]['other_view_modes'], array(), 'Field was not rendered in any other view mode.'); // Ensure the text on the original node did not change yet. $this->drupalGet('node/1'); $this->assertText('How are you?'); // Save the entity by moving the PrivateTempStore values to entity storage. $post = array('nocssjs' => 'true'); $response = $this->drupalPostWithFormat('quickedit/entity/' . 'node/1', 'json', $post); $this->assertResponse(200); $ajax_commands = Json::decode($response); $this->assertIdentical(1, count($ajax_commands), 'The entity submission HTTP request results in one AJAX command.'); $this->assertIdentical('quickeditEntitySaved', $ajax_commands[0]['command'], 'The first AJAX command is a quickeditEntitySaved command.'); $this->assertIdentical($ajax_commands[0]['data']['entity_type'], 'node', 'Saved entity is of type node.'); $this->assertIdentical($ajax_commands[0]['data']['entity_id'], '1', 'Entity id is 1.'); // Ensure the text on the original node did change. $this->drupalGet('node/1'); $this->assertText('Fine thanks.'); // Ensure no new revision was created and the log message is unchanged. $node = Node::load(1); $vids = \Drupal::entityManager()->getStorage('node')->revisionIds($node); $this->assertIdentical(1, count($vids), 'The node has only one revision.'); $this->assertIdentical($original_log, $node->revision_log->value, 'The revision log message is unchanged.'); // Now configure this node type to create new revisions automatically, // then again retrieve the field form, fill it, submit it (so it ends up // in PrivateTempStore) and then save the entity. Now there should be two // revisions. $node_type = NodeType::load('article'); $node_type->setNewRevision(TRUE); $node_type->save(); // Retrieve field form. $post = array('nocssjs' => 'true', 'reset' => 'true'); $response = $this->drupalPost('quickedit/form/' . 'node/1/body/en/full', 'application/vnd.drupal-ajax', $post); $this->assertResponse(200); $ajax_commands = Json::decode($response); $this->assertIdentical(1, count($ajax_commands), 'The field form HTTP request results in one AJAX command.'); $this->assertIdentical('quickeditFieldForm', $ajax_commands[0]['command'], 'The first AJAX command is a quickeditFieldForm command.'); $this->assertIdentical('<form ', Unicode::substr($ajax_commands[0]['data'], 0, 6), 'The quickeditFieldForm command contains a form.'); // Submit field form. preg_match('/\\sname="form_token" value="([^"]+)"/', $ajax_commands[0]['data'], $token_match); preg_match('/\\sname="form_build_id" value="([^"]+)"/', $ajax_commands[0]['data'], $build_id_match); $edit['body[0][value]'] = '<p>kthxbye</p>'; $post = array('form_id' => 'quickedit_field_form', 'form_token' => $token_match[1], 'form_build_id' => $build_id_match[1]); $post += $edit + $this->getAjaxPageStatePostData(); $response = $this->drupalPost('quickedit/form/' . 'node/1/body/en/full', 'application/vnd.drupal-ajax', $post); $this->assertResponse(200); $ajax_commands = Json::decode($response); $this->assertIdentical(1, count($ajax_commands), 'The field form HTTP request results in one AJAX command.'); $this->assertIdentical('quickeditFieldFormSaved', $ajax_commands[0]['command'], 'The first AJAX command is an quickeditFieldFormSaved command.'); $this->assertTrue(strpos($ajax_commands[0]['data'], 'kthxbye'), 'Form value saved and printed back.'); // Save the entity. $post = array('nocssjs' => 'true'); $response = $this->drupalPostWithFormat('quickedit/entity/' . 'node/1', 'json', $post); $this->assertResponse(200); $ajax_commands = Json::decode($response); $this->assertIdentical(1, count($ajax_commands)); $this->assertIdentical('quickeditEntitySaved', $ajax_commands[0]['command'], 'The first AJAX command is an quickeditEntitySaved command.'); $this->assertEqual($ajax_commands[0]['data'], ['entity_type' => 'node', 'entity_id' => 1], 'Updated entity type and ID returned'); // Test that a revision was created with the correct log message. $vids = \Drupal::entityManager()->getStorage('node')->revisionIds(Node::load(1)); $this->assertIdentical(2, count($vids), 'The node has two revisions.'); $revision = node_revision_load($vids[0]); $this->assertIdentical($original_log, $revision->revision_log->value, 'The first revision log message is unchanged.'); $revision = node_revision_load($vids[1]); $this->assertIdentical('Updated the <em class="placeholder">Body</em> field through in-place editing.', $revision->revision_log->value, 'The second revision log message was correctly generated by Quick Edit module.'); } }