3 namespace Drupal\comment\Tests;
5 use Drupal\Component\Serialization\Json;
6 use Drupal\Core\Language\LanguageInterface;
7 use Drupal\comment\CommentInterface;
9 use Drupal\comment\Entity\Comment;
12 * Tests the 'new' indicator posted on comments.
16 class CommentNewIndicatorTest extends CommentTestBase {
19 * Use the main node listing to test rendering on teasers.
23 * @todo Remove this dependency.
25 public static $modules = ['views'];
28 * Get node "x new comments" metadata from the server for the current user.
30 * @param array $node_ids
31 * An array of node IDs.
36 protected function renderNewCommentsNodeLinks(array $node_ids) {
39 for ($i = 0; $i < count($node_ids); $i++) {
40 $post['node_ids[' . $i . ']'] = $node_ids[$i];
42 $post['field_name'] = 'comment';
44 // Serialize POST values.
45 foreach ($post as $key => $value) {
46 // Encode according to application/x-www-form-urlencoded
47 // Both names and values needs to be urlencoded, according to
48 // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
49 $post[$key] = urlencode($key) . '=' . urlencode($value);
51 $post = implode('&', $post);
53 // Perform HTTP request.
54 return $this->curlExec([
55 CURLOPT_URL => \Drupal::url('comment.new_comments_node_links', [], ['absolute' => TRUE]),
57 CURLOPT_POSTFIELDS => $post,
58 CURLOPT_HTTPHEADER => [
59 'Accept: application/json',
60 'Content-Type: application/x-www-form-urlencoded',
66 * Tests new comment marker.
68 public function testCommentNewCommentsIndicator() {
69 // Test if the right links are displayed when no comment is present for the
71 $this->drupalLogin($this->adminUser);
72 $this->drupalGet('node');
73 $this->assertNoLink(t('@count comments', ['@count' => 0]));
74 $this->assertLink(t('Read more'));
75 // Verify the data-history-node-last-comment-timestamp attribute, which is
76 // used by the drupal.node-new-comments-link library to determine whether
77 // a "x new comments" link might be necessary or not. We do this in
78 // JavaScript to prevent breaking the render cache.
79 $this->assertIdentical(0, count($this->xpath('//*[@data-history-node-last-comment-timestamp]')), 'data-history-node-last-comment-timestamp attribute is not set.');
81 // Create a new comment. This helper function may be run with different
82 // comment settings so use $comment->save() to avoid complex setup.
83 /** @var \Drupal\comment\CommentInterface $comment */
84 $comment = Comment::create([
86 'entity_id' => $this->node->id(),
87 'entity_type' => 'node',
88 'field_name' => 'comment',
90 'uid' => $this->loggedInUser->id(),
91 'status' => CommentInterface::PUBLISHED,
92 'subject' => $this->randomMachineName(),
93 'hostname' => '127.0.0.1',
94 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
95 'comment_body' => [LanguageInterface::LANGCODE_NOT_SPECIFIED => [$this->randomMachineName()]],
98 $this->drupalLogout();
100 // Log in with 'web user' and check comment links.
101 $this->drupalLogin($this->webUser);
102 $this->drupalGet('node');
103 // Verify the data-history-node-last-comment-timestamp attribute. Given its
104 // value, the drupal.node-new-comments-link library would determine that the
105 // node received a comment after the user last viewed it, and hence it would
106 // perform an HTTP request to render the "new comments" node link.
107 $this->assertIdentical(1, count($this->xpath('//*[@data-history-node-last-comment-timestamp="' . $comment->getChangedTime() . '"]')), 'data-history-node-last-comment-timestamp attribute is set to the correct value.');
108 $this->assertIdentical(1, count($this->xpath('//*[@data-history-node-field-name="comment"]')), 'data-history-node-field-name attribute is set to the correct value.');
109 // The data will be pre-seeded on this particular page in drupalSettings, to
110 // avoid the need for the client to make a separate request to the server.
111 $settings = $this->getDrupalSettings();
112 $this->assertEqual($settings['history'], ['lastReadTimestamps' => [1 => 0]]);
113 $this->assertEqual($settings['comment'], [
114 'newCommentsLinks' => [
118 'new_comment_count' => 1,
119 'first_new_comment_link' => Url::fromRoute('entity.node.canonical', ['node' => 1])->setOptions([
127 // Pretend the data was not present in drupalSettings, i.e. test the
128 // separate request to the server.
129 $response = $this->renderNewCommentsNodeLinks([$this->node->id()]);
130 $this->assertResponse(200);
131 $json = Json::decode($response);
132 $expected = [$this->node->id() => [
133 'new_comment_count' => 1,
134 'first_new_comment_link' => $this->node->url('canonical', ['fragment' => 'new']),
136 $this->assertIdentical($expected, $json);
138 // Failing to specify node IDs for the endpoint should return a 404.
139 $this->renderNewCommentsNodeLinks([]);
140 $this->assertResponse(404);
142 // Accessing the endpoint as the anonymous user should return a 403.
143 $this->drupalLogout();
144 $this->renderNewCommentsNodeLinks([$this->node->id()]);
145 $this->assertResponse(403);
146 $this->renderNewCommentsNodeLinks([]);
147 $this->assertResponse(403);