updated core to 8.6.3

This commit is contained in:
2018-11-21 12:49:46 +01:00
parent 8ca34853a3
commit c92c348eee
521 changed files with 12199 additions and 4578 deletions
@@ -7,6 +7,7 @@ use Drupal\Core\Config\PreExistingConfigException;
use Drupal\Core\Config\UnmetDependenciesException;
use Drupal\Core\Access\AccessManagerInterface;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\InfoParserException;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Extension\ModuleInstallerInterface;
use Drupal\Core\Form\FormBase;
@@ -143,8 +144,14 @@ class ModulesListForm extends FormBase {
];
// Sort all modules by their names.
$modules = system_rebuild_module_data();
uasort($modules, 'system_sort_modules_by_info_name');
try {
$modules = system_rebuild_module_data();
uasort($modules, 'system_sort_modules_by_info_name');
}
catch (InfoParserException $e) {
$this->messenger()->addError($this->t('Modules could not be listed due to an error: %error', ['%error' => $e->getMessage()]));
$modules = [];
}
// Iterate over each of the modules.
$form['modules']['#tree'] = TRUE;
@@ -144,7 +144,7 @@ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
// Add the url.path.parent cache context. This code ignores the last path
// part so the result only depends on the path parents.
$breadcrumb->addCacheContexts(['url.path.parent']);
$breadcrumb->addCacheContexts(['url.path.parent', 'url.path.is_front']);
// Do not display a breadcrumb on the frontpage.
if ($this->pathMatcher->isFrontPage()) {
@@ -1,159 +0,0 @@
<?php
namespace Drupal\system\Tests\Ajax;
use Drupal\Core\Ajax\AddCssCommand;
use Drupal\Core\Ajax\AfterCommand;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\AlertCommand;
use Drupal\Core\Ajax\AppendCommand;
use Drupal\Core\Ajax\BeforeCommand;
use Drupal\Core\Ajax\ChangedCommand;
use Drupal\Core\Ajax\CssCommand;
use Drupal\Core\Ajax\DataCommand;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\InsertCommand;
use Drupal\Core\Ajax\PrependCommand;
use Drupal\Core\Ajax\RemoveCommand;
use Drupal\Core\Ajax\RestripeCommand;
use Drupal\Core\Ajax\SettingsCommand;
use Drupal\Core\EventSubscriber\AjaxResponseSubscriber;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Performs tests on AJAX framework commands.
*
* @group Ajax
*/
class CommandsTest extends AjaxTestBase {
/**
* Tests the various Ajax Commands.
*/
public function testAjaxCommands() {
$form_path = 'ajax_forms_test_ajax_commands_form';
$web_user = $this->drupalCreateUser(['access content']);
$this->drupalLogin($web_user);
$edit = [];
// Tests the 'add_css' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'add_css' command")]);
$expected = new AddCssCommand('my/file.css');
$this->assertCommand($commands, $expected->render(), "'add_css' AJAX command issued with correct data.");
// Tests the 'after' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'After': Click to put something after the div")]);
$expected = new AfterCommand('#after_div', 'This will be placed after');
$this->assertCommand($commands, $expected->render(), "'after' AJAX command issued with correct data.");
// Tests the 'alert' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'Alert': Click to alert")]);
$expected = new AlertCommand(t('Alert'));
$this->assertCommand($commands, $expected->render(), "'alert' AJAX Command issued with correct text.");
// Tests the 'append' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'Append': Click to append something")]);
$expected = new AppendCommand('#append_div', 'Appended text');
$this->assertCommand($commands, $expected->render(), "'append' AJAX command issued with correct data.");
// Tests the 'before' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'before': Click to put something before the div")]);
$expected = new BeforeCommand('#before_div', 'Before text');
$this->assertCommand($commands, $expected->render(), "'before' AJAX command issued with correct data.");
// Tests the 'changed' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX changed: Click to mark div changed.")]);
$expected = new ChangedCommand('#changed_div');
$this->assertCommand($commands, $expected->render(), "'changed' AJAX command issued with correct selector.");
// Tests the 'changed' command using the second argument.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX changed: Click to mark div changed with asterisk.")]);
$expected = new ChangedCommand('#changed_div', '#changed_div_mark_this');
$this->assertCommand($commands, $expected->render(), "'changed' AJAX command (with asterisk) issued with correct selector.");
// Tests the 'css' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("Set the '#box' div to be blue.")]);
$expected = new CssCommand('#css_div', ['background-color' => 'blue']);
$this->assertCommand($commands, $expected->render(), "'css' AJAX command issued with correct selector.");
// Tests the 'data' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX data command: Issue command.")]);
$expected = new DataCommand('#data_div', 'testkey', 'testvalue');
$this->assertCommand($commands, $expected->render(), "'data' AJAX command issued with correct key and value.");
// Tests the 'html' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX html: Replace the HTML in a selector.")]);
$expected = new HtmlCommand('#html_div', 'replacement text');
$this->assertCommand($commands, $expected->render(), "'html' AJAX command issued with correct data.");
// Tests the 'insert' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX insert: Let client insert based on #ajax['method'].")]);
$expected = new InsertCommand('#insert_div', 'insert replacement text');
$this->assertCommand($commands, $expected->render(), "'insert' AJAX command issued with correct data.");
// Tests the 'invoke' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX invoke command: Invoke addClass() method.")]);
$expected = new InvokeCommand('#invoke_div', 'addClass', ['error']);
$this->assertCommand($commands, $expected->render(), "'invoke' AJAX command issued with correct method and argument.");
// Tests the 'prepend' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'prepend': Click to prepend something")]);
$expected = new PrependCommand('#prepend_div', 'prepended text');
$this->assertCommand($commands, $expected->render(), "'prepend' AJAX command issued with correct data.");
// Tests the 'remove' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'remove': Click to remove text")]);
$expected = new RemoveCommand('#remove_text');
$this->assertCommand($commands, $expected->render(), "'remove' AJAX command issued with correct command and selector.");
// Tests the 'restripe' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'restripe' command")]);
$expected = new RestripeCommand('#restripe_table');
$this->assertCommand($commands, $expected->render(), "'restripe' AJAX command issued with correct selector.");
// Tests the 'settings' command.
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'settings' command")]);
$expected = new SettingsCommand(['ajax_forms_test' => ['foo' => 42]]);
$this->assertCommand($commands, $expected->render(), "'settings' AJAX command issued with correct data.");
}
/**
* Regression test: Settings command exists regardless of JS aggregation.
*/
public function testAttachedSettings() {
$assert = function ($message) {
$response = new AjaxResponse();
$response->setAttachments([
'library' => ['core/drupalSettings'],
'drupalSettings' => ['foo' => 'bar'],
]);
$ajax_response_attachments_processor = \Drupal::service('ajax_response.attachments_processor');
$subscriber = new AjaxResponseSubscriber($ajax_response_attachments_processor);
$event = new FilterResponseEvent(
\Drupal::service('http_kernel'),
new Request(),
HttpKernelInterface::MASTER_REQUEST,
$response
);
$subscriber->onResponse($event);
$expected = [
'command' => 'settings',
];
$this->assertCommand($response->getCommands(), $expected, $message);
};
$config = $this->config('system.performance');
$config->set('js.preprocess', FALSE)->save();
$assert('Settings command exists when JS aggregation is disabled.');
$config->set('js.preprocess', TRUE)->save();
$assert('Settings command exists when JS aggregation is enabled.');
}
}
@@ -1,216 +0,0 @@
<?php
namespace Drupal\system\Tests\Ajax;
use Drupal\ajax_test\Controller\AjaxTestController;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Url;
/**
* Performs tests on opening and manipulating dialogs via AJAX commands.
*
* @group Ajax
*/
class DialogTest extends AjaxTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['ajax_test', 'ajax_forms_test', 'contact'];
/**
* Test sending non-JS and AJAX requests to open and manipulate modals.
*/
public function testDialog() {
$this->drupalLogin($this->drupalCreateUser(['administer contact forms']));
// Ensure the elements render without notices or exceptions.
$this->drupalGet('ajax-test/dialog');
// Set up variables for this test.
$dialog_renderable = AjaxTestController::dialogContents();
$dialog_contents = \Drupal::service('renderer')->renderRoot($dialog_renderable);
$modal_expected_response = [
'command' => 'openDialog',
'selector' => '#drupal-modal',
'settings' => NULL,
'data' => $dialog_contents,
'dialogOptions' => [
'modal' => TRUE,
'title' => 'AJAX Dialog & contents',
],
];
$form_expected_response = [
'command' => 'openDialog',
'selector' => '#drupal-modal',
'settings' => NULL,
'dialogOptions' => [
'modal' => TRUE,
'title' => 'Ajax Form contents',
],
];
$entity_form_expected_response = [
'command' => 'openDialog',
'selector' => '#drupal-modal',
'settings' => NULL,
'dialogOptions' => [
'modal' => TRUE,
'title' => 'Add contact form',
],
];
$normal_expected_response = [
'command' => 'openDialog',
'selector' => '#ajax-test-dialog-wrapper-1',
'settings' => NULL,
'data' => $dialog_contents,
'dialogOptions' => [
'modal' => FALSE,
'title' => 'AJAX Dialog & contents',
],
];
$no_target_expected_response = [
'command' => 'openDialog',
'selector' => '#drupal-dialog-ajax-testdialog-contents',
'settings' => NULL,
'data' => $dialog_contents,
'dialogOptions' => [
'modal' => FALSE,
'title' => 'AJAX Dialog & contents',
],
];
$close_expected_response = [
'command' => 'closeDialog',
'selector' => '#ajax-test-dialog-wrapper-1',
'persist' => FALSE,
];
// Check that requesting a modal dialog without JS goes to a page.
$this->drupalGet('ajax-test/dialog-contents');
$this->assertRaw($dialog_contents, 'Non-JS modal dialog page present.');
// Check that requesting a modal dialog with XMLHttpRequest goes to a page.
$this->drupalGetXHR('ajax-test/dialog-contents');
$this->assertRaw($dialog_contents, 'Modal dialog page on XMLHttpRequest present.');
// Emulate going to the JS version of the page and check the JSON response.
$ajax_result = $this->drupalGetAjax('ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_modal']]);
$this->assertEqual($modal_expected_response, $ajax_result[3], 'Modal dialog JSON response matches.');
// Test the HTML escaping of & character.
$this->assertEqual($ajax_result[3]['dialogOptions']['title'], 'AJAX Dialog & contents');
$this->assertNotEqual($ajax_result[3]['dialogOptions']['title'], 'AJAX Dialog &amp; contents');
// Check that requesting a "normal" dialog without JS goes to a page.
$this->drupalGet('ajax-test/dialog-contents');
$this->assertRaw($dialog_contents, 'Non-JS normal dialog page present.');
// Emulate going to the JS version of the page and check the JSON response.
// This needs to use WebTestBase::drupalPostAjaxForm() so that the correct
// dialog options are sent.
$ajax_result = $this->drupalPostAjaxForm('ajax-test/dialog', [
// We have to mock a form element to make drupalPost submit from a link.
'textfield' => 'test',
], [], 'ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_dialog']], [], NULL, [
'submit' => [
'dialogOptions[target]' => 'ajax-test-dialog-wrapper-1',
],
]);
$this->assertEqual($normal_expected_response, $ajax_result[3], 'Normal dialog JSON response matches.');
// Emulate going to the JS version of the page and check the JSON response.
// This needs to use WebTestBase::drupalPostAjaxForm() so that the correct
// dialog options are sent.
$ajax_result = $this->drupalPostAjaxForm('ajax-test/dialog', [
// We have to mock a form element to make drupalPost submit from a link.
'textfield' => 'test',
], [], 'ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_dialog']], [], NULL, [
// Don't send a target.
'submit' => [],
]);
// Make sure the selector ID starts with the right string.
$this->assert(strpos($ajax_result[3]['selector'], $no_target_expected_response['selector']) === 0, 'Selector starts with right string.');
unset($ajax_result[3]['selector']);
unset($no_target_expected_response['selector']);
$this->assertEqual($no_target_expected_response, $ajax_result[3], 'Normal dialog with no target JSON response matches.');
// Emulate closing the dialog via an AJAX request. There is no non-JS
// version of this test.
$ajax_result = $this->drupalGetAjax('ajax-test/dialog-close');
$this->assertEqual($close_expected_response, $ajax_result[0], 'Close dialog JSON response matches.');
// Test submitting via a POST request through the button for modals. This
// approach more accurately reflects the real responses by Drupal because
// all of the necessary page variables are emulated.
$ajax_result = $this->drupalPostAjaxForm('ajax-test/dialog', [], 'button1');
// Check that CSS and JavaScript are "added" to the page dynamically.
$this->assertTrue(in_array('core/drupal.dialog.ajax', explode(',', $ajax_result[0]['settings']['ajaxPageState']['libraries'])), 'core/drupal.dialog.ajax library is added to the page.');
$dialog_css_exists = strpos($ajax_result[1]['data'], 'dialog.css') !== FALSE;
$this->assertTrue($dialog_css_exists, 'jQuery UI dialog CSS added to the page.');
$dialog_js_exists = strpos($ajax_result[2]['data'], 'dialog-min.js') !== FALSE;
$this->assertTrue($dialog_js_exists, 'jQuery UI dialog JS added to the page.');
$dialog_js_exists = strpos($ajax_result[2]['data'], 'dialog.ajax.js') !== FALSE;
$this->assertTrue($dialog_js_exists, 'Drupal dialog JS added to the page.');
// Check that the response matches the expected value.
$this->assertEqual($modal_expected_response, $ajax_result[4], 'POST request modal dialog JSON response matches.');
// Test the HTML escaping of & character.
$this->assertNotEqual($ajax_result[4]['dialogOptions']['title'], 'AJAX Dialog &amp; contents');
// Abbreviated test for "normal" dialogs, testing only the difference.
$ajax_result = $this->drupalPostAjaxForm('ajax-test/dialog', [], 'button2');
$this->assertEqual($normal_expected_response, $ajax_result[4], 'POST request normal dialog JSON response matches.');
// Check that requesting a form dialog without JS goes to a page.
$this->drupalGet('ajax-test/dialog-form');
// Check we get a chunk of the code, we can't test the whole form as form
// build id and token with be different.
$form = $this->xpath("//form[@id='ajax-test-form']");
$this->assertTrue(!empty($form), 'Non-JS form page present.');
// Emulate going to the JS version of the form and check the JSON response.
$ajax_result = $this->drupalGetAjax('ajax-test/dialog-form', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_modal']]);
$expected_ajax_settings = [
'edit-preview' => [
'callback' => '::preview',
'event' => 'click',
'url' => Url::fromRoute('ajax_test.dialog_form', [], [
'query' => [
MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_modal',
FormBuilderInterface::AJAX_FORM_REQUEST => TRUE,
],
])->toString(),
'dialogType' => 'ajax',
'submit' => [
'_triggering_element_name' => 'op',
'_triggering_element_value' => 'Preview',
],
],
];
$this->assertEqual($expected_ajax_settings, $ajax_result[0]['settings']['ajax']);
$this->setRawContent($ajax_result[3]['data']);
// Remove the data, the form build id and token will never match.
unset($ajax_result[3]['data']);
$form = $this->xpath("//form[@id='ajax-test-form']");
$this->assertTrue(!empty($form), 'Modal dialog JSON contains form.');
$this->assertEqual($form_expected_response, $ajax_result[3]);
// Check that requesting an entity form dialog without JS goes to a page.
$this->drupalGet('admin/structure/contact/add');
// Check we get a chunk of the code, we can't test the whole form as form
// build id and token with be different.
$form = $this->xpath("//form[@id='contact-form-add-form']");
$this->assertTrue(!empty($form), 'Non-JS entity form page present.');
// Emulate going to the JS version of the form and check the JSON response.
$ajax_result = $this->drupalGetAjax('admin/structure/contact/add', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_modal']]);
$this->setRawContent($ajax_result[3]['data']);
// Remove the data, the form build id and token will never match.
unset($ajax_result[3]['data']);
$form = $this->xpath("//form[@id='contact-form-add-form']");
$this->assertTrue(!empty($form), 'Modal dialog JSON contains entity form.');
$this->assertEqual($entity_form_expected_response, $ajax_result[3]);
}
}
@@ -1,98 +0,0 @@
<?php
namespace Drupal\system\Tests\Ajax;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests that AJAX-enabled forms work when multiple instances of the same form
* are on a page.
*
* @group Ajax
*/
class MultiFormTest extends AjaxTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['form_test'];
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Page']);
// Create a multi-valued field for 'page' nodes to use for Ajax testing.
$field_name = 'field_ajax_test';
FieldStorageConfig::create([
'entity_type' => 'node',
'field_name' => $field_name,
'type' => 'text',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
])->save();
FieldConfig::create([
'field_name' => $field_name,
'entity_type' => 'node',
'bundle' => 'page',
])->save();
entity_get_form_display('node', 'page', 'default')
->setComponent($field_name, ['type' => 'text_textfield'])
->save();
// Log in a user who can create 'page' nodes.
$this->drupalLogin($this->drupalCreateUser(['create page content']));
}
/**
* Tests that pages with the 'node_page_form' included twice work correctly.
*/
public function testMultiForm() {
// HTML IDs for elements within the field are potentially modified with
// each Ajax submission, but these variables are stable and help target the
// desired elements.
$field_name = 'field_ajax_test';
$form_xpath = '//form[starts-with(@id, "node-page-form")]';
$field_xpath = '//div[contains(@class, "field--name-field-ajax-test")]';
$button_name = $field_name . '_add_more';
$button_value = t('Add another item');
$button_xpath_suffix = '//input[@name="' . $button_name . '"]';
$field_items_xpath_suffix = '//input[@type="text"]';
// Ensure the initial page contains both node forms and the correct number
// of field items and "add more" button for the multi-valued field within
// each form.
$this->drupalGet('form-test/two-instances-of-same-form');
$fields = $this->xpath($form_xpath . $field_xpath);
$this->assertEqual(count($fields), 2);
foreach ($fields as $field) {
$this->assertEqual(count($field->xpath('.' . $field_items_xpath_suffix)), 1, 'Found the correct number of field items on the initial page.');
$this->assertFieldsByValue($field->xpath('.' . $button_xpath_suffix), NULL, 'Found the "add more" button on the initial page.');
}
$this->assertNoDuplicateIds(t('Initial page contains unique IDs'), 'Other');
// Submit the "add more" button of each form twice. After each corresponding
// page update, ensure the same as above.
for ($i = 0; $i < 2; $i++) {
$forms = $this->xpath($form_xpath);
foreach ($forms as $offset => $form) {
$form_html_id = (string) $form['id'];
$this->drupalPostAjaxForm(NULL, [], [$button_name => $button_value], NULL, [], [], $form_html_id);
$form = $this->xpath($form_xpath)[$offset];
$field = $form->xpath('.' . $field_xpath);
$this->assertEqual(count($field[0]->xpath('.' . $field_items_xpath_suffix)), $i + 2, 'Found the correct number of field items after an AJAX submission.');
$this->assertFieldsByValue($field[0]->xpath('.' . $button_xpath_suffix), NULL, 'Found the "add more" button after an AJAX submission.');
$this->assertNoDuplicateIds(t('Updated page contains unique IDs'), 'Other');
}
}
}
}
@@ -190,7 +190,7 @@ class SessionHttpsTest extends WebTestBase {
}
// The mock front controllers (http.php and https.php) add the script name
// to $_SERVER['REQEUST_URI'] and friends. Therefore it is necessary to
// to $_SERVER['REQUEST_URI'] and friends. Therefore it is necessary to
// strip that also.
$base_url .= 'index.php/';
@@ -169,3 +169,12 @@ function system_post_update_extra_fields(&$sandbox = NULL) {
$config_entity_updater->update($sandbox, 'entity_form_display', $callback);
$config_entity_updater->update($sandbox, 'entity_view_display', $callback);
}
/**
* Force cache clear to ensure aggregated JavaScript files are regenerated.
*
* @see https://www.drupal.org/project/drupal/issues/2995570
*/
function system_post_update_states_clear_cache() {
// Empty post-update hook.
}
@@ -60,4 +60,8 @@ foreach ($hierarchy as $tid => $parents) {
}
}
// Insert an extra record with no corresponding term.
// See https://www.drupal.org/project/drupal/issues/2997982
$query->values(['tid' => max($tids) + 1, 'parent' => 0]);
$query->execute();
@@ -6,7 +6,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Example implementation of accept header based content negotation.
* Example implementation of "accept header"-based content negotiation.
*/
class AcceptHeaderMiddleware implements HttpKernelInterface {
@@ -14,7 +14,7 @@ class AcceptHeaderRoutingTestServiceProvider implements ServiceModifierInterface
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
// Remove the basic content negotation middleware and replace it with a
// Remove the basic content negotiation middleware and replace it with a
// basic header based one.
$container->register('http_middleware.negotiation', 'Drupal\accept_header_routing_test\AcceptHeaderMiddleware')
->addTag('http_middleware', ['priority' => 400]);
@@ -7,7 +7,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Test controller for content negotation tests.
* Test controller for content negotiation tests.
*/
class TestController {
@@ -36,7 +36,7 @@ class EntityTestAccessControlHandler extends EntityAccessControlHandler {
/** @var \Drupal\entity_test\Entity\EntityTest $entity */
// Always forbid access to entities with the label 'forbid_access', used for
// \Drupal\system\Tests\Entity\EntityAccessHControlandlerTest::testDefaultEntityAccess().
// \Drupal\system\Tests\Entity\EntityAccessControlHandlerTest::testDefaultEntityAccess().
if ($entity->label() == 'forbid_access') {
return AccessResult::forbidden();
}
@@ -513,3 +513,10 @@ form_test.optional_container:
_title: 'Optional container testing'
requirements:
_access: 'TRUE'
form_test.javascript_states_form:
path: '/form-test/javascript-states-form'
defaults:
_form: '\Drupal\form_test\Form\JavascriptStatesForm'
requirements:
_access: 'TRUE'
@@ -0,0 +1,55 @@
<?php
namespace Drupal\form_test\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Builds a simple form to test states.
*
* @see \Drupal\FunctionalJavascriptTests\Core\Form\JavascriptStatesTest
*/
class JavascriptStatesForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'javascript_states_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['select'] = [
'#type' => 'select',
'#title' => 'select 1',
'#options' => [0 => 0, 1 => 1, 2 => 2],
];
$form['number'] = [
'#type' => 'number',
'#title' => 'enter 1',
];
$form['textfield'] = [
'#type' => 'textfield',
'#title' => 'textfield',
'#states' => [
'visible' => [
[':input[name="select"]' => ['value' => '1']],
'or',
[':input[name="number"]' => ['value' => '1']],
],
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
}
}
@@ -0,0 +1,6 @@
name: 'HTML mail test support'
description: 'Test if HTML in mails works as expected.'
type: module
package: Testing
version: VERSION
core: 8.x
@@ -0,0 +1,17 @@
<?php
/**
* @file
* Helper module for the html mail and url conversion tests.
*/
/**
* Implements hook_mail().
*/
function mail_html_test_mail($key, &$message, $params) {
switch ($key) {
case 'render_from_message_param':
$message['body'][] = \Drupal::service('renderer')->renderPlain($params['message']);
break;
}
}
@@ -0,0 +1,33 @@
<?php
namespace Drupal\mail_html_test\Plugin\Mail;
use Drupal\Core\Mail\MailFormatHelper;
use Drupal\Core\Mail\Plugin\Mail\TestMailCollector;
/**
* Defines a mail backend that captures sent HTML messages in the state system.
*
* This class is for running tests or for development and does not convert HTML
* to plaintext.
*
* @Mail(
* id = "test_html_mail_collector",
* label = @Translation("HTML mail collector"),
* description = @Translation("Does not send the message, but stores its HTML in Drupal within the state system. Used for testing.")
* )
*/
class TestHtmlMailCollector extends TestMailCollector {
/**
* {@inheritdoc}
*/
public function format(array $message) {
// Join the body array into one string.
$message['body'] = implode(PHP_EOL, $message['body']);
// Wrap the mail body for sending.
$message['body'] = MailFormatHelper::wrapMail($message['body']);
return $message;
}
}
@@ -50,6 +50,18 @@ menu_test.local_action6:
appears_on:
- menu_test.local_action1
menu_test.local_action7:
route_name: menu_test.local_action7
title: 'Local action with access'
appears_on:
- menu_test.local_action7
menu_test.local_action8:
route_name: menu_test.local_action8
title: 'Local action without access'
appears_on:
- menu_test.local_action7
menu_test.hidden_menu_add:
route_name: menu_test.hidden_menu_add
title: 'Add menu'
@@ -125,6 +125,20 @@ menu_test.local_action6:
requirements:
_access: 'TRUE'
menu_test.local_action7:
path: '/menu-test-local-action-7/cache-check'
defaults:
_controller: '\Drupal\menu_test\TestControllers::test2'
requirements:
_custom_access: '\Drupal\menu_test\Access\AccessCheck::menuLocalAction7'
menu_test.local_action8:
path: '/menu-test-local-action-8/cache-check'
defaults:
_controller: '\Drupal\menu_test\TestControllers::test2'
requirements:
_custom_access: '\Drupal\menu_test\Access\AccessCheck::menuLocalAction8'
menu_test.contextual_test:
path: '/menu-test-contextual/default'
defaults:
@@ -26,4 +26,18 @@ class AccessCheck implements AccessInterface {
return $result->setCacheMaxAge(0);
}
/**
* @return \Drupal\Core\Access\AccessResultForbidden
*/
public function menuLocalAction7() {
return AccessResult::forbidden()->addCacheTags(['menu_local_action7'])->addCacheContexts(['url.query_args:menu_local_action7']);
}
/**
* @return \Drupal\Core\Access\AccessResultAllowed
*/
public function menuLocalAction8() {
return AccessResult::allowed()->addCacheTags(['menu_local_action8'])->addCacheContexts(['url.query_args:menu_local_action8']);
}
}
@@ -5,10 +5,12 @@
* Test module.
*/
use Drupal\user\UserInterface;
/**
* Implements hook_user_login().
*/
function session_test_user_login($account) {
function session_test_user_login(UserInterface $account) {
if ($account->getUsername() == 'session_test_user') {
// Exit so we can verify that the session was regenerated
// before hook_user_login() was called.
@@ -287,7 +287,7 @@ class SystemTestController extends ControllerBase {
}
/**
* A plain Symfony reponse with Cache-Control: public, max-age=60.
* A plain Symfony response with Cache-Control: public, max-age=60.
*/
public function respondWithPublicResponse() {
return (new Response('test'))->setPublic()->setMaxAge(60);
@@ -17,7 +17,7 @@ class ThemeTestSubscriber implements EventSubscriberInterface {
/**
* The used container.
*
* @todo This variable is never initialzed, so we don't know what it is.
* @todo This variable is never initialized, so we don't know what it is.
* See https://www.drupal.org/node/2721315
*/
protected $container;
@@ -314,7 +314,7 @@ class UrlTest extends BrowserTestBase {
$url = $test_url . '?drupal=awesome';
$query = ['awesome' => 'drupal'];
$result = Url::fromUri($url, ['query' => $query])->toString();
$this->assertEqual('https://www.drupal.org/?awesome=drupal&drupal=awesome', $result);
$this->assertEqual('https://www.drupal.org/?drupal=awesome&awesome=drupal', $result);
}
}
@@ -1,9 +1,9 @@
<?php
namespace Drupal\system\Tests\Condition;
namespace Drupal\Tests\system\Functional\Condition;
use Drupal\node\Entity\Node;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that condition plugins basic form handling is working.
@@ -14,7 +14,7 @@ use Drupal\simpletest\WebTestBase;
*
* @group Condition
*/
class ConditionFormTest extends WebTestBase {
class ConditionFormTest extends BrowserTestBase {
public static $modules = ['node', 'condition_test'];
@@ -7,10 +7,12 @@ use Drupal\Component\Utility\Html;
use Drupal\Core\Language\LanguageInterface;
use Drupal\comment\CommentInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\media\Entity\Media;
use Drupal\node\Entity\Node;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\node\NodeInterface;
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
use Drupal\Tests\user\Traits\UserCreationTrait;
use Drupal\user\Entity\User;
@@ -25,6 +27,7 @@ class EntityReferenceSelectionAccessTest extends KernelTestBase {
use CommentTestTrait;
use ContentTypeCreationTrait;
use MediaTypeCreationTrait;
use UserCreationTrait;
/**
@@ -32,7 +35,7 @@ class EntityReferenceSelectionAccessTest extends KernelTestBase {
*
* @var array
*/
public static $modules = ['comment', 'field', 'node', 'system', 'taxonomy', 'text', 'user'];
public static $modules = ['comment', 'field', 'file', 'image', 'node', 'media', 'system', 'taxonomy', 'text', 'user'];
/**
* {@inheritdoc}
@@ -42,13 +45,16 @@ class EntityReferenceSelectionAccessTest extends KernelTestBase {
$this->installSchema('system', 'sequences');
$this->installSchema('comment', ['comment_entity_statistics']);
$this->installSchema('file', ['file_usage']);
$this->installEntitySchema('comment');
$this->installEntitySchema('file');
$this->installEntitySchema('media');
$this->installEntitySchema('node');
$this->installEntitySchema('taxonomy_term');
$this->installEntitySchema('user');
$this->installConfig(['comment', 'field', 'node', 'taxonomy', 'user']);
$this->installConfig(['comment', 'field', 'media', 'node', 'taxonomy', 'user']);
// Create the anonymous and the admin users.
$anonymous_user = User::create([
@@ -681,4 +687,92 @@ class EntityReferenceSelectionAccessTest extends KernelTestBase {
$this->assertReferenceable($selection_options, $referenceable_tests, 'Term handler (admin)');
}
/**
* Tests the selection handler for the media entity type.
*/
public function testMediaHandler() {
$selection_options = [
'target_type' => 'media',
'handler' => 'default',
'target_bundles' => NULL,
];
// Build a set of test data.
$media_type = $this->createMediaType('file');
$media_values = [
'published' => [
'bundle' => $media_type->id(),
'status' => 1,
'name' => 'Media published',
'uid' => 1,
],
'unpublished' => [
'bundle' => $media_type->id(),
'status' => 0,
'name' => 'Media unpublished',
'uid' => 1,
],
];
$media_entities = [];
$media_labels = [];
foreach ($media_values as $key => $values) {
$media = Media::create($values);
$media->save();
$media_entities[$key] = $media;
$media_labels[$key] = Html::escape($media->label());
}
// Test as a non-admin.
$normal_user = $this->createUser(['view media']);
$this->setCurrentUser($normal_user);
$referenceable_tests = [
[
'arguments' => [
[NULL, 'CONTAINS'],
],
'result' => [
$media_type->id() => [
$media_entities['published']->id() => $media_labels['published'],
],
],
],
[
'arguments' => [
['Media unpublished', 'CONTAINS'],
],
'result' => [],
],
];
$this->assertReferenceable($selection_options, $referenceable_tests, 'Media handler');
// Test as an admin.
$admin_user = $this->createUser(['view media', 'administer media']);
$this->setCurrentUser($admin_user);
$referenceable_tests = [
[
'arguments' => [
[NULL, 'CONTAINS'],
],
'result' => [
$media_type->id() => [
$media_entities['published']->id() => $media_labels['published'],
$media_entities['unpublished']->id() => $media_labels['unpublished'],
],
],
],
[
'arguments' => [
['Media unpublished', 'CONTAINS'],
],
'result' => [
$media_type->id() => [
$media_entities['unpublished']->id() => $media_labels['unpublished'],
],
],
],
];
$this->assertReferenceable($selection_options, $referenceable_tests, 'Media handler (admin)');
}
}
@@ -6,7 +6,7 @@ use Drupal\Component\PhpStorage\FileStorage;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the log message added by file_save_htacess().
* Tests the log message added by file_save_htaccess().
*
* @group File
*/
@@ -51,4 +51,29 @@ class ModulesListFormWebTest extends BrowserTestBase {
$this->assertText('simpletest');
}
public function testModulesListFormWithInvalidInfoFile() {
$broken_info_yml = <<<BROKEN
name: Module With Broken Info file
type: module
BROKEN;
$path = \Drupal::service('site.path') . "/modules/broken";
mkdir($path, 0777, TRUE);
file_put_contents("$path/broken.info.yml", $broken_info_yml);
$this->drupalLogin(
$this->drupalCreateUser(
['administer modules', 'administer permissions']
)
);
$this->drupalGet('admin/modules');
$this->assertSession()->statusCodeEquals(200);
// Confirm that the error message is shown.
$this->assertSession()
->pageTextContains('Modules could not be listed due to an error: Missing required keys (core) in ' . $path . '/broken.info.yml');
// Check that the module filter text box is available.
$this->assertTrue($this->xpath('//input[@name="text"]'));
}
}
@@ -2,8 +2,13 @@
namespace Drupal\Tests\system\Functional\Mail;
use Drupal\Component\Utility\Random;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Mail\MailFormatHelper;
use Drupal\Core\Mail\Plugin\Mail\TestMailCollector;
use Drupal\Core\Render\Markup;
use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\Tests\BrowserTestBase;
use Drupal\system_mail_failure_test\Plugin\Mail\TestPhpMailFailure;
@@ -19,7 +24,7 @@ class MailTest extends BrowserTestBase {
*
* @var array
*/
public static $modules = ['simpletest', 'system_mail_failure_test'];
public static $modules = ['simpletest', 'system_mail_failure_test', 'mail_html_test', 'file', 'image'];
/**
* Assert that the pluggable mail system is functional.
@@ -104,4 +109,178 @@ class MailTest extends BrowserTestBase {
$this->assertFalse(isset($sent_message['headers']['Errors-To']), 'Errors-to header must not be set, it is deprecated.');
}
/**
* Checks that relative paths in mails are converted into absolute URLs.
*/
public function testConvertRelativeUrlsIntoAbsolute() {
$language_interface = \Drupal::languageManager()->getCurrentLanguage();
// Use the HTML compatible state system collector mail backend.
$this->config('system.mail')->set('interface.default', 'test_html_mail_collector')->save();
// Fetch the hostname and port for matching against.
$http_host = \Drupal::request()->getSchemeAndHttpHost();
// Random generator.
$random = new Random();
// One random tag name.
$tag_name = strtolower($random->name(8, TRUE));
// Test root relative urls.
foreach (['href', 'src'] as $attribute) {
// Reset the state variable that holds sent messages.
\Drupal::state()->set('system.test_mail_collector', []);
$html = "<$tag_name $attribute=\"/root-relative\">root relative url in mail test</$tag_name>";
$expected_html = "<$tag_name $attribute=\"{$http_host}/root-relative\">root relative url in mail test</$tag_name>";
// Prepare render array.
$render = ['#markup' => Markup::create($html)];
// Send a test message that simpletest_mail_alter should cancel.
\Drupal::service('plugin.manager.mail')->mail('mail_html_test', 'render_from_message_param', 'relative_url@example.com', $language_interface->getId(), ['message' => $render]);
// Retrieve sent message.
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// Wrap the expected HTML and assert.
$expected_html = MailFormatHelper::wrapMail($expected_html);
$this->assertSame($expected_html, $sent_message['body'], "Asserting that {$attribute} is properly converted for mails.");
}
// Test protocol relative urls.
foreach (['href', 'src'] as $attribute) {
// Reset the state variable that holds sent messages.
\Drupal::state()->set('system.test_mail_collector', []);
$html = "<$tag_name $attribute=\"//example.com/protocol-relative\">protocol relative url in mail test</$tag_name>";
$expected_html = "<$tag_name $attribute=\"//example.com/protocol-relative\">protocol relative url in mail test</$tag_name>";
// Prepare render array.
$render = ['#markup' => Markup::create($html)];
// Send a test message that simpletest_mail_alter should cancel.
\Drupal::service('plugin.manager.mail')->mail('mail_html_test', 'render_from_message_param', 'relative_url@example.com', $language_interface->getId(), ['message' => $render]);
// Retrieve sent message.
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// Wrap the expected HTML and assert.
$expected_html = MailFormatHelper::wrapMail($expected_html);
$this->assertSame($expected_html, $sent_message['body'], "Asserting that {$attribute} is properly converted for mails.");
}
// Test absolute urls.
foreach (['href', 'src'] as $attribute) {
// Reset the state variable that holds sent messages.
\Drupal::state()->set('system.test_mail_collector', []);
$html = "<$tag_name $attribute=\"http://example.com/absolute\">absolute url in mail test</$tag_name>";
$expected_html = "<$tag_name $attribute=\"http://example.com/absolute\">absolute url in mail test</$tag_name>";
// Prepare render array.
$render = ['#markup' => Markup::create($html)];
// Send a test message that simpletest_mail_alter should cancel.
\Drupal::service('plugin.manager.mail')->mail('mail_html_test', 'render_from_message_param', 'relative_url@example.com', $language_interface->getId(), ['message' => $render]);
// Retrieve sent message.
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// Wrap the expected HTML and assert.
$expected_html = MailFormatHelper::wrapMail($expected_html);
$this->assertSame($expected_html, $sent_message['body'], "Asserting that {$attribute} is properly converted for mails.");
}
}
/**
* Checks that mails built from render arrays contain absolute paths.
*
* By default Drupal uses relative paths for images and links. When sending
* emails, absolute paths should be used instead.
*/
public function testRenderedElementsUseAbsolutePaths() {
$language_interface = \Drupal::languageManager()->getCurrentLanguage();
// Use the HTML compatible state system collector mail backend.
$this->config('system.mail')->set('interface.default', 'test_html_mail_collector')->save();
// Fetch the hostname and port for matching against.
$http_host = \Drupal::request()->getSchemeAndHttpHost();
// Random generator.
$random = new Random();
$image_name = $random->name();
// Create an image file.
$file = File::create(['uri' => "public://{$image_name}.png", 'filename' => "{$image_name}.png"]);
$file->save();
$base_path = base_path();
$path_pairs = [
'root relative' => [$file->getFileUri(), "{$http_host}{$base_path}{$this->publicFilesDirectory}/{$image_name}.png"],
'protocol relative' => ['//example.com/image.png', '//example.com/image.png'],
'absolute' => ['http://example.com/image.png', 'http://example.com/image.png'],
];
// Test images.
foreach ($path_pairs as $test_type => $paths) {
list($input_path, $expected_path) = $paths;
// Reset the state variable that holds sent messages.
\Drupal::state()->set('system.test_mail_collector', []);
// Build the render array.
$render = [
'#theme' => 'image',
'#uri' => $input_path,
];
$expected_html = "<img src=\"$expected_path\" alt=\"\" />";
// Send a test message that simpletest_mail_alter should cancel.
\Drupal::service('plugin.manager.mail')->mail('mail_html_test', 'render_from_message_param', 'relative_url@example.com', $language_interface->getId(), ['message' => $render]);
// Retrieve sent message.
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// Wrap the expected HTML and assert.
$expected_html = MailFormatHelper::wrapMail($expected_html);
$this->assertSame($expected_html, $sent_message['body'], "Asserting that {$test_type} paths are converted properly.");
}
// Test links.
$path_pairs = [
'root relative' => [Url::fromUserInput('/path/to/something'), "{$http_host}{$base_path}path/to/something"],
'protocol relative' => [Url::fromUri('//example.com/image.png'), '//example.com/image.png'],
'absolute' => [Url::fromUri('http://example.com/image.png'), 'http://example.com/image.png'],
];
foreach ($path_pairs as $paths) {
list($input_path, $expected_path) = $paths;
// Reset the state variable that holds sent messages.
\Drupal::state()->set('system.test_mail_collector', []);
// Build the render array.
$render = [
'#title' => 'Link',
'#type' => 'link',
'#url' => $input_path,
];
$expected_html = "<a href=\"$expected_path\">Link</a>";
// Send a test message that simpletest_mail_alter should cancel.
\Drupal::service('plugin.manager.mail')->mail('mail_html_test', 'render_from_message_param', 'relative_url@example.com', $language_interface->getId(), ['message' => $render]);
// Retrieve sent message.
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$sent_message = end($captured_emails);
// Wrap the expected HTML and assert.
$expected_html = MailFormatHelper::wrapMail($expected_html);
$this->assertSame($expected_html, $sent_message['body']);
}
}
}
@@ -0,0 +1,91 @@
<?php
namespace Drupal\Tests\system\Functional\Menu;
use Drupal\Tests\BrowserTestBase;
/**
* Tests breadcrumbs functionality.
*
* @group Menu
*/
class BreadcrumbFrontCacheContextsTest extends BrowserTestBase {
use AssertBreadcrumbTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'block',
'node',
'path',
'user',
];
/**
* A test node with path alias.
*
* @var \Drupal\node\NodeInterface
*/
protected $nodeWithAlias;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('system_breadcrumb_block');
$user = $this->drupalCreateUser();
$this->drupalCreateContentType([
'type' => 'page',
]);
// Create a node for front page.
$node_front = $this->drupalCreateNode([
'uid' => $user->id(),
]);
// Create a node with a random alias.
$this->nodeWithAlias = $this->drupalCreateNode([
'uid' => $user->id(),
'type' => 'page',
'path' => '/' . $this->randomMachineName(),
]);
// Configure 'node' as front page.
$this->config('system.site')
->set('page.front', '/node/' . $node_front->id())
->save();
\Drupal::cache('render')->deleteAll();
}
/**
* Validate that breadcrumb markup get the right cache contexts.
*
* Checking that the breadcrumb will be printed on node canonical routes even
* if it was rendered for the <front> page first.
*/
public function testBreadcrumbsFrontPageCache() {
// Hit front page first as anonymous user with 'cold' render cache.
$this->drupalGet('<front>');
$web_assert = $this->assertSession();
// Verify that no breadcrumb block presents.
$web_assert->elementNotExists('css', '.block-system-breadcrumb-block');
// Verify that breadcrumb appears correctly for the test content
// (which is not set as front page).
$this->drupalGet($this->nodeWithAlias->path->alias);
$breadcrumbs = $this->assertSession()->elementExists('css', '.block-system-breadcrumb-block');
$crumbs = $breadcrumbs->findAll('css', 'ol li');
$this->assertTrue(count($crumbs) === 1);
$this->assertTrue($crumbs[0]->getText() === 'Home');
}
}
@@ -38,7 +38,7 @@ class MenuAccessTest extends BrowserTestBase {
// Test that there's link rendered on the route.
$this->drupalGet('menu_test_access_check_session');
$this->assertLink('Test custom route access check');
// Page still accessible but thre should not be menu link.
// Page is still accessible but there should be no menu link.
$this->drupalGet('menu_test_access_check_session');
$this->assertResponse(200);
$this->assertNoLink('Test custom route access check');
@@ -1,15 +1,15 @@
<?php
namespace Drupal\system\Tests\Page;
namespace Drupal\Tests\system\Functional\Page;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Tests default HTML metatags on a page.
*
* @group Page
*/
class DefaultMetatagsTest extends WebTestBase {
class DefaultMetatagsTest extends BrowserTestBase {
/**
* Tests meta tags.
@@ -22,7 +22,7 @@ class DefaultMetatagsTest extends WebTestBase {
// Ensure that the charset one is the first metatag.
$result = $this->xpath('//meta');
$this->assertEqual((string) $result[0]->attributes()->charset, 'utf-8');
$this->assertEqual((string) $result[0]->getAttribute('charset'), 'utf-8');
// Ensure that the shortcut icon is on the page.
$result = $this->xpath('//link[@rel = "shortcut icon"]');
@@ -1,15 +1,19 @@
<?php
namespace Drupal\system\Tests\Pager;
namespace Drupal\Tests\system\Functional\Pager;
use Drupal\simpletest\WebTestBase;
use Behat\Mink\Element\NodeElement;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Tests pager functionality.
*
* @group Pager
*/
class PagerTest extends WebTestBase {
class PagerTest extends BrowserTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Modules to enable.
@@ -58,9 +62,9 @@ class PagerTest extends WebTestBase {
// Verify last page.
$elements = $this->xpath('//li[contains(@class, :class)]/a', [':class' => 'pager__item--last']);
preg_match('@page=(\d+)@', $elements[0]['href'], $matches);
preg_match('@page=(\d+)@', $elements[0]->getAttribute('href'), $matches);
$current_page = (int) $matches[1];
$this->drupalGet($GLOBALS['base_root'] . parse_url($this->getUrl())['path'] . $elements[0]['href'], ['external' => TRUE]);
$this->drupalGet($GLOBALS['base_root'] . parse_url($this->getUrl())['path'] . $elements[0]->getAttribute('href'), ['external' => TRUE]);
$this->assertPagerItems($current_page);
}
@@ -76,15 +80,18 @@ class PagerTest extends WebTestBase {
// Go to last page, the count of pager calls need to go to 1.
$elements = $this->xpath('//li[contains(@class, :class)]/a', [':class' => 'pager__item--last']);
$this->drupalGet($this->getAbsoluteUrl($elements[0]['href']));
$elements[0]->click();
$this->assertText(t('Pager calls: 1'), 'First link call to pager shows 1 calls.');
$this->assertText('[url.query_args.pagers:0]=0.60');
$this->assertCacheContext('url.query_args');
// Reset counter to 0.
$this->drupalGet('pager-test/query-parameters');
// Go back to first page, the count of pager calls need to go to 2.
$elements = $this->xpath('//li[contains(@class, :class)]/a', [':class' => 'pager__item--last']);
$elements[0]->click();
$elements = $this->xpath('//li[contains(@class, :class)]/a', [':class' => 'pager__item--first']);
$this->drupalGet($this->getAbsoluteUrl($elements[0]['href']));
$this->drupalGet($GLOBALS['base_root'] . parse_url($this->getUrl())['path'] . $elements[0]['href'], ['external' => TRUE]);
$elements[0]->click();
$this->assertText(t('Pager calls: 2'), 'Second link call to pager shows 2 calls.');
$this->assertText('[url.query_args.pagers:0]=0.0');
$this->assertCacheContext('url.query_args');
@@ -167,7 +174,7 @@ class PagerTest extends WebTestBase {
$this->drupalGet($GLOBALS['base_root'] . parse_url($this->getUrl())['path'] . $input_query, ['external' => TRUE]);
foreach ([0, 1, 4] as $pager_element) {
$active_page = $this->cssSelect("div.test-pager-{$pager_element} ul.pager__items li.is-active:contains('{$data['expected_page'][$pager_element]}')");
$destination = str_replace('%2C', ',', $active_page[0]->a['href'][0]->__toString());
$destination = str_replace('%2C', ',', $active_page[0]->find('css', 'a')->getAttribute('href'));
$this->assertEqual($destination, $data['expected_query']);
}
}
@@ -232,16 +239,18 @@ class PagerTest extends WebTestBase {
if ($current_page == $page) {
$this->assertClass($element, 'is-active', 'Element for current page has .is-active class.');
$this->assertTrue($element->a, 'Element for current page has link.');
$destination = $element->a['href'][0]->__toString();
$link = $element->find('css', 'a');
$this->assertTrue($link, 'Element for current page has link.');
$destination = $link->getAttribute('href');
// URL query string param is 0-indexed.
$this->assertEqual($destination, '?page=' . ($page - 1));
}
else {
$this->assertNoClass($element, 'is-active', "Element for page $page has no .is-active class.");
$this->assertClass($element, 'pager__item', "Element for page $page has .pager__item class.");
$this->assertTrue($element->a, "Link to page $page found.");
$destination = $element->a['href'][0]->__toString();
$link = $element->find('css', 'a');
$this->assertTrue($link, "Link to page $page found.");
$destination = $link->getAttribute('href');
$this->assertEqual($destination, '?page=' . ($page - 1));
}
unset($elements[--$page]);
@@ -252,32 +261,36 @@ class PagerTest extends WebTestBase {
// Verify first/previous and next/last items and links.
if (isset($first)) {
$this->assertClass($first, 'pager__item--first', 'Element for first page has .pager__item--first class.');
$this->assertTrue($first->a, 'Link to first page found.');
$this->assertNoClass($first->a, 'is-active', 'Link to first page is not active.');
$destination = $first->a['href'][0]->__toString();
$link = $first->find('css', 'a');
$this->assertTrue($link, 'Link to first page found.');
$this->assertNoClass($link, 'is-active', 'Link to first page is not active.');
$destination = $link->getAttribute('href');
$this->assertEqual($destination, '?page=0');
}
if (isset($previous)) {
$this->assertClass($previous, 'pager__item--previous', 'Element for first page has .pager__item--previous class.');
$this->assertTrue($previous->a, 'Link to previous page found.');
$this->assertNoClass($previous->a, 'is-active', 'Link to previous page is not active.');
$destination = $previous->a['href'][0]->__toString();
$link = $previous->find('css', 'a');
$this->assertTrue($link, 'Link to previous page found.');
$this->assertNoClass($link, 'is-active', 'Link to previous page is not active.');
$destination = $link->getAttribute('href');
// URL query string param is 0-indexed, $current_page is 1-indexed.
$this->assertEqual($destination, '?page=' . ($current_page - 2));
}
if (isset($next)) {
$this->assertClass($next, 'pager__item--next', 'Element for next page has .pager__item--next class.');
$this->assertTrue($next->a, 'Link to next page found.');
$this->assertNoClass($next->a, 'is-active', 'Link to next page is not active.');
$destination = $next->a['href'][0]->__toString();
$link = $next->find('css', 'a');
$this->assertTrue($link, 'Link to next page found.');
$this->assertNoClass($link, 'is-active', 'Link to next page is not active.');
$destination = $link->getAttribute('href');
// URL query string param is 0-indexed, $current_page is 1-indexed.
$this->assertEqual($destination, '?page=' . $current_page);
}
if (isset($last)) {
$link = $last->find('css', 'a');
$this->assertClass($last, 'pager__item--last', 'Element for last page has .pager__item--last class.');
$this->assertTrue($last->a, 'Link to last page found.');
$this->assertNoClass($last->a, 'is-active', 'Link to last page is not active.');
$destination = $last->a['href'][0]->__toString();
$this->assertTrue($link, 'Link to last page found.');
$this->assertNoClass($link, 'is-active', 'Link to last page is not active.');
$destination = $link->getAttribute('href');
// URL query string param is 0-indexed.
$this->assertEqual($destination, '?page=' . ($total_pages - 1));
}
@@ -286,35 +299,35 @@ class PagerTest extends WebTestBase {
/**
* Asserts that an element has a given class.
*
* @param \SimpleXMLElement $element
* @param \Behat\Mink\Element\NodeElement $element
* The element to test.
* @param string $class
* The class to assert.
* @param string $message
* (optional) A verbose message to output.
*/
protected function assertClass(\SimpleXMLElement $element, $class, $message = NULL) {
protected function assertClass(NodeElement $element, $class, $message = NULL) {
if (!isset($message)) {
$message = "Class .$class found.";
}
$this->assertTrue(strpos($element['class'], $class) !== FALSE, $message);
$this->assertTrue($element->hasClass($class) !== FALSE, $message);
}
/**
* Asserts that an element does not have a given class.
*
* @param \SimpleXMLElement $element
* @param \Behat\Mink\Element\NodeElement $element
* The element to test.
* @param string $class
* The class to assert.
* @param string $message
* (optional) A verbose message to output.
*/
protected function assertNoClass(\SimpleXMLElement $element, $class, $message = NULL) {
protected function assertNoClass(NodeElement $element, $class, $message = NULL) {
if (!isset($message)) {
$message = "Class .$class not found.";
}
$this->assertTrue(strpos($element['class'], $class) === FALSE, $message);
$this->assertTrue($element->hasClass($class) === FALSE, $message);
}
}
@@ -1,15 +1,15 @@
<?php
namespace Drupal\system\Tests\Render;
namespace Drupal\Tests\system\Functional\Render;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Functional tests for HtmlResponseAttachmentsProcessor.
*
* @group Render
*/
class HtmlResponseAttachmentsTest extends WebTestBase {
class HtmlResponseAttachmentsTest extends BrowserTestBase {
/**
* Modules to enable.
@@ -61,7 +61,7 @@ class HtmlResponseAttachmentsTest extends WebTestBase {
'</foo?bar=&lt;baz&gt;&amp;baz=false>; rel="alternate"',
'</foo/bar>; hreflang="nl"; rel="alternate"',
];
$this->assertEqual($this->drupalGetHeader('link'), implode(',', $expected_link_headers));
$this->assertEqual($this->getSession()->getResponseHeaders()['Link'], $expected_link_headers);
}
/**
@@ -93,9 +93,10 @@ class HtmlResponseAttachmentsTest extends WebTestBase {
* Helper function to make assertions about added HTTP headers.
*/
protected function assertTeapotHeaders() {
$this->assertHeader('X-Test-Teapot', 'Teapot Mode Active');
$this->assertHeader('X-Test-Teapot-Replace', 'Teapot replaced');
$this->assertHeader('X-Test-Teapot-No-Replace', 'This value is not replaced,This one is added');
$headers = $this->getSession()->getResponseHeaders();
$this->assertEquals($headers['X-Test-Teapot'], ['Teapot Mode Active']);
$this->assertEquals($headers['X-Test-Teapot-Replace'], ['Teapot replaced']);
$this->assertEquals($headers['X-Test-Teapot-No-Replace'], ['This value is not replaced', 'This one is added']);
}
/**
@@ -117,8 +118,8 @@ class HtmlResponseAttachmentsTest extends WebTestBase {
$this->fail('Unable to find feed link.');
}
else {
foreach ($test_meta->attributes() as $attribute => $value) {
$this->assertEqual($value, $test_meta_attributes[$attribute]);
foreach ($test_meta_attributes as $attribute => $value) {
$this->assertEquals($value, $test_meta->getAttribute($attribute));
}
}
}
@@ -136,8 +137,7 @@ class HtmlResponseAttachmentsTest extends WebTestBase {
$this->fail('Unable to find the head meta.');
}
else {
$test_meta_attributes = $test_meta->attributes();
$this->assertEqual($test_meta_attributes['test-attribute'], 'testvalue');
$this->assertEqual($test_meta->getAttribute('test-attribute'), 'testvalue');
}
}
@@ -1,16 +1,19 @@
<?php
namespace Drupal\system\Tests\Render;
namespace Drupal\Tests\system\Functional\Render;
use Drupal\Core\Url;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Tests that URL bubbleable metadata is correctly bubbled.
*
* @group Render
*/
class UrlBubbleableMetadataBubblingTest extends WebTestBase {
class UrlBubbleableMetadataBubblingTest extends BrowserTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Modules to enable.
@@ -24,7 +27,6 @@ class UrlBubbleableMetadataBubblingTest extends WebTestBase {
*/
protected function setUp() {
parent::setUp();
$this->dumpHeaders = TRUE;
}
/**
@@ -1,9 +1,9 @@
<?php
namespace Drupal\system\Tests\Routing;
namespace Drupal\Tests\system\Functional\Routing;
use Drupal\Core\Url;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
* Tests for $_GET['destination'] and $_REQUEST['destination'] validation.
@@ -15,7 +15,7 @@ use Drupal\simpletest\WebTestBase;
*
* @group Routing
*/
class DestinationTest extends WebTestBase {
class DestinationTest extends BrowserTestBase {
/**
* {@inheritdoc}
@@ -26,6 +26,9 @@ class DestinationTest extends WebTestBase {
* Tests that $_GET/$_REQUEST['destination'] only contain internal URLs.
*/
public function testDestination() {
$http_client = $this->getHttpClient();
$session = $this->getSession();
$test_cases = [
[
'input' => 'node',
@@ -61,10 +64,12 @@ class DestinationTest extends WebTestBase {
foreach ($test_cases as $test_case) {
// Test $_GET['destination'].
$this->drupalGet('system-test/get-destination', ['query' => ['destination' => $test_case['input']]]);
$this->assertIdentical($test_case['output'], $this->getRawContent(), $test_case['message']);
$this->assertIdentical($test_case['output'], $session->getPage()->getContent(), $test_case['message']);
// Test $_REQUEST['destination'].
$post_output = $this->drupalPost('system-test/request-destination', '*', ['destination' => $test_case['input']]);
$this->assertIdentical($test_case['output'], $post_output, $test_case['message']);
$post_output = $http_client->request('POST', $this->buildUrl('system-test/request-destination'), [
'form_params' => ['destination' => $test_case['input']],
]);
$this->assertIdentical($test_case['output'], (string) $post_output->getBody(), $test_case['message']);
}
// Make sure that 404 pages do not populate $_GET['destination'] with
@@ -72,7 +77,7 @@ class DestinationTest extends WebTestBase {
\Drupal::configFactory()->getEditable('system.site')->set('page.404', '/system-test/get-destination')->save();
$this->drupalGet('http://example.com', ['external' => FALSE]);
$this->assertResponse(404);
$this->assertIdentical(Url::fromRoute('<front>')->toString(), $this->getRawContent(), 'External URL is not allowed on 404 pages.');
$this->assertIdentical(Url::fromRoute('<front>')->toString(), $session->getPage()->getContent(), 'External URL is not allowed on 404 pages.');
}
}
@@ -6,7 +6,7 @@ use Drupal\filter\Entity\FilterFormat;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
/**
* Tests that the allowed html configutations are updated with attributes.
* Tests that the allowed html configurations are updated with attributes.
*
* @group Entity
* @group legacy
@@ -3,10 +3,10 @@
namespace Drupal\Tests\system\Kernel\Entity;
use Drupal\Component\Utility\Html;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\NodeType;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
/**
* Tests entity reference selection plugins.
@@ -5,11 +5,11 @@ namespace Drupal\Tests\system\Kernel\Installer;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests that we handle the absence of a module dependency during install.
* Tests that we handle module dependency resolution during install.
*
* @group Installer
*/
class InstallerMissingDependenciesTest extends KernelTestBase {
class InstallerDependenciesResolutionTest extends KernelTestBase {
/**
* {@inheritdoc}
@@ -19,7 +19,7 @@ class InstallerMissingDependenciesTest extends KernelTestBase {
/**
* Verifies that the exception message in the profile step is correct.
*/
public function testSetUpWithMissingDependencies() {
public function testDependenciesResolution() {
// Prime the drupal_get_filename() static cache with the location of the
// testing profile as it is not the currently active profile and we don't
// yet have any cached way to retrieve its location.
@@ -32,8 +32,11 @@ class InstallerMissingDependenciesTest extends KernelTestBase {
]);
$message = $info['required_modules']['description']->render();
$this->assertContains('Fictional', $message);
$this->assertContains('Missing_module1', $message);
$this->assertContains('Missing_module2', $message);
$this->assertNotContains('Block', $message);
$this->assertNotContains('Node', $message);
}
}
@@ -151,7 +151,7 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@@ -168,7 +168,7 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([0 => new Link('Home', new Url('<front>'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@@ -203,7 +203,11 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([0 => new Link('Home', new Url('<front>')), 1 => new Link('Example', new Url('example'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent', 'user.permissions'], $breadcrumb->getCacheContexts());
$this->assertEquals([
'url.path.is_front',
'url.path.parent',
'user.permissions',
], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@@ -254,7 +258,12 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
new Link('Example', new Url('example')),
new Link('Bar', new Url('example_bar')),
], $breadcrumb->getLinks());
$this->assertEquals(['bar', 'url.path.parent', 'user.permissions'], $breadcrumb->getCacheContexts());
$this->assertEquals([
'bar',
'url.path.is_front',
'url.path.parent',
'user.permissions',
], $breadcrumb->getCacheContexts());
$this->assertEquals(['example'], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@@ -281,7 +290,7 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
// No path matched, though at least the frontpage is displayed.
$this->assertEquals([0 => new Link('Home', new Url('<front>'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@@ -325,7 +334,7 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
// No path matched, though at least the frontpage is displayed.
$this->assertEquals([0 => new Link('Home', new Url('<front>'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals(['url.path.is_front', 'url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
@@ -373,7 +382,11 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([0 => new Link('Home', new Url('<front>')), 1 => new Link('Admin', new Url('user_page'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent', 'user.permissions'], $breadcrumb->getCacheContexts());
$this->assertEquals([
'url.path.is_front',
'url.path.parent',
'user.permissions',
], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}