updated core and modules

This commit is contained in:
Bachir Soussi Chiadmi
2017-09-09 16:27:51 +02:00
parent 027aa99b32
commit 41863f872c
7810 changed files with 318922 additions and 83631 deletions
@@ -5,8 +5,8 @@ package: Testing
# version: VERSION
# core: 8.x
# Information added by Drupal.org packaging script on 2016-09-03
version: '8.x-1.0-alpha1+23-dev'
# Information added by Drupal.org packaging script on 2017-08-14
version: '8.x-1.0'
core: '8.x'
project: 'devel'
datestamp: 1472897643
datestamp: 1502732047
@@ -9,8 +9,8 @@ dependencies:
- text
- entity_test
# Information added by Drupal.org packaging script on 2016-09-03
version: '8.x-1.0-alpha1+23-dev'
# Information added by Drupal.org packaging script on 2017-08-14
version: '8.x-1.0'
core: '8.x'
project: 'devel'
datestamp: 1472897643
datestamp: 1502732047
@@ -5,8 +5,8 @@ package: Testing
# version: VERSION
# core: 8.x
# Information added by Drupal.org packaging script on 2016-09-03
version: '8.x-1.0-alpha1+23-dev'
# Information added by Drupal.org packaging script on 2017-08-14
version: '8.x-1.0'
core: '8.x'
project: 'devel'
datestamp: 1472897643
datestamp: 1502732047
@@ -0,0 +1,20 @@
<?php
/**
* @file
* Helper module for devel test.
*/
/**
* Implements hook_mail().
*/
function devel_test_mail($key, &$message, $params) {
switch ($key) {
case 'devel_mail_log':
$message['subject'] = $params['subject'];
$message['body'][] = $params['body'];
$message['headers']['From'] = $params['headers']['from'];
$message['headers'] += $params['headers']['additional'];
break;
}
}
@@ -0,0 +1,6 @@
services:
devel_test.test_route_subscriber:
class: Drupal\devel_test\Routing\TestRouteSubscriber
tags:
- { name: event_subscriber }
@@ -0,0 +1,20 @@
<?php
namespace Drupal\devel_test\Routing;
use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;
/**
* Router subscriber class for testing purpose.
*/
class TestRouteSubscriber extends RouteSubscriberBase {
/**
* {@inheritdoc}
*/
protected function alterRoutes(RouteCollection $collection) {
\Drupal::state()->set('devel_test_route_rebuild','Router rebuild fired');
}
}
@@ -0,0 +1,261 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Tests container info pages and links.
*
* @group devel
*/
class DevelContainerInfoTest extends BrowserTestBase {
use DevelWebAssertHelper;
/**
* {@inheritdoc}
*/
public static $modules = ['devel', 'devel_test', 'block'];
/**
* The user for tests.
*
* @var \Drupal\user\UserInterface
*/
protected $develUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('local_tasks_block');
$this->drupalPlaceBlock('page_title_block');
$this->develUser = $this->drupalCreateUser(['access devel information']);
$this->drupalLogin($this->develUser);
}
/**
* Tests container info menu link.
*/
public function testContainerInfoMenuLink() {
$this->drupalPlaceBlock('system_menu_block:devel');
// Ensures that the events info link is present on the devel menu and that
// it points to the correct page.
$this->drupalGet('');
$this->clickLink('Container Info');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->addressEquals('/devel/container/service');
$this->assertSession()->pageTextContains('Container services');
}
/**
* Tests service list page.
*/
public function testServiceList() {
$this->drupalGet('/devel/container/service');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Container services');
$this->assertContainerInfoLocalTasks();
$page = $this->getSession()->getPage();
// Ensures that the services table is found.
$table = $page->find('css', 'table.devel-service-list');
$this->assertNotNull($table);
// Ensures that the expected table headers are found.
/** @var $headers \Behat\Mink\Element\NodeElement[] */
$headers = $table->findAll('css', 'thead th');
$this->assertEquals(4, count($headers));
$expected_headers = ['ID', 'Class', 'Alias', 'Operations'];
$actual_headers = array_map(function ($element) {
return $element->getText();
}, $headers);
$this->assertSame($expected_headers, $actual_headers);
// Ensures that all the serivices are listed in the table.
$cached_definition = \Drupal::service('kernel')->getCachedContainerDefinition();
$this->assertNotNull($cached_definition);
$rows = $table->findAll('css', 'tbody tr');
$this->assertEquals(count($cached_definition['services']), count($rows));
// Tests the presence of some (arbitrarily chosen) services in the table.
$expected_services = [
'config.factory' => [
'class' => 'Drupal\Core\Config\ConfigFactory',
'alias' => '',
],
'devel.route_subscriber' => [
'class' => 'Drupal\devel\Routing\RouteSubscriber',
'alias' => '',
],
'plugin.manager.element_info' => [
'class' => 'Drupal\Core\Render\ElementInfoManager',
'alias' => 'element_info',
],
];
foreach ($expected_services as $service_id => $expected) {
$row = $table->find('css', sprintf('tbody tr:contains("%s")', $service_id));
$this->assertNotNull($row);
/** @var $cells \Behat\Mink\Element\NodeElement[] */
$cells = $row->findAll('css', 'td');
$this->assertEquals(4, count($cells));
$cell_service_id = $cells[0];
$this->assertEquals($service_id, $cell_service_id->getText());
$this->assertTrue($cell_service_id->hasClass('table-filter-text-source'));
$cell_class = $cells[1];
$this->assertEquals($expected['class'], $cell_class->getText());
$this->assertTrue($cell_class->hasClass('table-filter-text-source'));
$cell_alias = $cells[2];
$this->assertEquals($expected['alias'], $cell_alias->getText());
$this->assertTrue($cell_class->hasClass('table-filter-text-source'));
$cell_operations = $cells[3];
$actual_href = $cell_operations->findLink('Devel')->getAttribute('href');
$expected_href = Url::fromRoute('devel.container_info.service.detail', ['service_id' => $service_id])->toString();
$this->assertEquals($expected_href, $actual_href);
}
// Ensures that the page is accessible ony to users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet('devel/container/service');
$this->assertSession()->statusCodeEquals(403);
}
/**
* Tests service detail page.
*/
public function testServiceDetail() {
$service_id = 'devel.dumper';
// Ensures that the page works as expected.
$this->drupalGet("/devel/container/service/$service_id");
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains("Service $service_id detail");
// Ensures that the page returns a 404 error if the requested service is
// not defined.
$this->drupalGet('/devel/container/service/not.exists');
$this->assertSession()->statusCodeEquals(404);
// Ensures that the page is accessible ony to users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet("devel/container/service/$service_id");
$this->assertSession()->statusCodeEquals(403);
}
/**
* Tests parameter list page.
*/
public function testParameterList() {
// Ensures that the page works as expected.
$this->drupalGet('/devel/container/parameter');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Container parameters');
$this->assertContainerInfoLocalTasks();
$page = $this->getSession()->getPage();
// Ensures that the parameters table is found.
$table = $page->find('css', 'table.devel-parameter-list');
$this->assertNotNull($table);
// Ensures that the expected table headers are found.
/** @var $headers \Behat\Mink\Element\NodeElement[] */
$headers = $table->findAll('css', 'thead th');
$this->assertEquals(2, count($headers));
$expected_headers = ['Name', 'Operations'];
$actual_headers = array_map(function ($element) {
return $element->getText();
}, $headers);
$this->assertSame($expected_headers, $actual_headers);
// Ensures that all the parameters are listed in the table.
$cached_definition = \Drupal::service('kernel')->getCachedContainerDefinition();
$this->assertNotNull($cached_definition);
$rows = $table->findAll('css', 'tbody tr');
$this->assertEquals(count($cached_definition['parameters']), count($rows));
// Tests the presence of some parameters in the table.
$expected_parameters = [
'container.modules',
'cache_bins',
'factory.keyvalue',
'twig.config',
];
foreach ($expected_parameters as $parameter_name) {
$row = $table->find('css', sprintf('tbody tr:contains("%s")', $parameter_name));
$this->assertNotNull($row);
/** @var $cells \Behat\Mink\Element\NodeElement[] */
$cells = $row->findAll('css', 'td');
$this->assertEquals(2, count($cells));
$cell_parameter_name = $cells[0];
$this->assertEquals($parameter_name, $cell_parameter_name->getText());
$this->assertTrue($cell_parameter_name->hasClass('table-filter-text-source'));
$cell_operations = $cells[1];
$actual_href = $cell_operations->findLink('Devel')->getAttribute('href');
$expected_href = Url::fromRoute('devel.container_info.parameter.detail', ['parameter_name' => $parameter_name])->toString();
$this->assertEquals($expected_href, $actual_href);
}
// Ensures that the page is accessible ony to users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet('devel/container/service');
$this->assertSession()->statusCodeEquals(403);
}
/**
* Tests parameter detail page.
*/
public function testParameterDetail() {
$parameter_name = 'cache_bins';
// Ensures that the page works as expected.
$this->drupalGet("/devel/container/parameter/$parameter_name");
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains("Parameter $parameter_name value");
// Ensures that the page returns a 404 error if the requested parameter is
// not defined.
$this->drupalGet('/devel/container/parameter/not_exists');
$this->assertSession()->statusCodeEquals(404);
// Ensures that the page is accessible ony to users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet("devel/container/service/$parameter_name");
$this->assertSession()->statusCodeEquals(403);
}
/**
* Asserts that container info local tasks are present.
*/
protected function assertContainerInfoLocalTasks() {
$expected_local_tasks = [
['devel.container_info.service', []],
['devel.container_info.parameter', []],
];
$this->assertLocalTasks($expected_local_tasks);
}
}
@@ -0,0 +1,151 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Behat\Mink\Element\NodeElement;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Tests element info pages and links.
*
* @group devel
*/
class DevelElementInfoTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel', 'block'];
/**
* The user for the test.
*
* @var \Drupal\user\UserInterface
*/
protected $develUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('system_menu_block:devel');
$this->drupalPlaceBlock('page_title_block');
$this->develUser = $this->drupalCreateUser(['access devel information']);
$this->drupalLogin($this->develUser);
}
/**
* Tests element info menu link.
*/
public function testElementInfoMenuLink() {
$this->drupalPlaceBlock('system_menu_block:devel');
// Ensures that the element info link is present on the devel menu and that
// it points to the correct page.
$this->drupalGet('');
$this->clickLink('Element Info');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->addressEquals('/devel/elements');
$this->assertSession()->pageTextContains('Element Info');
}
/**
* Tests element list page.
*/
public function testElementList() {
$this->drupalGet('/devel/elements');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Element Info');
$page = $this->getSession()->getPage();
// Ensures that the element list table is found.
$table = $page->find('css', 'table.devel-element-list');
$this->assertNotNull($table);
// Ensures that the expected table headers are found.
$headers = $table->findAll('css', 'thead th');
$this->assertEquals(4, count($headers));
$expected_headers = ['Name', 'Provider', 'Class', 'Operations'];
$actual_headers = array_map(function (NodeElement $element) {
return $element->getText();
}, $headers);
$this->assertSame($expected_headers, $actual_headers);
// Tests the presence of some (arbitrarily chosen) elements in the table.
$expected_elements = [
'button' => [
'class' => 'Drupal\Core\Render\Element\Button',
'provider' => 'core',
],
'form' => [
'class' => 'Drupal\Core\Render\Element\Form',
'provider' => 'core',
],
'html' => [
'class' => 'Drupal\Core\Render\Element\Html',
'provider' => 'core',
],
];
foreach ($expected_elements as $element_name => $element) {
$row = $table->find('css', sprintf('tbody tr:contains("%s")', $element_name));
$this->assertNotNull($row);
/** @var $cells \Behat\Mink\Element\NodeElement[] */
$cells = $row->findAll('css', 'td');
$this->assertEquals(4, count($cells));
$cell = $cells[0];
$this->assertEquals($element_name, $cell->getText());
$this->assertTrue($cell->hasClass('table-filter-text-source'));
$cell = $cells[1];
$this->assertEquals($element['provider'], $cell->getText());
$this->assertTrue($cell->hasClass('table-filter-text-source'));
$cell = $cells[2];
$this->assertEquals($element['class'], $cell->getText());
$this->assertTrue($cell->hasClass('table-filter-text-source'));
$cell = $cells[3];
$actual_href = $cell->findLink('Devel')->getAttribute('href');
$expected_href = Url::fromRoute('devel.elements_page.detail', ['element_name' => $element_name])->toString();
$this->assertEquals($expected_href, $actual_href);
}
// Ensures that the page is accessible only to the users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet('devel/elements');
$this->assertSession()->statusCodeEquals(403);
}
/**
* Tests element detail page.
*/
public function testElementDetail() {
$element_name = 'button';
// Ensures that the page works as expected.
$this->drupalGet("/devel/elements/$element_name");
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains("Element $element_name");
// Ensures that the page returns a 404 error if the requested element is
// not defined.
$this->drupalGet('/devel/elements/not_exists');
$this->assertSession()->statusCodeEquals(404);
// Ensures that the page is accessible ony to users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet("/devel/elements/$element_name");
$this->assertSession()->statusCodeEquals(403);
}
}
@@ -0,0 +1,158 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Behat\Mink\Element\NodeElement;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Tests entity type info pages and links.
*
* @group devel
*/
class DevelEntityTypeInfoTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel', 'block'];
/**
* The user for the test.
*
* @var \Drupal\user\UserInterface
*/
protected $develUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('system_menu_block:devel');
$this->drupalPlaceBlock('page_title_block');
$this->develUser = $this->drupalCreateUser(['access devel information']);
$this->drupalLogin($this->develUser);
}
/**
* Tests entity info menu link.
*/
public function testEntityInfoMenuLink() {
$this->drupalPlaceBlock('system_menu_block:devel');
// Ensures that the entity type info link is present on the devel menu and that
// it points to the correct page.
$this->drupalGet('');
$this->clickLink('Entity Info');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->addressEquals('/devel/entity/info');
$this->assertSession()->pageTextContains('Entity Info');
}
/**
* Tests entity type list page.
*/
public function testEntityTypeList() {
$this->drupalGet('/devel/entity/info');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Entity Info');
$page = $this->getSession()->getPage();
// Ensures that the entity type list table is found.
$table = $page->find('css', 'table.devel-entity-type-list');
$this->assertNotNull($table);
// Ensures that the expected table headers are found.
$headers = $table->findAll('css', 'thead th');
$this->assertEquals(5, count($headers));
$expected_headers = ['ID', 'Name', 'Provider', 'Class', 'Operations'];
$actual_headers = array_map(function (NodeElement $element) {
return $element->getText();
}, $headers);
$this->assertSame($expected_headers, $actual_headers);
// Tests the presence of some (arbitrarily chosen) entity types in the table.
$expected_types = [
'date_format' => [
'name' => 'Date format',
'class' => 'Drupal\Core\Datetime\Entity\DateFormat',
'provider' => 'core',
],
'block' => [
'name' => 'Block',
'class' => 'Drupal\block\Entity\Block',
'provider' => 'block',
],
'entity_view_mode' => [
'name' => 'View mode',
'class' => 'Drupal\Core\Entity\Entity\EntityViewMode',
'provider' => 'core',
],
];
foreach ($expected_types as $entity_type_id => $entity_type) {
$row = $table->find('css', sprintf('tbody tr:contains("%s")', $entity_type_id));
$this->assertNotNull($row);
/** @var $cells \Behat\Mink\Element\NodeElement[] */
$cells = $row->findAll('css', 'td');
$this->assertEquals(5, count($cells));
$cell = $cells[0];
$this->assertEquals($entity_type_id, $cell->getText());
$this->assertTrue($cell->hasClass('table-filter-text-source'));
$cell = $cells[1];
$this->assertEquals($entity_type['name'], $cell->getText());
$this->assertTrue($cell->hasClass('table-filter-text-source'));
$cell = $cells[2];
$this->assertEquals($entity_type['provider'], $cell->getText());
$this->assertTrue($cell->hasClass('table-filter-text-source'));
$cell = $cells[3];
$this->assertEquals($entity_type['class'], $cell->getText());
$this->assertTrue($cell->hasClass('table-filter-text-source'));
$cell = $cells[4];
$actual_href = $cell->findLink('Devel')->getAttribute('href');
$expected_href = Url::fromRoute('devel.entity_info_page.detail', ['entity_type_id' => $entity_type_id])->toString();
$this->assertEquals($expected_href, $actual_href);
}
// Ensures that the page is accessible only to the users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet('devel/entity/info');
$this->assertSession()->statusCodeEquals(403);
}
/**
* Tests entity type detail page.
*/
public function testEntityTypeDetail() {
$entity_type_id = 'date_format';
// Ensures that the page works as expected.
$this->drupalGet("/devel/entity/info/$entity_type_id");
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains("Entity type $entity_type_id");
// Ensures that the page returns a 404 error if the requested entity type is
// not defined.
$this->drupalGet('/devel/entity/info/not_exists');
$this->assertSession()->statusCodeEquals(404);
// Ensures that the page is accessible ony to users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet("/devel/entity/info/$entity_type_id");
$this->assertSession()->statusCodeEquals(403);
}
}
@@ -0,0 +1,161 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Tests\BrowserTestBase;
/**
* Tests devel error handler.
*
* @group devel
*/
class DevelErrorHandlerTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel'];
/**
* Tests devel error handler.
*/
public function testErrorHandler() {
$messages_selector = 'div.messages--warning';
$expected_notice = new FormattableMarkup('%type: @message in %function (line ', [
'%type' => 'Notice',
'@message' => 'Undefined variable: undefined',
'%function' => 'Drupal\devel\Form\SettingsForm->demonstrateErrorHandlers()',
]);
$expected_warning = new FormattableMarkup('%type: @message in %function (line ', [
'%type' => 'Warning',
'@message' => 'Division by zero',
'%function' => 'Drupal\devel\Form\SettingsForm->demonstrateErrorHandlers()',
]);
$config = $this->config('system.logging');
$config->set('error_level', ERROR_REPORTING_DISPLAY_VERBOSE)->save();
$admin_user = $this->drupalCreateUser(['administer site configuration', 'access devel information']);
$this->drupalLogin($admin_user);
// Ensures that the error handler config is present on the config page and
// by default the standard error handler is selected.
$error_handlers = \Drupal::config('devel.settings')->get('error_handlers');
$this->assertEquals($error_handlers, [DEVEL_ERROR_HANDLER_STANDARD => DEVEL_ERROR_HANDLER_STANDARD]);
$this->drupalGet('admin/config/development/devel');
$this->assertOptionSelected('edit-error-handlers', DEVEL_ERROR_HANDLER_STANDARD);
// Ensures that selecting the DEVEL_ERROR_HANDLER_NONE option no error
// (raw or message) is shown on the site in case of php errors.
$edit = [
'error_handlers[]' => DEVEL_ERROR_HANDLER_NONE,
];
$this->drupalPostForm('admin/config/development/devel', $edit, t('Save configuration'));
$this->assertSession()->pageTextContains('The configuration options have been saved.');
$error_handlers = \Drupal::config('devel.settings')->get('error_handlers');
$this->assertEquals($error_handlers, [DEVEL_ERROR_HANDLER_NONE => DEVEL_ERROR_HANDLER_NONE]);
$this->assertOptionSelected('edit-error-handlers', DEVEL_ERROR_HANDLER_NONE);
$this->clickLink('notice+warning');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->responseNotContains($expected_notice);
$this->assertSession()->responseNotContains($expected_warning);
$this->assertSession()->elementNotExists('css', $messages_selector);
// Ensures that selecting the DEVEL_ERROR_HANDLER_BACKTRACE_KINT option a
// backtrace above the rendered page is shown on the site in case of php
// errors.
$edit = [
'error_handlers[]' => DEVEL_ERROR_HANDLER_BACKTRACE_KINT,
];
$this->drupalPostForm('admin/config/development/devel', $edit, t('Save configuration'));
$this->assertSession()->pageTextContains('The configuration options have been saved.');
$error_handlers = \Drupal::config('devel.settings')->get('error_handlers');
$this->assertEquals($error_handlers, [DEVEL_ERROR_HANDLER_BACKTRACE_KINT => DEVEL_ERROR_HANDLER_BACKTRACE_KINT]);
$this->assertOptionSelected('edit-error-handlers', DEVEL_ERROR_HANDLER_BACKTRACE_KINT);
$this->clickLink('notice+warning');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->elementNotExists('css', $messages_selector);
// Ensures that selecting the DEVEL_ERROR_HANDLER_BACKTRACE_DPM option a
// backtrace in the message area is shown on the site in case of php errors.
$edit = [
'error_handlers[]' => DEVEL_ERROR_HANDLER_BACKTRACE_DPM,
];
$this->drupalPostForm('admin/config/development/devel', $edit, t('Save configuration'));
$this->assertSession()->pageTextContains('The configuration options have been saved.');
$error_handlers = \Drupal::config('devel.settings')->get('error_handlers');
$this->assertEquals($error_handlers, [DEVEL_ERROR_HANDLER_BACKTRACE_DPM => DEVEL_ERROR_HANDLER_BACKTRACE_DPM]);
$this->assertOptionSelected('edit-error-handlers', DEVEL_ERROR_HANDLER_BACKTRACE_DPM);
$this->clickLink('notice+warning');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->responseContains($expected_notice);
$this->assertSession()->responseContains($expected_warning);
$this->assertSession()->elementContains('css', $messages_selector, $expected_notice);
$this->assertSession()->elementContains('css', $messages_selector, $expected_warning);
// Ensures that when multiple handlers are selected, the output produced by
// every handler is shown on the site in case of php errors.
$edit = [
'error_handlers[]' => [
DEVEL_ERROR_HANDLER_BACKTRACE_KINT => DEVEL_ERROR_HANDLER_BACKTRACE_KINT,
DEVEL_ERROR_HANDLER_BACKTRACE_DPM => DEVEL_ERROR_HANDLER_BACKTRACE_DPM,
],
];
$this->drupalPostForm('admin/config/development/devel', $edit, t('Save configuration'));
$this->assertSession()->pageTextContains('The configuration options have been saved.');
$error_handlers = \Drupal::config('devel.settings')->get('error_handlers');
$this->assertEquals($error_handlers, [
DEVEL_ERROR_HANDLER_BACKTRACE_KINT => DEVEL_ERROR_HANDLER_BACKTRACE_KINT,
DEVEL_ERROR_HANDLER_BACKTRACE_DPM => DEVEL_ERROR_HANDLER_BACKTRACE_DPM,
]);
$this->assertOptionSelected('edit-error-handlers', DEVEL_ERROR_HANDLER_BACKTRACE_KINT);
$this->assertOptionSelected('edit-error-handlers', DEVEL_ERROR_HANDLER_BACKTRACE_DPM);
$this->clickLink('notice+warning');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->responseContains($expected_notice);
$this->assertSession()->responseContains($expected_warning);
$this->assertSession()->elementContains('css', $messages_selector, $expected_notice);
$this->assertSession()->elementContains('css', $messages_selector, $expected_warning);
// Ensures that setting the error reporting to all the output produced by
// handlers is shown on the site in case of php errors.
$config->set('error_level', ERROR_REPORTING_DISPLAY_ALL)->save();
$this->clickLink('notice+warning');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->responseContains($expected_notice);
$this->assertSession()->responseContains($expected_warning);
$this->assertSession()->elementContains('css', $messages_selector, $expected_notice);
$this->assertSession()->elementContains('css', $messages_selector, $expected_warning);
// Ensures that setting the error reporting to some the output produced by
// handlers is shown on the site in case of php errors.
$config->set('error_level', ERROR_REPORTING_DISPLAY_SOME)->save();
$this->clickLink('notice+warning');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->responseContains($expected_notice);
$this->assertSession()->responseContains($expected_warning);
$this->assertSession()->elementContains('css', $messages_selector, $expected_notice);
$this->assertSession()->elementContains('css', $messages_selector, $expected_warning);
// Ensures that setting the error reporting to none the output produced by
// handlers is not shown on the site in case of php errors.
$config->set('error_level', ERROR_REPORTING_HIDE)->save();
$this->clickLink('notice+warning');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->responseNotContains($expected_notice);
$this->assertSession()->responseNotContains($expected_warning);
$this->assertSession()->elementNotExists('css', $messages_selector);
}
}
@@ -0,0 +1,135 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Tests event info pages and links.
*
* @group devel
*/
class DevelEventInfoTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel', 'block'];
/**
* The user for the test.
*
* @var \Drupal\user\UserInterface
*/
protected $develUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('page_title_block');
$this->develUser = $this->drupalCreateUser(['access devel information']);
$this->drupalLogin($this->develUser);
}
/**
* Tests event info menu link.
*/
public function testEventsInfoMenuLink() {
$this->drupalPlaceBlock('system_menu_block:devel');
// Ensures that the events info link is present on the devel menu and that
// it points to the correct page.
$this->drupalGet('');
$this->clickLink('Events Info');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->addressEquals('/devel/events');
$this->assertSession()->pageTextContains('Events');
}
/**
* Tests event info page.
*/
public function testEventList() {
$event_dispatcher = \Drupal::service('event_dispatcher');
$this->drupalGet('/devel/events');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Events');
$page = $this->getSession()->getPage();
// Ensures that the event table is found.
$table = $page->find('css', 'table.devel-event-list');
$this->assertNotNull($table);
// Ensures that the expected table headers are found.
/** @var $headers \Behat\Mink\Element\NodeElement[] */
$headers = $table->findAll('css', 'thead th');
$this->assertEquals(3, count($headers));
$expected_headers = ['Event Name', 'Callable', 'Priority'];
$actual_headers = array_map(function ($element) {
return $element->getText();
}, $headers);
$this->assertSame($expected_headers, $actual_headers);
// Ensures that all the events are listed in the table.
$events = $event_dispatcher->getListeners();
$event_header_row = $table->findAll('css', 'tbody tr th.devel-event-name-header');
$this->assertEquals(count($events), count($event_header_row));
// Tests the presence of some (arbitrarily chosen) events and related
// listeners in the table. The event items are tested dynamically so no
// test failures are expected if listeners change.
$expected_events = [
'config.delete',
'kernel.request',
'routing.route_alter',
];
foreach ($expected_events as $event_name) {
$listeners = $event_dispatcher->getListeners($event_name);
// Ensures that the event header is present in the table.
$event_header_row = $table->findAll('css', sprintf('tbody tr th:contains("%s")', $event_name));
$this->assertNotNull($event_header_row);
$this->assertEquals(1, count($event_header_row));
// Ensures that all the event listener are listed in the table.
/** @var $event_rows \Behat\Mink\Element\NodeElement[] */
$event_rows = $table->findAll('css', sprintf('tbody tr:contains("%s")', $event_name));
// Remove the header row.
array_shift($event_rows);
$this->assertEquals(count($listeners), count($event_rows));
foreach ($listeners as $index => $listener) {
/** @var $cells \Behat\Mink\Element\NodeElement[] */
$cells = $event_rows[$index]->findAll('css', 'td');
$this->assertEquals(3, count($cells));
$cell_event_name = $cells[0];
$this->assertEquals($event_name, $cell_event_name->getText());
$this->assertTrue($cell_event_name->hasClass('table-filter-text-source'));
$this->assertTrue($cell_event_name->hasClass('visually-hidden'));
$cell_callable = $cells[1];
is_callable($listener, TRUE, $callable_name);
$this->assertEquals($callable_name, $cell_callable->getText());
$cell_methods = $cells[2];
$this->assertEquals($index, $cell_methods->getText());
}
}
// Ensures that the page is accessible only to the users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet('devel/events');
$this->assertSession()->statusCodeEquals(403);
}
}
@@ -0,0 +1,151 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests layout info pages and links.
*
* @group devel
*/
class DevelLayoutInfoTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel', 'block', 'layout_discovery'];
/**
* The user for the test.
*
* @var \Drupal\user\UserInterface
*/
protected $develUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
// TODO find a cleaner way to skip layout info tests when running tests on
// Drupal branch < 8.3.x.
if (version_compare(\Drupal::VERSION, '8.3', '<')) {
$this->markTestSkipped('Devel Layout Info Tests only available on version 8.3.x+.');
}
parent::setUp();
$this->drupalPlaceBlock('page_title_block');
$this->develUser = $this->drupalCreateUser(['access devel information']);
$this->drupalLogin($this->develUser);
}
/**
* Tests layout info menu link.
*/
public function testLayoutsInfoMenuLink() {
$this->drupalPlaceBlock('system_menu_block:devel');
// Ensures that the layout info link is present on the devel menu and that
// it points to the correct page.
$this->drupalGet('');
$this->clickLink('Layouts Info');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->addressEquals('/devel/layouts');
$this->assertSession()->pageTextContains('Layout');
}
/**
* Tests layout info page.
*/
public function testLayoutList() {
$this->drupalGet('/devel/layouts');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Layouts');
$page = $this->getSession()->getPage();
// Ensures that the layout table is found.
$table = $page->find('css', 'table.devel-layout-list');
$this->assertNotNull($table);
// Ensures that the expected table headers are found.
/** @var $headers \Behat\Mink\Element\NodeElement[] */
$headers = $table->findAll('css', 'thead th');
$this->assertEquals(6, count($headers));
$expected_headers = ['Icon', 'Label', 'Description', 'Category', 'Regions', 'Provider'];
$actual_headers = array_map(function ($element) {
return $element->getText();
}, $headers);
$this->assertSame($expected_headers, $actual_headers);
// Ensures that all the layouts are listed in the table.
$layout_manager = \Drupal::service('plugin.manager.core.layout');
$layouts = $layout_manager->getDefinitions();
$table_rows = $table->findAll('css', 'tbody tr');
$this->assertEquals(count($layouts), count($table_rows));
$index = 0;
foreach ($layouts as $layout) {
$cells = $table_rows[$index]->findAll('css', 'td');
$this->assertEquals(6, count($cells));
$cell_layout_icon = $cells[0];
if (empty($layout->getIconPath())) {
// @todo test that the icon path image is set correctly
}
else {
$this->assertNull($cell_layout_icon->getText());
}
$cell_layout_label = $cells[1];
$this->assertEquals($cell_layout_label->getText(), $layout->getLabel());
$cell_layout_description = $cells[2];
$this->assertEquals($cell_layout_description->getText(), $layout->getDescription());
$cell_layout_category = $cells[3];
$this->assertEquals($cell_layout_category->getText(), $layout->getCategory());
$cell_layout_regions = $cells[4];
$this->assertEquals($cell_layout_regions->getText(), implode(', ', $layout->getRegionLabels()));
$cell_layout_provider = $cells[5];
$this->assertEquals($cell_layout_provider->getText(), $layout->getProvider());
$index++;
}
// Ensures that the page is accessible only to the users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet('devel/layouts');
$this->assertSession()->statusCodeEquals(403);
}
/**
* Tests the dependency with layout_discovery module.
*/
public function testLayoutDiscoveryDependency() {
$this->container->get('module_installer')->uninstall(['layout_discovery']);
$this->drupalPlaceBlock('system_menu_block:devel');
// Ensures that the layout info link is not present on the devel menu.
$this->drupalGet('');
$this->assertSession()->linkNotExists('Layouts Info');
// Ensures that the layouts info page is not available.
$this->drupalGet('/devel/layouts');
$this->assertSession()->statusCodeEquals(404);
// Check a few other devel pages to verify devel module stil works.
$this->drupalGet('/devel/events');
$this->assertSession()->statusCodeEquals(200);
$this->drupalGet('devel/routes');
$this->assertSession()->statusCodeEquals(200);
$this->drupalGet('/devel/container/service');
$this->assertSession()->statusCodeEquals(200);
}
}
@@ -0,0 +1,33 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests devel requirements.
*
* @group devel
*/
class DevelRequirementsTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel'];
/**
* Tests that the status page shows a warning when evel is enabled.
*/
public function testStatusPage() {
$admin_user = $this->drupalCreateUser(['administer site configuration']);
$this->drupalLogin($admin_user);
$this->drupalGet('admin/reports/status');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Devel module enabled');
$this->assertSession()->pageTextContains('The Devel module provides access to internal debugging information; therefore it\'s recommended to disable this module on sites in production.');
}
}
@@ -0,0 +1,197 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Tests routes info pages and links.
*
* @group devel
*/
class DevelRouteInfoTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel', 'devel_test', 'block'];
/**
* The user for the test.
*
* @var \Drupal\user\UserInterface
*/
protected $develUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('system_menu_block:devel');
$this->drupalPlaceBlock('page_title_block');
$this->develUser = $this->drupalCreateUser(['access devel information']);
$this->drupalLogin($this->develUser);
}
/**
* Tests routes info.
*/
public function testRouteList() {
// Ensures that the routes info link is present on the devel menu and that
// it points to the correct page.
$this->drupalGet('');
$this->clickLink('Routes Info');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->addressEquals('/devel/routes');
$this->assertSession()->pageTextContains('Routes');
$page = $this->getSession()->getPage();
// Ensures that the expected table headers are found.
/** @var $headers \Behat\Mink\Element\NodeElement[] */
$headers = $page->findAll('css', 'table.devel-route-list thead th');
$this->assertEquals(4, count($headers));
$expected_items = ['Route Name', 'Path', 'Allowed Methods', 'Operations'];
foreach ($headers as $key => $element) {
$this->assertSame($element->getText(), $expected_items[$key]);
}
// Ensures that all the routes are listed in the table.
$routes = \Drupal::service('router.route_provider')->getAllRoutes();
$rows = $page->findAll('css', 'table.devel-route-list tbody tr');
$this->assertEquals(count($routes), count($rows));
// Tests the presence of some (arbitrarily chosen) routes in the table.
$expected_routes = [
'<current>' => [
'path' => '/<current>',
'methods' => ['GET', 'POST'],
'dynamic' => FALSE,
],
'user.login' => [
'path' => '/user/login',
'methods' => ['GET', 'POST'],
'dynamic' => FALSE,
],
'entity.user.canonical' => [
'path' => '/user/{user}',
'methods' => ['GET', 'POST'],
'dynamic' => TRUE,
],
'entity.user.devel_load' => [
'path' => '/devel/user/{user}',
'methods' => ['ANY'],
'dynamic' => TRUE,
],
];
foreach ($expected_routes as $route_name => $expected) {
$row = $page->find('css', sprintf('table.devel-route-list tbody tr:contains("%s")', $route_name));
$this->assertNotNull($row);
/** @var $cells \Behat\Mink\Element\NodeElement[] */
$cells = $row->findAll('css', 'td');
$this->assertEquals(4, count($cells));
$cell_route_name = $cells[0];
$this->assertEquals($route_name, $cell_route_name->getText());
$this->assertTrue($cell_route_name->hasClass('table-filter-text-source'));
$cell_path = $cells[1];
$this->assertEquals($expected['path'], $cell_path->getText());
$this->assertTrue($cell_path->hasClass('table-filter-text-source'));
$cell_methods = $cells[2];
$this->assertEquals(implode('', $expected['methods']), $cell_methods->getText());
$cell_operations = $cells[3];
$actual_href = $cell_operations->findLink('Devel')->getAttribute('href');
if ($expected['dynamic']) {
$parameters = ['query' => ['route_name' => $route_name]];
}
else {
$parameters = ['query' => ['path' => $expected['path']]];
}
$expected_href = Url::fromRoute('devel.route_info.item', [], $parameters)->toString();
$this->assertEquals($expected_href, $actual_href);
}
// Ensures that the page is accessible only to the users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet('devel/routes');
$this->assertSession()->statusCodeEquals(403);
}
/**
* Tests route detail page.
*/
public function testRouteDetail() {
$expected_title = 'Route detail';
$xpath_warning_messages = '//div[contains(@class, "messages--warning")]';
// Ensures that devel route detail link in the menu works properly.
$url = $this->develUser->toUrl();
$path = '/' . $url->getInternalPath();
$this->drupalGet($url);
$this->clickLink('Current route info');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains($expected_title);
$expected_url = Url::fromRoute('devel.route_info.item', [], ['query' => ['path' => $path]]);
$this->assertSession()->addressEquals($expected_url);
$this->assertSession()->elementNotExists('xpath', $xpath_warning_messages);
// Ensures that devel route detail works properly even when dynamic cache
// is enabled.
$url = Url::fromRoute('devel.simple_page');
$path = '/' . $url->getInternalPath();
$this->drupalGet($url);
$this->clickLink('Current route info');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains($expected_title);
$expected_url = Url::fromRoute('devel.route_info.item', [], ['query' => ['path' => $path]]);
$this->assertSession()->addressEquals($expected_url);
$this->assertSession()->elementNotExists('xpath', $xpath_warning_messages);
// Ensures that if a non existent path is passed as input, a warning
// message is shown.
$this->drupalGet('devel/routes/item', ['query' => ['path' => '/undefined']]);
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains($expected_title);
$this->assertSession()->elementExists('xpath', $xpath_warning_messages);
// Ensures that the route detail page works properly when a valid route
// name input is passed.
$this->drupalGet('devel/routes/item', ['query' => ['route_name' => 'devel.simple_page']]);
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains($expected_title);
$this->assertSession()->elementNotExists('xpath', $xpath_warning_messages);
// Ensures that if a non existent route name is passed as input a warning
// message is shown.
$this->drupalGet('devel/routes/item', ['query' => ['route_name' => 'not.exists']]);
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains($expected_title);
$this->assertSession()->elementExists('xpath', $xpath_warning_messages);
// Ensures that if no 'path' nor 'name' query string is passed as input,
// devel route detail page does not return errors.
$this->drupalGet('devel/routes/item');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains($expected_title);
// Ensures that the page is accessible ony to the users with the adequate
// permissions.
$this->drupalLogout();
$this->drupalGet('devel/routes/item');
$this->assertSession()->statusCodeEquals(403);
}
}
@@ -0,0 +1,46 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests routes rebuild.
*
* @group devel
*/
class DevelRouterRebuildTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['devel', 'devel_test'];
/**
* Test routes rebuild.
*/
public function testRouterRebuildConfirmForm() {
// Reset the state flag.
\Drupal::state()->set('devel_test_route_rebuild', NULL);
$this->drupalGet('devel/menu/reset');
$this->assertSession()->statusCodeEquals(403);
$web_user = $this->drupalCreateUser(['administer site configuration']);
$this->drupalLogin($web_user);
$this->drupalGet('devel/menu/reset');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('Are you sure you want to rebuild the router?');
$route_rebuild_state = \Drupal::state()->get('devel_test_route_rebuild');
$this->assertEmpty($route_rebuild_state);
$this->drupalPostForm('devel/menu/reset', [], t('Rebuild'));
$this->assertSession()->pageTextContains('The router has been rebuilt.');
$route_rebuild_state = \Drupal::state()->get('devel_test_route_rebuild');
$this->assertEquals('Router rebuild fired', $route_rebuild_state);
}
}
@@ -0,0 +1,209 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Behat\Mink\Element\NodeElement;
use Drupal\Tests\BrowserTestBase;
/**
* Tests devel state editor.
*
* @group devel
*/
class DevelStateEditorTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel', 'block'];
/**
* The state store.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The user for tests.
*
* @var \Drupal\user\UserInterface
*/
protected $develUser;
/**
* The user for tests.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->state = $this->container->get('state');
$this->drupalPlaceBlock('page_title_block');
$this->develUser = $this->drupalCreateUser(['access devel information']);
$this->adminUser = $this->drupalCreateUser(['access devel information', 'administer site configuration']);
}
/**
* Tests state editor menu link.
*/
public function testStateEditMenuLink() {
$this->drupalPlaceBlock('system_menu_block:devel');
$this->drupalLogin($this->develUser);
// Ensures that the state editor link is present on the devel menu and that
// it points to the correct page.
$this->drupalGet('');
$this->clickLink('State editor');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->addressEquals('/devel/state');
$this->assertSession()->pageTextContains('State editor');
}
/**
* Tests state listing.
*/
public function testStateListing() {
$table_selector = 'table.devel-state-list';
// Ensure that state listing page is accessible only by users with the
// adequate permissions.
$this->drupalGet('devel/state');
$this->assertSession()->statusCodeEquals(403);
$this->drupalLogin($this->develUser);
$this->drupalGet('devel/state');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains('State editor');
// Ensure that the state variables table is visible.
$table = $this->assertSession()->elementExists('css', $table_selector);
// Ensure that all state variables are listed in the table.
$states = \Drupal::keyValue('state')->getAll();
$rows = $table->findAll('css', 'tbody tr');
$this->assertEquals(count($rows), count($states), 'All states are listed in the table.');
// Ensure that the added state variables are listed in the table.
$this->state->set('devel.simple', 'Hello!');
$this->drupalGet('devel/state');
$table = $this->assertSession()->elementExists('css', $table_selector);
$this->assertSession()->elementExists('css', sprintf('tbody td:contains("%s")', 'devel.simple'), $table);
// Ensure that the operations column and the actions buttons are not
// available for user without 'administer site configuration' permission.
$headers = $table->findAll('css', 'thead th');
$this->assertEquals(count($headers), 2, 'Correct number of table header cells found.');
$this->assertElementsTextEquals($headers, ['Name', 'Value']);
$this->assertSession()->elementNotExists('css', 'ul.dropbutton li a', $table);
// Ensure that the operations column and the actions buttons are
// available for user with 'administer site configuration' permission.
$this->drupalLogin($this->adminUser);
$this->drupalGet('devel/state');
$table = $this->assertSession()->elementExists('css', $table_selector);
$headers = $table->findAll('css', 'thead th');
$this->assertEquals(count($headers), 3, 'Correct number of table header cells found.');
$this->assertElementsTextEquals($headers, ['Name', 'Value', 'Operations']);
$this->assertSession()->elementExists('css', 'ul.dropbutton li a', $table);
// Test that the edit button works properly.
$this->clickLink('Edit');
$this->assertSession()->statusCodeEquals(200);
}
/**
* Tests state edit.
*/
public function testStateEdit() {
// Create some state variables for the test.
$this->state->set('devel.simple', 0);
$this->state->set('devel.array', ['devel' => 'value']);
$this->state->set('devel.object', $this->randomObject());
// Ensure that state edit form is accessible only by users with the
// adequate permissions.
$this->drupalLogin($this->develUser);
$this->drupalGet('devel/state/edit/devel.simple');
$this->assertSession()->statusCodeEquals(403);
$this->drupalLogin($this->adminUser);
// Ensure that accessing an un-existent state variable cause a warning
// message.
$this->drupalGet('devel/state/edit/devel.unknown');
$this->assertSession()->pageTextContains(strtr('State @name does not exist in the system.', ['@name' => 'devel.unknown']));
// Ensure that state variables that contain simple type can be edited and
// saved.
$this->drupalGet('devel/state/edit/devel.simple');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains(strtr('Edit state variable: @name', ['@name' => 'devel.simple']));
$input = $this->assertSession()->fieldExists('edit-new-value');
$this->assertFalse($input->hasAttribute('disabled'));
$button = $this->assertSession()->buttonExists('edit-submit');
$this->assertFalse($button->hasAttribute('disabled'));
$edit = ['new_value' => 1];
$this->drupalPostForm('devel/state/edit/devel.simple', $edit, 'Save');
$this->assertSession()->pageTextContains(strtr('Variable @name was successfully edited.', ['@name' => 'devel.simple']));
$this->assertEquals(1, $this->state->get('devel.simple'));
// Ensure that state variables that contain array can be edited and saved
// and the new value is properly validated.
$this->drupalGet('devel/state/edit/devel.array');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains(strtr('Edit state variable: @name', ['@name' => 'devel.array']));
$input = $this->assertSession()->fieldExists('edit-new-value');
$this->assertFalse($input->hasAttribute('disabled'));
$button = $this->assertSession()->buttonExists('edit-submit');
$this->assertFalse($button->hasAttribute('disabled'));
// Try to save an invalid yaml input.
$edit = ['new_value' => 'devel: \'value updated'];
$this->drupalPostForm('devel/state/edit/devel.array', $edit, 'Save');
$this->assertSession()->pageTextContains('Invalid input:');
$edit = ['new_value' => 'devel: \'value updated\''];
$this->drupalPostForm('devel/state/edit/devel.array', $edit, 'Save');
$this->assertSession()->pageTextContains(strtr('Variable @name was successfully edited.', ['@name' => 'devel.array']));
$this->assertEquals(['devel' => 'value updated'], $this->state->get('devel.array'));
// Ensure that state variables that contain objects cannot be edited.
$this->drupalGet('devel/state/edit/devel.object');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains(strtr('Edit state variable: @name', ['@name' => 'devel.object']));
$this->assertSession()->pageTextContains(strtr('Only simple structures are allowed to be edited. State @name contains objects.', ['@name' => 'devel.object']));
$this->assertSession()->fieldDisabled('edit-new-value');
$button = $this->assertSession()->buttonExists('edit-submit');
$this->assertTrue($button->hasAttribute('disabled'));
// Ensure that the cancel link works as expected.
$this->clickLink('Cancel');
$this->assertSession()->addressEquals('devel/state');
}
/**
* Checks that the passed in elements have the expected text.
*
* @param \Behat\Mink\Element\NodeElement[] $elements
* The elements for which check the text.
* @param array $expected_elements_text
* The expected text for the passed in elements.
*/
protected function assertElementsTextEquals(array $elements, array $expected_elements_text) {
$actual_text = array_map(function (NodeElement $element) {
return $element->getText();
}, $elements);
$this->assertSame($expected_elements_text, $actual_text);
}
}
@@ -0,0 +1,268 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Tests\BrowserTestBase;
/**
* Tests devel toolbar module functionality.
*
* @group devel
*/
class DevelToolbarTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel', 'toolbar', 'block'];
/**
* The user for tests.
*
* @var \Drupal\user\UserInterface
*/
protected $toolbarUser;
/**
* The user for tests.
*
* @var \Drupal\user\UserInterface
*/
protected $develUser;
/**
* The dafault toolbar items.
*
* @var array
*/
protected $defaultToolbarItems = [
'devel.cache_clear',
'devel.container_info.service',
'devel.admin_settings_link',
'devel.execute_php',
'devel.menu_rebuild',
'devel.reinstall',
'devel.route_info',
'devel.run_cron',
];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->drupalPlaceBlock('local_tasks_block');
$this->drupalPlaceBlock('page_title_block');
$this->develUser = $this->drupalCreateUser([
'administer site configuration',
'access devel information',
'execute php code',
'access toolbar',
]);
$this->toolbarUser = $this->drupalCreateUser([
'access toolbar',
]);
}
/**
* Tests configuration form.
*/
public function testConfigurationForm() {
// Ensures that the page is accessible ony to users with the adequate
// permissions.
$this->drupalGet('admin/config/development/devel/toolbar');
$this->assertSession()->statusCodeEquals(403);
// Ensures that the config page is accessible for users with the adequate
// permissions and exists the Devel toolbar local task.
$this->drupalLogin($this->develUser);
$this->drupalGet('admin/config/development/devel/toolbar');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->elementExists('css', '.tabs .primary a:contains("Toolbar Settings")');
$this->assertSession()->pageTextContains('Devel Toolbar Settings');
// Ensures and that all devel menu links are listed in the configuration
// page.
foreach ($this->getMenuLinkInfos() as $link) {
$this->assertSession()->fieldExists(sprintf('toolbar_items[%s]', $link['id']));
}
// Ensures and that the default configuration items are selected by
// default.
foreach ($this->defaultToolbarItems as $item) {
$this->assertSession()->checkboxChecked(sprintf('toolbar_items[%s]', $item));
}
// Ensures that the configuration save works as expected.
$edit = [
'toolbar_items[devel.event_info]' => 'devel.event_info',
'toolbar_items[devel.theme_registry]' => 'devel.theme_registry',
];
$this->drupalPostForm('admin/config/development/devel/toolbar', $edit, t('Save configuration'));
$this->assertSession()->pageTextContains('The configuration options have been saved.');
$expected_items = array_merge($this->defaultToolbarItems, ['devel.event_info', 'devel.theme_registry']);
sort($expected_items);
$config_items = \Drupal::config('devel.toolbar.settings')->get('toolbar_items');
sort($config_items);
$this->assertEquals($expected_items, $config_items);
}
/**
* Tests cache metadata headers.
*/
public function testCacheHeaders() {
// Disable user toolbar tab so we can test properly if the devel toolbar
// implementation interferes with the page cacheability.
\Drupal::service('module_installer')->install(['toolbar_disable_user_toolbar']);
// The menu is not loaded for users without the adequate permission,
// so no cache tags for configuration are added.
$this->drupalLogin($this->toolbarUser);
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'config:devel.toolbar.settings');
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'config:system.menu.devel');
// Make sure that the configuration cache tags are present for users with
// the adequate permission.
$this->drupalLogin($this->develUser);
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', 'config:devel.toolbar.settings');
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Tags', 'config:system.menu.devel');
// The Devel toolbar implementation should not interfere with the page
// cacheability, so you expect a MISS value in the X-Drupal-Dynamic-Cache
// header the first time.
$this->assertSession()->responseHeaderContains('X-Drupal-Dynamic-Cache', 'MISS');
// Triggers a page reload and verify that the page is served from the
// cache.
$this->drupalGet('');
$this->assertSession()->responseHeaderContains('X-Drupal-Dynamic-Cache', 'HIT');
}
/**
* Tests toolbar integration.
*/
public function testToolbarIntegration() {
$library_css_url = 'devel/css/devel.toolbar.css';
$toolbar_selector = '#toolbar-bar .toolbar-tab';
$toolbar_tab_selector = '#toolbar-bar .toolbar-tab a.toolbar-icon-devel';
$toolbar_tray_selector = '#toolbar-bar .toolbar-tab #toolbar-item-devel-tray';
// Ensures that devel toolbar item is accessible only for user with the
// adequate permissions.
$this->drupalGet('');
$this->assertSession()->responseNotContains($library_css_url);
$this->assertSession()->elementNotExists('css', $toolbar_selector);
$this->assertSession()->elementNotExists('css', $toolbar_tab_selector);
$this->drupalLogin($this->toolbarUser);
$this->assertSession()->responseNotContains($library_css_url);
$this->assertSession()->elementExists('css', $toolbar_selector);
$this->assertSession()->elementNotExists('css', $toolbar_tab_selector);
$this->drupalLogin($this->develUser);
$this->assertSession()->responseContains($library_css_url);
$this->assertSession()->elementExists('css', $toolbar_selector);
$this->assertSession()->elementExists('css', $toolbar_tab_selector);
$this->assertSession()->elementTextContains('css', $toolbar_tab_selector, 'Devel');
// Ensures that the configure link in the toolbar is present and point to
// the correct page.
$this->clickLink('Configure');
$this->assertSession()->addressEquals('admin/config/development/devel/toolbar');
// Ensures that the toolbar tray contains the all the menu links. To the
// links not marked as always visible will be assigned a css class that
// allow to hide they when the toolbar has horizontal orientation.
$this->drupalGet('');
$toolbar_tray = $this->assertSession()->elementExists('css', $toolbar_tray_selector);
$devel_menu_items = $this->getMenuLinkInfos();
$toolbar_items = $toolbar_tray->findAll('css', 'ul.toolbar-menu a');
$this->assertCount(count($devel_menu_items), $toolbar_items);
foreach ($devel_menu_items as $link) {
$item_selector = sprintf('ul.toolbar-menu a:contains("%s")', $link['title']);
$item = $this->assertSession()->elementExists('css', $item_selector, $toolbar_tray);
// TODO: find a more correct way to test link url.
$this->assertContains(strtok($link['url'], '?'), $item->getAttribute('href'));
$not_visible = !in_array($link['id'], $this->defaultToolbarItems);
$this->assertTrue($not_visible === $item->hasClass('toolbar-horizontal-item-hidden'));
}
// Ensures that changing the toolbar settings configuration the changes are
// immediately visible.
$saved_items = $this->config('devel.toolbar.settings')->get('toolbar_items');
$saved_items[] = 'devel.event_info';
$this->config('devel.toolbar.settings')
->set('toolbar_items', $saved_items)
->save();
$this->drupalGet('');
$toolbar_tray = $this->assertSession()->elementExists('css', $toolbar_tray_selector);
$item = $this->assertSession()->elementExists('css', sprintf('ul.toolbar-menu a:contains("%s")', 'Events Info'), $toolbar_tray);
$this->assertFalse($item->hasClass('toolbar-horizontal-item-hidden'));
// Ensures that disabling a menu link it will not more shown in the toolbar
// and that the changes are immediately visible.
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$menu_link_manager->updateDefinition('devel.event_info', ['enabled' => FALSE]);
$this->drupalGet('');
$toolbar_tray = $this->assertSession()->elementExists('css', $toolbar_tray_selector);
$this->assertSession()->elementNotExists('css', sprintf('ul.toolbar-menu a:contains("%s")', 'Events Info'), $toolbar_tray);
}
/**
* Tests devel when toolbar module is not installed.
*/
public function testToolbarModuleNotInstalled() {
// Ensures that when toolbar module is not installed all works properly.
\Drupal::service('module_installer')->uninstall(['toolbar']);
$this->drupalLogin($this->develUser);
// Toolbar settings page should respond with 404.
$this->drupalGet('admin/config/development/devel/toolbar');
$this->assertSession()->statusCodeEquals(404);
// Primary local task should not contains toolbar tab.
$this->drupalGet('admin/config/development/devel');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->elementNotExists('css', '.tabs .primary a:contains("Toolbar Settings")');
// Toolbar setting config and devel menu cache tags sholud not present.
$this->drupalGet('');
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'config:devel.toolbar.settings');
$this->assertSession()->responseHeaderNotContains('X-Drupal-Cache-Tags', 'config:system.menu.devel');
}
/**
* Helper function for retrieve the menu link informations.
*
* @return array
* An array containing the menu link informations.
*/
protected function getMenuLinkInfos() {
$parameters = new MenuTreeParameters();
$parameters->onlyEnabledLinks()->setTopLevelOnly();
$tree = \Drupal::menuTree()->load('devel', $parameters);
$links = [];
foreach ($tree as $element) {
$links[] = [
'id' => $element->link->getPluginId(),
'title' => $element->link->getTitle(),
'url' => $element->link->getUrlObject()->toString(),
];
}
return $links;
}
}
@@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\devel\Functional;
use Drupal\Core\Url;
/**
* Provides convenience methods for assertions in browser tests.
*/
trait DevelWebAssertHelper {
/**
* Asserts local tasks in the page output.
*
* @param array $routes
* A list of expected local tasks, prepared as an array of route names and
* their associated route parameters, to assert on the page (in the given
* order).
* @param int $level
* (optional) The local tasks level to assert; 0 for primary, 1 for
* secondary. Defaults to 0.
*/
protected function assertLocalTasks(array $routes, $level = 0) {
$type_class = $level == 0 ? 'tabs primary' : 'tabs secondary';
$elements = $this->xpath('//*[contains(@class, :class)]//a', [':class' => $type_class]);
$this->assertTrue(count($elements), 'Local tasks found.');
foreach ($routes as $index => $route_info) {
list($route_name, $route_parameters) = $route_info;
$expected = Url::fromRoute($route_name, $route_parameters)->toString();
$this->assertEquals($expected, $elements[$index]->getAttribute('href'));
}
}
}
@@ -0,0 +1,202 @@
<?php
namespace Drupal\Tests\devel\Kernel;
use Drupal\Core\Mail\Plugin\Mail\TestMailCollector;
use Drupal\devel\Plugin\Mail\DevelMailLog;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests sending mails with debug interface.
*
* @group devel
*/
class DevelMailLogTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['devel', 'devel_test', 'system'];
/**
* The mail manager.
*
* @var \Drupal\Core\Mail\MailManagerInterface
*/
protected $mailManager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', 'mail');
$this->installConfig(['system', 'devel']);
// Configure system.site mail settings.
$this->config('system.site')->set('mail', 'devel-test@example.com')->save();
$this->mailManager = $this->container->get('plugin.manager.mail');
}
/**
* Tests devel_mail_log plugin as default mail backend.
*/
public function testDevelMailLogDefaultBackend() {
// Configure devel_mail_log as default mail backends.
$this->setDevelMailLogAsDefaultBackend();
// Ensures that devel_mail_log is the default mail plugin .
$mail_backend = $this->mailManager->getInstance(['module' => 'default', 'key' => 'default']);
$this->assertInstanceOf(DevelMailLog::class, $mail_backend);
$mail_backend = $this->mailManager->getInstance(['module' => 'somemodule', 'key' => 'default']);
$this->assertInstanceOf(DevelMailLog::class, $mail_backend);
}
/**
* Tests devel_mail_log plugin with multiple mail backend.
*/
public function testDevelMailLogMultipleBackend() {
// Configure test_mail_collector as default mail backend.
$this->config('system.mail')
->set('interface.default', 'test_mail_collector')
->save();
// Configure devel_mail_log as a module-specific mail backend.
$this->config('system.mail')
->set('interface.somemodule', 'devel_mail_log')
->save();
// Ensures that devel_mail_log is not the default mail plugin.
$mail_backend = $this->mailManager->getInstance(['module' => 'default', 'key' => 'default']);
$this->assertInstanceOf(TestMailCollector::class, $mail_backend);
// Ensures that devel_mail_log is used as mail backend only for the
// specified module.
$mail_backend = $this->mailManager->getInstance(['module' => 'somemodule', 'key' => 'default']);
$this->assertInstanceOf(DevelMailLog::class, $mail_backend);
}
/**
* Tests devel_mail_log default settings.
*/
public function testDevelMailDefaultSettings() {
$config = \Drupal::config('devel.settings');
$this->assertEquals('temporary://devel-mails', $config->get('debug_mail_directory'));
$this->assertEquals('%to-%subject-%datetime.mail.txt', $config->get('debug_mail_file_format'));
}
/**
* Tests devel mail log output.
*/
public function testDevelMailLogOutput() {
$config = \Drupal::config('devel.settings');
// Parameters used for send the email.
$mail = [
'module' => 'devel_test',
'key' => 'devel_mail_log',
'to' => 'drupal@example.com',
'reply' => 'replyto@example.com',
'lang' => \Drupal::languageManager()->getCurrentLanguage(),
];
// Parameters used for compose the email in devel_test module.
// @see devel_test_mail()
$params = [
'subject' => 'Devel mail log subject',
'body' => 'Devel mail log body',
'headers' => [
'from' => 'postmaster@example.com',
'additional' => [
'X-stupid' => 'dumb',
],
],
];
// Configure devel_mail_log as default mail backends.
$this->setDevelMailLogAsDefaultBackend();
// Changes the default filename pattern removing the dynamic date
// placeholder for a more predictable filename output.
$random = $this->randomMachineName();
$filename_pattern = '%to-%subject-' . $random . '.mail.txt';
$this->config('devel.settings')
->set('debug_mail_file_format', $filename_pattern)
->save();
$expected_filename = 'drupal@example.com-Devel_mail_log_subject-' . $random . '.mail.txt';
$expected_output = <<<EOF
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed; delsp=yes
Content-Transfer-Encoding: 8Bit
X-Mailer: Drupal
Return-Path: devel-test@example.com
Sender: devel-test@example.com
From: postmaster@example.com
Reply-to: replyto@example.com
X-stupid: dumb
To: drupal@example.com
Subject: Devel mail log subject
Devel mail log body
EOF;
// Ensures that the mail is captured by devel_mail_log and the placeholders
// in the filename are properly resolved.
$default_output_directory = $config->get('debug_mail_directory');
$expected_file_path = $default_output_directory . '/' . $expected_filename;
$this->mailManager->mail($mail['module'], $mail['key'], $mail['to'], $mail['lang'], $params, $mail['reply']);
$this->assertFileExists($expected_file_path);
$this->assertStringEqualsFile($expected_file_path, $expected_output);
// Ensures that even changing the default output directory devel_mail_log
// works as expected.
$changed_output_directory = 'temporary://my-folder';
$expected_file_path = $changed_output_directory . '/' . $expected_filename;
$this->config('devel.settings')
->set('debug_mail_directory', $changed_output_directory)
->save();
$result = $this->mailManager->mail($mail['module'], $mail['key'], $mail['to'], $mail['lang'], $params, $mail['reply']);
$this->assertSame(TRUE, $result['result']);
$this->assertFileExists($expected_file_path);
$this->assertStringEqualsFile($expected_file_path, $expected_output);
// Ensures that if the default output directory is a public directory it
// will be protected by adding an .htaccess.
$public_output_directory = 'public://my-folder';
$expected_file_path = $public_output_directory . '/' . $expected_filename;
$this->config('devel.settings')
->set('debug_mail_directory', $public_output_directory)
->save();
$this->mailManager->mail($mail['module'], $mail['key'], $mail['to'], $mail['lang'], $params, $mail['reply']);
$this->assertFileExists($expected_file_path);
$this->assertStringEqualsFile($expected_file_path, $expected_output);
$this->assertFileExists($public_output_directory . '/.htaccess');
}
/**
* Configure devel_mail_log as default mail backend.
*/
private function setDevelMailLogAsDefaultBackend() {
// TODO can this be avoided?
// KernelTestBase enforce the usage of 'test_mail_collector' plugin for
// collect the mails. Since we need to test devel mail plugin we manually
// configure the mail implementation to use 'devel_mail_log'.
$GLOBALS['config']['system.mail']['interface']['default'] = 'devel_mail_log';
// Configure devel_mail_log as default mail backend.
$this->config('system.mail')
->set('interface.default', 'devel_mail_log')
->save();
}
}
@@ -0,0 +1,127 @@
<?php
namespace Drupal\Tests\devel\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
/**
* Tests query debug.
*
* @group devel
*/
class DevelQueryDebugTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['devel', 'system', 'user'];
/**
* The user used in test.
*
* @var \Drupal\user\UserInterface
*/
protected $develUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', 'sequences');
$this->installConfig(['system', 'devel']);
$this->installEntitySchema('user');
$devel_role = Role::create([
'id' => 'admin',
'permissions' => ['access devel information'],
]);
$devel_role->save();
$this->develUser = User::create([
'name' => $this->randomMachineName(),
'roles' => [$devel_role->id()],
]);
$this->develUser->save();
}
/**
* Tests devel_query_debug_alter() for select queries.
*/
public function testSelectQueryDebugTag() {
// Clear the messages stack.
$this->getDrupalMessages();
// Ensures that no debug message is shown to user without the adequate
// permissions.
$query = \Drupal::database()->select('users', 'u');
$query->fields('u', ['uid']);
$query->addTag('debug');
$query->execute();
$messages = $this->getDrupalMessages();
$this->assertEmpty($messages);
// Ensures that the SQL debug message is shown to user with the adequate
// permissions. We expect only one status message containing the SQL for
// the debugged query.
\Drupal::currentUser()->setAccount($this->develUser);
$expected_message = "SELECT u.uid AS uid\nFROM \n{users} u";
$query = \Drupal::database()->select('users', 'u');
$query->fields('u', ['uid']);
$query->addTag('debug');
$query->execute();
$messages = $this->getDrupalMessages();
$this->assertTrue(!empty($messages['status']));
$this->assertCount(1, $messages['status']);
$this->assertEquals(strip_tags($messages['status'][0]), $expected_message);
}
/**
* Tests devel_query_debug_alter() for entity queries.
*/
public function testEntityQueryDebugTag() {
// Clear the messages stack.
$this->getDrupalMessages();
// Ensures that no debug message is shown to user without the adequate
// permissions.
$query = \Drupal::entityQuery('user');
$query->addTag('debug');
$query->execute();
$messages = $this->getDrupalMessages();
$this->assertEmpty($messages);
// Ensures that the SQL debug message is shown to user with the adequate
// permissions. We expect only one status message containing the SQL for
// the debugged entity query.
\Drupal::currentUser()->setAccount($this->develUser);
$expected_message = "SELECT base_table.uid AS uid, base_table.uid AS base_table_uid\nFROM \n{users} base_table";
$query = \Drupal::entityQuery('user');
$query->addTag('debug');
$query->execute();
$messages = $this->getDrupalMessages();
$this->assertTrue(!empty($messages['status']));
$this->assertCount(1, $messages['status']);
$this->assertEquals(strip_tags($messages['status'][0]), $expected_message);
}
/**
* Retrieves the drupal messages.
*
* @return array
* The messages
*/
protected function getDrupalMessages() {
return drupal_get_messages();
}
}