3 namespace Drupal\diff\Tests;
5 use Drupal\language\Entity\ConfigurableLanguage;
6 use Drupal\system\Tests\Menu\AssertBreadcrumbTrait;
9 * Tests the diff revisions overview.
13 class DiffRevisionTest extends DiffTestBase {
15 use AssertBreadcrumbTrait;
22 public static $modules = [
24 'content_translation',
29 * Run all test fragments.
31 public function testAll() {
32 $this->doTestRevisionDiffOverview();
33 $this->doTestOverviewPager();
34 $this->doTestRevisionOverviewErrorMessages();
35 $this->doTestEntityReference();
39 * Tests the revision diff overview.
41 protected function doTestRevisionDiffOverview() {
42 $this->drupalPlaceBlock('system_breadcrumb_block');
43 // Login as admin with the required permission.
44 $this->loginAsAdmin(['delete any article content']);
47 $title = 'test_title_a';
49 'title[0][value]' => $title,
50 'body[0][value]' => '<p>Revision 1</p>
51 <p>first_unique_text</p>
52 <p>second_unique_text</p>',
54 $this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
55 $node = $this->drupalGetNodeByTitle($title);
56 $created = $node->getCreatedTime();
57 $this->drupalGet('node/' . $node->id());
59 // Make sure the revision tab doesn't exist.
60 $this->assertNoLink('Revisions');
62 // Create a second revision, with a revision comment.
63 $this->drupalGet('node/add/article');
65 'body[0][value]' => '<p>Revision 2</p>
66 <p>first_unique_text</p>
67 <p>second_unique_text</p>',
69 'revision_log[0][value]' => 'Revision 2 comment',
71 $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
72 $this->drupalGet('node/' . $node->id());
74 // Check the revisions overview.
75 $this->clickLink(t('Revisions'));
76 $rows = $this->xpath('//tbody/tr');
77 // Make sure only two revisions available.
78 $this->assertEqual(count($rows), 2);
79 // Assert the revision summary.
80 $this->assertUniqueText('Revision 2 comment');
81 $this->assertText('Initial revision.');
83 // Compare the revisions in standard mode.
84 $this->drupalPostForm(NULL, NULL, t('Compare selected revisions'));
85 $this->clickLink('Split fields');
86 // Assert breadcrumbs are properly displayed.
87 $this->assertRaw('<nav class="breadcrumb"');
90 "node/" . $node->id() => $node->label(),
91 "node/" . $node->id() . "/revisions" => 'Revisions',
93 $this->assertBreadcrumb(NULL, $trail);
94 // Extract the changes.
95 $this->assertText('Body');
96 $rows = $this->xpath('//tbody/tr');
97 $head = $this->xpath('//thead/tr');
98 $diff_row = $rows[1]->td;
99 // Assert the revision comment.
100 $this->assertRaw('diff-revision__item-message">Revision 2 comment');
101 // Assert changes made to the body, text 1 changed to 2.
102 $this->assertEqual((string) ($diff_row[0]), '1');
103 $this->assertEqual((string) ($diff_row[1]), '-');
104 $this->assertEqual((string) (($diff_row[2]->span)), '1');
105 $this->assertEqual(htmlspecialchars_decode(strip_tags($diff_row[2]->asXML())), '<p>Revision 1</p>');
106 $this->assertEqual((string) ($diff_row[3]), '1');
107 $this->assertEqual((string) ($diff_row[4]), '+');
108 $this->assertEqual((string) (($diff_row[5]->span)), '2');
109 $this->assertEqual(htmlspecialchars_decode((strip_tags($diff_row[5]->asXML()))), '<p>Revision 2</p>');
111 // Compare the revisions in markdown mode.
112 $this->clickLink('Strip tags');
113 $rows = $this->xpath('//tbody/tr');
114 // Assert breadcrumbs are properly displayed.
115 $this->assertRaw('<nav class="breadcrumb"');
118 "node/" . $node->id() => $node->label(),
119 "node/" . $node->id() . "/revisions" => 'Revisions',
121 $this->assertBreadcrumb(NULL, $trail);
122 // Extract the changes.
123 $diff_row = $rows[1]->td;
124 // Assert changes made to the body, text 1 changed to 2.
125 $this->assertEqual((string) ($diff_row[0]), '-');
126 $this->assertEqual((string) (($diff_row[1]->span)), '1');
127 $this->assertEqual(htmlspecialchars_decode(strip_tags($diff_row[1]->asXML())), 'Revision 1');
128 $this->assertEqual((string) (($diff_row[2])), '+');
129 $this->assertEqual((string) (($diff_row[3]->span)), '2');
130 $this->assertEqual(htmlspecialchars_decode((strip_tags($diff_row[3]->asXML()))), 'Revision 2');
132 // Compare the revisions in single column mode.
133 $this->clickLink('Unified fields');
134 // Assert breadcrumbs are properly displayed.
135 $this->assertRaw('<nav class="breadcrumb"');
138 "node/" . $node->id() => $node->label(),
139 "node/" . $node->id() . "/revisions" => 'Revisions',
141 $this->assertBreadcrumb(NULL, $trail);
142 // Extract the changes.
143 $rows = $this->xpath('//tbody/tr');
144 $diff_row = $rows[1]->td;
145 // Assert changes made to the body, text 1 changed to 2.
146 $this->assertEqual((string) ($diff_row[0]), '1');
147 $this->assertEqual((string) ($diff_row[1]), '');
148 $this->assertEqual((string) ($diff_row[2]), '-');
149 $this->assertEqual((string) (($diff_row[3]->span)), '1');
150 $this->assertEqual(htmlspecialchars_decode(strip_tags($diff_row[3]->asXML())), '<p>Revision 1</p>');
151 $diff_row = $rows[2]->td;
152 $this->assertEqual((string) ($diff_row[0]), '');
153 $this->assertEqual((string) ($diff_row[1]), '1');
154 $this->assertEqual((string) (($diff_row[2])), '+');
155 $this->assertEqual((string) (($diff_row[3]->span)), '2');
156 $this->assertEqual(htmlspecialchars_decode((strip_tags($diff_row[3]->asXML()))), '<p>Revision 2</p>');
157 $this->assertUniqueText('first_unique_text');
158 $this->assertUniqueText('second_unique_text');
159 $diff_row = $rows[3]->td;
160 $this->assertEqual((string) ($diff_row[0]), '2');
161 $this->assertEqual((string) ($diff_row[1]), '2');
162 $diff_row = $rows[4]->td;
163 $this->assertEqual((string) ($diff_row[0]), '3');
164 $this->assertEqual((string) ($diff_row[1]), '3');
166 $this->clickLink('Strip tags');
167 // Extract the changes.
168 $rows = $this->xpath('//tbody/tr');
169 $diff_row = $rows[1]->td;
171 // Assert changes made to the body, with strip_tags filter and make sure
172 // there are no line numbers.
173 $this->assertEqual((string) ($diff_row[0]), '-');
174 $this->assertEqual((string) (($diff_row[1]->span)), '1');
175 $this->assertEqual(htmlspecialchars_decode(strip_tags($diff_row[1]->asXML())), 'Revision 1');
176 $diff_row = $rows[2]->td;
177 $this->assertEqual((string) (($diff_row[0])), '+');
178 $this->assertEqual((string) (($diff_row[1]->span)), '2');
179 $this->assertEqual(htmlspecialchars_decode((strip_tags($diff_row[1]->asXML()))), 'Revision 2');
181 $this->drupalGet('node/' . $node->id());
182 $this->clickLink(t('Revisions'));
183 // Revert the revision, confirm.
184 $this->clickLink(t('Revert'));
185 $this->drupalPostForm(NULL, NULL, t('Revert'));
186 $this->assertText('Article ' . $title . ' has been reverted to the revision from');
188 // Make sure three revisions are available.
189 $rows = $this->xpath('//tbody/tr');
190 $this->assertEqual(count($rows), 3);
191 // Make sure the reverted comment is there.
192 $this->assertText('Copy of the revision from');
194 // Delete the first revision (last entry in table).
195 $this->clickLink(t('Delete'), 0);
196 $this->drupalPostForm(NULL, NULL, t('Delete'));
197 $this->assertText('of Article ' . $title . ' has been deleted.');
199 // Make sure two revisions are available.
200 $rows = $this->xpath('//tbody/tr');
201 $this->assertEqual(count($rows), 2);
203 // Delete one revision so that we are left with only 1 revision.
204 $this->clickLink(t('Delete'), 0);
205 $this->drupalPostForm(NULL, NULL, t('Delete'));
206 $this->assertText('of Article ' . $title . ' has been deleted.');
208 // Make sure we only have 1 revision now.
209 $rows = $this->xpath('//tbody/tr');
210 $this->assertEqual(count($rows), 1);
212 // Assert that there are no radio buttons for revision selection.
213 $this->assertNoFieldByXPath('//input[@type="radio"]');
214 // Assert that there is no submit button.
215 $this->assertNoFieldByXPath('//input[@type="submit"]');
217 // Create two new revisions of node.
219 'title[0][value]' => 'new test title',
220 'body[0][value]' => '<p>new body</p>',
222 $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save and keep published');
225 'title[0][value]' => 'newer test title',
226 'body[0][value]' => '<p>newer body</p>',
228 $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save and keep published');
230 $this->clickLink(t('Revisions'));
231 // Assert the revision summary.
232 $this->assertNoUniqueText('Changes on: Title, Body');
233 $this->assertText('Copy of the revision from');
238 $this->drupalPostForm(NULL, $edit, t('Compare selected revisions'));
239 $this->clickLink('Strip tags');
240 // Check markdown layout is used when navigating between revisions.
241 $rows = $this->xpath('//tbody/tr');
242 $diff_row = $rows[3]->td;
243 $this->assertEqual(htmlspecialchars_decode(strip_tags($diff_row[3]->asXML())), 'new body');
244 $this->clickLink('Next change');
245 // The filter should be the same as the previous screen.
246 $rows = $this->xpath('//tbody/tr');
247 $diff_row = $rows[3]->td;
248 $this->assertEqual(htmlspecialchars_decode(strip_tags($diff_row[3]->asXML())), 'newer body');
250 // Get the node, create a new revision that is not the current one.
251 $node = $this->getNodeByTitle('newer test title');
252 $node->setNewRevision(TRUE);
253 $node->isDefaultRevision(FALSE);
255 $this->drupalGet('node/' . $node->id() . '/revisions');
257 // Check that the last revision is not the current one.
258 $this->assertLink(t('Set as current revision'));
259 $text = $this->xpath('//tbody/tr[2]/td[4]/em');
260 $this->assertEqual($text[0], 'Current revision');
262 // Set the last revision as current.
263 $this->clickLink('Set as current revision');
264 $this->drupalPostForm(NULL, [], t('Revert'));
266 // Check the last revision is set as current.
267 $text = $this->xpath('//tbody/tr[1]/td[4]/em');
268 $this->assertEqual($text[0], 'Current revision');
269 $this->assertNoLink(t('Set as current revision'));
273 * Tests pager on diff overview.
275 protected function doTestOverviewPager() {
276 $config = \Drupal::configFactory()->getEditable('diff.settings');
277 $config->set('general_settings.revision_pager_limit', 10)->save();
279 $this->loginAsAdmin(['view article revisions']);
281 $node = $this->drupalCreateNode([
284 // Create 11 more revisions in order to trigger paging on the revisions
286 for ($i = 0; $i < 11; $i++) {
287 $node->setNewRevision(TRUE);
291 // Check the number of elements on the first page.
292 $this->drupalGet('node/' . $node->id() . '/revisions');
293 $element = $this->xpath('//*[@id="edit-node-revisions-table"]/tbody/tr');
294 $this->assertEqual(count($element), 10);
295 // Check that the pager exists.
296 $this->assertRaw('page=1');
298 $this->clickLinkPartialName('Next page');
299 // Check the number of elements on the second page.
300 $element = $this->xpath('//*[@id="edit-node-revisions-table"]/tbody/tr');
301 $this->assertEqual(count($element), 2);
302 $this->assertRaw('page=0');
303 $this->clickLinkPartialName('Previous page');
307 * Tests the revisions overview error messages.
309 * @todo Move to DiffLocaleTest?
311 protected function doTestRevisionOverviewErrorMessages() {
312 // Enable some languages for this test.
313 $language = ConfigurableLanguage::createFromLangcode('de');
316 // Login as admin with the required permissions.
317 $this->loginAsAdmin([
318 'administer node form display',
319 'administer languages',
320 'administer content translation',
321 'create content translations',
322 'translate any entity',
325 // Make article content translatable.
327 'entity_types[node]' => TRUE,
328 'settings[node][article][translatable]' => TRUE,
329 'settings[node][article][settings][language][language_alterable]' => TRUE,
331 $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
333 // Create an article.
334 $title = 'test_title_b';
336 'title[0][value]' => $title,
337 'body[0][value]' => '<p>Revision 1</p>',
339 $this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
340 $node = $this->drupalGetNodeByTitle($title);
341 $revision1 = $node->getRevisionId();
343 // Create a revision, changing the node language to German.
345 'langcode[0][value]' => 'de',
346 'body[0][value]' => '<p>Revision 2</p>',
349 $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
351 // Check the revisions overview, ensure only one revisions is available.
352 $this->clickLink(t('Revisions'));
353 $rows = $this->xpath('//tbody/tr');
354 $this->assertEqual(count($rows), 1);
356 // Compare the revisions and assert the first error message.
357 $this->drupalPostForm(NULL, NULL, t('Compare selected revisions'));
358 $this->assertText('Multiple revisions are needed for comparison.');
360 // Create another revision, changing the node language back to English.
362 'langcode[0][value]' => 'en',
363 'body[0][value]' => '<p>Revision 3</p>',
366 $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
367 $node = $this->drupalGetNodeByTitle($title, TRUE);
368 $revision3 = $node->getRevisionId();
370 // Check the revisions overview, ensure two revisions are available.
371 $this->clickLink(t('Revisions'));
372 $rows = $this->xpath('//tbody/tr');
373 $this->assertEqual(count($rows), 2);
374 $this->assertNoFieldChecked('edit-node-revisions-table-0-select-column-one');
375 $this->assertFieldChecked('edit-node-revisions-table-0-select-column-two');
376 $this->assertNoFieldChecked('edit-node-revisions-table-1-select-column-one');
377 $this->assertNoFieldChecked('edit-node-revisions-table-1-select-column-two');
379 // Compare the revisions and assert the second error message.
380 $this->drupalPostForm(NULL, NULL, t('Compare selected revisions'));
381 $this->assertText('Select two revisions to compare.');
383 // Check the same revisions twice and compare.
385 'radios_left' => $revision3,
386 'radios_right' => $revision3,
388 $this->drupalPostForm('/node/' . $node->id() . '/revisions', $edit, 'Compare selected revisions');
389 // Assert the third error message.
390 $this->assertText('Select different revisions to compare.');
392 // Check different revisions and compare. This time should work correctly.
394 'radios_left' => $revision3,
395 'radios_right' => $revision1,
397 $this->drupalPostForm('/node/' . $node->id() . '/revisions', $edit, 'Compare selected revisions');
398 $this->assertLinkByHref('node/' . $node->id() . '/revisions/view/' . $revision1 . '/' . $revision3);
402 * Tests Reference to Deleted Entities.
404 protected function doTestEntityReference() {
405 // Login as admin with the required permissions.
406 $this->loginAsAdmin([
407 'administer node fields',
410 // Adding Entity Reference to Article Content Type.
411 $this->drupalPostForm('admin/structure/types/manage/article/fields/add-field', [
412 'new_storage_type' => 'field_ui:entity_reference:node',
413 'label' => 'Content reference test',
414 'field_name' => 'content',
415 ], t('Save and continue'));
417 // Create an first article.
418 $title = 'test_title_c';
420 'title[0][value]' => $title,
421 'body[0][value]' => '<p>First article</p>',
423 $this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
424 $node_one = $this->drupalGetNodeByTitle($title);
426 // Create second article.
427 $title = 'test_title_d';
429 'title[0][value]' => $title,
430 'body[0][value]' => '<p>Second article</p>',
432 $this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
433 $node_two = $this->drupalGetNodeByTitle($title);
435 // Create revision and add entity reference from second node to first.
437 'body[0][value]' => '<p>First Revision</p>',
438 'field_content[0][target_id]' => $node_two->getTitle(),
441 $this->drupalPostForm('node/' . $node_one->id() . '/edit', $edit, t('Save and keep published'));
443 // Delete referenced node.
446 // Access revision of first node.
447 $this->drupalGet('/node/' . $node_one->id());
448 $this->clickLink(t('Revisions'));
449 $this->drupalPostForm(NULL, NULL, t('Compare selected revisions'));
450 // Revision section should appear.
451 $this->assertResponse(200);