Chris@17: drupalLogin($this->adminUser); Chris@17: Chris@17: // Set comment variables. Chris@17: $this->setCommentForm(TRUE); Chris@17: $this->setCommentSubject(TRUE); Chris@17: $this->setCommentPreview(DRUPAL_DISABLED); Chris@17: Chris@17: // Create a node and three comments. Chris@17: $node = $this->drupalCreateNode(['type' => 'article', 'promote' => 1]); Chris@17: $comments = []; Chris@17: $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_FLAT, 'Comment paging changed.'); Chris@17: Chris@17: // Set comments to one per page so that we are able to test paging without Chris@17: // needing to insert large numbers of comments. Chris@17: $this->setCommentsPerPage(1); Chris@17: Chris@17: // Check the first page of the node, and confirm the correct comments are Chris@17: // shown. Chris@17: $this->drupalGet('node/' . $node->id()); Chris@17: $this->assertRaw(t('next'), 'Paging links found.'); Chris@17: $this->assertTrue($this->commentExists($comments[0]), 'Comment 1 appears on page 1.'); Chris@17: $this->assertFalse($this->commentExists($comments[1]), 'Comment 2 does not appear on page 1.'); Chris@17: $this->assertFalse($this->commentExists($comments[2]), 'Comment 3 does not appear on page 1.'); Chris@17: Chris@17: // Check the second page. Chris@17: $this->drupalGet('node/' . $node->id(), ['query' => ['page' => 1]]); Chris@17: $this->assertTrue($this->commentExists($comments[1]), 'Comment 2 appears on page 2.'); Chris@17: $this->assertFalse($this->commentExists($comments[0]), 'Comment 1 does not appear on page 2.'); Chris@17: $this->assertFalse($this->commentExists($comments[2]), 'Comment 3 does not appear on page 2.'); Chris@17: Chris@17: // Check the third page. Chris@17: $this->drupalGet('node/' . $node->id(), ['query' => ['page' => 2]]); Chris@17: $this->assertTrue($this->commentExists($comments[2]), 'Comment 3 appears on page 3.'); Chris@17: $this->assertFalse($this->commentExists($comments[0]), 'Comment 1 does not appear on page 3.'); Chris@17: $this->assertFalse($this->commentExists($comments[1]), 'Comment 2 does not appear on page 3.'); Chris@17: Chris@17: // Post a reply to the oldest comment and test again. Chris@17: $oldest_comment = reset($comments); Chris@17: $this->drupalGet('comment/reply/node/' . $node->id() . '/comment/' . $oldest_comment->id()); Chris@17: $reply = $this->postComment(NULL, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: $this->setCommentsPerPage(2); Chris@17: // We are still in flat view - the replies should not be on the first page, Chris@17: // even though they are replies to the oldest comment. Chris@17: $this->drupalGet('node/' . $node->id(), ['query' => ['page' => 0]]); Chris@17: $this->assertFalse($this->commentExists($reply, TRUE), 'In flat mode, reply does not appear on page 1.'); Chris@17: Chris@17: // If we switch to threaded mode, the replies on the oldest comment Chris@17: // should be bumped to the first page and comment 6 should be bumped Chris@17: // to the second page. Chris@17: $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Switched to threaded mode.'); Chris@17: $this->drupalGet('node/' . $node->id(), ['query' => ['page' => 0]]); Chris@17: $this->assertTrue($this->commentExists($reply, TRUE), 'In threaded mode, reply appears on page 1.'); Chris@17: $this->assertFalse($this->commentExists($comments[1]), 'In threaded mode, comment 2 has been bumped off of page 1.'); Chris@17: Chris@17: // If (# replies > # comments per page) in threaded expanded view, Chris@17: // the overage should be bumped. Chris@17: $reply2 = $this->postComment(NULL, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: $this->drupalGet('node/' . $node->id(), ['query' => ['page' => 0]]); Chris@17: $this->assertFalse($this->commentExists($reply2, TRUE), 'In threaded mode where # replies > # comments per page, the newest reply does not appear on page 1.'); Chris@17: Chris@17: // Test that the page build process does not somehow generate errors when Chris@17: // # comments per page is set to 0. Chris@17: $this->setCommentsPerPage(0); Chris@17: $this->drupalGet('node/' . $node->id(), ['query' => ['page' => 0]]); Chris@17: $this->assertFalse($this->commentExists($reply2, TRUE), 'Threaded mode works correctly when comments per page is 0.'); Chris@17: Chris@17: $this->drupalLogout(); Chris@17: } Chris@17: Chris@17: /** Chris@17: * Confirms comment paging works correctly with flat and threaded comments. Chris@17: */ Chris@17: public function testCommentPermalink() { Chris@17: $this->drupalLogin($this->adminUser); Chris@17: Chris@17: // Set comment variables. Chris@17: $this->setCommentForm(TRUE); Chris@17: $this->setCommentSubject(TRUE); Chris@17: $this->setCommentPreview(DRUPAL_DISABLED); Chris@17: Chris@17: // Create a node and three comments. Chris@17: $node = $this->drupalCreateNode(['type' => 'article', 'promote' => 1]); Chris@17: $comments = []; Chris@17: $comments[] = $this->postComment($node, 'comment 1: ' . $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: $comments[] = $this->postComment($node, 'comment 2: ' . $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: $comments[] = $this->postComment($node, 'comment 3: ' . $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_FLAT, 'Comment paging changed.'); Chris@17: Chris@17: // Set comments to one per page so that we are able to test paging without Chris@17: // needing to insert large numbers of comments. Chris@17: $this->setCommentsPerPage(1); Chris@17: Chris@17: // Navigate to each comment permalink as anonymous and assert it appears on Chris@17: // the page. Chris@17: foreach ($comments as $index => $comment) { Chris@17: $this->drupalGet($comment->toUrl()); Chris@17: $this->assertTrue($this->commentExists($comment), sprintf('Comment %d appears on page %d.', $index + 1, $index + 1)); Chris@17: } Chris@17: } Chris@17: Chris@17: /** Chris@17: * Tests comment ordering and threading. Chris@17: */ Chris@17: public function testCommentOrderingThreading() { Chris@17: $this->drupalLogin($this->adminUser); Chris@17: Chris@17: // Set comment variables. Chris@17: $this->setCommentForm(TRUE); Chris@17: $this->setCommentSubject(TRUE); Chris@17: $this->setCommentPreview(DRUPAL_DISABLED); Chris@17: Chris@17: // Display all the comments on the same page. Chris@17: $this->setCommentsPerPage(1000); Chris@17: Chris@17: // Create a node and three comments. Chris@17: $node = $this->drupalCreateNode(['type' => 'article', 'promote' => 1]); Chris@17: $comments = []; Chris@17: $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: // Post a reply to the second comment. Chris@17: $this->drupalGet('comment/reply/node/' . $node->id() . '/comment/' . $comments[1]->id()); Chris@17: $comments[] = $this->postComment(NULL, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: // Post a reply to the first comment. Chris@17: $this->drupalGet('comment/reply/node/' . $node->id() . '/comment/' . $comments[0]->id()); Chris@17: $comments[] = $this->postComment(NULL, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: // Post a reply to the last comment. Chris@17: $this->drupalGet('comment/reply/node/' . $node->id() . '/comment/' . $comments[2]->id()); Chris@17: $comments[] = $this->postComment(NULL, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: // Post a reply to the second comment. Chris@17: $this->drupalGet('comment/reply/node/' . $node->id() . '/comment/' . $comments[3]->id()); Chris@17: $comments[] = $this->postComment(NULL, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: // At this point, the comment tree is: Chris@17: // - 0 Chris@17: // - 4 Chris@17: // - 1 Chris@17: // - 3 Chris@17: // - 6 Chris@17: // - 2 Chris@17: // - 5 Chris@17: Chris@17: $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_FLAT, 'Comment paging changed.'); Chris@17: Chris@17: $expected_order = [ Chris@17: 0, Chris@17: 1, Chris@17: 2, Chris@17: 3, Chris@17: 4, Chris@17: 5, Chris@17: 6, Chris@17: ]; Chris@17: $this->drupalGet('node/' . $node->id()); Chris@17: $this->assertCommentOrder($comments, $expected_order); Chris@17: Chris@17: $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Switched to threaded mode.'); Chris@17: Chris@17: $expected_order = [ Chris@17: 0, Chris@17: 4, Chris@17: 1, Chris@17: 3, Chris@17: 6, Chris@17: 2, Chris@17: 5, Chris@17: ]; Chris@17: $this->drupalGet('node/' . $node->id()); Chris@17: $this->assertCommentOrder($comments, $expected_order); Chris@17: } Chris@17: Chris@17: /** Chris@17: * Asserts that the comments are displayed in the correct order. Chris@17: * Chris@17: * @param \Drupal\comment\CommentInterface[] $comments Chris@17: * An array of comments, must be of the type CommentInterface. Chris@17: * @param array $expected_order Chris@17: * An array of keys from $comments describing the expected order. Chris@17: */ Chris@17: public function assertCommentOrder(array $comments, array $expected_order) { Chris@17: $expected_cids = []; Chris@17: Chris@17: // First, rekey the expected order by cid. Chris@17: foreach ($expected_order as $key) { Chris@17: $expected_cids[] = $comments[$key]->id(); Chris@17: } Chris@17: Chris@18: $comment_anchors = $this->xpath('//article[starts-with(@id,"comment-")]'); Chris@17: $result_order = []; Chris@17: foreach ($comment_anchors as $anchor) { Chris@17: $result_order[] = substr($anchor->getAttribute('id'), 8); Chris@17: } Chris@17: return $this->assertEqual($expected_cids, $result_order, format_string('Comment order: expected @expected, returned @returned.', ['@expected' => implode(',', $expected_cids), '@returned' => implode(',', $result_order)])); Chris@17: } Chris@17: Chris@17: /** Chris@17: * Tests calculation of first page with new comment. Chris@17: */ Chris@17: public function testCommentNewPageIndicator() { Chris@17: $this->drupalLogin($this->adminUser); Chris@17: Chris@17: // Set comment variables. Chris@17: $this->setCommentForm(TRUE); Chris@17: $this->setCommentSubject(TRUE); Chris@17: $this->setCommentPreview(DRUPAL_DISABLED); Chris@17: Chris@17: // Set comments to one per page so that we are able to test paging without Chris@17: // needing to insert large numbers of comments. Chris@17: $this->setCommentsPerPage(1); Chris@17: Chris@17: // Create a node and three comments. Chris@17: $node = $this->drupalCreateNode(['type' => 'article', 'promote' => 1]); Chris@17: $comments = []; Chris@17: $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: $comments[] = $this->postComment($node, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: // Post a reply to the second comment. Chris@17: $this->drupalGet('comment/reply/node/' . $node->id() . '/comment/' . $comments[1]->id()); Chris@17: $comments[] = $this->postComment(NULL, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: // Post a reply to the first comment. Chris@17: $this->drupalGet('comment/reply/node/' . $node->id() . '/comment/' . $comments[0]->id()); Chris@17: $comments[] = $this->postComment(NULL, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: // Post a reply to the last comment. Chris@17: $this->drupalGet('comment/reply/node/' . $node->id() . '/comment/' . $comments[2]->id()); Chris@17: $comments[] = $this->postComment(NULL, $this->randomMachineName(), $this->randomMachineName(), TRUE); Chris@17: Chris@17: // At this point, the comment tree is: Chris@17: // - 0 Chris@17: // - 4 Chris@17: // - 1 Chris@17: // - 3 Chris@17: // - 2 Chris@17: // - 5 Chris@17: Chris@17: $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_FLAT, 'Comment paging changed.'); Chris@17: Chris@17: $expected_pages = [ Chris@17: // Page of comment 5 Chris@17: 1 => 5, Chris@17: // Page of comment 4 Chris@17: 2 => 4, Chris@17: // Page of comment 3 Chris@17: 3 => 3, Chris@17: // Page of comment 2 Chris@17: 4 => 2, Chris@17: // Page of comment 1 Chris@17: 5 => 1, Chris@17: // Page of comment 0 Chris@17: 6 => 0, Chris@17: ]; Chris@17: Chris@17: $node = Node::load($node->id()); Chris@17: foreach ($expected_pages as $new_replies => $expected_page) { Chris@17: $returned_page = \Drupal::entityManager()->getStorage('comment') Chris@17: ->getNewCommentPageNumber($node->get('comment')->comment_count, $new_replies, $node, 'comment'); Chris@17: $this->assertIdentical($expected_page, $returned_page, format_string('Flat mode, @new replies: expected page @expected, returned page @returned.', ['@new' => $new_replies, '@expected' => $expected_page, '@returned' => $returned_page])); Chris@17: } Chris@17: Chris@17: $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Switched to threaded mode.'); Chris@17: Chris@17: $expected_pages = [ Chris@17: // Page of comment 5 Chris@17: 1 => 5, Chris@17: // Page of comment 4 Chris@17: 2 => 1, Chris@17: // Page of comment 4 Chris@17: 3 => 1, Chris@17: // Page of comment 4 Chris@17: 4 => 1, Chris@17: // Page of comment 4 Chris@17: 5 => 1, Chris@17: // Page of comment 0 Chris@17: 6 => 0, Chris@17: ]; Chris@17: Chris@17: \Drupal::entityManager()->getStorage('node')->resetCache([$node->id()]); Chris@17: $node = Node::load($node->id()); Chris@17: foreach ($expected_pages as $new_replies => $expected_page) { Chris@17: $returned_page = \Drupal::entityManager()->getStorage('comment') Chris@17: ->getNewCommentPageNumber($node->get('comment')->comment_count, $new_replies, $node, 'comment'); Chris@17: $this->assertEqual($expected_page, $returned_page, format_string('Threaded mode, @new replies: expected page @expected, returned page @returned.', ['@new' => $new_replies, '@expected' => $expected_page, '@returned' => $returned_page])); Chris@17: } Chris@17: } Chris@17: Chris@17: /** Chris@17: * Confirms comment paging works correctly with two pagers. Chris@17: */ Chris@17: public function testTwoPagers() { Chris@17: // Add another field to article content-type. Chris@17: $this->addDefaultCommentField('node', 'article', 'comment_2'); Chris@17: // Set default to display comment list with unique pager id. Chris@17: entity_get_display('node', 'article', 'default') Chris@17: ->setComponent('comment_2', [ Chris@17: 'label' => 'hidden', Chris@17: 'type' => 'comment_default', Chris@17: 'weight' => 30, Chris@17: 'settings' => [ Chris@17: 'pager_id' => 1, Chris@17: 'view_mode' => 'default', Chris@17: ], Chris@17: ]) Chris@17: ->save(); Chris@17: Chris@17: // Make sure pager appears in formatter summary and settings form. Chris@17: $account = $this->drupalCreateUser(['administer node display']); Chris@17: $this->drupalLogin($account); Chris@17: $this->drupalGet('admin/structure/types/manage/article/display'); Chris@17: $this->assertNoText(t('Pager ID: @id', ['@id' => 0]), 'No summary for standard pager'); Chris@17: $this->assertText(t('Pager ID: @id', ['@id' => 1])); Chris@17: $this->drupalPostForm(NULL, [], 'comment_settings_edit'); Chris@17: // Change default pager to 2. Chris@17: $this->drupalPostForm(NULL, ['fields[comment][settings_edit_form][settings][pager_id]' => 2], t('Save')); Chris@17: $this->assertText(t('Pager ID: @id', ['@id' => 2])); Chris@17: // Revert the changes. Chris@17: $this->drupalPostForm(NULL, [], 'comment_settings_edit'); Chris@17: $this->drupalPostForm(NULL, ['fields[comment][settings_edit_form][settings][pager_id]' => 0], t('Save')); Chris@17: $this->assertNoText(t('Pager ID: @id', ['@id' => 0]), 'No summary for standard pager'); Chris@17: Chris@17: $this->drupalLogin($this->adminUser); Chris@17: Chris@17: // Add a new node with both comment fields open. Chris@17: $node = $this->drupalCreateNode(['type' => 'article', 'promote' => 1, 'uid' => $this->webUser->id()]); Chris@17: // Set comment options. Chris@17: $comments = []; Chris@17: foreach (['comment', 'comment_2'] as $field_name) { Chris@17: $this->setCommentForm(TRUE, $field_name); Chris@17: $this->setCommentPreview(DRUPAL_OPTIONAL, $field_name); Chris@17: $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_FLAT, 'Comment paging changed.', $field_name); Chris@17: Chris@17: // Set comments to one per page so that we are able to test paging without Chris@17: // needing to insert large numbers of comments. Chris@17: $this->setCommentsPerPage(1, $field_name); Chris@17: for ($i = 0; $i < 3; $i++) { Chris@17: $comment = t('Comment @count on field @field', [ Chris@17: '@count' => $i + 1, Chris@17: '@field' => $field_name, Chris@17: ]); Chris@17: $comments[] = $this->postComment($node, $comment, $comment, TRUE, $field_name); Chris@17: } Chris@17: } Chris@17: Chris@17: // Check the first page of the node, and confirm the correct comments are Chris@17: // shown. Chris@17: $this->drupalGet('node/' . $node->id()); Chris@17: $this->assertRaw(t('next'), 'Paging links found.'); Chris@17: $this->assertRaw('Comment 1 on field comment'); Chris@17: $this->assertRaw('Comment 1 on field comment_2'); Chris@17: // Navigate to next page of field 1. Chris@17: $this->clickLinkWithXPath('//h3/a[normalize-space(text())=:label]/ancestor::section[1]//a[@rel="next"]', [':label' => 'Comment 1 on field comment']); Chris@17: // Check only one pager updated. Chris@17: $this->assertRaw('Comment 2 on field comment'); Chris@17: $this->assertRaw('Comment 1 on field comment_2'); Chris@17: // Return to page 1. Chris@17: $this->drupalGet('node/' . $node->id()); Chris@17: // Navigate to next page of field 2. Chris@17: $this->clickLinkWithXPath('//h3/a[normalize-space(text())=:label]/ancestor::section[1]//a[@rel="next"]', [':label' => 'Comment 1 on field comment_2']); Chris@17: // Check only one pager updated. Chris@17: $this->assertRaw('Comment 1 on field comment'); Chris@17: $this->assertRaw('Comment 2 on field comment_2'); Chris@17: // Navigate to next page of field 1. Chris@17: $this->clickLinkWithXPath('//h3/a[normalize-space(text())=:label]/ancestor::section[1]//a[@rel="next"]', [':label' => 'Comment 1 on field comment']); Chris@17: // Check only one pager updated. Chris@17: $this->assertRaw('Comment 2 on field comment'); Chris@17: $this->assertRaw('Comment 2 on field comment_2'); Chris@17: } Chris@17: Chris@17: /** Chris@17: * Follows a link found at a give xpath query. Chris@17: * Chris@17: * Will click the first link found with the given xpath query by default, Chris@17: * or a later one if an index is given. Chris@17: * Chris@17: * If the link is discovered and clicked, the test passes. Fail otherwise. Chris@17: * Chris@17: * @param string $xpath Chris@17: * Xpath query that targets an anchor tag, or set of anchor tags. Chris@17: * @param array $arguments Chris@17: * An array of arguments with keys in the form ':name' matching the Chris@17: * placeholders in the query. The values may be either strings or numeric Chris@17: * values. Chris@17: * @param int $index Chris@17: * Link position counting from zero. Chris@17: * Chris@17: * @return string|false Chris@17: * Page contents on success, or FALSE on failure. Chris@17: * Chris@17: * @see WebTestBase::clickLink() Chris@17: */ Chris@17: protected function clickLinkWithXPath($xpath, $arguments = [], $index = 0) { Chris@17: $url_before = $this->getUrl(); Chris@17: $urls = $this->xpath($xpath, $arguments); Chris@17: if (isset($urls[$index])) { Chris@17: $url_target = $this->getAbsoluteUrl($urls[$index]->getAttribute('href')); Chris@17: $this->pass(new FormattableMarkup('Clicked link %label (@url_target) from @url_before', ['%label' => $xpath, '@url_target' => $url_target, '@url_before' => $url_before]), 'Browser'); Chris@17: return $this->drupalGet($url_target); Chris@17: } Chris@17: $this->fail(new FormattableMarkup('Link %label does not exist on @url_before', ['%label' => $xpath, '@url_before' => $url_before]), 'Browser'); Chris@17: return FALSE; Chris@17: } Chris@17: Chris@17: }