diff --git a/core/modules/comment/src/Tests/CommentLinksTest.php b/core/modules/comment/src/Tests/CommentLinksTest.php index 04326f1..e64a68c 100644 --- a/core/modules/comment/src/Tests/CommentLinksTest.php +++ b/core/modules/comment/src/Tests/CommentLinksTest.php @@ -7,12 +7,13 @@ namespace Drupal\comment\Tests; +use Drupal\comment\Plugin\Field\FieldType\CommentItem; use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface; use Drupal\Core\Language\LanguageInterface; use Drupal\comment\CommentInterface; /** - * Tests comment links based on environment configurations. + * Basic comment links tests to ensure markup present. * * @group comment */ @@ -65,274 +66,52 @@ public function testCommentLinks() { $roles = $this->web_user->getRoles(); entity_delete_multiple('user_role', array(reset($roles))); - // Matrix of possible environmental conditions and configuration settings. - // See setEnvironment() for details. - $conditions = array( - 'authenticated' => array(FALSE, TRUE), - 'comment count' => array(FALSE, TRUE), - 'access comments' => array(0, 1), - 'post comments' => array(0, 1), - 'form' => array(CommentItemInterface::FORM_BELOW, CommentItemInterface::FORM_SEPARATE_PAGE), - // USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL is irrelevant for this - // test; there is only a difference between open and closed registration. - 'user_register' => array(USER_REGISTER_VISITORS, USER_REGISTER_ADMINISTRATORS_ONLY), - // @todo Complete test coverage for: - //'comments' => array(CommentItemInterface::OPEN, CommentItemInterface::CLOSED, CommentInterface::_HIDDEN), - //// COMMENT_ANONYMOUS_MUST_CONTACT is irrelevant for this test. - //'contact ' => array(COMMENT_ANONYMOUS_MAY_CONTACT, COMMENT_ANONYMOUS_MAYNOT_CONTACT), - ); - - $environments = $this->generatePermutations($conditions); - foreach ($environments as $info) { - $this->assertCommentLinks($info); - } - $this->seen = array(); - } - - /** - * Re-configures the environment, module settings, and user permissions. - * - * @param array $info - * An associative array describing the environment to setup: - * - Environment conditions: - * - authenticated: Boolean whether to test with $this->web_user or - * anonymous. - * - comment count: Boolean whether to test with a new/unread comment on - * $this->node or no comments. - * - Configuration settings: - * - form: CommentItemInterface::FORM_BELOW or CommentItemInterface::FORM_SEPARATE_PAGE. - * - user_register: USER_REGISTER_ADMINISTRATORS_ONLY or - * USER_REGISTER_VISITORS. - * - contact: COMMENT_ANONYMOUS_MAY_CONTACT or - * COMMENT_ANONYMOUS_MAYNOT_CONTACT. - * - comments: CommentItemInterface::OPEN, CommentItemInterface::CLOSED or - * CommentItemInterface::HIDDEN. - * - User permissions: - * These are granted or revoked for the user, according to the - * 'authenticated' flag above. Pass 0 or 1 as parameter values. See - * user_role_change_permissions(). - * - access comments - * - post comments - * - skip comment approval - * - edit own comments - * - * @return array - * Configured settings. - */ - protected function setEnvironment(array $info) { - static $current; - - // Apply defaults to initial environment. - if (!isset($current)) { - $current = array( - 'authenticated' => FALSE, - 'comment count' => FALSE, - 'form' => CommentItemInterface::FORM_BELOW, - 'user_register' => USER_REGISTER_VISITORS, - 'contact' => COMMENT_ANONYMOUS_MAY_CONTACT, - 'comments' => CommentItemInterface::OPEN, - 'access comments' => 0, - 'post comments' => 0, - // Enabled by default, because it's irrelevant for this test. - 'skip comment approval' => 1, - 'edit own comments' => 0, - ); - } - // Complete new environment with current environment. - $info = array_merge($current, $info); - - // Change environment conditions. - if ($current['authenticated'] != $info['authenticated']) { - if ($this->loggedInUser) { - $this->drupalLogout(); - } - else { - $this->drupalLogin($this->web_user); - } - } - if ($current['comment count'] != $info['comment count']) { - if ($info['comment count']) { - // Create a comment via CRUD API functionality, since - // $this->postComment() relies on actual user permissions. - $comment = entity_create('comment', array( - 'cid' => NULL, - 'entity_id' => $this->node->id(), - 'entity_type' => 'node', - 'field_name' => 'comment', - 'pid' => 0, - 'uid' => 0, - 'status' => CommentInterface::PUBLISHED, - 'subject' => $this->randomMachineName(), - 'hostname' => '127.0.0.1', - 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, - 'comment_body' => array(LanguageInterface::LANGCODE_NOT_SPECIFIED => array($this->randomMachineName())), - )); - $comment->save(); - $this->comment = $comment; - } - else { - $cids = db_query("SELECT cid FROM {comment}")->fetchCol(); - entity_delete_multiple('comment', $cids); - unset($this->comment); - } - } + // Create a comment via CRUD API functionality, since + // $this->postComment() relies on actual user permissions. + $comment = entity_create('comment', array( + 'cid' => NULL, + 'entity_id' => $this->node->id(), + 'entity_type' => 'node', + 'field_name' => 'comment', + 'pid' => 0, + 'uid' => 0, + 'status' => CommentInterface::PUBLISHED, + 'subject' => $this->randomMachineName(), + 'hostname' => '127.0.0.1', + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + 'comment_body' => array(LanguageInterface::LANGCODE_NOT_SPECIFIED => array($this->randomMachineName())), + )); + $comment->save(); + $this->comment = $comment; // Change comment settings. - $this->setCommentSettings('form_location', $info['form'], 'Set comment form location'); - $this->setCommentAnonymous($info['contact']); - if ($this->node->comment->status != $info['comments']) { - $this->node->comment = $info['comments']; - $this->node->save(); - } - - // Change user settings. - \Drupal::config('user.settings')->set('register', $info['user_register'])->save(); + $this->setCommentSettings('form_location', CommentItem::FORM_BELOW, 'Set comment form location'); + $this->setCommentAnonymous(TRUE); + $this->node->comment = CommentItem::OPEN; + $this->node->save(); // Change user permissions. - $rid = ($this->loggedInUser ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID); - $perms = array_intersect_key($info, array( + $perms = array( 'access comments' => 1, 'post comments' => 1, 'skip comment approval' => 1, 'edit own comments' => 1, - )); - user_role_change_permissions($rid, $perms); - - // Output verbose debugging information. - // @see \Drupal\simpletest\TestBase::error() - $t_form = array( - CommentItemInterface::FORM_BELOW => 'below', - CommentItemInterface::FORM_SEPARATE_PAGE => 'separate page', - ); - $t_contact = array( - COMMENT_ANONYMOUS_MAY_CONTACT => 'optional', - COMMENT_ANONYMOUS_MAYNOT_CONTACT => 'disabled', - COMMENT_ANONYMOUS_MUST_CONTACT => 'required', - ); - $t_comments = array( - CommentItemInterface::OPEN => 'open', - CommentItemInterface::CLOSED => 'closed', - CommentItemInterface::HIDDEN => 'hidden', ); - $verbose = $info; - $verbose['form'] = $t_form[$info['form']]; - $verbose['contact'] = $t_contact[$info['contact']]; - $verbose['comments'] = $t_comments[$info['comments']]; - $message = t('Changed environment:
@verbose', array( - '@verbose' => var_export($verbose, TRUE), - )); - $this->assert('debug', $message, 'Debug'); - - // Update current environment. - $current = $info; - - return $info; - } - - /** - * Asserts that comment links appear according to the passed environment. - * - * @param array $info - * An associative array describing the environment to pass to - * setEnvironment(). - */ - protected function assertCommentLinks(array $info) { - $info = $this->setEnvironment($info); + user_role_change_permissions(DRUPAL_ANONYMOUS_RID, $perms); $nid = $this->node->id(); + // Assert basic link is output, actual functionality is unit-tested in + // \Drupal\comment\Tests\CommentLinkBuilderTest. foreach (array('node', "node/$nid") as $path) { $this->drupalGet($path); - // User is allowed to view comments. - if ($info['access comments']) { - if ($path == '') { - // In teaser view, a link containing the comment count is always - // expected. - if ($info['comment count']) { - $this->assertLink(t('1 comment')); - - // For logged in users, a link containing the amount of new/unread - // comments is expected. - // See important note about - // \Drupal::service('comment.manager')->getCountNewComments() below. - if ($this->loggedInUser && isset($this->comment) && !isset($this->seen[$this->comment->id()])) { - $this->assertLink(t('1 new comment')); - $this->seen[$this->comment->id()] = TRUE; - } - } - } - } - else { - $this->assertNoLink(t('1 comment')); - $this->assertNoLink(t('1 new comment')); - } - // \Drupal::service('comment.manager')->getCountNewComments() is based on - // node views, so comments are marked as read when a node is viewed, - // regardless of whether we have access to comments. - if ($path == "node/$nid" && $this->loggedInUser && isset($this->comment)) { - $this->seen[$this->comment->id()] = TRUE; - } - - // User is not allowed to post comments. - if (!$info['post comments']) { - $this->assertNoLink('Add new comment'); - - // Anonymous users should see a note to log in or register in case - // authenticated users are allowed to post comments. - // @see \Drupal\comment\CommentManagerInterface::forbiddenMessage() - if (!$this->loggedInUser) { - if ($this->web_user->hasPermission('post comments')) { - // The note depends on whether users are actually able to register. - if ($info['user_register'] != USER_REGISTER_ADMINISTRATORS_ONLY) { - $this->assertText('Log in or register to post comments'); - } - else { - $this->assertText('Log in to post comments'); - } - } - else { - $this->assertNoText('Log in or register to post comments'); - $this->assertNoText('Log in to post comments'); - } - } - } - // User is allowed to post comments. - else { - $this->assertNoText('Log in or register to post comments'); - - // "Add new comment" is always expected, except when there are no - // comments or if the user cannot see them. - if ($path == "node/$nid" && $info['form'] == CommentItemInterface::FORM_BELOW && (!$info['comment count'] || !$info['access comments'])) { - $this->assertNoLink('Add new comment'); - } - else { - $this->assertLink('Add new comment'); - - // Verify that the "Add new comment" link points to the correct URL - // based on the comment form location configuration. - if ($info['form'] == CommentItemInterface::FORM_SEPARATE_PAGE) { - $this->assertLinkByHref("comment/reply/node/$nid/comment#comment-form", 0, 'Comment form link destination is on a separate page.'); - $this->assertNoLinkByHref("node/$nid#comment-form"); - } - else { - $this->assertLinkByHref("node/$nid#comment-form", 0, 'Comment form link destination is on node.'); - $this->assertNoLinkByHref("comment/reply/node/$nid/comment#comment-form"); - } - } - - // Also verify that the comment form appears according to the configured - // location. - if ($path == "node/$nid") { - $elements = $this->xpath('//form[@id=:id]', array(':id' => 'comment-form')); - if ($info['form'] == CommentItemInterface::FORM_BELOW) { - $this->assertTrue(count($elements), 'Comment form found below.'); - } - else { - $this->assertFalse(count($elements), 'Comment form not found below.'); - } - } + // In teaser view, a link containing the comment count is always + // expected. + if ($path == 'node') { + $this->assertLink(t('1 comment')); } + $this->assertLink('Add new comment'); } } diff --git a/core/modules/comment/tests/src/CommentLinkBuilderTest.php b/core/modules/comment/tests/src/CommentLinkBuilderTest.php index 62f6bff..405ec6a 100644 --- a/core/modules/comment/tests/src/CommentLinkBuilderTest.php +++ b/core/modules/comment/tests/src/CommentLinkBuilderTest.php @@ -17,14 +17,42 @@ /** * @coversDefaultClass \Drupal\comment\CommentLinkBuilder * @group comment - * @group larowlan */ class CommentLinkBuilderTest extends UnitTestCase { + /** + * Comment manager mock. + * + * @var \Drupal\comment\CommentManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ protected $commentManager; + + /** + * String translation mock. + * + * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject + */ protected $stringTranslation; + + /** + * Module handler mock. + * + * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject + */ protected $moduleHandler; + + /** + * Current user proxy mock. + * + * @var \Drupal\Core\Session\AccountProxyInterface|\PHPUnit_Framework_MockObject_MockObject + */ protected $currentUser; + + /** + * Timestamp used in test. + * + * @var int + */ protected $timestamp; /** @@ -32,6 +60,9 @@ class CommentLinkBuilderTest extends UnitTestCase { */ protected $commentLinkBuilder; + /** + * Prepares mocks for the test. + */ public function setUp() { $this->commentManager = $this->getMock('\Drupal\comment\CommentManagerInterface'); $this->stringTranslation = $this->getMock('\Drupal\Core\StringTranslation\TranslationInterface'); @@ -58,15 +89,21 @@ public function setUp() { /** * Test the buildLinks method. * - * @param \Drupal\node\NodeInterface $node - * @param $context - * @param $comment_status - * @param $has_access_comments - * @param $history_exists - * @param $has_post_comments - * @param $form_location - * @param $is_anonymous - * @param $expected + * @param \Drupal\node\NodeInterface|\PHPUnit_Framework_MockObject_MockObject $node + * Mock node. + * @param array $context + * Context for the links. + * @param bool $has_access_comments + * TRUE if the user has 'access comments' permission. + * @param bool $history_exists + * TRUE if the history module exists. + * @param bool $has_post_comments + * TRUE if the use has 'post comments' permission. + * @param bool $is_anonymous + * TRUE if the user is anonymous. + * @param array $expected + * Array of expected links keyed by link ID. Can be either string (link + * title) or array of link properties. * * @dataProvider getLinkCombinations * @@ -113,7 +150,7 @@ public function testCommentLinkBuilder(NodeInterface $node, $context, $has_acces else { $this->assertSame($links, $expected); } - if ($context['view_mode'] == 'rss') { + if ($context['view_mode'] == 'rss' && $node->get('comment')->status) { $found = FALSE; if ($node->get('comment')->status) { foreach ($node->rss_elements as $element) { @@ -127,17 +164,12 @@ public function testCommentLinkBuilder(NodeInterface $node, $context, $has_acces } } + /** + * Data provider for ::testCommentLinkBuilder. + */ public function getLinkCombinations() { $cases = array(); - /** - * NodeInterface $node, - * $context, - * $has_access_comments, - * $history_exists, - * $has_post_comments, - * $is_anonymous, - * $expected*/ - // Doesn't have the field. + // No links should be created if the entity doesn't have the field. $cases[] = array( $this->getMockNode(FALSE, CommentItem::OPEN, CommentItem::FORM_BELOW, 1), array('view_mode' => 'teaser'), @@ -148,7 +180,7 @@ public function getLinkCombinations() { array(), ); foreach (array('search_result', 'search_index', 'print') as $view_mode) { - // Nothing for these view modes. + // Nothing should be output in these view modes. $cases[] = array( $this->getMockNode(TRUE, CommentItem::OPEN, CommentItem::FORM_BELOW, 1), array('view_mode' => $view_mode), @@ -159,7 +191,8 @@ public function getLinkCombinations() { array(), ); } - $combinations = $conditions = array( + // All other combinations. + $combinations = array( 'is_anonymous' => array(FALSE, TRUE), 'comment_count' => array(0, 1), 'has_access_comments' => array(0, 1), @@ -186,26 +219,39 @@ public function getLinkCombinations() { $combination['is_anonymous'], ); $expected = array(); - if ($combination['view_mode'] == 'teaser') { - if ($combination['comment_count'] && $combination['has_access_comments']) { - $expected['comment-comments'] = '1 comment'; - } - if ($combination['history_exists'] && $combination['comment_count']) { + // When comments are enabled in teaser mode, and comments exist, and the + // user has access - we can output the comment count. + if ($combination['comments'] && $combination['view_mode'] == 'teaser' && $combination['comment_count'] && $combination['has_access_comments']) { + $expected['comment-comments'] = '1 comment'; + // And if history module exists, we can show a 'new comments' link. + if ($combination['history_exists']) { $expected['comment-new-comments'] = ''; } } + // All view modes other than RSS. if ($combination['view_mode'] != 'rss') { + // Where commenting is open. if ($combination['comments'] == CommentItem::OPEN) { + // And the user has post-comments permission. if ($combination['has_post_comments']) { - $expected['comment-add'] = array('title' => 'Add new comment'); - if ($combination['form_location'] == CommentItem::FORM_BELOW) { - $expected['comment-add']['route_name'] = 'node.view'; - } - else { - $expected['comment-add']['route_name'] = 'comment.reply'; + // If the view mode is teaser, or the user can access comments and + // comments exist or the form is on a separate page. + if ($combination['view_mode'] == 'teaser' || ($combination['has_access_comments'] && $combination['comment_count']) || $combination['form_location'] == CommentItem::FORM_SEPARATE_PAGE) { + // There should be a add comment link. + $expected['comment-add'] = array('title' => 'Add new comment'); + if ($combination['form_location'] == CommentItem::FORM_BELOW) { + // On the same page. + $expected['comment-add']['route_name'] = 'node.view'; + } + else { + // On a separate page. + $expected['comment-add']['route_name'] = 'comment.reply'; + } } } elseif ($combination['is_anonymous']) { + // Anonymous users get the forbidden message if the can't post + // comments. $expected['comment-forbidden'] = "Can't let you do that Dave."; } } @@ -217,6 +263,21 @@ public function getLinkCombinations() { return $cases; } + /** + * Builds a mock node based on given scenario. + * + * @param bool $has_field + * TRUE if the node has the 'comment' field. + * @param int $comment_status + * One of CommentItem::OPEN|HIDDEN|CLOSED + * @param int $form_location + * One of CommentItem::FORM_BELOW|FORM_SEPARATE_PAGE + * @param int $comment_count + * Number of comments against the field. + * + * @return \Drupal\node\NodeInterface|\PHPUnit_Framework_MockObject_MockObject + * Mock node for testing. + */ protected function getMockNode($has_field, $comment_status, $form_location, $comment_count) { $node = $this->getMock('\Drupal\node\NodeInterface'); $node->expects($this->once())