Update to Drupal 8.1.5. For more information, see https://www.drupal.org/project/drupal/releases/8.1.5
This commit is contained in:
parent
13b6ca7cc2
commit
38ba7c357d
342 changed files with 7814 additions and 1534 deletions
31
core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php
Normal file
31
core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests;
|
||||
|
||||
use Drupal\Tests\WebAssert;
|
||||
|
||||
/**
|
||||
* Defines a class with methods for asserting presence of elements during tests.
|
||||
*/
|
||||
class JSWebAssert extends WebAssert {
|
||||
|
||||
/**
|
||||
* Waits for AJAX request to be completed.
|
||||
*
|
||||
* @param int $timeout
|
||||
* (Optional) Timeout in milliseconds, defaults to 10000.
|
||||
* @param string $message
|
||||
* (optional) A message for exception.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* When the request is not completed. If left blank, a default message will
|
||||
* be displayed.
|
||||
*/
|
||||
public function assertWaitOnAjaxRequest($timeout = 10000, $message = 'Unable to complete AJAX request.') {
|
||||
$result = $this->session->wait($timeout, '(typeof(jQuery)=="undefined" || (0 === jQuery.active && 0 === jQuery(\':animated\').length))');
|
||||
if (!$result) {
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -33,6 +33,24 @@ abstract class JavascriptTestBase extends BrowserTestBase {
|
|||
return parent::initMink();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function tearDown() {
|
||||
// Wait for all requests to finish. It is possible that an AJAX request is
|
||||
// still on-going.
|
||||
$result = $this->getSession()->wait(5000, '(typeof(jQuery)=="undefined" || (0 === jQuery.active && 0 === jQuery(\':animated\').length))');
|
||||
if (!$result) {
|
||||
// If the wait is unsuccessful, there may still be an AJAX request in
|
||||
// progress. If we tear down now, then this AJAX request may fail with
|
||||
// missing database tables, because tear down will have removed them. Rather
|
||||
// than allow it to fail, throw an explicit exception now explaining what
|
||||
// the problem is.
|
||||
throw new \RuntimeException('Unfinished AJAX requests whilst tearing down a test');
|
||||
}
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the element with the given CSS selector is visible.
|
||||
*
|
||||
|
@ -84,4 +102,11 @@ abstract class JavascriptTestBase extends BrowserTestBase {
|
|||
$this->assertTrue($result, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function assertSession($name = NULL) {
|
||||
return new JSWebAssert($this->getSession($name), $this->baseUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
427
core/tests/Drupal/FunctionalTests/AssertLegacyTrait.php
Normal file
427
core/tests/Drupal/FunctionalTests/AssertLegacyTrait.php
Normal file
|
@ -0,0 +1,427 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests;
|
||||
|
||||
use Drupal\KernelTests\AssertLegacyTrait as BaseAssertLegacyTrait;
|
||||
|
||||
/**
|
||||
* Provides convenience methods for assertions in browser tests.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0. Use the methods on
|
||||
* \Drupal\Tests\WebAssert instead, for example
|
||||
* @code
|
||||
* $this->assertSession()->statusCodeEquals(200);
|
||||
* @endcode
|
||||
*/
|
||||
trait AssertLegacyTrait {
|
||||
|
||||
use BaseAssertLegacyTrait;
|
||||
|
||||
/**
|
||||
* Asserts that the element with the given CSS selector is present.
|
||||
*
|
||||
* @param string $css_selector
|
||||
* The CSS selector identifying the element to check.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->elementExists() instead.
|
||||
*/
|
||||
protected function assertElementPresent($css_selector) {
|
||||
$this->assertSession()->elementExists('css', $css_selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the element with the given CSS selector is not present.
|
||||
*
|
||||
* @param string $css_selector
|
||||
* The CSS selector identifying the element to check.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->elementNotExists() instead.
|
||||
*/
|
||||
protected function assertElementNotPresent($css_selector) {
|
||||
$this->assertSession()->elementNotExists('css', $css_selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if the page (with HTML stripped) contains the text.
|
||||
*
|
||||
* Note that stripping HTML tags also removes their attributes, such as
|
||||
* the values of text fields.
|
||||
*
|
||||
* @param string $text
|
||||
* Plain text to look for.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->pageTextContains() or
|
||||
* $this->assertSession()->responseContains() instead.
|
||||
*/
|
||||
protected function assertText($text) {
|
||||
$content_type = $this->getSession()->getResponseHeader('Content-type');
|
||||
// In case of a Non-HTML response (example: XML) check the original
|
||||
// response.
|
||||
if (strpos($content_type, 'html') === FALSE) {
|
||||
$this->assertSession()->responseContains($text);
|
||||
}
|
||||
else {
|
||||
$this->assertSession()->pageTextContains($text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if the page (with HTML stripped) does not contains the text.
|
||||
*
|
||||
* Note that stripping HTML tags also removes their attributes, such as
|
||||
* the values of text fields.
|
||||
*
|
||||
* @param string $text
|
||||
* Plain text to look for.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->pageTextNotContains() or
|
||||
* $this->assertSession()->responseNotContains() instead.
|
||||
*/
|
||||
protected function assertNoText($text) {
|
||||
$content_type = $this->getSession()->getResponseHeader('Content-type');
|
||||
// In case of a Non-HTML response (example: XML) check the original
|
||||
// response.
|
||||
if (strpos($content_type, 'html') === FALSE) {
|
||||
$this->assertSession()->responseNotContains($text);
|
||||
}
|
||||
else {
|
||||
$this->assertSession()->pageTextNotContains($text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the page responds with the specified response code.
|
||||
*
|
||||
* @param int $code
|
||||
* Response code. For example 200 is a successful page request. For a list
|
||||
* of all codes see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->statusCodeEquals() instead.
|
||||
*/
|
||||
protected function assertResponse($code) {
|
||||
$this->assertSession()->statusCodeEquals($code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a field exists with the given name and value.
|
||||
*
|
||||
* @param string $name
|
||||
* Name of field to assert.
|
||||
* @param string $value
|
||||
* (optional) Value of the field to assert. You may pass in NULL (default)
|
||||
* to skip checking the actual value, while still checking that the field
|
||||
* exists.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->fieldExists() or
|
||||
* $this->assertSession()->fieldValueEquals() instead.
|
||||
*/
|
||||
protected function assertFieldByName($name, $value = NULL) {
|
||||
$this->assertSession()->fieldExists($name);
|
||||
if ($value !== NULL) {
|
||||
$this->assertSession()->fieldValueEquals($name, (string) $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a field exists with the given ID and value.
|
||||
*
|
||||
* @param string $id
|
||||
* ID of field to assert.
|
||||
* @param string|\Drupal\Component\Render\MarkupInterface $value
|
||||
* (optional) Value for the field to assert. You may pass in NULL to skip
|
||||
* checking the value, while still checking that the field exists.
|
||||
* However, the default value ('') asserts that the field value is an empty
|
||||
* string.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->fieldExists() or
|
||||
* $this->assertSession()->fieldValueEquals() instead.
|
||||
*/
|
||||
protected function assertFieldById($id, $value = NULL) {
|
||||
$this->assertFieldByName($id, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a field exists with the given name or ID.
|
||||
*
|
||||
* @param string $field
|
||||
* Name or ID of field to assert.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->fieldExists() instead.
|
||||
*/
|
||||
protected function assertField($field) {
|
||||
$this->assertSession()->fieldExists($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a field exists with the given name or ID does NOT exist.
|
||||
*
|
||||
* @param string $field
|
||||
* Name or ID of field to assert.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->fieldNotExists() instead.
|
||||
*/
|
||||
protected function assertNoField($field) {
|
||||
$this->assertSession()->fieldNotExists($field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if the raw text IS found on the loaded page, fail otherwise.
|
||||
*
|
||||
* Raw text refers to the raw HTML that the page generated.
|
||||
*
|
||||
* @param string $raw
|
||||
* Raw (HTML) string to look for.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->responseContains() instead.
|
||||
*/
|
||||
protected function assertRaw($raw) {
|
||||
$this->assertSession()->responseContains($raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if the raw text IS not found on the loaded page, fail otherwise.
|
||||
*
|
||||
* Raw text refers to the raw HTML that the page generated.
|
||||
*
|
||||
* @param string $raw
|
||||
* Raw (HTML) string to look for.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->responseNotContains() instead.
|
||||
*/
|
||||
protected function assertNoRaw($raw) {
|
||||
$this->assertSession()->responseNotContains($raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass if the page title is the given string.
|
||||
*
|
||||
* @param string $expected_title
|
||||
* The string the page title should be.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->titleEquals() instead.
|
||||
*/
|
||||
protected function assertTitle($expected_title) {
|
||||
// Cast MarkupInterface to string.
|
||||
$expected_title = (string) $expected_title;
|
||||
return $this->assertSession()->titleEquals($expected_title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if a link with the specified label is found.
|
||||
*
|
||||
* An optional link index may be passed.
|
||||
*
|
||||
* @param string|\Drupal\Component\Render\MarkupInterface $label
|
||||
* Text between the anchor tags.
|
||||
* @param int $index
|
||||
* Link position counting from zero.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->linkExists() instead.
|
||||
*/
|
||||
protected function assertLink($label, $index = 0) {
|
||||
return $this->assertSession()->linkExists($label, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if a link with the specified label is not found.
|
||||
*
|
||||
* @param string|\Drupal\Component\Render\MarkupInterface $label
|
||||
* Text between the anchor tags.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->linkNotExists() instead.
|
||||
*/
|
||||
protected function assertNoLink($label) {
|
||||
return $this->assertSession()->linkNotExists($label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if a link containing a given href (part) is found.
|
||||
*
|
||||
* @param string $href
|
||||
* The full or partial value of the 'href' attribute of the anchor tag.
|
||||
* @param int $index
|
||||
* Link position counting from zero.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->linkByHref() instead.
|
||||
*/
|
||||
protected function assertLinkByHref($href, $index = 0) {
|
||||
$this->assertSession()->linkByHrefExists($href, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if a link containing a given href (part) is not found.
|
||||
*
|
||||
* @param string $href
|
||||
* The full or partial value of the 'href' attribute of the anchor tag.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->linkByHrefNotExists() instead.
|
||||
*/
|
||||
protected function assertNoLinkByHref($href) {
|
||||
$this->assertSession()->linkByHrefNotExists($href);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a field does not exist with the given ID and value.
|
||||
*
|
||||
* @param string $id
|
||||
* ID of field to assert.
|
||||
* @param string $value
|
||||
* (optional) Value for the field, to assert that the field's value on the
|
||||
* page doesn't match it. You may pass in NULL to skip checking the value,
|
||||
* while still checking that the field doesn't exist. However, the default
|
||||
* value ('') asserts that the field value is not an empty string.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->fieldNotExists() or
|
||||
* $this->assertSession()->fieldValueNotEquals() instead.
|
||||
*/
|
||||
protected function assertNoFieldById($id, $value = '') {
|
||||
if ($this->getSession()->getPage()->findField($id)) {
|
||||
$this->assertSession()->fieldValueNotEquals($id, (string) $value);
|
||||
}
|
||||
else {
|
||||
$this->assertSession()->fieldNotExists($id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if the internal browser's URL matches the given path.
|
||||
*
|
||||
* @param \Drupal\Core\Url|string $path
|
||||
* The expected system path or URL.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->addressEquals() instead.
|
||||
*/
|
||||
protected function assertUrl($path) {
|
||||
$this->assertSession()->addressEquals($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a select option in the current page exists.
|
||||
*
|
||||
* @param string $id
|
||||
* ID of select field to assert.
|
||||
* @param string $option
|
||||
* Option to assert.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->optionExists() instead.
|
||||
*/
|
||||
protected function assertOption($id, $option) {
|
||||
return $this->assertSession()->optionExists($id, $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a select option does NOT exist in the current page.
|
||||
*
|
||||
* @param string $id
|
||||
* ID of select field to assert.
|
||||
* @param string $option
|
||||
* Option to assert.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->optionNotExists() instead.
|
||||
*/
|
||||
protected function assertNoOption($id, $option) {
|
||||
return $this->assertSession()->optionNotExists($id, $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if the raw text IS found escaped on the loaded page, fail otherwise.
|
||||
*
|
||||
* Raw text refers to the raw HTML that the page generated.
|
||||
*
|
||||
* @param string $raw
|
||||
* Raw (HTML) string to look for.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->assertEscaped() instead.
|
||||
*/
|
||||
protected function assertEscaped($raw) {
|
||||
$this->assertSession()->assertEscaped($raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if the raw text is not found escaped on the loaded page.
|
||||
*
|
||||
* Raw text refers to the raw HTML that the page generated.
|
||||
*
|
||||
* @param string $raw
|
||||
* Raw (HTML) string to look for.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->assertNoEscaped() instead.
|
||||
*/
|
||||
protected function assertNoEscaped($raw) {
|
||||
$this->assertSession()->assertNoEscaped($raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts whether an expected cache tag was present in the last response.
|
||||
*
|
||||
* @param string $expected_cache_tag
|
||||
* The expected cache tag.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->responseHeaderContains() instead.
|
||||
*/
|
||||
protected function assertCacheTag($expected_cache_tag) {
|
||||
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', $expected_cache_tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns WebAssert object.
|
||||
*
|
||||
* @param string $name
|
||||
* (optional) Name of the session. Defaults to the active session.
|
||||
*
|
||||
* @return \Drupal\Tests\WebAssert
|
||||
* A new web-assert option for asserting the presence of elements with.
|
||||
*/
|
||||
abstract public function assertSession($name = NULL);
|
||||
|
||||
/**
|
||||
* Builds an XPath query.
|
||||
*
|
||||
* Builds an XPath query by replacing placeholders in the query by the value
|
||||
* of the arguments.
|
||||
*
|
||||
* XPath 1.0 (the version supported by libxml2, the underlying XML library
|
||||
* used by PHP) doesn't support any form of quotation. This function
|
||||
* simplifies the building of XPath expression.
|
||||
*
|
||||
* @param string $xpath
|
||||
* An XPath query, possibly with placeholders in the form ':name'.
|
||||
* @param array $args
|
||||
* An array of arguments with keys in the form ':name' matching the
|
||||
* placeholders in the query. The values may be either strings or numeric
|
||||
* values.
|
||||
*
|
||||
* @return string
|
||||
* An XPath query with arguments replaced.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use $this->assertSession()->buildXPathQuery() instead.
|
||||
*/
|
||||
protected function buildXPathQuery($xpath, array $args = array()) {
|
||||
return $this->assertSession()->buildXPathQuery($xpath, $args);
|
||||
}
|
||||
|
||||
}
|
|
@ -188,7 +188,8 @@ class ConfigDependencyTest extends EntityKernelTestBase {
|
|||
/** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
|
||||
$config_manager = \Drupal::service('config.manager');
|
||||
/** @var \Drupal\Core\Config\Entity\ConfigEntityStorage $storage */
|
||||
$storage = $this->container->get('entity.manager')->getStorage('config_test');
|
||||
$storage = $this->container->get('entity.manager')
|
||||
->getStorage('config_test');
|
||||
// Test dependencies between modules.
|
||||
$entity1 = $storage->create(
|
||||
array(
|
||||
|
@ -221,14 +222,42 @@ class ConfigDependencyTest extends EntityKernelTestBase {
|
|||
$config_manager->uninstall('module', 'node');
|
||||
$this->assertFalse($storage->load('entity1'), 'Entity 1 deleted');
|
||||
$this->assertFalse($storage->load('entity2'), 'Entity 2 deleted');
|
||||
}
|
||||
|
||||
// Set a more complicated test where dependencies will be fixed.
|
||||
\Drupal::state()->set('config_test.fix_dependencies', array($entity1->getConfigDependencyName()));
|
||||
\Drupal::state()->set('config_test.on_dependency_removal_called', []);
|
||||
// Entity1 will be deleted because it depends on node.
|
||||
$entity1 = $storage->create(
|
||||
/**
|
||||
* Data provider for self::testConfigEntityUninstallComplex().
|
||||
*/
|
||||
public function providerConfigEntityUninstallComplex() {
|
||||
// Ensure that alphabetical order has no influence on dependency fixing and
|
||||
// removal.
|
||||
return [
|
||||
[['a', 'b', 'c', 'd']],
|
||||
[['d', 'c', 'b', 'a']],
|
||||
[['c', 'd', 'a', 'b']],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests complex configuration entity dependency handling during uninstall.
|
||||
*
|
||||
* Configuration entities can be deleted or updated during module uninstall
|
||||
* because they have dependencies on the module.
|
||||
*
|
||||
* @param array $entity_id_suffixes
|
||||
* The suffixes to add to the 4 entities created by the test.
|
||||
*
|
||||
* @dataProvider providerConfigEntityUninstallComplex
|
||||
*/
|
||||
public function testConfigEntityUninstallComplex(array $entity_id_suffixes) {
|
||||
/** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
|
||||
$config_manager = \Drupal::service('config.manager');
|
||||
/** @var \Drupal\Core\Config\Entity\ConfigEntityStorage $storage */
|
||||
$storage = $this->container->get('entity.manager')
|
||||
->getStorage('config_test');
|
||||
// Entity 1 will be deleted because it depends on node.
|
||||
$entity_1 = $storage->create(
|
||||
array(
|
||||
'id' => 'entity1',
|
||||
'id' => 'entity_' . $entity_id_suffixes[0],
|
||||
'dependencies' => array(
|
||||
'enforced' => array(
|
||||
'module' => array('node', 'config_test')
|
||||
|
@ -236,77 +265,85 @@ class ConfigDependencyTest extends EntityKernelTestBase {
|
|||
),
|
||||
)
|
||||
);
|
||||
$entity1->save();
|
||||
$entity_1->save();
|
||||
|
||||
// Entity2 has a dependency on Entity1 but it can be fixed because
|
||||
// Entity 2 has a dependency on entity 1 but it can be fixed because
|
||||
// \Drupal\config_test\Entity::onDependencyRemoval() will remove the
|
||||
// dependency before config entities are deleted.
|
||||
$entity2 = $storage->create(
|
||||
$entity_2 = $storage->create(
|
||||
array(
|
||||
'id' => 'entity2',
|
||||
'id' => 'entity_' . $entity_id_suffixes[1],
|
||||
'dependencies' => array(
|
||||
'enforced' => array(
|
||||
'config' => array($entity1->getConfigDependencyName()),
|
||||
'config' => array($entity_1->getConfigDependencyName()),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
$entity2->save();
|
||||
$entity_2->save();
|
||||
|
||||
// Entity3 will be unchanged because it is dependent on Entity2 which can
|
||||
// Entity 3 will be unchanged because it is dependent on entity 2 which can
|
||||
// be fixed. The ConfigEntityInterface::onDependencyRemoval() method will
|
||||
// not be called for this entity.
|
||||
$entity3 = $storage->create(
|
||||
$entity_3 = $storage->create(
|
||||
array(
|
||||
'id' => 'entity3',
|
||||
'id' => 'entity_' . $entity_id_suffixes[2],
|
||||
'dependencies' => array(
|
||||
'enforced' => array(
|
||||
'config' => array($entity2->getConfigDependencyName()),
|
||||
'config' => array($entity_2->getConfigDependencyName()),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
$entity3->save();
|
||||
$entity_3->save();
|
||||
|
||||
// Entity4's config dependency will be fixed but it will still be deleted
|
||||
// Entity 4's config dependency will be fixed but it will still be deleted
|
||||
// because it also depends on the node module.
|
||||
$entity4 = $storage->create(
|
||||
$entity_4 = $storage->create(
|
||||
array(
|
||||
'id' => 'entity4',
|
||||
'id' => 'entity_' . $entity_id_suffixes[3],
|
||||
'dependencies' => array(
|
||||
'enforced' => array(
|
||||
'config' => array($entity1->getConfigDependencyName()),
|
||||
'config' => array($entity_1->getConfigDependencyName()),
|
||||
'module' => array('node', 'config_test')
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
$entity4->save();
|
||||
$entity_4->save();
|
||||
|
||||
// Set a more complicated test where dependencies will be fixed.
|
||||
\Drupal::state()->set('config_test.fix_dependencies', array($entity_1->getConfigDependencyName()));
|
||||
\Drupal::state()->set('config_test.on_dependency_removal_called', []);
|
||||
|
||||
// Do a dry run using
|
||||
// \Drupal\Core\Config\ConfigManager::getConfigEntitiesToChangeOnDependencyRemoval().
|
||||
$config_entities = $config_manager->getConfigEntitiesToChangeOnDependencyRemoval('module', ['node']);
|
||||
$this->assertEqual($entity1->uuid(), $config_entities['delete'][0]->uuid(), 'Entity 1 will be deleted.');
|
||||
$this->assertEqual($entity2->uuid(), reset($config_entities['update'])->uuid(), 'Entity 2 will be updated.');
|
||||
$this->assertEqual($entity3->uuid(), reset($config_entities['unchanged'])->uuid(), 'Entity 3 is not changed.');
|
||||
$this->assertEqual($entity4->uuid(), $config_entities['delete'][1]->uuid(), 'Entity 4 will be deleted.');
|
||||
$this->assertEqual($entity_1->uuid(), $config_entities['delete'][1]->uuid(), 'Entity 1 will be deleted.');
|
||||
$this->assertEqual($entity_2->uuid(), reset($config_entities['update'])->uuid(), 'Entity 2 will be updated.');
|
||||
$this->assertEqual($entity_3->uuid(), reset($config_entities['unchanged'])->uuid(), 'Entity 3 is not changed.');
|
||||
$this->assertEqual($entity_4->uuid(), $config_entities['delete'][0]->uuid(), 'Entity 4 will be deleted.');
|
||||
|
||||
$called = \Drupal::state()->get('config_test.on_dependency_removal_called', []);
|
||||
$this->assertFalse(in_array($entity3->id(), $called), 'ConfigEntityInterface::onDependencyRemoval() is not called for entity 3.');
|
||||
$this->assertIdentical(['entity1', 'entity2', 'entity4'], $called, 'The most dependent entites have ConfigEntityInterface::onDependencyRemoval() called first.');
|
||||
$this->assertFalse(in_array($entity_3->id(), $called), 'ConfigEntityInterface::onDependencyRemoval() is not called for entity 3.');
|
||||
$this->assertIdentical([$entity_1->id(), $entity_4->id(), $entity_2->id()], $called, 'The most dependent entites have ConfigEntityInterface::onDependencyRemoval() called first.');
|
||||
|
||||
// Perform a module rebuild so we can know where the node module is located
|
||||
// and uninstall it.
|
||||
// @todo Remove as part of https://www.drupal.org/node/2186491
|
||||
system_rebuild_module_data();
|
||||
// Perform the uninstall.
|
||||
$config_manager->uninstall('module', 'node');
|
||||
|
||||
// Test that expected actions have been performed.
|
||||
$this->assertFalse($storage->load('entity1'), 'Entity 1 deleted');
|
||||
$entity2 = $storage->load('entity2');
|
||||
$this->assertTrue($entity2, 'Entity 2 not deleted');
|
||||
$this->assertEqual($entity2->calculateDependencies()->getDependencies()['config'], array(), 'Entity 2 dependencies updated to remove dependency on Entity1.');
|
||||
$entity3 = $storage->load('entity3');
|
||||
$this->assertTrue($entity3, 'Entity 3 not deleted');
|
||||
$this->assertEqual($entity3->calculateDependencies()->getDependencies()['config'], [$entity2->getConfigDependencyName()], 'Entity 3 still depends on Entity 2.');
|
||||
$this->assertFalse($storage->load('entity4'), 'Entity 4 deleted');
|
||||
$this->assertFalse($storage->load($entity_1->id()), 'Entity 1 deleted');
|
||||
$entity_2 = $storage->load($entity_2->id());
|
||||
$this->assertTrue($entity_2, 'Entity 2 not deleted');
|
||||
$this->assertEqual($entity_2->calculateDependencies()->getDependencies()['config'], array(), 'Entity 2 dependencies updated to remove dependency on entity 1.');
|
||||
$entity_3 = $storage->load($entity_3->id());
|
||||
$this->assertTrue($entity_3, 'Entity 3 not deleted');
|
||||
$this->assertEqual($entity_3->calculateDependencies()->getDependencies()['config'], [$entity_2->getConfigDependencyName()], 'Entity 3 still depends on entity 2.');
|
||||
$this->assertFalse($storage->load($entity_4->id()), 'Entity 4 deleted');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -456,8 +493,8 @@ class ConfigDependencyTest extends EntityKernelTestBase {
|
|||
$entity3->save();
|
||||
|
||||
$config_entities = $config_manager->getConfigEntitiesToChangeOnDependencyRemoval('content', [$content_entity->getConfigDependencyName()]);
|
||||
$this->assertEqual($entity1->uuid(), $config_entities['delete'][0]->uuid(), 'Entity 1 will be deleted.');
|
||||
$this->assertEqual($entity2->uuid(), $config_entities['delete'][1]->uuid(), 'Entity 2 will be deleted.');
|
||||
$this->assertEqual($entity1->uuid(), $config_entities['delete'][1]->uuid(), 'Entity 1 will be deleted.');
|
||||
$this->assertEqual($entity2->uuid(), $config_entities['delete'][0]->uuid(), 'Entity 2 will be deleted.');
|
||||
$this->assertTrue(empty($config_entities['update']), 'No dependencies of the content entity will be updated.');
|
||||
$this->assertTrue(empty($config_entities['unchanged']), 'No dependencies of the content entity will be unchanged.');
|
||||
}
|
||||
|
|
|
@ -97,6 +97,8 @@ class ConnectionTest extends DatabaseTestBase {
|
|||
// Set up identical replica and confirm connection options are identical.
|
||||
Database::addConnectionInfo('default', 'replica', $connection_info['default']);
|
||||
$db2 = Database::getConnection('replica', 'default');
|
||||
// Getting a driver class ensures the namespace option is set.
|
||||
$this->assertEquals($db->getDriverClass('select'), $db2->getDriverClass('select'));
|
||||
$connectionOptions2 = $db2->getConnectionOptions();
|
||||
|
||||
// Get a fresh copy of the default connection options.
|
||||
|
|
|
@ -375,4 +375,50 @@ class SelectComplexTest extends DatabaseTestBase {
|
|||
$this->assertTrue($exception, 'Exception was thrown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that join conditions can use Condition objects.
|
||||
*/
|
||||
public function testJoinConditionObject() {
|
||||
// Same test as testDefaultJoin, but with a Condition object.
|
||||
$query = db_select('test_task', 't');
|
||||
$join_cond = db_and()->where('t.pid = p.id');
|
||||
$people_alias = $query->join('test', 'p', $join_cond);
|
||||
$name_field = $query->addField($people_alias, 'name', 'name');
|
||||
$query->addField('t', 'task', 'task');
|
||||
$priority_field = $query->addField('t', 'priority', 'priority');
|
||||
|
||||
$query->orderBy($priority_field);
|
||||
$result = $query->execute();
|
||||
|
||||
$num_records = 0;
|
||||
$last_priority = 0;
|
||||
foreach ($result as $record) {
|
||||
$num_records++;
|
||||
$this->assertTrue($record->$priority_field >= $last_priority, 'Results returned in correct order.');
|
||||
$this->assertNotEqual($record->$name_field, 'Ringo', 'Taskless person not selected.');
|
||||
$last_priority = $record->$priority_field;
|
||||
}
|
||||
|
||||
$this->assertEqual($num_records, 7, 'Returned the correct number of rows.');
|
||||
|
||||
// Test a condition object that creates placeholders.
|
||||
$t1_name = 'John';
|
||||
$t2_name = 'George';
|
||||
$join_cond = db_and()
|
||||
->condition('t1.name', $t1_name)
|
||||
->condition('t2.name', $t2_name);
|
||||
$query = db_select('test', 't1');
|
||||
$query->innerJoin('test', 't2', $join_cond);
|
||||
$query->addField('t1', 'name', 't1_name');
|
||||
$query->addField('t2', 'name', 't2_name');
|
||||
|
||||
$num_records = $query->countQuery()->execute()->fetchField();
|
||||
$this->assertEqual($num_records, 1, 'Query expected to return 1 row. Actual: ' . $num_records);
|
||||
if ($num_records == 1) {
|
||||
$record = $query->execute()->fetchObject();
|
||||
$this->assertEqual($record->t1_name, $t1_name, 'Query expected to retrieve name ' . $t1_name . ' from table t1. Actual: ' . $record->t1_name);
|
||||
$this->assertEqual($record->t2_name, $t2_name, 'Query expected to retrieve name ' . $t2_name . ' from table t2. Actual: ' . $record->t2_name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\KernelTests\Core\DrupalKernel;
|
||||
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests DIC compilation to disk.
|
||||
*
|
||||
* @group DrupalKernel
|
||||
*/
|
||||
class DrupalKernelTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
// DrupalKernel relies on global $config_directories and requires those
|
||||
// directories to exist. Therefore, create the directories, but do not
|
||||
// invoke KernelTestBase::setUp(), since that would set up further
|
||||
// environment aspects, which would distort this test, because it tests
|
||||
// the DrupalKernel (re-)building itself.
|
||||
$this->root = static::getDrupalRoot();
|
||||
$this->bootEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a kernel for testings.
|
||||
*
|
||||
* Because the bootstrap is in DrupalKernel::boot and that involved loading
|
||||
* settings from the filesystem we need to go to extra lengths to build a kernel
|
||||
* for testing.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* A request object to use in booting the kernel.
|
||||
* @param array $modules_enabled
|
||||
* A list of modules to enable on the kernel.
|
||||
*
|
||||
* @return \Drupal\Core\DrupalKernel
|
||||
* New kernel for testing.
|
||||
*/
|
||||
protected function getTestKernel(Request $request, array $modules_enabled = NULL) {
|
||||
// Manually create kernel to avoid replacing settings.
|
||||
$class_loader = require $this->root . '/autoload.php';
|
||||
$kernel = DrupalKernel::createFromRequest($request, $class_loader, 'testing');
|
||||
$this->setSetting('container_yamls', []);
|
||||
$this->setSetting('hash_salt', $this->databasePrefix);
|
||||
if (isset($modules_enabled)) {
|
||||
$kernel->updateModules($modules_enabled);
|
||||
}
|
||||
$kernel->boot();
|
||||
|
||||
return $kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests DIC compilation.
|
||||
*/
|
||||
public function testCompileDIC() {
|
||||
// @todo: write a memory based storage backend for testing.
|
||||
$modules_enabled = array(
|
||||
'system' => 'system',
|
||||
'user' => 'user',
|
||||
);
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$this->getTestKernel($request, $modules_enabled);
|
||||
|
||||
// Instantiate it a second time and we should get the compiled Container
|
||||
// class.
|
||||
$kernel = $this->getTestKernel($request);
|
||||
$container = $kernel->getContainer();
|
||||
$refClass = new \ReflectionClass($container);
|
||||
$is_compiled_container = !$refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
|
||||
$this->assertTrue($is_compiled_container);
|
||||
// Verify that the list of modules is the same for the initial and the
|
||||
// compiled container.
|
||||
$module_list = array_keys($container->get('module_handler')->getModuleList());
|
||||
$this->assertEqual(array_values($modules_enabled), $module_list);
|
||||
|
||||
// Get the container another time, simulating a "production" environment.
|
||||
$container = $this->getTestKernel($request, NULL)
|
||||
->getContainer();
|
||||
|
||||
$refClass = new \ReflectionClass($container);
|
||||
$is_compiled_container = !$refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
|
||||
$this->assertTrue($is_compiled_container);
|
||||
|
||||
// Verify that the list of modules is the same for the initial and the
|
||||
// compiled container.
|
||||
$module_list = array_keys($container->get('module_handler')->getModuleList());
|
||||
$this->assertEqual(array_values($modules_enabled), $module_list);
|
||||
|
||||
// Test that our synthetic services are there.
|
||||
$class_loader = $container->get('class_loader');
|
||||
$refClass = new \ReflectionClass($class_loader);
|
||||
$this->assertTrue($refClass->hasMethod('loadClass'), 'Container has a class loader');
|
||||
|
||||
// We make this assertion here purely to show that the new container below
|
||||
// is functioning correctly, i.e. we get a brand new ContainerBuilder
|
||||
// which has the required new services, after changing the list of enabled
|
||||
// modules.
|
||||
$this->assertFalse($container->has('service_provider_test_class'));
|
||||
|
||||
// Add another module so that we can test that the new module's bundle is
|
||||
// registered to the new container.
|
||||
$modules_enabled['service_provider_test'] = 'service_provider_test';
|
||||
$this->getTestKernel($request, $modules_enabled);
|
||||
|
||||
// Instantiate it a second time and we should not get a ContainerBuilder
|
||||
// class because we are loading the container definition from cache.
|
||||
$kernel = $this->getTestKernel($request, $modules_enabled);
|
||||
$container = $kernel->getContainer();
|
||||
|
||||
$refClass = new \ReflectionClass($container);
|
||||
$is_container_builder = $refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
|
||||
$this->assertFalse($is_container_builder, 'Container is not a builder');
|
||||
|
||||
// Assert that the new module's bundle was registered to the new container.
|
||||
$this->assertTrue($container->has('service_provider_test_class'), 'Container has test service');
|
||||
|
||||
// Test that our synthetic services are there.
|
||||
$class_loader = $container->get('class_loader');
|
||||
$refClass = new \ReflectionClass($class_loader);
|
||||
$this->assertTrue($refClass->hasMethod('loadClass'), 'Container has a class loader');
|
||||
|
||||
// Check that the location of the new module is registered.
|
||||
$modules = $container->getParameter('container.modules');
|
||||
$this->assertEqual($modules['service_provider_test'], array(
|
||||
'type' => 'module',
|
||||
'pathname' => drupal_get_filename('module', 'service_provider_test'),
|
||||
'filename' => NULL,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests repeated loading of compiled DIC with different environment.
|
||||
*/
|
||||
public function testRepeatedBootWithDifferentEnvironment() {
|
||||
$request = Request::createFromGlobals();
|
||||
$class_loader = require $this->root . '/autoload.php';
|
||||
|
||||
$environments = [
|
||||
'testing1',
|
||||
'testing1',
|
||||
'testing2',
|
||||
'testing2',
|
||||
];
|
||||
|
||||
foreach ($environments as $environment) {
|
||||
$kernel = DrupalKernel::createFromRequest($request, $class_loader, $environment);
|
||||
$this->setSetting('container_yamls', []);
|
||||
$this->setSetting('hash_salt', $this->databasePrefix);
|
||||
$kernel->boot();
|
||||
}
|
||||
|
||||
$this->pass('Repeatedly loaded compiled DIC with different environment');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests setting of site path after kernel boot.
|
||||
*/
|
||||
public function testPreventChangeOfSitePath() {
|
||||
// @todo: write a memory based storage backend for testing.
|
||||
$modules_enabled = array(
|
||||
'system' => 'system',
|
||||
'user' => 'user',
|
||||
);
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$kernel = $this->getTestKernel($request, $modules_enabled);
|
||||
$pass = FALSE;
|
||||
try {
|
||||
$kernel->setSitePath('/dev/null');
|
||||
}
|
||||
catch (\LogicException $e) {
|
||||
$pass = TRUE;
|
||||
}
|
||||
$this->assertTrue($pass, 'Throws LogicException if DrupalKernel::setSitePath() is called after boot');
|
||||
}
|
||||
|
||||
}
|
|
@ -146,7 +146,7 @@ class EntityAutocompleteTest extends EntityKernelTestBase {
|
|||
* The label of the entity to query by.
|
||||
*
|
||||
* @return mixed
|
||||
* The JSON value encoded in its appropriate PHP type.
|
||||
* The JSON value encoded in its appropriate PHP type.
|
||||
*/
|
||||
protected function getAutocompleteResult($input) {
|
||||
$request = Request::create('entity_reference_autocomplete/' . $this->entityType . '/default');
|
||||
|
|
|
@ -512,6 +512,89 @@ class EntityQueryTest extends EntityKernelTestBase {
|
|||
$this->assertResult(6, 14);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test queries with delta conditions.
|
||||
*/
|
||||
public function testDelta() {
|
||||
$figures = $this->figures;
|
||||
// Test numeric delta value in field condition.
|
||||
$this->queryResults = $this->factory->get('entity_test_mulrev')
|
||||
->condition("$figures.0.color", 'red')
|
||||
->sort('id')
|
||||
->execute();
|
||||
// As unit 0 at delta 0 was the red triangle bit 0 needs to be set.
|
||||
$this->assertResult(1, 3, 5, 7, 9, 11, 13, 15);
|
||||
|
||||
$this->queryResults = $this->factory->get('entity_test_mulrev')
|
||||
->condition("$figures.1.color", 'red')
|
||||
->sort('id')
|
||||
->execute();
|
||||
// Delta 1 is not red.
|
||||
$this->assertResult();
|
||||
|
||||
// Test on two different deltas.
|
||||
$query = $this->factory->get('entity_test_mulrev');
|
||||
$or = $query->andConditionGroup()
|
||||
->condition("$figures.0.color", 'red')
|
||||
->condition("$figures.1.color", 'blue');
|
||||
$this->queryResults = $query
|
||||
->condition($or)
|
||||
->sort('id')
|
||||
->execute();
|
||||
$this->assertResult(3, 7, 11, 15);
|
||||
|
||||
// Test the delta range condition.
|
||||
$this->queryResults = $this->factory->get('entity_test_mulrev')
|
||||
->condition("$figures.%delta.color", array('blue', 'red'), 'IN')
|
||||
->condition("$figures.%delta", array(0, 1), 'IN')
|
||||
->sort('id')
|
||||
->execute();
|
||||
// Figure delta 0 or 1 can be blue or red, this matches a lot of entities.
|
||||
$this->assertResult(1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15);
|
||||
|
||||
// Test the delta range condition without conditions on the value.
|
||||
$this->queryResults = $this->factory->get('entity_test_mulrev')
|
||||
->condition("$figures.%delta", 1)
|
||||
->sort('id')
|
||||
->execute();
|
||||
// Entity needs to have atleast two figures.
|
||||
$this->assertResult(3, 7, 11, 15);
|
||||
|
||||
// Numeric delta on single value base field should return results only if
|
||||
// the first item is being targeted.
|
||||
$this->queryResults = $this->factory->get('entity_test_mulrev')
|
||||
->condition("id.0.value", array(1, 3, 5), 'IN')
|
||||
->sort('id')
|
||||
->execute();
|
||||
$this->assertResult(1, 3, 5);
|
||||
$this->queryResults = $this->factory->get('entity_test_mulrev')
|
||||
->condition("id.1.value", array(1, 3, 5), 'IN')
|
||||
->sort('id')
|
||||
->execute();
|
||||
$this->assertResult();
|
||||
|
||||
// Delta range condition on single value base field should return results
|
||||
// only if just the field value is targeted.
|
||||
$this->queryResults = $this->factory->get('entity_test_mulrev')
|
||||
->condition("id.%delta.value", array(1, 3, 5), 'IN')
|
||||
->sort('id')
|
||||
->execute();
|
||||
$this->assertResult(1, 3, 5);
|
||||
$this->queryResults = $this->factory->get('entity_test_mulrev')
|
||||
->condition("id.%delta.value", array(1, 3, 5), 'IN')
|
||||
->condition("id.%delta", 0, '=')
|
||||
->sort('id')
|
||||
->execute();
|
||||
$this->assertResult(1, 3, 5);
|
||||
$this->queryResults = $this->factory->get('entity_test_mulrev')
|
||||
->condition("id.%delta.value", array(1, 3, 5), 'IN')
|
||||
->condition("id.%delta", 1, '=')
|
||||
->sort('id')
|
||||
->execute();
|
||||
$this->assertResult();
|
||||
|
||||
}
|
||||
|
||||
protected function assertResult() {
|
||||
$assert = array();
|
||||
$expected = func_get_args();
|
||||
|
|
|
@ -1179,7 +1179,7 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
'kernel',
|
||||
// @see \Drupal\simpletest\TestBase::prepareEnvironment()
|
||||
'generatedTestFiles',
|
||||
// @see \Drupal\simpletest\KernelTestBase::containerBuild()
|
||||
// Properties from the old KernelTestBase class that has been removed.
|
||||
'keyValueFactory',
|
||||
);
|
||||
if (in_array($name, $denied) || strpos($name, 'original') === 0) {
|
||||
|
@ -1209,6 +1209,9 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public static function assertEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) {
|
||||
// Cast objects implementing MarkupInterface to string instead of
|
||||
// relying on PHP casting them to string depending on what they are being
|
||||
// comparing with.
|
||||
$expected = static::castSafeStrings($expected);
|
||||
$actual = static::castSafeStrings($actual);
|
||||
parent::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase);
|
||||
|
|
|
@ -6,6 +6,8 @@ use Behat\Mink\Driver\GoutteDriver;
|
|||
use Behat\Mink\Element\Element;
|
||||
use Behat\Mink\Mink;
|
||||
use Behat\Mink\Session;
|
||||
use Drupal\Component\FileCache\FileCacheFactory;
|
||||
use Drupal\Component\Serialization\Yaml;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
|
@ -20,9 +22,13 @@ use Drupal\Core\StreamWrapper\StreamWrapperInterface;
|
|||
use Drupal\Core\Test\TestRunnerKernel;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Core\Test\TestDatabase;
|
||||
use Drupal\FunctionalTests\AssertLegacyTrait;
|
||||
use Drupal\simpletest\AssertHelperTrait;
|
||||
use Drupal\simpletest\ContentTypeCreationTrait;
|
||||
use Drupal\simpletest\BlockCreationTrait;
|
||||
use Drupal\simpletest\NodeCreationTrait;
|
||||
use Drupal\user\Entity\Role;
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\user\UserInterface;
|
||||
use Symfony\Component\CssSelector\CssSelectorConverter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
|
@ -31,13 +37,25 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
*
|
||||
* Tests extending BrowserTestBase must exist in the
|
||||
* Drupal\Tests\yourmodule\Functional namespace and live in the
|
||||
* modules/yourmodule/Tests/Functional directory.
|
||||
* modules/yourmodule/tests/src/Functional directory.
|
||||
*
|
||||
* @ingroup testing
|
||||
*/
|
||||
abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
||||
use AssertHelperTrait;
|
||||
use BlockCreationTrait {
|
||||
placeBlock as drupalPlaceBlock;
|
||||
}
|
||||
use AssertLegacyTrait;
|
||||
use RandomGeneratorTrait;
|
||||
use SessionTestTrait;
|
||||
use NodeCreationTrait {
|
||||
getNodeByTitle as drupalGetNodeByTitle;
|
||||
createNode as drupalCreateNode;
|
||||
}
|
||||
use ContentTypeCreationTrait {
|
||||
createContentType as drupalCreateContentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class loader.
|
||||
|
@ -273,6 +291,13 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
*/
|
||||
protected $baseUrl;
|
||||
|
||||
/**
|
||||
* The original array of shutdown function callbacks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $originalShutdownCallbacks = [];
|
||||
|
||||
/**
|
||||
* Initializes Mink sessions.
|
||||
*/
|
||||
|
@ -505,6 +530,12 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
if ($this->mink) {
|
||||
$this->mink->stopSessions();
|
||||
}
|
||||
|
||||
// Restore original shutdown callbacks.
|
||||
if (function_exists('drupal_register_shutdown_function')) {
|
||||
$callbacks = &drupal_register_shutdown_function();
|
||||
$callbacks = $this->originalShutdownCallbacks;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -530,7 +561,7 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
* A new web-assert option for asserting the presence of elements with.
|
||||
*/
|
||||
public function assertSession($name = NULL) {
|
||||
return new WebAssert($this->getSession($name));
|
||||
return new WebAssert($this->getSession($name), $this->baseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -546,6 +577,46 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
$session->setCookie('SIMPLETEST_USER_AGENT', drupal_generate_test_ua($this->databasePrefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an a absolute URL from a system path or a URL object.
|
||||
*
|
||||
* @param string|\Drupal\Core\Url $path
|
||||
* A system path or a URL.
|
||||
* @param array $options
|
||||
* Options to be passed to Url::fromUri().
|
||||
*
|
||||
* @return string
|
||||
* An absolute URL stsring.
|
||||
*/
|
||||
protected function buildUrl($path, array $options = array()) {
|
||||
if ($path instanceof Url) {
|
||||
$url_options = $path->getOptions();
|
||||
$options = $url_options + $options;
|
||||
$path->setOptions($options);
|
||||
return $path->setAbsolute()->toString();
|
||||
}
|
||||
// The URL generator service is not necessarily available yet; e.g., in
|
||||
// interactive installer tests.
|
||||
elseif ($this->container->has('url_generator')) {
|
||||
$force_internal = isset($options['external']) && $options['external'] == FALSE;
|
||||
if (!$force_internal && UrlHelper::isExternal($path)) {
|
||||
return Url::fromUri($path, $options)->toString();
|
||||
}
|
||||
else {
|
||||
$uri = $path === '<front>' ? 'base:/' : 'base:/' . $path;
|
||||
// Path processing is needed for language prefixing. Skip it when a
|
||||
// path that may look like an external URL is being used as internal.
|
||||
$options['path_processing'] = !$force_internal;
|
||||
return Url::fromUri($uri, $options)
|
||||
->setAbsolute()
|
||||
->toString();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $this->getAbsoluteUrl($path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a Drupal path or an absolute path.
|
||||
*
|
||||
|
@ -559,28 +630,8 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
*/
|
||||
protected function drupalGet($path, array $options = array()) {
|
||||
$options['absolute'] = TRUE;
|
||||
$url = $this->buildUrl($path, $options);
|
||||
|
||||
if ($path instanceof Url) {
|
||||
$url_options = $path->getOptions();
|
||||
$options = $url_options + $options;
|
||||
$path->setOptions($options);
|
||||
$url = $path->setAbsolute()->toString();
|
||||
}
|
||||
// The URL generator service is not necessarily available yet; e.g., in
|
||||
// interactive installer tests.
|
||||
elseif ($this->container->has('url_generator')) {
|
||||
if (UrlHelper::isExternal($path)) {
|
||||
$url = Url::fromUri($path, $options)->toString();
|
||||
}
|
||||
else {
|
||||
// This is needed for language prefixing.
|
||||
$options['path_processing'] = TRUE;
|
||||
$url = Url::fromUri('base:/' . $path, $options)->toString();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$url = $this->getAbsoluteUrl($path);
|
||||
}
|
||||
$session = $this->getSession();
|
||||
|
||||
$this->prepareRequest();
|
||||
|
@ -874,6 +925,16 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
// Edit the form values.
|
||||
foreach ($edit as $name => $value) {
|
||||
$field = $assert_session->fieldExists($name, $form);
|
||||
|
||||
// Provide support for the values '1' and '0' for checkboxes instead of
|
||||
// TRUE and FALSE.
|
||||
// @todo Get rid of supporting 1/0 by converting all tests cases using
|
||||
// this to boolean values.
|
||||
$field_type = $field->getAttribute('type');
|
||||
if ($field_type === 'checkbox') {
|
||||
$value = (bool) $value;
|
||||
}
|
||||
|
||||
$field->setValue($value);
|
||||
}
|
||||
|
||||
|
@ -893,6 +954,90 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a form submission.
|
||||
*
|
||||
* It will be done as usual POST request with Mink.
|
||||
*
|
||||
* @param \Drupal\Core\Url|string $path
|
||||
* Location of the post form. Either a Drupal path or an absolute path or
|
||||
* NULL to post to the current page. For multi-stage forms you can set the
|
||||
* path to NULL and have it post to the last received page. Example:
|
||||
*
|
||||
* @code
|
||||
* // First step in form.
|
||||
* $edit = array(...);
|
||||
* $this->drupalPostForm('some_url', $edit, t('Save'));
|
||||
*
|
||||
* // Second step in form.
|
||||
* $edit = array(...);
|
||||
* $this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
* @endcode
|
||||
* @param array $edit
|
||||
* Field data in an associative array. Changes the current input fields
|
||||
* (where possible) to the values indicated.
|
||||
*
|
||||
* When working with form tests, the keys for an $edit element should match
|
||||
* the 'name' parameter of the HTML of the form. For example, the 'body'
|
||||
* field for a node has the following HTML:
|
||||
* @code
|
||||
* <textarea id="edit-body-und-0-value" class="text-full form-textarea
|
||||
* resize-vertical" placeholder="" cols="60" rows="9"
|
||||
* name="body[0][value]"></textarea>
|
||||
* @endcode
|
||||
* When testing this field using an $edit parameter, the code becomes:
|
||||
* @code
|
||||
* $edit["body[0][value]"] = 'My test value';
|
||||
* @endcode
|
||||
*
|
||||
* A checkbox can be set to TRUE to be checked and should be set to FALSE to
|
||||
* be unchecked. Multiple select fields can be tested using 'name[]' and
|
||||
* setting each of the desired values in an array:
|
||||
* @code
|
||||
* $edit = array();
|
||||
* $edit['name[]'] = array('value1', 'value2');
|
||||
* @endcode
|
||||
* @param string $submit
|
||||
* Value of the submit button whose click is to be emulated. For example,
|
||||
* t('Save'). The processing of the request depends on this value. For
|
||||
* example, a form may have one button with the value t('Save') and another
|
||||
* button with the value t('Delete'), and execute different code depending
|
||||
* on which one is clicked.
|
||||
*
|
||||
* This function can also be called to emulate an Ajax submission. In this
|
||||
* case, this value needs to be an array with the following keys:
|
||||
* - path: A path to submit the form values to for Ajax-specific processing.
|
||||
* - triggering_element: If the value for the 'path' key is a generic Ajax
|
||||
* processing path, this needs to be set to the name of the element. If
|
||||
* the name doesn't identify the element uniquely, then this should
|
||||
* instead be an array with a single key/value pair, corresponding to the
|
||||
* element name and value. The \Drupal\Core\Form\FormAjaxResponseBuilder
|
||||
* uses this to find the #ajax information for the element, including
|
||||
* which specific callback to use for processing the request.
|
||||
*
|
||||
* This can also be set to NULL in order to emulate an Internet Explorer
|
||||
* submission of a form with a single text field, and pressing ENTER in that
|
||||
* textfield: under these conditions, no button information is added to the
|
||||
* POST data.
|
||||
* @param array $options
|
||||
* Options to be forwarded to the url generator.
|
||||
*/
|
||||
protected function drupalPostForm($path, array $edit, $submit, array $options = array()) {
|
||||
if (is_object($submit)) {
|
||||
// Cast MarkupInterface objects to string.
|
||||
$submit = (string) $submit;
|
||||
}
|
||||
if (is_array($edit)) {
|
||||
$edit = $this->castSafeStrings($edit);
|
||||
}
|
||||
|
||||
if (isset($path)) {
|
||||
$this->drupalGet($path, $options);
|
||||
}
|
||||
|
||||
$this->submitForm($edit, $submit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get the options of select field.
|
||||
*
|
||||
|
@ -951,6 +1096,10 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
'value' => $this->publicFilesDirectory,
|
||||
'required' => TRUE,
|
||||
);
|
||||
$settings['settings']['file_private_path'] = (object) [
|
||||
'value' => $this->privateFilesDirectory,
|
||||
'required' => TRUE,
|
||||
];
|
||||
$this->writeSettings($settings);
|
||||
// Allow for test-specific overrides.
|
||||
$settings_testing_file = DRUPAL_ROOT . '/' . $this->originalSiteDirectory . '/settings.testing.php';
|
||||
|
@ -961,11 +1110,14 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
// testing specific overrides.
|
||||
file_put_contents($directory . '/settings.php', "\n\$test_class = '" . get_class($this) . "';\n" . 'include DRUPAL_ROOT . \'/\' . $site_path . \'/settings.testing.php\';' . "\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
$settings_services_file = DRUPAL_ROOT . '/' . $this->originalSiteDirectory . '/testing.services.yml';
|
||||
if (file_exists($settings_services_file)) {
|
||||
// Copy the testing-specific service overrides in place.
|
||||
copy($settings_services_file, $directory . '/services.yml');
|
||||
if (!file_exists($settings_services_file)) {
|
||||
// Otherwise, use the default services as a starting point for overrides.
|
||||
$settings_services_file = DRUPAL_ROOT . '/sites/default/default.services.yml';
|
||||
}
|
||||
// Copy the testing-specific service overrides in place.
|
||||
copy($settings_services_file, $directory . '/services.yml');
|
||||
|
||||
// Since Drupal is bootstrapped already, install_begin_request() will not
|
||||
// bootstrap into DRUPAL_BOOTSTRAP_CONFIGURATION (again). Hence, we have to
|
||||
|
@ -990,6 +1142,10 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
// using File API; a potential error must trigger a PHP warning.
|
||||
chmod($directory, 0777);
|
||||
|
||||
// During tests, cacheable responses should get the debugging cacheability
|
||||
// headers by default.
|
||||
$this->setContainerParameter('http.response.debug_cacheability_headers', TRUE);
|
||||
|
||||
$request = \Drupal::request();
|
||||
$this->kernel = DrupalKernel::createFromRequest($request, $this->classLoader, 'prod', TRUE);
|
||||
$this->kernel->prepareLegacyRequest($request);
|
||||
|
@ -1000,13 +1156,13 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
$config = $container->get('config.factory');
|
||||
|
||||
// Manually create and configure private and temporary files directories.
|
||||
// While these could be preset/enforced in settings.php like the public
|
||||
// files directory above, some tests expect them to be configurable in the
|
||||
// UI. If declared in settings.php, they would no longer be configurable.
|
||||
file_prepare_directory($this->privateFilesDirectory, FILE_CREATE_DIRECTORY);
|
||||
file_prepare_directory($this->tempFilesDirectory, FILE_CREATE_DIRECTORY);
|
||||
// While the temporary files path could be preset/enforced in settings.php
|
||||
// like the public files directory above, some tests expect it to be
|
||||
// configurable in the UI. If declared in settings.php, it would no longer
|
||||
// be configurable.
|
||||
$config->getEditable('system.file')
|
||||
->set('path.private', $this->privateFilesDirectory)
|
||||
->set('path.temporary', $this->tempFilesDirectory)
|
||||
->save();
|
||||
|
||||
|
@ -1241,6 +1397,14 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
));
|
||||
|
||||
drupal_set_time_limit($this->timeLimit);
|
||||
|
||||
// Save and clean the shutdown callbacks array because it is static cached
|
||||
// and will be changed by the test run. Otherwise it will contain callbacks
|
||||
// from both environments and the testing environment will try to call the
|
||||
// handlers defined by the original one.
|
||||
$callbacks = &drupal_register_shutdown_function();
|
||||
$this->originalShutdownCallbacks = $callbacks;
|
||||
$callbacks = [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1383,6 +1547,7 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
*/
|
||||
protected function refreshVariables() {
|
||||
// Clear the tag cache.
|
||||
$this->container->get('cache_tags.invalidator')->resetChecksums();
|
||||
// @todo Replace drupal_static() usage within classes and provide a
|
||||
// proper interface for invoking reset() on a cache backend:
|
||||
// https://www.drupal.org/node/2311945.
|
||||
|
@ -1402,13 +1567,13 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
/**
|
||||
* Returns whether a given user account is logged in.
|
||||
*
|
||||
* @param \Drupal\user\UserInterface $account
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The user account object to check.
|
||||
*
|
||||
* @return bool
|
||||
* Return TRUE if the user is logged in, FALSE otherwise.
|
||||
*/
|
||||
protected function drupalUserIsLoggedIn(UserInterface $account) {
|
||||
protected function drupalUserIsLoggedIn(AccountInterface $account) {
|
||||
$logged_in = FALSE;
|
||||
|
||||
if (isset($account->sessionId)) {
|
||||
|
@ -1419,30 +1584,6 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
return $logged_in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the element with the given CSS selector is present.
|
||||
*
|
||||
* @param string $css_selector
|
||||
* The CSS selector identifying the element to check.
|
||||
* @param string $message
|
||||
* Optional message to show alongside the assertion.
|
||||
*/
|
||||
protected function assertElementPresent($css_selector, $message = '') {
|
||||
$this->assertNotEmpty($this->getSession()->getDriver()->find($this->cssSelectToXpath($css_selector)), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the element with the given CSS selector is not present.
|
||||
*
|
||||
* @param string $css_selector
|
||||
* The CSS selector identifying the element to check.
|
||||
* @param string $message
|
||||
* Optional message to show alongside the assertion.
|
||||
*/
|
||||
protected function assertElementNotPresent($css_selector, $message = '') {
|
||||
$this->assertEmpty($this->getSession()->getDriver()->find($this->cssSelectToXpath($css_selector)), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks the element with the given CSS selector.
|
||||
*
|
||||
|
@ -1529,4 +1670,134 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
return (new CssSelectorConverter($html))->toXPath($selector, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches elements using a CSS selector in the raw content.
|
||||
*
|
||||
* The search is relative to the root element (HTML tag normally) of the page.
|
||||
*
|
||||
* @param string $selector
|
||||
* CSS selector to use in the search.
|
||||
*
|
||||
* @return \Behat\Mink\Element\NodeElement[]
|
||||
* The list of elements on the page that match the selector.
|
||||
*/
|
||||
protected function cssSelect($selector) {
|
||||
return $this->getSession()->getPage()->findAll('css', $selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Follows a link by complete name.
|
||||
*
|
||||
* Will click the first link found with this link text.
|
||||
*
|
||||
* If the link is discovered and clicked, the test passes. Fail otherwise.
|
||||
*
|
||||
* @param string|\Drupal\Component\Render\MarkupInterface $label
|
||||
* Text between the anchor tags.
|
||||
*/
|
||||
protected function clickLink($label) {
|
||||
$label = (string) $label;
|
||||
$this->getSession()->getPage()->clickLink($label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the plain-text content from the current page.
|
||||
*/
|
||||
protected function getTextContent() {
|
||||
return $this->getSession()->getPage()->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an xpath search on the contents of the internal browser.
|
||||
*
|
||||
* The search is relative to the root element (HTML tag normally) of the page.
|
||||
*
|
||||
* @param string $xpath
|
||||
* The xpath string to use in the search.
|
||||
* @param array $arguments
|
||||
* An array of arguments with keys in the form ':name' matching the
|
||||
* placeholders in the query. The values may be either strings or numeric
|
||||
* values.
|
||||
*
|
||||
* @return \Behat\Mink\Element\NodeElement[]
|
||||
* The list of elements matching the xpath expression.
|
||||
*/
|
||||
protected function xpath($xpath, array $arguments = []) {
|
||||
$xpath = $this->assertSession()->buildXPathQuery($xpath, $arguments);
|
||||
return $this->getSession()->getPage()->findAll('xpath', $xpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration accessor for tests. Returns non-overridden configuration.
|
||||
*
|
||||
* @param string $name
|
||||
* Configuration name.
|
||||
*
|
||||
* @return \Drupal\Core\Config\Config
|
||||
* The configuration object with original configuration data.
|
||||
*/
|
||||
protected function config($name) {
|
||||
return $this->container->get('config.factory')->getEditable($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of an HTTP response header.
|
||||
*
|
||||
* If multiple requests were required to retrieve the page, only the headers
|
||||
* from the last request will be checked by default.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the header to retrieve. Names are case-insensitive (see RFC
|
||||
* 2616 section 4.2).
|
||||
*
|
||||
* @return string|null
|
||||
* The HTTP header value or NULL if not found.
|
||||
*/
|
||||
protected function drupalGetHeader($name) {
|
||||
return $this->getSession()->getResponseHeader($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current URL from the browser.
|
||||
*
|
||||
* @return string
|
||||
* The current URL.
|
||||
*/
|
||||
protected function getUrl() {
|
||||
return $this->getSession()->getCurrentUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function assertEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) {
|
||||
// Cast objects implementing MarkupInterface to string instead of
|
||||
// relying on PHP casting them to string depending on what they are being
|
||||
// comparing with.
|
||||
$expected = static::castSafeStrings($expected);
|
||||
$actual = static::castSafeStrings($actual);
|
||||
parent::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes parameters in the services.yml file.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the parameter.
|
||||
* @param mixed $value
|
||||
* The value of the parameter.
|
||||
*/
|
||||
protected function setContainerParameter($name, $value) {
|
||||
$filename = $this->siteDirectory . '/services.yml';
|
||||
chmod($filename, 0666);
|
||||
|
||||
$services = Yaml::decode(file_get_contents($filename));
|
||||
$services['parameters'][$name] = $value;
|
||||
file_put_contents($filename, Yaml::encode($services));
|
||||
|
||||
// Ensure that the cache is deleted for the yaml file loader.
|
||||
$file_cache = FileCacheFactory::get('container_yaml_loader');
|
||||
$file_cache->delete($filename);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -222,6 +222,17 @@ class ContainerTest extends \PHPUnit_Framework_TestCase {
|
|||
$this->assertTrue($this->container->has('another.service'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that Container::has() for aliased services works properly.
|
||||
*
|
||||
* @covers ::has
|
||||
*/
|
||||
public function testHasForAliasedService() {
|
||||
$service = $this->container->has('service.provider');
|
||||
$aliased_service = $this->container->has('service.provider_alias');
|
||||
$this->assertSame($service, $aliased_service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that Container::get() for circular dependencies works properly.
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
|
||||
|
|
|
@ -493,6 +493,60 @@ namespace Drupal\Tests\Component\DependencyInjection\Dumper {
|
|||
$this->dumper->getArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that references to aliases work correctly.
|
||||
*
|
||||
* @covers ::getReferenceCall
|
||||
*
|
||||
* @dataProvider publicPrivateDataProvider
|
||||
*/
|
||||
public function testGetServiceDefinitionWithReferenceToAlias($public) {
|
||||
$bar_definition = new Definition('\stdClass');
|
||||
$bar_definition_php_array = array(
|
||||
'class' => '\stdClass',
|
||||
);
|
||||
if (!$public) {
|
||||
$bar_definition->setPublic(FALSE);
|
||||
$bar_definition_php_array['public'] = FALSE;
|
||||
}
|
||||
$bar_definition_php_array['arguments_count'] = 0;
|
||||
|
||||
$services['bar'] = $bar_definition;
|
||||
|
||||
$aliases['bar.alias'] = 'bar';
|
||||
|
||||
$foo = new Definition('\stdClass');
|
||||
$foo->addArgument(new Reference('bar.alias'));
|
||||
|
||||
$services['foo'] = $foo;
|
||||
|
||||
$this->containerBuilder->getAliases()->willReturn($aliases);
|
||||
$this->containerBuilder->getDefinitions()->willReturn($services);
|
||||
$this->containerBuilder->getDefinition('bar')->willReturn($bar_definition);
|
||||
$dump = $this->dumper->getArray();
|
||||
if ($public) {
|
||||
$service_definition = $this->getServiceCall('bar');
|
||||
}
|
||||
else {
|
||||
$service_definition = $this->getPrivateServiceCall('bar', $bar_definition_php_array, TRUE);
|
||||
}
|
||||
$data = array(
|
||||
'class' => '\stdClass',
|
||||
'arguments' => $this->getCollection(array(
|
||||
$service_definition,
|
||||
)),
|
||||
'arguments_count' => 1,
|
||||
);
|
||||
$this->assertEquals($this->serializeDefinition($data), $dump['services']['foo'], 'Expected definition matches dump.');
|
||||
}
|
||||
|
||||
public function publicPrivateDataProvider() {
|
||||
return array(
|
||||
array(TRUE),
|
||||
array(FALSE),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that getDecoratedService() is unsupported.
|
||||
*
|
||||
|
|
|
@ -35,11 +35,10 @@ class ImageTest extends UnitTestCase {
|
|||
*
|
||||
* @return array
|
||||
* Keyed array containing:
|
||||
* - 'input' - Array which contains input for
|
||||
* Image::scaleDimensions().
|
||||
* - 'output' - Array which contains expected output after passing
|
||||
* through Image::scaleDimensions. Also contains a boolean
|
||||
* 'return_value' which should match the expected return value.
|
||||
* - 'input' - Array which contains input for Image::scaleDimensions().
|
||||
* - 'output' - Array which contains expected output after passing
|
||||
* through Image::scaleDimensions. Also contains a boolean
|
||||
* 'return_value' which should match the expected return value.
|
||||
*
|
||||
* @see testScaleDimensions()
|
||||
*/
|
||||
|
|
|
@ -474,11 +474,11 @@ class UnicodeTest extends UnitTestCase {
|
|||
/**
|
||||
* Provides data for self::testValidateUtf8().
|
||||
*
|
||||
* Invalid UTF-8 examples sourced from http://stackoverflow.com/a/11709412/109119.
|
||||
*
|
||||
* @return array
|
||||
* An array of arrays, each containing the parameters for
|
||||
* self::testValidateUtf8().
|
||||
*
|
||||
* Invalid UTF-8 examples sourced from http://stackoverflow.com/a/11709412/109119.
|
||||
*/
|
||||
public function providerTestValidateUtf8() {
|
||||
return array(
|
||||
|
|
|
@ -77,7 +77,7 @@ class UuidTest extends UnitTestCase {
|
|||
* Dataprovider for UUID instance tests.
|
||||
*
|
||||
* @return array
|
||||
* An array of arrays containing
|
||||
* An array of arrays containing
|
||||
* - The Uuid to check against.
|
||||
* - (bool) Whether or not the Uuid is valid.
|
||||
* - Failure message.
|
||||
|
|
|
@ -48,6 +48,7 @@ class ComposerIntegrationTest extends UnitTestCase {
|
|||
$this->root . '/core/lib/Drupal/Component/Assertion',
|
||||
$this->root . '/core/lib/Drupal/Component/Bridge',
|
||||
$this->root . '/core/lib/Drupal/Component/Datetime',
|
||||
$this->root . '/core/lib/Drupal/Component/DependencyInjection',
|
||||
$this->root . '/core/lib/Drupal/Component/Diff',
|
||||
$this->root . '/core/lib/Drupal/Component/Discovery',
|
||||
$this->root . '/core/lib/Drupal/Component/EventDispatcher',
|
||||
|
|
|
@ -33,6 +33,21 @@ class ChainedFastBackendTest extends UnitTestCase {
|
|||
*/
|
||||
protected $bin;
|
||||
|
||||
/**
|
||||
* Tests that chained fast backend cannot be constructed with two instances of
|
||||
* the same service.
|
||||
*/
|
||||
public function testConsistentAndFastBackendCannotBeTheSameService() {
|
||||
// ToDo: It should throw a proper exception. See https://www.drupal.org/node/2751847.
|
||||
$this->setExpectedException(\PHPUnit_Framework_Error::class, 'Consistent cache backend and fast cache backend cannot use the same service.');
|
||||
$cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
|
||||
$chained_fast_backend = new ChainedFastBackend(
|
||||
$cache,
|
||||
$cache,
|
||||
'foo'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a get() on the fast backend, with no hit on the consistent backend.
|
||||
*/
|
||||
|
|
|
@ -31,15 +31,18 @@ class QueryArgsCacheContextTest extends UnitTestCase {
|
|||
*/
|
||||
public function providerTestGetContext() {
|
||||
return [
|
||||
[[], NULL, NULL],
|
||||
[[], 'foo', NULL],
|
||||
[[], NULL, ''],
|
||||
[[], 'foo', ''],
|
||||
// Non-empty query arguments.
|
||||
[['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], NULL, 'alpaca=&llama=rocks&panda=drools&z=0'],
|
||||
[['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'llama', 'rocks'],
|
||||
[['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'alpaca', '?valueless?'],
|
||||
[['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'panda', 'drools'],
|
||||
[['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'z', '0'],
|
||||
[['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'chicken', NULL],
|
||||
[['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'chicken', ''],
|
||||
[['llama' => ['rocks', 'kitty']], 'llama', '0=rocks&1=kitty'],
|
||||
[['llama' => ['rocks' => 'fuzzball', 'monkey' => 'patch']], 'llama', 'rocks=fuzzball&monkey=patch'],
|
||||
[['llama' => ['rocks' => ['nested', 'bonobo']]], 'llama', 'rocks%5B0%5D=nested&rocks%5B1%5D=bonobo'],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\Core\Config;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigDependencyManager;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* Tests the ConfigDependencyManager class.
|
||||
*
|
||||
* @group Config
|
||||
*
|
||||
* @coversDefaultClass \Drupal\Core\Config\Entity\ConfigDependencyManager
|
||||
*/
|
||||
class ConfigDependencyManagerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @dataProvider providerTestSortAll
|
||||
*/
|
||||
public function testSortAll(array $data, array $expected_order) {
|
||||
$dependency_manager = new ConfigDependencyManager();
|
||||
$dependency_manager->setData($data);
|
||||
$this->assertEquals($expected_order, $dependency_manager->sortAll());
|
||||
}
|
||||
|
||||
public function providerTestSortAll() {
|
||||
$datasets[] = [
|
||||
[
|
||||
'provider.entity_b' => [],
|
||||
'provider.entity_a' => [],
|
||||
],
|
||||
['provider.entity_a', 'provider.entity_b'],
|
||||
];
|
||||
|
||||
$datasets[] = [
|
||||
[
|
||||
'provider.entity_a' => [],
|
||||
'provider.entity_b' => [],
|
||||
],
|
||||
['provider.entity_a', 'provider.entity_b'],
|
||||
];
|
||||
|
||||
$datasets[] = [
|
||||
[
|
||||
'provider.entity_b' => ['dependencies' => ['config' => ['provider.entity_a']]],
|
||||
'provider.entity_a' => [],
|
||||
],
|
||||
['provider.entity_a', 'provider.entity_b'],
|
||||
];
|
||||
|
||||
$datasets[] = [
|
||||
[
|
||||
'provider.entity_a' => [],
|
||||
'provider.entity_b' => ['dependencies' => ['config' => ['provider.entity_a']]],
|
||||
],
|
||||
['provider.entity_a', 'provider.entity_b'],
|
||||
];
|
||||
|
||||
$datasets[] = [
|
||||
[
|
||||
'provider.entity_b' => [],
|
||||
'provider.entity_a' => ['dependencies' => ['config' => ['provider.entity_b']]],
|
||||
],
|
||||
['provider.entity_b', 'provider.entity_a'],
|
||||
];
|
||||
|
||||
$datasets[] = [
|
||||
[
|
||||
'provider.entity_a' => ['dependencies' => ['config' => ['provider.entity_b']]],
|
||||
'provider.entity_b' => [],
|
||||
],
|
||||
['provider.entity_b', 'provider.entity_a'],
|
||||
];
|
||||
|
||||
$datasets[] = [
|
||||
[
|
||||
'provider.entity_a' => ['dependencies' => ['config' => ['provider.entity_b']]],
|
||||
'provider.entity_b' => [],
|
||||
'block.block.a' => [],
|
||||
'block.block.b' => [],
|
||||
],
|
||||
['block.block.a', 'provider.entity_b', 'block.block.b', 'provider.entity_a'],
|
||||
];
|
||||
|
||||
$datasets[] = [
|
||||
[
|
||||
'provider.entity_b' => [],
|
||||
'block.block.b' => [],
|
||||
'block.block.a' => [],
|
||||
'provider.entity_a' => ['dependencies' => ['config' => ['provider.entity_b']]],
|
||||
],
|
||||
['block.block.a', 'provider.entity_b', 'block.block.b', 'provider.entity_a'],
|
||||
];
|
||||
|
||||
$datasets[] = [
|
||||
[
|
||||
'provider.entity_b' => [],
|
||||
'block.block.b' => [],
|
||||
'block.block.a' => [],
|
||||
'provider.entity_a' => ['dependencies' => ['config' => ['provider.entity_b']]],
|
||||
'provider.entity_c' => ['dependencies' => ['config' => ['block.block.a']]],
|
||||
],
|
||||
['block.block.a', 'block.block.b', 'provider.entity_b', 'provider.entity_a', 'provider.entity_c'],
|
||||
];
|
||||
|
||||
$datasets[] = [
|
||||
[
|
||||
'provider.entity_b' => ['dependencies' => ['module' => ['system']]],
|
||||
'block.block.b' => [],
|
||||
'block.block.a' => ['dependencies' => ['module' => ['system']]],
|
||||
'provider.entity_a' => ['dependencies' => ['config' => ['provider.entity_c']]],
|
||||
'provider.entity_c' => ['dependencies' => ['config' => ['block.block.a']]],
|
||||
],
|
||||
['block.block.b', 'block.block.a', 'provider.entity_c', 'provider.entity_a', 'provider.entity_b'],
|
||||
];
|
||||
|
||||
return $datasets;
|
||||
}
|
||||
|
||||
}
|
|
@ -158,8 +158,8 @@ class StorageComparerTest extends UnitTestCase {
|
|||
$this->storageComparer->createChangelist();
|
||||
$expected = array(
|
||||
'field.storage.node.body',
|
||||
'views.view.test_view',
|
||||
'field.field.node.article.body',
|
||||
'views.view.test_view',
|
||||
);
|
||||
$this->assertEquals($expected, $this->storageComparer->getChangelist('create'));
|
||||
$this->assertEmpty($this->storageComparer->getChangelist('delete'));
|
||||
|
@ -196,8 +196,8 @@ class StorageComparerTest extends UnitTestCase {
|
|||
|
||||
$this->storageComparer->createChangelist();
|
||||
$expected = array(
|
||||
'field.field.node.article.body',
|
||||
'views.view.test_view',
|
||||
'field.field.node.article.body',
|
||||
'field.storage.node.body',
|
||||
);
|
||||
$this->assertEquals($expected, $this->storageComparer->getChangelist('delete'));
|
||||
|
@ -236,8 +236,8 @@ class StorageComparerTest extends UnitTestCase {
|
|||
$this->storageComparer->createChangelist();
|
||||
$expected = array(
|
||||
'field.storage.node.body',
|
||||
'system.site',
|
||||
'field.field.node.article.body',
|
||||
'system.site',
|
||||
);
|
||||
$this->assertEquals($expected, $this->storageComparer->getChangelist('update'));
|
||||
$this->assertEmpty($this->storageComparer->getChangelist('create'));
|
||||
|
|
|
@ -150,19 +150,16 @@ class ConnectionTest extends UnitTestCase {
|
|||
return array(
|
||||
array(
|
||||
'nonexistent_class',
|
||||
'stub',
|
||||
'\\',
|
||||
'nonexistent_class',
|
||||
),
|
||||
array(
|
||||
'Drupal\\Core\\Database\\Driver\\mysql\\Select',
|
||||
'mysql',
|
||||
'Drupal\Tests\Core\Database\Stub\Select',
|
||||
NULL,
|
||||
'Select',
|
||||
),
|
||||
array(
|
||||
'Drupal\\Tests\\Core\\Database\\Stub\\Driver\\Schema',
|
||||
'stub',
|
||||
'Drupal\\Tests\\Core\\Database\\Stub\\Driver',
|
||||
'Schema',
|
||||
),
|
||||
|
@ -174,11 +171,10 @@ class ConnectionTest extends UnitTestCase {
|
|||
*
|
||||
* @dataProvider providerGetDriverClass
|
||||
*/
|
||||
public function testGetDriverClass($expected, $driver, $namespace, $class) {
|
||||
public function testGetDriverClass($expected, $namespace, $class) {
|
||||
$mock_pdo = $this->getMock('Drupal\Tests\Core\Database\Stub\StubPDO');
|
||||
$connection = new StubConnection($mock_pdo, array('namespace' => $namespace));
|
||||
// Set the driver using our stub class' public property.
|
||||
$connection->driver = $driver;
|
||||
$this->assertEquals($expected, $connection->getDriverClass($class));
|
||||
}
|
||||
|
||||
|
|
9
core/tests/Drupal/Tests/Core/Database/Stub/Select.php
Normal file
9
core/tests/Drupal/Tests/Core/Database/Stub/Select.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\Core\Database\Stub;
|
||||
|
||||
use Drupal\Core\Database\Driver\mysql\Select as QuerySelect;
|
||||
|
||||
class Select extends QuerySelect {
|
||||
|
||||
}
|
|
@ -2,377 +2,501 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Entity;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Entity\Entity;
|
||||
use Drupal\Core\Entity\EntityMalformedException;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\Exception\UndefinedLinkTemplateException;
|
||||
use Drupal\Core\Entity\RevisionableInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* Tests URL handling of the \Drupal\Core\Entity\Entity class.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\Core\Entity\Entity
|
||||
*
|
||||
* @group Entity
|
||||
*/
|
||||
class EntityUrlTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The mocked entity manager.
|
||||
* The entity manager mock used in this test.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
* @var \Prophecy\Prophecy\ProphecyInterface|\Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The mocked URL generator.
|
||||
* The ID of the entity type used in this test.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\UrlGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
* @var string
|
||||
*/
|
||||
protected $urlGenerator;
|
||||
protected $entityTypeId = 'test_entity';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* The entity type mock used in this test.
|
||||
*
|
||||
* @var \Prophecy\Prophecy\ProphecyInterface|\Drupal\Core\Entity\EntityTypeInterface
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
protected $entityType;
|
||||
|
||||
$this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
|
||||
$this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
|
||||
/**
|
||||
* The ID of the entity used in this test.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $entityId = 1;
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('entity.manager', $this->entityManager);
|
||||
$container->set('url_generator', $this->urlGenerator);
|
||||
\Drupal::setContainer($container);
|
||||
/**
|
||||
* The revision ID of the entity used in this test.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $revisionId = 2;
|
||||
|
||||
/**
|
||||
* The language code of the entity used in this test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'en';
|
||||
|
||||
/**
|
||||
* Indicator for default revisions.
|
||||
*
|
||||
* @var true
|
||||
*/
|
||||
const DEFAULT_REVISION = TRUE;
|
||||
|
||||
/**
|
||||
* Indicator for non-default revisions.
|
||||
*
|
||||
* @var false
|
||||
*/
|
||||
const NON_DEFAULT_REVISION = FALSE;
|
||||
|
||||
/**
|
||||
* Tests the toUrl() method without an entity ID.
|
||||
*
|
||||
* @covers ::toUrl
|
||||
*/
|
||||
public function testToUrlNoId() {
|
||||
$entity = $this->getEntity(Entity::class, []);
|
||||
|
||||
$this->setExpectedException(EntityMalformedException::class, 'The "' . $this->entityTypeId . '" entity cannot have a URI as it does not have an ID');
|
||||
$entity->toUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the toUrl() method with simple link templates.
|
||||
*
|
||||
* @param string $link_template
|
||||
* The link template to test.
|
||||
* @param string $expected_route_name
|
||||
* The expected route name of the generated URL.
|
||||
*
|
||||
* @dataProvider providerTestToUrlLinkTemplates
|
||||
*
|
||||
* @covers ::toUrl
|
||||
* @covers ::linkTemplates
|
||||
* @covers ::urlRouteParameters
|
||||
*/
|
||||
public function testToUrlLinkTemplates($link_template, $expected_route_name) {
|
||||
$values = ['id' => $this->entityId, 'langcode' => $this->langcode];
|
||||
$entity = $this->getEntity(Entity::class, $values);
|
||||
$this->registerLinkTemplate($link_template);
|
||||
|
||||
/** @var \Drupal\Core\Url $url */
|
||||
$url = $entity->toUrl($link_template);
|
||||
// The entity ID is the sole route parameter for the link templates tested
|
||||
// here.
|
||||
$this->assertUrl($expected_route_name, ['test_entity' => $this->entityId], $entity, TRUE, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for testToUrlLinkTemplates().
|
||||
*
|
||||
* @return array
|
||||
* An array of test cases for testToUrlLinkTemplates().
|
||||
*/
|
||||
public function providerTestToUrlLinkTemplates() {
|
||||
$test_cases = [];
|
||||
|
||||
$test_cases['canonical'] = ['canonical', 'entity.test_entity.canonical'];
|
||||
$test_cases['version-history'] = ['version-history', 'entity.test_entity.version_history'];
|
||||
$test_cases['edit-form'] = ['edit-form', 'entity.test_entity.edit_form'];
|
||||
$test_cases['delete-form'] = ['delete-form', 'entity.test_entity.delete_form'];
|
||||
$test_cases['revision'] = ['revision', 'entity.test_entity.revision'];
|
||||
|
||||
return $test_cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the toUrl() method with the 'revision' link template.
|
||||
*
|
||||
* @param bool $is_default_revision
|
||||
* Whether or not the mock entity should be the default revision.
|
||||
* @param string $link_template
|
||||
* The link template to test.
|
||||
* @param string $expected_route_name
|
||||
* The expected route name of the generated URL.
|
||||
* @param array $expected_route_parameters
|
||||
* The expected route parameters of the generated URL.
|
||||
*
|
||||
* @dataProvider providerTestToUrlLinkTemplateRevision
|
||||
*
|
||||
* @covers ::toUrl
|
||||
* @covers ::linkTemplates
|
||||
* @covers ::urlRouteParameters
|
||||
*/
|
||||
public function testToUrlLinkTemplateRevision($is_default_revision, $link_template, $expected_route_name, array $expected_route_parameters) {
|
||||
$values = ['id' => $this->entityId, 'langcode' => $this->langcode];
|
||||
$entity = $this->getEntity(RevisionableEntity::class, $values);
|
||||
$entity->method('getRevisionId')->willReturn($this->revisionId);
|
||||
$entity->method('isDefaultRevision')->willReturn($is_default_revision);
|
||||
$this->registerLinkTemplate($link_template);
|
||||
// Even though this is tested with both the 'canonical' and the 'revision'
|
||||
// template registered with the entity, we always ask for the 'revision'
|
||||
// link template, to test that it falls back to the 'canonical' link
|
||||
// template in case of the default revision.
|
||||
/** @var \Drupal\Core\Url $url */
|
||||
$url = $entity->toUrl('revision');
|
||||
$this->assertUrl($expected_route_name, $expected_route_parameters, $entity, TRUE, $url);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for testToUrlLinkTemplateRevision().
|
||||
*
|
||||
* @return array
|
||||
* An array of test cases for testToUrlLinkTemplateRevision().
|
||||
*/
|
||||
public function providerTestToUrlLinkTemplateRevision() {
|
||||
$test_cases = [];
|
||||
|
||||
$route_parameters = ['test_entity' => $this->entityId];
|
||||
$test_cases['default_revision'] = [static::DEFAULT_REVISION, 'canonical', 'entity.test_entity.canonical', $route_parameters];
|
||||
// Add the revision ID to the expected route parameters.
|
||||
$route_parameters['test_entity_revision'] = $this->revisionId;
|
||||
$test_cases['non_default_revision'] = [static::NON_DEFAULT_REVISION, 'revision', 'entity.test_entity.revision', $route_parameters];
|
||||
|
||||
return $test_cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the toUrl() method with the 'collection' link template.
|
||||
*
|
||||
* @covers ::toUrl
|
||||
* @covers ::linkTemplates
|
||||
* @covers ::urlRouteParameters
|
||||
*/
|
||||
public function testToUrlLinkTemplateCollection() {
|
||||
$entity = $this->getEntity(Entity::class, ['id' => $this->entityId]);
|
||||
$link_template = 'collection';
|
||||
$this->registerLinkTemplate($link_template);
|
||||
|
||||
/** @var \Drupal\Core\Url $url */
|
||||
$url = $entity->toUrl($link_template);
|
||||
$this->assertUrl('entity.test_entity.collection', [], $entity, FALSE, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the toUrl() method with neither link templates nor a URI callback.
|
||||
*
|
||||
* @param array $bundle_info
|
||||
* An array of bundle info to register.
|
||||
* @param string $uri_callback
|
||||
* The entity type URI callback to register.
|
||||
*
|
||||
* @dataProvider providerTestToUrlUriCallbackUndefined
|
||||
*
|
||||
* @covers ::toUrl
|
||||
* @covers ::linkTemplates
|
||||
*/
|
||||
public function testToUrlUriCallbackUndefined(array $bundle_info, $uri_callback) {
|
||||
$entity = $this->getEntity(Entity::class, ['id' => $this->entityId]);
|
||||
|
||||
$this->registerBundleInfo($bundle_info);
|
||||
$this->entityType->getUriCallback()->willReturn($uri_callback);
|
||||
|
||||
$link_template = 'canonical';
|
||||
$this->setExpectedException(UndefinedLinkTemplateException::class, "No link template '$link_template' found for the '$this->entityTypeId' entity type");
|
||||
$entity->toUrl($link_template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for testToUrlUriCallbackUndefined().
|
||||
*
|
||||
* @return array
|
||||
* An array of test cases for testToUrlUriCallbackUndefined().
|
||||
*/
|
||||
public function providerTestToUrlUriCallbackUndefined() {
|
||||
$test_cases = [];
|
||||
|
||||
$test_cases['no_callback'] = [[], NULL];
|
||||
$test_cases['uri_callback'] = [[], 'not_a_callable'];
|
||||
$test_cases['bundle_uri_callback'] = [['uri_callback' => 'not_a_callable'], NULL];
|
||||
|
||||
return $test_cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the toUrl() method with a URI callback.
|
||||
*
|
||||
* @param array $bundle_info
|
||||
* An array of bundle info to register.
|
||||
* @param string $uri_callback
|
||||
* The entity type URI callback to register.
|
||||
*
|
||||
* @covers ::toUrl
|
||||
* @covers ::linkTemplates
|
||||
*
|
||||
* @dataProvider providerTestToUrlUriCallback
|
||||
*/
|
||||
public function testToUrlUriCallback(array $bundle_info, $uri_callback) {
|
||||
$entity = $this->getEntity(Entity::class, ['id' => $this->entityId, 'langcode' => $this->langcode]);
|
||||
|
||||
$this->registerBundleInfo($bundle_info);
|
||||
$this->entityType->getUriCallback()->willReturn($uri_callback);
|
||||
|
||||
/** @var \Drupal\Core\Url $url */
|
||||
$url = $entity->toUrl('canonical');
|
||||
$this->assertUrl('<none>', [], $entity, TRUE, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for testToUrlUriCallback().
|
||||
*
|
||||
* @return array
|
||||
* An array of test cases for testToUrlUriCallback().
|
||||
*/
|
||||
public function providerTestToUrlUriCallback() {
|
||||
$test_cases = [];
|
||||
|
||||
$uri_callback = function () { return Url::fromRoute('<none>'); };
|
||||
$test_cases['uri_callback'] = [[], $uri_callback];
|
||||
$test_cases['bundle_uri_callback'] = [['uri_callback' => $uri_callback], NULL];
|
||||
|
||||
return $test_cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the urlInfo() method.
|
||||
*
|
||||
* Note that urlInfo() is a deprecated alias for toUrl().
|
||||
* See testToUrl().
|
||||
* @param string $rel
|
||||
* The link relation to test.
|
||||
* @param array $options
|
||||
* An array of URL options to test with.
|
||||
*
|
||||
* @covers ::urlInfo
|
||||
*
|
||||
* @dataProvider providerTestToUrl
|
||||
* @dataProvider providerTestUrlInfo
|
||||
*/
|
||||
public function testUrlInfo($entity_class, $link_template, $expected, $langcode = NULL) {
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $entity */
|
||||
$entity = $this->getMockForAbstractClass($entity_class, array(array('id' => 'test_entity_id'), 'test_entity_type'));
|
||||
$uri = $this->getTestUrlInfo($entity, $link_template, [], $langcode);
|
||||
public function testUrlInfo($rel, $options) {
|
||||
$entity = $this->getEntity(Entity::class, [], ['toUrl']);
|
||||
$entity->expects($this->once())
|
||||
->method('toUrl')
|
||||
->with($rel, $options);
|
||||
|
||||
$this->assertSame($expected, $uri->getRouteName());
|
||||
$this->assertSame($entity, $uri->getOption('entity'));
|
||||
|
||||
if ($langcode) {
|
||||
$this->assertEquals($langcode, $uri->getOption('language')->getId());
|
||||
}
|
||||
else {
|
||||
if ($entity instanceof ConfigEntityInterface) {
|
||||
// Config entities do not provide a language with their URIs.
|
||||
$this->assertEquals(NULL, $uri->getOption('language'));
|
||||
}
|
||||
else {
|
||||
$this->assertEquals(LanguageInterface::LANGCODE_NOT_SPECIFIED, $uri->getOption('language')->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Tests the toUrl() method.
|
||||
*
|
||||
* @covers ::toUrl
|
||||
*
|
||||
* @dataProvider providerTestToUrl
|
||||
*/
|
||||
public function testToUrl($entity_class, $link_template, $expected, $langcode = NULL) {
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $entity */
|
||||
$entity = $this->getMockForAbstractClass($entity_class, array(array('id' => 'test_entity_id'), 'test_entity_type'));
|
||||
$uri = $this->getTestToUrl($entity, $link_template, [], $langcode);
|
||||
|
||||
$this->assertSame($expected, $uri->getRouteName());
|
||||
$this->assertSame($entity, $uri->getOption('entity'));
|
||||
|
||||
if ($langcode) {
|
||||
$this->assertEquals($langcode, $uri->getOption('language')->getId());
|
||||
}
|
||||
else {
|
||||
if ($entity instanceof ConfigEntityInterface) {
|
||||
// Config entities do not provide a language with their URIs.
|
||||
$this->assertEquals(NULL, $uri->getOption('language'));
|
||||
}
|
||||
else {
|
||||
$this->assertEquals(LanguageInterface::LANGCODE_NOT_SPECIFIED, $uri->getOption('language')->getId());
|
||||
}
|
||||
}
|
||||
$entity->urlInfo($rel, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for Entity::toUrl() exercising different language options.
|
||||
* Provides data for testUrlInfo().
|
||||
*
|
||||
* @covers ::toUrl
|
||||
* @return array
|
||||
* An array of test cases for testUrlInfo().
|
||||
*/
|
||||
public function testToUrlWithSpecificLanguageInOptions() {
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $entity */
|
||||
$entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array('id' => 'test_entity_id'), 'test_entity_type'));
|
||||
public function providerTestUrlInfo() {
|
||||
$test_cases = [];
|
||||
|
||||
// Ensure that a specified language overrides the current translation
|
||||
// language.
|
||||
$uri = $this->getTestToUrl($entity, 'edit-form', [], 'en');
|
||||
$this->assertEquals('en', $uri->getOption('language')->getId());
|
||||
$test_cases['default'] = ['canonical', []];
|
||||
$test_cases['with_option'] = ['canonical', ['absolute' => TRUE]];
|
||||
$test_cases['revision'] = ['revision', []];
|
||||
|
||||
$uri = $this->getTestToUrl($entity, 'edit-form', ['language' => new Language(['id' => 'fr'])], 'en');
|
||||
$this->assertEquals('fr', $uri->getOption('language')->getId());
|
||||
return $test_cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test data for testUrlInfo().
|
||||
* Tests the url() method without an entity ID.
|
||||
*
|
||||
* @param string $rel
|
||||
* The link relation to test.
|
||||
*
|
||||
* @covers ::url
|
||||
* @covers ::hasLinkTemplate
|
||||
* @covers ::linkTemplates
|
||||
*
|
||||
* @dataProvider providerTestUrl
|
||||
*/
|
||||
public function providerTestToUrl() {
|
||||
return array(
|
||||
array('Drupal\Core\Entity\Entity', 'edit-form', 'entity.test_entity_type.edit_form', NULL),
|
||||
// Specify a langcode.
|
||||
array('Drupal\Core\Entity\Entity', 'edit-form', 'entity.test_entity_type.edit_form', 'es'),
|
||||
array('Drupal\Core\Entity\Entity', 'edit-form', 'entity.test_entity_type.edit_form', 'en'),
|
||||
array('Drupal\Core\Config\Entity\ConfigEntityBase', 'edit-form', 'entity.test_entity_type.edit_form', NULL),
|
||||
// Test that overriding the default $rel parameter works.
|
||||
array('Drupal\Core\Config\Entity\ConfigEntityBase', FALSE, 'entity.test_entity_type.edit_form', NULL),
|
||||
);
|
||||
public function testUrlEmpty($rel) {
|
||||
$entity = $this->getEntity(Entity::class, []);
|
||||
$this->assertEquals('', $entity->url($rel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the toUrl() method with an invalid link template.
|
||||
* Provides data for testUrlEmpty().
|
||||
*
|
||||
* @covers ::toUrl
|
||||
*
|
||||
* @expectedException \Drupal\Core\Entity\Exception\UndefinedLinkTemplateException
|
||||
*
|
||||
* @expectedExceptionMessage No link template 'canonical' found for the 'test_entity_type' entity type
|
||||
*
|
||||
* @dataProvider providerTestToUrlForInvalidLinkTemplate
|
||||
* @return array
|
||||
* An array of test cases for testUrlEmpty().
|
||||
*/
|
||||
public function testToUrlForInvalidLinkTemplate($entity_class, $link_template) {
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $entity */
|
||||
$entity = $this->getMockForAbstractClass($entity_class, array(array('id' => 'test_entity_id'), 'test_entity_type'));
|
||||
$uri = $this->getTestToUrl($entity, $link_template);
|
||||
public function providerTestUrlEmpty() {
|
||||
$test_cases = [];
|
||||
|
||||
$this->assertEmpty($uri);
|
||||
}
|
||||
$test_cases['default'] = ['canonical', []];
|
||||
$test_cases['revision'] = ['revision', []];
|
||||
|
||||
/**
|
||||
* Provides test data for testUrlInfoForInvalidLinkTemplate().
|
||||
*/
|
||||
public function providerTestToUrlForInvalidLinkTemplate() {
|
||||
return array(
|
||||
array('Drupal\Core\Entity\Entity', 'canonical'),
|
||||
array('Drupal\Core\Entity\Entity', FALSE),
|
||||
array('Drupal\Core\Config\Entity\ConfigEntityBase', 'canonical'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a \Drupal\Core\Url object based on the entity and link template.
|
||||
*
|
||||
* Method urlInfo() is deprecated and replaced with toUrl().
|
||||
* See also getTestToUrl().
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The test entity.
|
||||
* @param string $link_template
|
||||
* The link template.
|
||||
* @param string $langcode
|
||||
* The langcode.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* The URL for this entity's link template.
|
||||
*/
|
||||
protected function getTestUrlInfo(EntityInterface $entity, $link_template, array $options = [], $langcode = NULL) {
|
||||
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
|
||||
$entity_type->expects($this->any())
|
||||
->method('getLinkTemplates')
|
||||
->will($this->returnValue(array(
|
||||
'edit-form' => 'test_entity_type.edit',
|
||||
)));
|
||||
|
||||
if ($langcode) {
|
||||
$entity->langcode = $langcode;
|
||||
}
|
||||
|
||||
$this->entityManager
|
||||
->expects($this->any())
|
||||
->method('getDefinition')
|
||||
->with('test_entity_type')
|
||||
->will($this->returnValue($entity_type));
|
||||
|
||||
// If no link template is given, call without a value to test the default.
|
||||
if ($link_template) {
|
||||
$uri = $entity->urlInfo($link_template, $options);
|
||||
}
|
||||
else {
|
||||
if ($entity instanceof ConfigEntityInterface) {
|
||||
$uri = $entity->urlInfo('edit-form', $options);
|
||||
}
|
||||
else {
|
||||
$uri = $entity->urlInfo('canonical', $options);
|
||||
}
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a \Drupal\Core\Url object based on the entity and link template.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The test entity.
|
||||
* @param string $link_template
|
||||
* The link template.
|
||||
* @param string $langcode
|
||||
* The langcode.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* The URL for this entity's link template.
|
||||
*/
|
||||
protected function getTestToUrl(EntityInterface $entity, $link_template, array $options = [], $langcode = NULL) {
|
||||
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
|
||||
$entity_type->expects($this->any())
|
||||
->method('getLinkTemplates')
|
||||
->will($this->returnValue(array(
|
||||
'edit-form' => 'test_entity_type.edit',
|
||||
)));
|
||||
|
||||
if ($langcode) {
|
||||
$entity->langcode = $langcode;
|
||||
}
|
||||
|
||||
$this->entityManager
|
||||
->expects($this->any())
|
||||
->method('getDefinition')
|
||||
->with('test_entity_type')
|
||||
->will($this->returnValue($entity_type));
|
||||
|
||||
// If no link template is given, call without a value to test the default.
|
||||
if ($link_template) {
|
||||
$uri = $entity->toUrl($link_template, $options);
|
||||
}
|
||||
else {
|
||||
if ($entity instanceof ConfigEntityInterface) {
|
||||
$uri = $entity->toUrl('edit-form', $options);
|
||||
}
|
||||
else {
|
||||
$uri = $entity->toUrl('canonical', $options);
|
||||
}
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the toUrl() method when an entity is still "new".
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityInterface::isNew()
|
||||
*
|
||||
* @covers ::toUrl
|
||||
*
|
||||
* @expectedException \Drupal\Core\Entity\EntityMalformedException
|
||||
*/
|
||||
public function testToUrlForNewEntity() {
|
||||
$entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array(), 'test_entity_type'));
|
||||
$entity->toUrl();
|
||||
return $test_cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the url() method.
|
||||
*
|
||||
* @covers ::url
|
||||
*/
|
||||
public function testUrl() {
|
||||
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
|
||||
$entity_type->expects($this->any())
|
||||
->method('getLinkTemplates')
|
||||
->will($this->returnValue(array(
|
||||
'canonical' => 'test_entity_type.view',
|
||||
)));
|
||||
|
||||
$this->entityManager
|
||||
->expects($this->any())
|
||||
->method('getDefinition')
|
||||
->with('test_entity_type')
|
||||
->will($this->returnValue($entity_type));
|
||||
|
||||
$invalid_entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array(), 'test_entity_type'));
|
||||
$this->assertSame('', $invalid_entity->url());
|
||||
|
||||
$no_link_entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array('id' => 'test_entity_id'), 'test_entity_type'));
|
||||
$this->assertSame('', $no_link_entity->url('banana'));
|
||||
|
||||
$valid_entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array('id' => 'test_entity_id'), 'test_entity_type'));
|
||||
|
||||
$language = new Language(array('id' => LanguageInterface::LANGCODE_NOT_SPECIFIED));
|
||||
$this->urlGenerator->expects($this->any())
|
||||
->method('generateFromRoute')
|
||||
// Sadly returnValueMap() uses ===, see \PHPUnit_Framework_MockObject_Stub_ReturnValueMap::invoke
|
||||
// so the $language object can't be compared directly.
|
||||
->willReturnCallback(function ($route_name, $route_parameters, $options) use ($language) {
|
||||
if ($route_name === 'entity.test_entity_type.canonical' && $route_parameters === array('test_entity_type' => 'test_entity_id') && array_keys($options) === ['entity_type', 'entity', 'language'] && $options['language'] == $language) {
|
||||
return '/entity/test_entity_type/test_entity_id';
|
||||
}
|
||||
if ($route_name === 'entity.test_entity_type.canonical' && $route_parameters === array('test_entity_type' => 'test_entity_id') && array_keys($options) === ['absolute', 'entity_type', 'entity', 'language'] && $options['language'] == $language) {
|
||||
return 'http://drupal/entity/test_entity_type/test_entity_id';
|
||||
}
|
||||
});
|
||||
|
||||
$this->assertSame('/entity/test_entity_type/test_entity_id', $valid_entity->url());
|
||||
$this->assertSame('http://drupal/entity/test_entity_type/test_entity_id', $valid_entity->url('canonical', array('absolute' => TRUE)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the retrieval of link templates.
|
||||
* @param string $rel
|
||||
* The link relation to test.
|
||||
* @param array $options
|
||||
* An array of URL options to call url() with.
|
||||
* @param array $default_options
|
||||
* An array of URL options that toUrl() should generate.
|
||||
* @param array $expected_options
|
||||
* An array of combined URL options that should be set on the final URL.
|
||||
*
|
||||
* @covers ::url
|
||||
* @covers ::hasLinkTemplate
|
||||
* @covers ::linkTemplates
|
||||
*
|
||||
* @dataProvider providerTestLinkTemplates
|
||||
* @dataProvider providerTestUrl
|
||||
*/
|
||||
public function testLinkTemplates($override_templates, $expected) {
|
||||
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
|
||||
$entity_type->expects($this->any())
|
||||
->method('getLinkTemplates')
|
||||
->will($this->returnValue(array(
|
||||
'canonical' => 'test_entity_type.view',
|
||||
)));
|
||||
public function testUrl($rel, $options, $default_options, $expected_options) {
|
||||
$entity = $this->getEntity(Entity::class, ['id' => $this->entityId], ['toUrl']);
|
||||
$this->registerLinkTemplate($rel);
|
||||
|
||||
$this->entityManager
|
||||
->expects($this->any())
|
||||
->method('getDefinition')
|
||||
->with('test_entity_type')
|
||||
->will($this->returnValue($entity_type));
|
||||
$uri = $this->prophesize(Url::class);
|
||||
$uri->getOptions()->willReturn($default_options);
|
||||
$uri->setOptions($expected_options)->shouldBeCalled();
|
||||
|
||||
$entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array('id' => 'test_entity_id'), 'test_entity_type'), '', TRUE, TRUE, TRUE, array('linkTemplates'));
|
||||
$entity->expects($this->any())
|
||||
->method('linkTemplates')
|
||||
->will($this->returnCallback(function () use ($entity_type, $override_templates) {
|
||||
$templates = $entity_type->getLinkTemplates();
|
||||
if ($override_templates) {
|
||||
$templates['bananas'] = 'test_entity_type.bananas';
|
||||
}
|
||||
return $templates;
|
||||
}));
|
||||
$this->assertSame($expected['canonical'], $entity->hasLinkTemplate('canonical'));
|
||||
$this->assertSame($expected['bananas'], $entity->hasLinkTemplate('bananas'));
|
||||
$url_string = "/test-entity/{$this->entityId}/$rel";
|
||||
$uri->toString()->willReturn($url_string);
|
||||
|
||||
$entity->expects($this->once())
|
||||
->method('toUrl')
|
||||
->with($rel)
|
||||
->willReturn($uri->reveal());
|
||||
|
||||
$this->assertEquals($url_string, $entity->url($rel, $options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test data for testLinkTemplates().
|
||||
* Provides data for testUrl().
|
||||
*
|
||||
* @return array
|
||||
* An array of test cases for testUrl().
|
||||
*/
|
||||
public function providerTestLinkTemplates() {
|
||||
return array(
|
||||
array(FALSE, array(
|
||||
'canonical' => TRUE,
|
||||
'bananas' => FALSE,
|
||||
)),
|
||||
array(TRUE, array(
|
||||
'canonical' => TRUE,
|
||||
'bananas' => TRUE,
|
||||
)),
|
||||
);
|
||||
public function providerTestUrl() {
|
||||
$test_cases = [];
|
||||
|
||||
$test_cases['default'] = ['canonical', [], [], []];
|
||||
$test_cases['revision'] = ['revision', [], [], []];
|
||||
$test_cases['option'] = ['canonical', ['absolute' => TRUE], [], ['absolute' => TRUE]];
|
||||
$test_cases['default_option'] = ['canonical', [], ['absolute' => TRUE], ['absolute' => TRUE]];
|
||||
$test_cases['option_merge'] = ['canonical', ['absolute' => TRUE], ['entity_type' => $this->entityTypeId], ['absolute' => TRUE, 'entity_type' => $this->entityTypeId]];
|
||||
$test_cases['option_override'] = ['canonical', ['absolute' => TRUE], ['absolute' => FALSE], ['absolute' => TRUE]];
|
||||
|
||||
return $test_cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mock entity for testing.
|
||||
*
|
||||
* @param string $class
|
||||
* The class name to mock. Should be \Drupal\Core\Entity\Entity or a
|
||||
* subclass.
|
||||
* @param array $values
|
||||
* An array of entity values to construct the mock entity with.
|
||||
* @param array $methods
|
||||
* (optional) An array of additional methods to mock on the entity object.
|
||||
* The getEntityType() and entityManager() methods are always mocked.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\Entity|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected function getEntity($class, array $values, array $methods = []) {
|
||||
$methods = array_merge($methods, ['getEntityType', 'entityManager']);
|
||||
|
||||
// Prophecy does not allow prophesizing abstract classes while actually
|
||||
// calling their code. We use Prophecy below because that allows us to
|
||||
// add method prophecies later while still revealing the prophecy now.
|
||||
$entity = $this->getMockBuilder($class)
|
||||
->setConstructorArgs([$values, $this->entityTypeId])
|
||||
->setMethods($methods)
|
||||
->getMockForAbstractClass();
|
||||
|
||||
$this->entityType = $this->prophesize(EntityTypeInterface::class);
|
||||
$this->entityType->getLinkTemplates()->willReturn([]);
|
||||
$this->entityType->getKey('langcode')->willReturn(FALSE);
|
||||
$entity->method('getEntityType')->willReturn($this->entityType->reveal());
|
||||
|
||||
$this->entityManager = $this->prophesize(EntityManagerInterface::class);
|
||||
$entity->method('entityManager')->willReturn($this->entityManager->reveal());
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a given URL object matches the expectations.
|
||||
*
|
||||
* @param string $expected_route_name
|
||||
* The expected route name of the generated URL.
|
||||
* @param array $expected_route_parameters
|
||||
* The expected route parameters of the generated URL.
|
||||
* @param \Drupal\Core\Entity\Entity|\PHPUnit_Framework_MockObject_MockObject $entity
|
||||
* The entity that is expected to be set as a URL option.
|
||||
* @param bool $has_language
|
||||
* Whether or not the URL is expected to have a language option.
|
||||
* @param \Drupal\Core\Url $url
|
||||
* The URL option to make the assertions on.
|
||||
*/
|
||||
protected function assertUrl($expected_route_name, array $expected_route_parameters, $entity, $has_language, Url $url) {
|
||||
$this->assertEquals($expected_route_name, $url->getRouteName());
|
||||
$this->assertEquals($expected_route_parameters, $url->getRouteParameters());
|
||||
$this->assertEquals($this->entityTypeId, $url->getOption('entity_type'));
|
||||
$this->assertEquals($entity, $url->getOption('entity'));
|
||||
if ($has_language) {
|
||||
$this->assertEquals($this->langcode, $url->getOption('language')->getId());
|
||||
}
|
||||
else {
|
||||
$this->assertNull($url->getOption('language'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a link template for the mock entity.
|
||||
*
|
||||
* @param string $link_template
|
||||
* The link template to register.
|
||||
*/
|
||||
protected function registerLinkTemplate($link_template) {
|
||||
$link_templates = [
|
||||
// The path is actually never used because we never invoke the URL
|
||||
// generator but perform assertions on the URL object directly.
|
||||
$link_template => "/test-entity/{test_entity}/$link_template",
|
||||
];
|
||||
$this->entityType->getLinkTemplates()->willReturn($link_templates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers bundle information for the mock entity type.
|
||||
*
|
||||
* @param array $bundle_info
|
||||
* The bundle information to register.
|
||||
*/
|
||||
protected function registerBundleInfo($bundle_info) {
|
||||
$this->entityManager
|
||||
->getBundleInfo($this->entityTypeId)
|
||||
->willReturn([$this->entityTypeId => $bundle_info])
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class RevisionableEntity extends Entity implements RevisionableInterface {}
|
||||
|
|
|
@ -820,6 +820,16 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
|
|||
'length' => 32,
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'area' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'depth' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'color' => array(
|
||||
|
@ -829,8 +839,14 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
|
|||
),
|
||||
),
|
||||
),
|
||||
'unique keys' => array(),
|
||||
'indexes' => array(),
|
||||
'unique keys' => array(
|
||||
'area' => array('area'),
|
||||
'shape' => array(array('shape', 10)),
|
||||
),
|
||||
'indexes' => array(
|
||||
'depth' => array('depth'),
|
||||
'color' => array(array('color', 3)),
|
||||
),
|
||||
));
|
||||
|
||||
$field_storage = $this->storageDefinitions[$field_name];
|
||||
|
@ -905,11 +921,27 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
|
|||
'length' => 32,
|
||||
'not null' => FALSE,
|
||||
),
|
||||
$field_name . '_area' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
$field_name . '_depth' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
),
|
||||
'primary key' => array('entity_id', 'deleted', 'delta', 'langcode'),
|
||||
'indexes' => array(
|
||||
'bundle' => array('bundle'),
|
||||
'revision_id' => array('revision_id'),
|
||||
$field_name . '_depth' => array($field_name . '_depth'),
|
||||
$field_name . '_color' => array(array($field_name . '_color', 3)),
|
||||
),
|
||||
'unique keys' => array(
|
||||
$field_name . '_area' => array($field_name . '_area'),
|
||||
$field_name . '_shape' => array(array($field_name . '_shape', 10)),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
$field_name . '_color' => array(
|
||||
|
|
|
@ -9,6 +9,7 @@ use Drupal\Tests\UnitTestCase;
|
|||
/**
|
||||
* Tests the image class.
|
||||
*
|
||||
* @requires extension gd
|
||||
* @group Image
|
||||
*/
|
||||
class ImageTest extends UnitTestCase {
|
||||
|
|
|
@ -22,7 +22,7 @@ use Symfony\Component\HttpFoundation\RequestStack;
|
|||
/**
|
||||
* Base class for the actual unit tests testing \Drupal\Core\Render\Renderer.
|
||||
*/
|
||||
class RendererTestBase extends UnitTestCase {
|
||||
abstract class RendererTestBase extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The tested renderer.
|
||||
|
|
|
@ -300,7 +300,7 @@ class UrlGeneratorTest extends UnitTestCase {
|
|||
// No cacheability to test; UrlGenerator::generate() doesn't support
|
||||
// collecting cacheability metadata.
|
||||
|
||||
$this->routeProcessorManager->expects($this->exactly(7))
|
||||
$this->routeProcessorManager->expects($this->any())
|
||||
->method('processOutbound')
|
||||
->with($this->anything());
|
||||
|
||||
|
@ -316,6 +316,10 @@ class UrlGeneratorTest extends UnitTestCase {
|
|||
|
||||
$path = $this->generator->getPathFromRoute('test_2', array('narf' => '5'));
|
||||
$this->assertEquals('test/two/5', $path);
|
||||
|
||||
// Specify a query parameter with NULL.
|
||||
$options = ['query' => ['page' => NULL], 'fragment' => 'bottom'];
|
||||
$this->assertGenerateFromRoute('test_2', ['narf' => 5], $options, '/goodbye/cruel/world?page#bottom', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -82,6 +82,8 @@ class UnroutedUrlTest extends UnitTestCase {
|
|||
// [$uri, $is_external]
|
||||
// An external URI.
|
||||
['https://www.drupal.org', TRUE],
|
||||
// A protocol-relative URL.
|
||||
['//www.drupal.org', TRUE],
|
||||
// An internal, unrouted, base-relative URI.
|
||||
['base:robots.txt', FALSE],
|
||||
// Base-relative URIs with special characters.
|
||||
|
@ -114,7 +116,6 @@ class UnroutedUrlTest extends UnitTestCase {
|
|||
// Schemeless paths.
|
||||
['test'],
|
||||
['/test'],
|
||||
['//test'],
|
||||
// Schemeless path with a query string.
|
||||
['foo?bar'],
|
||||
// Only a query string.
|
||||
|
|
|
@ -335,6 +335,18 @@ class UrlTest extends UnitTestCase {
|
|||
$this->assertEquals('http://example.com/test', $url->getUri());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the getUri() and isExternal() methods for protocol-relative URLs.
|
||||
*
|
||||
* @covers ::getUri
|
||||
* @covers ::isExternal
|
||||
*/
|
||||
public function testGetUriForProtocolRelativeUrl() {
|
||||
$url = Url::fromUri('//example.com/test');
|
||||
$this->assertEquals('//example.com/test', $url->getUri());
|
||||
$this->assertTrue($url->isExternal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the getInternalPath method().
|
||||
*
|
||||
|
|
|
@ -69,7 +69,9 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->urlGenerator = $this->getMock('\Drupal\Core\Routing\UrlGenerator', array(), array(), '', FALSE);
|
||||
$this->urlGenerator = $this->getMockBuilder('\Drupal\Core\Routing\UrlGenerator')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
|
||||
$this->renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
|
||||
$this->linkGenerator = new LinkGenerator($this->urlGenerator, $this->moduleHandler, $this->renderer);
|
||||
|
@ -487,6 +489,33 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests altering the URL object using hook_link_alter().
|
||||
*
|
||||
* @covers ::generate
|
||||
*/
|
||||
public function testGenerateWithAlterHook() {
|
||||
$options = ['query' => [], 'language' => NULL, 'set_active_class' => FALSE, 'absolute' => FALSE];
|
||||
$this->urlGenerator->expects($this->any())
|
||||
->method('generateFromRoute')
|
||||
->will($this->returnValueMap([
|
||||
['test_route_1', [], $options, TRUE, (new GeneratedUrl())->setGeneratedUrl('/test-route-1')],
|
||||
['test_route_2', [], $options, TRUE, (new GeneratedUrl())->setGeneratedUrl('/test-route-2')],
|
||||
]));
|
||||
|
||||
$url = new Url('test_route_2');
|
||||
$url->setUrlGenerator($this->urlGenerator);
|
||||
|
||||
$this->moduleHandler->expects($this->atLeastOnce())
|
||||
->method('alter')
|
||||
->willReturnCallback(function ($hook, &$options) {
|
||||
$options['url'] = (new Url('test_route_1'))->setUrlGenerator($this->urlGenerator);
|
||||
});
|
||||
|
||||
$expected_link_markup = '<a href="/test-route-1">Test</a>';
|
||||
$this->assertEquals($expected_link_markup, (string) $this->linkGenerator->generate('Test', $url)->getGeneratedLink());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a link with certain properties exists in a given HTML snippet.
|
||||
*
|
||||
|
|
134
core/tests/Drupal/Tests/TestSuites/TestSuiteBaseTest.php
Normal file
134
core/tests/Drupal/Tests/TestSuites/TestSuiteBaseTest.php
Normal file
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\TestSuites;
|
||||
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Tests\TestSuites\TestSuiteBase
|
||||
*
|
||||
* @group TestSuite
|
||||
*/
|
||||
class TestSuiteBaseTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* Helper method to set up the file system.
|
||||
*
|
||||
* @return array[]
|
||||
* A Drupal filesystem suitable for use with vfsStream.
|
||||
*/
|
||||
protected function getFilesystem() {
|
||||
return [
|
||||
'core' => [
|
||||
'modules' => [],
|
||||
'profiles' => [],
|
||||
'tests' => [
|
||||
'Drupal' => [
|
||||
'NotUnitTests' => [
|
||||
'CoreNotUnitTest.php' => '<?php',
|
||||
],
|
||||
'Tests' => [
|
||||
'CoreUnitTest.php' => '<?php',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* Test data for testAddTestsBySuiteNamespaceCore(). An array of arrays:
|
||||
* - A filesystem array for vfsStream.
|
||||
* - The sub-namespace of the test suite.
|
||||
* - The array of tests expected to be discovered.
|
||||
*/
|
||||
public function provideCoreTests() {
|
||||
$filesystem = $this->getFilesystem();
|
||||
return [
|
||||
'unit-tests' => [
|
||||
$filesystem,
|
||||
'Unit',
|
||||
[
|
||||
'Drupal\Tests\CoreUnitTest' => 'vfs://root/core/tests/Drupal/Tests/CoreUnitTest.php',
|
||||
],
|
||||
],
|
||||
'not-unit-tests' => [
|
||||
$filesystem,
|
||||
'NotUnit',
|
||||
[
|
||||
'Drupal\NotUnitTests\CoreNotUnitTest' => 'vfs://root/core/tests/Drupal/NotUnitTests/CoreNotUnitTest.php',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for special case behavior of unit test suite namespaces in core.
|
||||
*
|
||||
* @covers ::addTestsBySuiteNamespace
|
||||
*
|
||||
* @dataProvider provideCoreTests
|
||||
*/
|
||||
public function testAddTestsBySuiteNamespaceCore($filesystem, $suite_namespace, $expected_tests) {
|
||||
// Set up the file system.
|
||||
$vfs = vfsStream::setup('root');
|
||||
vfsStream::create($filesystem, $vfs);
|
||||
|
||||
// Make a stub suite base to test.
|
||||
$stub = new StubTestSuiteBase('test_me');
|
||||
|
||||
// Access addTestsBySuiteNamespace().
|
||||
$ref_add_tests = new \ReflectionMethod($stub, 'addTestsBySuiteNamespace');
|
||||
$ref_add_tests->setAccessible(TRUE);
|
||||
|
||||
// Invoke addTestsBySuiteNamespace().
|
||||
$ref_add_tests->invokeArgs($stub, [vfsStream::url('root'), $suite_namespace]);
|
||||
|
||||
// Determine if we loaded the expected test files.
|
||||
$this->assertNotEmpty($stub->testFiles);
|
||||
$this->assertEmpty(array_diff_assoc($expected_tests, $stub->testFiles));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub subclass of TestSuiteBase.
|
||||
*
|
||||
* We use this class to alter the behavior of TestSuiteBase so it can be
|
||||
* testable.
|
||||
*/
|
||||
class StubTestSuiteBase extends TestSuiteBase {
|
||||
|
||||
/**
|
||||
* Test files discovered by addTestsBySuiteNamespace().
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $testFiles = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function findExtensionDirectories($root) {
|
||||
// We have to stub findExtensionDirectories() because we can't inject a
|
||||
// vfsStream filesystem into drupal_phpunit_find_extension_directories(),
|
||||
// which uses \SplFileInfo->getRealPath(). getRealPath() resolves
|
||||
// stream-based paths to an empty string. See
|
||||
// https://github.com/mikey179/vfsStream/wiki/Known-Issues
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addTestFiles($filenames) {
|
||||
// We stub addTestFiles() because the parent implementation can't deal with
|
||||
// vfsStream-based filesystems due to an error in
|
||||
// stream_resolve_include_path(). See
|
||||
// https://github.com/mikey179/vfsStream/issues/5 Here we just store the
|
||||
// test file being added in $this->testFiles.
|
||||
$this->testFiles = array_merge($this->testFiles, $filenames);
|
||||
}
|
||||
|
||||
}
|
|
@ -2,15 +2,58 @@
|
|||
|
||||
namespace Drupal\Tests;
|
||||
|
||||
use Behat\Mink\Exception\ExpectationException;
|
||||
use Behat\Mink\WebAssert as MinkWebAssert;
|
||||
use Behat\Mink\Element\TraversableElement;
|
||||
use Behat\Mink\Exception\ElementNotFoundException;
|
||||
use Behat\Mink\Session;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Defines a class with methods for asserting presence of elements during tests.
|
||||
*/
|
||||
class WebAssert extends MinkWebAssert {
|
||||
|
||||
/**
|
||||
* The absolute URL of the site under test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Behat\Mink\Session $session
|
||||
* The Behat session object;
|
||||
* @param string $base_url
|
||||
* The base URL of the site under test.
|
||||
*/
|
||||
public function __construct(Session $session, $base_url = '') {
|
||||
parent::__construct($session);
|
||||
$this->baseUrl = $base_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function cleanUrl($url) {
|
||||
if ($url instanceof Url) {
|
||||
$url = $url->setAbsolute()->toString();
|
||||
}
|
||||
// Strip the base URL from the beginning for absolute URLs.
|
||||
if ($this->baseUrl !== '' && strpos($url, $this->baseUrl) === 0) {
|
||||
$url = substr($url, strlen($this->baseUrl));
|
||||
}
|
||||
// Make sure there is a forward slash at the beginning of relative URLs for
|
||||
// consistency.
|
||||
if (parse_url($url, PHP_URL_HOST) === NULL && strpos($url, '/') !== 0) {
|
||||
$url = "/$url";
|
||||
}
|
||||
return parent::cleanUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that specific button exists on the current page.
|
||||
*
|
||||
|
@ -36,6 +79,24 @@ class WebAssert extends MinkWebAssert {
|
|||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the specific button does NOT exist on the current page.
|
||||
*
|
||||
* @param string $button
|
||||
* One of id|name|label|value for the button.
|
||||
* @param \Behat\Mink\Element\TraversableElement $container
|
||||
* (optional) The document to check against. Defaults to the current page.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
* When the button exists.
|
||||
*/
|
||||
public function buttonNotExists($button, TraversableElement $container = NULL) {
|
||||
$container = $container ?: $this->session->getPage();
|
||||
$node = $container->findButton($button);
|
||||
|
||||
$this->assert(NULL === $node, sprintf('A button "%s" appears on this page, but it should not.', $button));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that specific select field exists on the current page.
|
||||
*
|
||||
|
@ -64,4 +125,301 @@ class WebAssert extends MinkWebAssert {
|
|||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that specific option in a select field exists on the current page.
|
||||
*
|
||||
* @param string $select
|
||||
* One of id|name|label|value for the select field.
|
||||
* @param string $option
|
||||
* The option value.
|
||||
* @param \Behat\Mink\Element\TraversableElement $container
|
||||
* (optional) The document to check against. Defaults to the current page.
|
||||
*
|
||||
* @return \Behat\Mink\Element\NodeElement
|
||||
* The matching option element
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementNotFoundException
|
||||
* When the element doesn't exist.
|
||||
*/
|
||||
public function optionExists($select, $option, TraversableElement $container = NULL) {
|
||||
$container = $container ?: $this->session->getPage();
|
||||
$select_field = $container->find('named', array(
|
||||
'select',
|
||||
$this->session->getSelectorsHandler()->xpathLiteral($select),
|
||||
));
|
||||
|
||||
if ($select_field === NULL) {
|
||||
throw new ElementNotFoundException($this->session, 'select', 'id|name|label|value', $select);
|
||||
}
|
||||
|
||||
$option_field = $select_field->find('named', array('option', $option));
|
||||
|
||||
if ($option_field === NULL) {
|
||||
throw new ElementNotFoundException($this->session, 'select', 'id|name|label|value', $option);
|
||||
}
|
||||
|
||||
return $option_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that an option in a select field does NOT exist on the current page.
|
||||
*
|
||||
* @param string $select
|
||||
* One of id|name|label|value for the select field.
|
||||
* @param string $option
|
||||
* The option value that shoulkd not exist.
|
||||
* @param \Behat\Mink\Element\TraversableElement $container
|
||||
* (optional) The document to check against. Defaults to the current page.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementNotFoundException
|
||||
* When the select element doesn't exist.
|
||||
*/
|
||||
public function optionNotExists($select, $option, TraversableElement $container = NULL) {
|
||||
$container = $container ?: $this->session->getPage();
|
||||
$select_field = $container->find('named', array(
|
||||
'select',
|
||||
$this->session->getSelectorsHandler()->xpathLiteral($select),
|
||||
));
|
||||
|
||||
if ($select_field === NULL) {
|
||||
throw new ElementNotFoundException($this->session, 'select', 'id|name|label|value', $select);
|
||||
}
|
||||
|
||||
$option_field = $select_field->find('named', array('option', $option));
|
||||
|
||||
$this->assert($option_field === NULL, sprintf('An option "%s" exists in select "%s", but it should not.', $option, $select));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass if the page title is the given string.
|
||||
*
|
||||
* @param string $expected_title
|
||||
* The string the page title should be.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
* Thrown when element doesn't exist, or the title is a different one.
|
||||
*/
|
||||
public function titleEquals($expected_title) {
|
||||
$title_element = $this->session->getPage()->find('css', 'title');
|
||||
if (!$title_element) {
|
||||
throw new ExpectationException('No title element found on the page', $this->session);
|
||||
}
|
||||
$actual_title = $title_element->getText();
|
||||
$this->assert($expected_title === $actual_title, 'Title found');
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if a link with the specified label is found.
|
||||
*
|
||||
* An optional link index may be passed.
|
||||
*
|
||||
* @param string $label
|
||||
* Text between the anchor tags.
|
||||
* @param int $index
|
||||
* Link position counting from zero.
|
||||
* @param string $message
|
||||
* (optional) A message to display with the assertion. Do not translate
|
||||
* messages: use strtr() to embed variables in the message text, not
|
||||
* t(). If left blank, a default message will be displayed.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
* Thrown when element doesn't exist, or the link label is a different one.
|
||||
*/
|
||||
public function linkExists($label, $index = 0, $message = '') {
|
||||
$message = ($message ? $message : strtr('Link with label %label found.', ['%label' => $label]));
|
||||
$links = $this->session->getPage()->findAll('named', ['link', $label]);
|
||||
$this->assert(!empty($links[$index]), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if a link with the specified label is not found.
|
||||
*
|
||||
* An optional link index may be passed.
|
||||
*
|
||||
* @param string $label
|
||||
* Text between the anchor tags.
|
||||
* @param string $message
|
||||
* (optional) A message to display with the assertion. Do not translate
|
||||
* messages: use strtr() to embed variables in the message text, not
|
||||
* t(). If left blank, a default message will be displayed.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
* Thrown when element doesn't exist, or the link label is a different one.
|
||||
*/
|
||||
public function linkNotExists($label, $message = '') {
|
||||
$message = ($message ? $message : strtr('Link with label %label found.', ['%label' => $label]));
|
||||
$links = $this->session->getPage()->findAll('named', ['link', $label]);
|
||||
$this->assert(empty($links), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if a link containing a given href (part) is found.
|
||||
*
|
||||
* @param string $href
|
||||
* The full or partial value of the 'href' attribute of the anchor tag.
|
||||
* @param int $index
|
||||
* Link position counting from zero.
|
||||
* @param string $message
|
||||
* (optional) A message to display with the assertion. Do not translate
|
||||
* messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
|
||||
* variables in the message text, not t(). If left blank, a default message
|
||||
* will be displayed.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
* Thrown when element doesn't exist, or the link label is a different one.
|
||||
*/
|
||||
public function linkByHrefExists($href, $index = 0, $message = '') {
|
||||
$xpath = $this->buildXPathQuery('//a[contains(@href, :href)]', [':href' => $href]);
|
||||
$message = ($message ? $message : strtr('Link containing href %href found.', ['%href' => $href]));
|
||||
$links = $this->session->getPage()->findAll('xpath', $xpath);
|
||||
$this->assert(!empty($links[$index]), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if a link containing a given href (part) is not found.
|
||||
*
|
||||
* @param string $href
|
||||
* The full or partial value of the 'href' attribute of the anchor tag.
|
||||
* @param string $message
|
||||
* (optional) A message to display with the assertion. Do not translate
|
||||
* messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
|
||||
* variables in the message text, not t(). If left blank, a default message
|
||||
* will be displayed.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
* Thrown when element doesn't exist, or the link label is a different one.
|
||||
*/
|
||||
public function linkByHrefNotExists($href, $message = '') {
|
||||
$xpath = $this->buildXPathQuery('//a[contains(@href, :href)]', [':href' => $href]);
|
||||
$message = ($message ? $message : strtr('Link containing href %href found.', ['%href' => $href]));
|
||||
$links = $this->session->getPage()->findAll('xpath', $xpath);
|
||||
$this->assert(empty($links), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an XPath query.
|
||||
*
|
||||
* Builds an XPath query by replacing placeholders in the query by the value
|
||||
* of the arguments.
|
||||
*
|
||||
* XPath 1.0 (the version supported by libxml2, the underlying XML library
|
||||
* used by PHP) doesn't support any form of quotation. This function
|
||||
* simplifies the building of XPath expression.
|
||||
*
|
||||
* @param string $xpath
|
||||
* An XPath query, possibly with placeholders in the form ':name'.
|
||||
* @param array $args
|
||||
* An array of arguments with keys in the form ':name' matching the
|
||||
* placeholders in the query. The values may be either strings or numeric
|
||||
* values.
|
||||
*
|
||||
* @return string
|
||||
* An XPath query with arguments replaced.
|
||||
*/
|
||||
public function buildXPathQuery($xpath, array $args = array()) {
|
||||
// Replace placeholders.
|
||||
foreach ($args as $placeholder => $value) {
|
||||
if (is_object($value)) {
|
||||
throw new \InvalidArgumentException('Just pass in scalar values.');
|
||||
}
|
||||
// XPath 1.0 doesn't support a way to escape single or double quotes in a
|
||||
// string literal. We split double quotes out of the string, and encode
|
||||
// them separately.
|
||||
if (is_string($value)) {
|
||||
// Explode the text at the quote characters.
|
||||
$parts = explode('"', $value);
|
||||
|
||||
// Quote the parts.
|
||||
foreach ($parts as &$part) {
|
||||
$part = '"' . $part . '"';
|
||||
}
|
||||
|
||||
// Return the string.
|
||||
$value = count($parts) > 1 ? 'concat(' . implode(', \'"\', ', $parts) . ')' : $parts[0];
|
||||
}
|
||||
|
||||
// Use preg_replace_callback() instead of preg_replace() to prevent the
|
||||
// regular expression engine from trying to substitute backreferences.
|
||||
$replacement = function ($matches) use ($value) {
|
||||
return $value;
|
||||
};
|
||||
$xpath = preg_replace_callback('/' . preg_quote($placeholder) . '\b/', $replacement, $xpath);
|
||||
}
|
||||
return $xpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if the raw text IS NOT found escaped on the loaded page.
|
||||
*
|
||||
* Raw text refers to the raw HTML that the page generated.
|
||||
*
|
||||
* @param string $raw
|
||||
* Raw (HTML) string to look for.
|
||||
*/
|
||||
public function assertNoEscaped($raw) {
|
||||
$this->responseNotContains(Html::escape($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if the raw text IS found escaped on the loaded page.
|
||||
*
|
||||
* Raw text refers to the raw HTML that the page generated.
|
||||
*
|
||||
* @param string $raw
|
||||
* Raw (HTML) string to look for.
|
||||
*/
|
||||
public function assertEscaped($raw) {
|
||||
$this->responseContains(Html::escape($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a condition.
|
||||
*
|
||||
* The parent method is overridden because it is a private method.
|
||||
*
|
||||
* @param bool $condition
|
||||
* The condition.
|
||||
* @param string $message
|
||||
* The success message.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
* When the condition is not fulfilled.
|
||||
*/
|
||||
public function assert($condition, $message) {
|
||||
if ($condition) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ExpectationException($message, $this->session->getDriver());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a given form field element is disabled.
|
||||
*
|
||||
* @param string $field
|
||||
* One of id|name|label|value for the field.
|
||||
* @param \Behat\Mink\Element\TraversableElement $container
|
||||
* (optional) The document to check against. Defaults to the current page.
|
||||
*
|
||||
* @return \Behat\Mink\Element\NodeElement
|
||||
* The matching element.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ElementNotFoundException
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
*/
|
||||
public function fieldDisabled($field, TraversableElement $container = NULL) {
|
||||
$container = $container ?: $this->session->getPage();
|
||||
$node = $container->findField($field);
|
||||
|
||||
if ($node === NULL) {
|
||||
throw new ElementNotFoundException($this->session->getDriver(), 'field', 'id|name|label|value', $field);
|
||||
}
|
||||
|
||||
if (!$node->hasAttribute('disabled')) {
|
||||
throw new ExpectationException("Field $field is disabled", $this->session->getDriver());
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Reference in a new issue