diff --git a/core/modules/book/src/Tests/BookBreadcrumbTest.php b/core/modules/book/tests/src/Functional/BookBreadcrumbTest.php
similarity index 95%
rename from core/modules/book/src/Tests/BookBreadcrumbTest.php
rename to core/modules/book/tests/src/Functional/BookBreadcrumbTest.php
index 57e1b3d..69c0d62 100644
--- a/core/modules/book/src/Tests/BookBreadcrumbTest.php
+++ b/core/modules/book/tests/src/Functional/BookBreadcrumbTest.php
@@ -1,15 +1,15 @@
xpath('//nav[@class="breadcrumb"]/ol/li/a');
$got_breadcrumb = array();
foreach ($links as $link) {
- $got_breadcrumb[] = (string) $link;
+ $got_breadcrumb[] = $link->getText();
}
// Home link and four parent book nodes should be in the breadcrumb.
$this->assertEqual(5, count($got_breadcrumb));
@@ -162,7 +162,7 @@ public function testBreadcrumbTitleUpdates() {
$links = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
$got_breadcrumb = array();
foreach ($links as $link) {
- $got_breadcrumb[] = (string) $link;
+ $got_breadcrumb[] = $link->getText();
}
$this->assertEqual(5, count($got_breadcrumb));
$this->assertEqual($edit['title[0][value]'], end($got_breadcrumb));
@@ -183,7 +183,7 @@ public function testBreadcrumbAccessUpdates() {
$links = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
$got_breadcrumb = array();
foreach ($links as $link) {
- $got_breadcrumb[] = (string) $link;
+ $got_breadcrumb[] = $link->getText();
}
$this->assertEqual(5, count($got_breadcrumb));
$this->assertEqual($edit['title[0][value]'], end($got_breadcrumb));
@@ -193,7 +193,7 @@ public function testBreadcrumbAccessUpdates() {
$links = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
$got_breadcrumb = array();
foreach ($links as $link) {
- $got_breadcrumb[] = (string) $link;
+ $got_breadcrumb[] = $link->getText();
}
$this->assertEqual(4, count($got_breadcrumb));
$this->assertEqual($nodes[2]->getTitle(), end($got_breadcrumb));
diff --git a/core/modules/book/src/Tests/BookTest.php b/core/modules/book/tests/src/Functional/BookTest.php
similarity index 87%
rename from core/modules/book/src/Tests/BookTest.php
rename to core/modules/book/tests/src/Functional/BookTest.php
index 7ebec63..53afc1a 100644
--- a/core/modules/book/src/Tests/BookTest.php
+++ b/core/modules/book/tests/src/Functional/BookTest.php
@@ -1,11 +1,11 @@
assertPattern($this->generateOutlinePattern($nodes), format_string('Node @number outline confirmed.', array('@number' => $number)));
+ $this->assertPattern($this->generateOutlinePattern($nodes));
}
else {
$this->pass(format_string('Node %number does not have outline.', array('%number' => $number)));
@@ -267,14 +267,14 @@ function checkBookNode(EntityInterface $node, $nodes, $previous = FALSE, $up = F
$url = $previous->urlInfo();
$url->setOptions(array('attributes' => array('rel' => array('prev'), 'title' => t('Go to previous page'))));
$text = SafeMarkup::format('‹ @label', array('@label' => $previous->label()));
- $this->assertRaw(\Drupal::l($text, $url), 'Previous page link found.');
+ $this->assertRaw(\Drupal::l($text, $url));
}
if ($up) {
/** @var \Drupal\Core\Url $url */
$url = $up->urlInfo();
$url->setOptions(array('attributes' => array('title' => t('Go to parent page'))));
- $this->assertRaw(\Drupal::l('Up', $url), 'Up page link found.');
+ $this->assertRaw(\Drupal::l('Up', $url));
}
if ($next) {
@@ -282,7 +282,7 @@ function checkBookNode(EntityInterface $node, $nodes, $previous = FALSE, $up = F
$url = $next->urlInfo();
$url->setOptions(array('attributes' => array('rel' => array('next'), 'title' => t('Go to next page'))));
$text = SafeMarkup::format('@label ›', array('@label' => $next->label()));
- $this->assertRaw(\Drupal::l($text, $url), 'Next page link found.');
+ $this->assertRaw(\Drupal::l($text, $url));
}
// Compute the expected breadcrumb.
@@ -296,7 +296,7 @@ function checkBookNode(EntityInterface $node, $nodes, $previous = FALSE, $up = F
$links = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
$got_breadcrumb = array();
foreach ($links as $link) {
- $got_breadcrumb[] = (string) $link['href'];
+ $got_breadcrumb[] = $link->getAttribute('href');
}
// Compare expected and got breadcrumbs.
@@ -304,8 +304,8 @@ function checkBookNode(EntityInterface $node, $nodes, $previous = FALSE, $up = F
// Check printer friendly version.
$this->drupalGet('book/export/html/' . $node->id());
- $this->assertText($node->label(), 'Printer friendly title found.');
- $this->assertRaw($node->body->processed, 'Printer friendly body found.');
+ $this->assertText($node->label());
+ $this->assertRaw($node->body->processed);
$number++;
}
@@ -384,35 +384,35 @@ function testBookExport() {
// Make sure each part of the book is there.
foreach ($nodes as $node) {
- $this->assertText($node->label(), 'Node title found in printer friendly version.');
- $this->assertRaw($node->body->processed, 'Node body found in printer friendly version.');
+ $this->assertText($node->label());
+ $this->assertRaw($node->body->processed);
}
// Make sure we can't export an unsupported format.
$this->drupalGet('book/export/foobar/' . $this->book->id());
- $this->assertResponse('404', 'Unsupported export format returned "not found".');
+ $this->assertResponse('404');
// Make sure we get a 404 on a not existing book node.
$this->drupalGet('book/export/html/123');
- $this->assertResponse('404', 'Not existing book node returned "not found".');
+ $this->assertResponse('404');
// Make sure an anonymous user cannot view printer-friendly version.
$this->drupalLogout();
// Load the book and verify there is no printer-friendly version link.
$this->drupalGet('node/' . $this->book->id());
- $this->assertNoLink(t('Printer-friendly version'), 'Anonymous user is not shown link to printer-friendly version.');
+ $this->assertNoLink(t('Printer-friendly version'));
// Try getting the URL directly, and verify it fails.
$this->drupalGet('book/export/html/' . $this->book->id());
- $this->assertResponse('403', 'Anonymous user properly forbidden.');
+ $this->assertResponse('403');
// Now grant anonymous users permission to view the printer-friendly
// version and verify that node access restrictions still prevent them from
// seeing it.
user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, array('access printer-friendly version'));
$this->drupalGet('book/export/html/' . $this->book->id());
- $this->assertResponse('403', 'Anonymous user properly forbidden from seeing the printer-friendly version when denied by node access.');
+ $this->assertResponse('403');
}
/**
@@ -428,14 +428,14 @@ function testBookNavigationBlock() {
$edit = array();
$edit[RoleInterface::ANONYMOUS_ID . '[node test view]'] = TRUE;
$this->drupalPostForm('admin/people/permissions/' . RoleInterface::ANONYMOUS_ID, $edit, t('Save permissions'));
- $this->assertText(t('The changes have been saved.'), "Permission 'node test view' successfully assigned to anonymous users.");
+ $this->assertText(t('The changes have been saved.'));
// Test correct display of the block.
$nodes = $this->createBook();
$this->drupalGet('');
- $this->assertText($block->label(), 'Book navigation block is displayed.');
- $this->assertText($this->book->label(), format_string('Link to book root (@title) is displayed.', array('@title' => $nodes[0]->label())));
- $this->assertNoText($nodes[0]->label(), 'No links to individual book pages are displayed.');
+ $this->assertText($block->label());
+ $this->assertText($this->book->label());
+ $this->assertNoText($nodes[0]->label());
}
/**
@@ -503,7 +503,7 @@ function testNavigationBlockOnAccessModuleInstalled() {
$edit = array();
$edit[RoleInterface::ANONYMOUS_ID . '[node test view]'] = TRUE;
$this->drupalPostForm('admin/people/permissions/' . RoleInterface::ANONYMOUS_ID, $edit, t('Save permissions'));
- $this->assertText(t('The changes have been saved.'), "Permission 'node test view' successfully assigned to anonymous users.");
+ $this->assertText(t('The changes have been saved.'));
// Create a book.
$this->createBook();
@@ -511,16 +511,16 @@ function testNavigationBlockOnAccessModuleInstalled() {
// Test correct display of the block to registered users.
$this->drupalLogin($this->webUser);
$this->drupalGet('node/' . $this->book->id());
- $this->assertText($block->label(), 'Book navigation block is displayed to registered users.');
+ $this->assertText($block->label());
$this->drupalLogout();
// Test correct display of the block to anonymous users.
$this->drupalGet('node/' . $this->book->id());
- $this->assertText($block->label(), 'Book navigation block is displayed to anonymous users.');
+ $this->assertText($block->label());
// Test the 'book pages' block_mode setting.
$this->drupalGet('');
- $this->assertNoText($block->label(), 'Book navigation block is not shown on non-book pages.');
+ $this->assertNoText($block->label());
}
/**
@@ -534,7 +534,7 @@ function testBookDelete() {
// Test access to delete top-level and child book nodes.
$this->drupalGet('node/' . $this->book->id() . '/outline/remove');
- $this->assertResponse('403', 'Deleting top-level book node properly forbidden.');
+ $this->assertResponse('403');
$this->drupalPostForm('node/' . $nodes[4]->id() . '/outline/remove', $edit, t('Remove'));
$node_storage->resetCache(array($nodes[4]->id()));
$node4 = $node_storage->load($nodes[4]->id());
@@ -571,34 +571,6 @@ function testBookDelete() {
}
/**
- * Tests re-ordering of books.
- */
- public function testBookOrdering() {
- // Create new book.
- $this->createBook();
- $book = $this->book;
-
- $this->drupalLogin($this->adminUser);
- $node1 = $this->createBookNode($book->id());
- $node2 = $this->createBookNode($book->id());
- $pid = $node1->book['nid'];
-
- // Head to admin screen and attempt to re-order.
- $this->drupalGet('admin/structure/book/' . $book->id());
- $edit = array(
- "table[book-admin-{$node1->id()}][weight]" => 1,
- "table[book-admin-{$node2->id()}][weight]" => 2,
- // Put node 2 under node 1.
- "table[book-admin-{$node2->id()}][pid]" => $pid,
- );
- $this->drupalPostForm(NULL, $edit, t('Save book pages'));
- // Verify weight was updated.
- $this->assertFieldByName("table[book-admin-{$node1->id()}][weight]", 1);
- $this->assertFieldByName("table[book-admin-{$node2->id()}][weight]", 2);
- $this->assertFieldByName("table[book-admin-{$node2->id()}][pid]", $pid);
- }
-
- /**
* Tests outline of a book.
*/
public function testBookOutline() {
@@ -612,7 +584,7 @@ public function testBookOutline() {
$this->drupalLogin($this->adminUser);
$this->drupalGet('node/' . $empty_book->id() . '/outline');
$this->assertRaw(t('Book outline'));
- $this->assertOptionSelected('edit-book-bid', 0, 'Node does not belong to a book');
+ $this->assertOptionSelected('edit-book-bid', 0);
$this->assertNoLink(t('Remove from book outline'));
$edit = array();
@@ -701,7 +673,7 @@ public function testAdminBookListing() {
// Load the book page and assert the created book title is displayed.
$this->drupalLogin($this->adminUser);
$this->drupalGet('admin/structure/book');
- $this->assertText($this->book->label(), 'The book title is displayed on the administrative book listing page.');
+ $this->assertText($this->book->label());
}
/**
@@ -718,7 +690,7 @@ public function testAdminBookNodeListing() {
$this->assertText($this->book->label(), 'The book title is displayed on the administrative book listing page.');
$elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a');
- $this->assertEqual((string) $elements[0], 'View', 'View link is found from the list.');
+ $this->assertEqual((string) $elements[0]->getText(), 'View', 'View link is found from the list.');
}
/**
diff --git a/core/modules/book/tests/src/FunctionalJavascript/BookJavascriptTest.php b/core/modules/book/tests/src/FunctionalJavascript/BookJavascriptTest.php
new file mode 100644
index 0000000..2ab7d3a
--- /dev/null
+++ b/core/modules/book/tests/src/FunctionalJavascript/BookJavascriptTest.php
@@ -0,0 +1,137 @@
+ 'book',
+ 'title' => 'Book',
+ 'book' => ['bid' => 'new'],
+ ]);
+ $book->save();
+ $page1 = Node::create([
+ 'type' => 'book',
+ 'title' => '1st page',
+ 'book' => ['bid' => $book->id(), 'pid' => $book->id(), 'weight' => 0],
+ ]);
+ $page1->save();
+ $page2 = Node::create([
+ 'type' => 'book',
+ 'title' => '2nd page',
+ 'book' => ['bid' => $book->id(), 'pid' => $book->id(), 'weight' => 1],
+ ]);
+ $page2->save();
+
+ // Head to admin screen and attempt to re-order.
+ $this->drupalLogin($this->drupalCreateUser(['administer book outlines']));
+ $this->drupalGet('admin/structure/book/' . $book->id());
+
+ $session = $this->getSession();
+ $page = $session->getPage();
+
+ $weight_select1 = $page->findField("table[book-admin-{$page1->id()}][weight]");
+ $weight_select2 = $page->findField("table[book-admin-{$page2->id()}][weight]");
+
+ // Check that rows weight selects are hidden.
+ $this->assertFalse($weight_select1->isVisible());
+ $this->assertFalse($weight_select2->isVisible());
+
+ // Check that '2nd page' row is heavier than '1st page' row.
+ $this->assertTrue($weight_select2->getValue() > $weight_select1->getValue());
+
+ // Check that '1st page' precedes the '2nd page'.
+ $this->assertFirstPrecedesSecond('1st page', '2nd');
+
+ // Check that the 'unsaved changes' text is not present in the message area.
+ $this->assertSession()->pageTextNotContains('You have unsaved changes.');
+
+ // Drag and drop the '1st page' row over the '2nd page' row.
+ // @todo: Investigate why if trying the reverse (2nd over 1st), the 2nd is
+ // indented instead of moved upward. This might be a bug in tabledrag.js.
+ $dragged = $this->xpath("//tr[@data-drupal-selector='edit-table-book-admin-{$page1->id()}']//a[@class='tabledrag-handle']")[0];
+ $target = $this->xpath("//tr[@data-drupal-selector='edit-table-book-admin-{$page2->id()}']//a[@class='tabledrag-handle']")[0];
+ $dragged->dragTo($target);
+
+ // Give javascript some time to manipulate the DOM.
+ $this->getSession()->wait(500);
+
+ // Check that the 'unsaved changes' text appeared in the message area.
+ $this->assertSession()->pageTextContains('You have unsaved changes.');
+
+ // Check that '2nd page' page precedes the '1st page'.
+ $this->assertFirstPrecedesSecond('2nd page', '1st page');
+
+ // Toggle row weight selects as visible.
+ $page->findButton(t('Show row weights'))->click();
+
+ // Check that rows weight selects are visible.
+ $this->assertTrue($weight_select1->isVisible());
+ $this->assertTrue($weight_select2->isVisible());
+
+ // Check that '1st page' row became heavier than '1st page' row.
+ $this->assertTrue($weight_select1->getValue() > $weight_select2->getValue());
+
+ // Toggle row weight selects back to hidden.
+ $page->findButton(t('Hide row weights'))->click();
+
+ // Check that rows weight selects are hidden again.
+ $this->assertFalse($weight_select1->isVisible());
+ $this->assertFalse($weight_select2->isVisible());
+
+ $this->submitForm([], t('Save book pages'));
+ $this->assertSession()->pageTextContains(t('Updated book @book.', ['@book' => $book->getTitle()]));
+
+ // Check again that '2nd page' is on top after form submit.
+ $this->assertFirstPrecedesSecond('2nd page', '1st page');
+
+ // Check that page reordering was done in the backend.
+ $page1 = Node::load($page1->id());
+ $page2 = Node::load($page2->id());
+ $this->assertTrue($page1->book['weight'] > $page2->book['weight']);
+ }
+
+ /**
+ * Asserts that the first piece of markup precedes the second.
+ *
+ * @param string $first
+ * The first string to be checked.
+ * @param string $second
+ * The second string to be checked.
+ *
+ * @throws \Behat\Mink\Exception\ExpectationException
+ * When any of the strings is not found.
+ */
+ protected function assertFirstPrecedesSecond($first, $second) {
+ $session = $this->getSession();
+ $text = $session->getPage()->getHtml();
+ if (($pos1 = strpos($text, $first)) === FALSE) {
+ throw new ExpectationException("Cannot find '$first'", $session->getDriver());
+ }
+ if (($pos2 = strpos($text, $second)) === FALSE) {
+ throw new ExpectationException("Cannot find '$second'", $session->getDriver());
+ }
+ $this->assertTrue($pos2 > $pos1, "'$first' precedes '$second'");
+ }
+
+}
diff --git a/core/tests/Drupal/FunctionalTests/AssertLegacyTrait.php b/core/tests/Drupal/FunctionalTests/AssertLegacyTrait.php
index 6ca9f85..ad42806 100644
--- a/core/tests/Drupal/FunctionalTests/AssertLegacyTrait.php
+++ b/core/tests/Drupal/FunctionalTests/AssertLegacyTrait.php
@@ -204,6 +204,39 @@ protected function assertNoRaw($raw) {
}
/**
+ * Triggers a pass if the Perl regex pattern is found in the raw content.
+ *
+ * @param string $pattern
+ * Perl regex to look for including the regex delimiters.
+ *
+ * @deprecated Scheduled for removal in Drupal 9.0.0.
+ * Use $this->assertSession()->responseMatches() instead.
+ */
+ protected function assertPattern($pattern) {
+ $this->assertSession()->responseMatches($pattern);
+ }
+
+ /**
+ * Asserts that a select option in the current page is checked.
+ *
+ * @param string $select
+ * The locator of the select field to assert.
+ * @param string $option
+ * Option to assert.
+ *
+ * @deprecated Scheduled for removal in Drupal 9.0.0. Use methods provided by
+ * \Drupal\Tests\WebAssert instead, for example:
+ * @code
+ * $option = $this->assertSession()->optionExists($select, $value);
+ * $this->assertTrue($option->getAttribute('selected'));
+ * @endcode
+ */
+ protected function assertOptionSelected($select, $option) {
+ $node = $this->assertSession()->optionExists($select, $option);
+ $this->assertTrue($node->getAttribute('selected'));
+ }
+
+ /**
* Pass if the page title is the given string.
*
* @param string $expected_title