composer update
This commit is contained in:
parent
f6abc3dce2
commit
71dfaca858
1753 changed files with 45274 additions and 14619 deletions
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
/**
|
||||
* Various tests of AJAX behavior.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class ElementValidationTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Tries to post an Ajax change to a form that has a validated element.
|
||||
*
|
||||
* The drivertext field is Ajax-enabled. An additional field is not, but
|
||||
* is set to be a required field. In this test the required field is not
|
||||
* filled in, and we want to see if the activation of the "drivertext"
|
||||
* Ajax-enabled field fails due to the required field being empty.
|
||||
*/
|
||||
public function testAjaxElementValidation() {
|
||||
$edit = ['drivertext' => t('some dumb text')];
|
||||
|
||||
// Post with 'drivertext' as the triggering element.
|
||||
$this->drupalPostAjaxForm('ajax_validation_test', $edit, 'drivertext');
|
||||
// Look for a validation failure in the resultant JSON.
|
||||
$this->assertNoText(t('Error message'), 'No error message in resultant JSON');
|
||||
$this->assertText('ajax_forms_test_validation_form_callback invoked', 'The correct callback was invoked');
|
||||
|
||||
$this->drupalGet('ajax_validation_test');
|
||||
$edit = ['drivernumber' => 12345];
|
||||
|
||||
// Post with 'drivernumber' as the triggering element.
|
||||
$this->drupalPostAjaxForm('ajax_validation_test', $edit, 'drivernumber');
|
||||
// Look for a validation failure in the resultant JSON.
|
||||
$this->assertNoText(t('Error message'), 'No error message in resultant JSON');
|
||||
$this->assertText('ajax_forms_test_validation_number_form_callback invoked', 'The correct callback was invoked');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\DataCommand;
|
||||
|
||||
/**
|
||||
* Tests that form values are properly delivered to AJAX callbacks.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class FormValuesTest extends AjaxTestBase {
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser(['access content']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits forms with select and checkbox elements via Ajax.
|
||||
*/
|
||||
public function testSimpleAjaxFormValue() {
|
||||
// Verify form values of a select element.
|
||||
foreach (['red', 'green', 'blue'] as $item) {
|
||||
$edit = [
|
||||
'select' => $item,
|
||||
];
|
||||
$commands = $this->drupalPostAjaxForm('ajax_forms_test_get_form', $edit, 'select');
|
||||
$expected = new DataCommand('#ajax_selected_color', 'form_state_value_select', $item);
|
||||
$this->assertCommand($commands, $expected->render(), 'Verification of AJAX form values from a selectbox issued with a correct value.');
|
||||
}
|
||||
|
||||
// Verify form values of a checkbox element.
|
||||
foreach ([FALSE, TRUE] as $item) {
|
||||
$edit = [
|
||||
'checkbox' => $item,
|
||||
];
|
||||
$commands = $this->drupalPostAjaxForm('ajax_forms_test_get_form', $edit, 'checkbox');
|
||||
$expected = new DataCommand('#ajax_checkbox_value', 'form_state_value_select', (int) $item);
|
||||
$this->assertCommand($commands, $expected->render(), 'Verification of AJAX form values from a checkbox issued with a correct value.');
|
||||
}
|
||||
|
||||
// Verify that AJAX elements with invalid callbacks return error code 500.
|
||||
// Ensure the test error log is empty before these tests.
|
||||
$this->assertNoErrorsLogged();
|
||||
// We don't need to check for the X-Drupal-Ajax-Token header with these
|
||||
// invalid requests.
|
||||
$this->assertAjaxHeader = FALSE;
|
||||
foreach (['null', 'empty', 'nonexistent'] as $key) {
|
||||
$element_name = 'select_' . $key . '_callback';
|
||||
$edit = [
|
||||
$element_name => 'red',
|
||||
];
|
||||
$commands = $this->drupalPostAjaxForm('ajax_forms_test_get_form', $edit, $element_name);
|
||||
$this->assertResponse(500);
|
||||
}
|
||||
// Switch this back to the default.
|
||||
$this->assertAjaxHeader = TRUE;
|
||||
// The exceptions are expected. Do not interpret them as a test failure.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,216 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\AddCssCommand;
|
||||
use Drupal\Core\Ajax\AlertCommand;
|
||||
use Drupal\Core\Ajax\AppendCommand;
|
||||
use Drupal\Core\Ajax\HtmlCommand;
|
||||
use Drupal\Core\Ajax\PrependCommand;
|
||||
use Drupal\Core\Ajax\SettingsCommand;
|
||||
use Drupal\Core\Asset\AttachedAssets;
|
||||
|
||||
/**
|
||||
* Performs tests on AJAX framework functions.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class FrameworkTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Verifies the Ajax rendering of a command in the settings.
|
||||
*/
|
||||
public function testAJAXRender() {
|
||||
// Verify that settings command is generated if JavaScript settings exist.
|
||||
$commands = $this->drupalGetAjax('ajax-test/render');
|
||||
$expected = new SettingsCommand(['ajax' => 'test'], TRUE);
|
||||
$this->assertCommand($commands, $expected->render(), 'JavaScript settings command is present.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests AjaxResponse::prepare() AJAX commands ordering.
|
||||
*/
|
||||
public function testOrder() {
|
||||
$expected_commands = [];
|
||||
|
||||
// Expected commands, in a very specific order.
|
||||
$asset_resolver = \Drupal::service('asset.resolver');
|
||||
$css_collection_renderer = \Drupal::service('asset.css.collection_renderer');
|
||||
$js_collection_renderer = \Drupal::service('asset.js.collection_renderer');
|
||||
$renderer = \Drupal::service('renderer');
|
||||
$expected_commands[0] = new SettingsCommand(['ajax' => 'test'], TRUE);
|
||||
$build['#attached']['library'][] = 'ajax_test/order-css-command';
|
||||
$assets = AttachedAssets::createFromRenderArray($build);
|
||||
$css_render_array = $css_collection_renderer->render($asset_resolver->getCssAssets($assets, FALSE));
|
||||
$expected_commands[1] = new AddCssCommand($renderer->renderRoot($css_render_array));
|
||||
$build['#attached']['library'][] = 'ajax_test/order-header-js-command';
|
||||
$build['#attached']['library'][] = 'ajax_test/order-footer-js-command';
|
||||
$assets = AttachedAssets::createFromRenderArray($build);
|
||||
list($js_assets_header, $js_assets_footer) = $asset_resolver->getJsAssets($assets, FALSE);
|
||||
$js_header_render_array = $js_collection_renderer->render($js_assets_header);
|
||||
$js_footer_render_array = $js_collection_renderer->render($js_assets_footer);
|
||||
$expected_commands[2] = new PrependCommand('head', $js_header_render_array);
|
||||
$expected_commands[3] = new AppendCommand('body', $js_footer_render_array);
|
||||
$expected_commands[4] = new HtmlCommand('body', 'Hello, world!');
|
||||
|
||||
// Load any page with at least one CSS file, at least one JavaScript file
|
||||
// and at least one #ajax-powered element. The latter is an assumption of
|
||||
// drupalPostAjaxForm(), the two former are assumptions of the Ajax
|
||||
// renderer.
|
||||
// @todo refactor AJAX Framework + tests to make less assumptions.
|
||||
$this->drupalGet('ajax_forms_test_lazy_load_form');
|
||||
|
||||
// Verify AJAX command order — this should always be the order:
|
||||
// 1. JavaScript settings
|
||||
// 2. CSS files
|
||||
// 3. JavaScript files in the header
|
||||
// 4. JavaScript files in the footer
|
||||
// 5. Any other AJAX commands, in whatever order they were added.
|
||||
$commands = $this->drupalPostAjaxForm(NULL, [], NULL, 'ajax-test/order', [], [], NULL, []);
|
||||
$this->assertCommand(array_slice($commands, 0, 1), $expected_commands[0]->render(), 'Settings command is first.');
|
||||
$this->assertCommand(array_slice($commands, 1, 1), $expected_commands[1]->render(), 'CSS command is second (and CSS files are ordered correctly).');
|
||||
$this->assertCommand(array_slice($commands, 2, 1), $expected_commands[2]->render(), 'Header JS command is third.');
|
||||
$this->assertCommand(array_slice($commands, 3, 1), $expected_commands[3]->render(), 'Footer JS command is fourth.');
|
||||
$this->assertCommand(array_slice($commands, 4, 1), $expected_commands[4]->render(), 'HTML command is fifth.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of an error alert command.
|
||||
*/
|
||||
public function testAJAXRenderError() {
|
||||
// Verify custom error message.
|
||||
$edit = [
|
||||
'message' => 'Custom error message.',
|
||||
];
|
||||
$commands = $this->drupalGetAjax('ajax-test/render-error', ['query' => $edit]);
|
||||
$expected = new AlertCommand($edit['message']);
|
||||
$this->assertCommand($commands, $expected->render(), 'Custom error message is output.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that new JavaScript and CSS files are lazy-loaded on an AJAX request.
|
||||
*/
|
||||
public function testLazyLoad() {
|
||||
$asset_resolver = \Drupal::service('asset.resolver');
|
||||
$css_collection_renderer = \Drupal::service('asset.css.collection_renderer');
|
||||
$js_collection_renderer = \Drupal::service('asset.js.collection_renderer');
|
||||
$renderer = \Drupal::service('renderer');
|
||||
|
||||
$expected = [
|
||||
'setting_name' => 'ajax_forms_test_lazy_load_form_submit',
|
||||
'setting_value' => 'executed',
|
||||
'library_1' => 'system/admin',
|
||||
'library_2' => 'system/drupal.system',
|
||||
];
|
||||
|
||||
// Get the base page.
|
||||
$this->drupalGet('ajax_forms_test_lazy_load_form');
|
||||
$original_settings = $this->getDrupalSettings();
|
||||
$original_libraries = explode(',', $original_settings['ajaxPageState']['libraries']);
|
||||
|
||||
// Verify that the base page doesn't have the settings and files that are to
|
||||
// be lazy loaded as part of the next requests.
|
||||
$this->assertTrue(!isset($original_settings[$expected['setting_name']]), format_string('Page originally lacks the %setting, as expected.', ['%setting' => $expected['setting_name']]));
|
||||
$this->assertTrue(!in_array($expected['library_1'], $original_libraries), format_string('Page originally lacks the %library library, as expected.', ['%library' => $expected['library_1']]));
|
||||
$this->assertTrue(!in_array($expected['library_2'], $original_libraries), format_string('Page originally lacks the %library library, as expected.', ['%library' => $expected['library_2']]));
|
||||
|
||||
// Calculate the expected CSS and JS.
|
||||
$assets = new AttachedAssets();
|
||||
$assets->setLibraries([$expected['library_1']])
|
||||
->setAlreadyLoadedLibraries($original_libraries);
|
||||
$css_render_array = $css_collection_renderer->render($asset_resolver->getCssAssets($assets, FALSE));
|
||||
$expected_css_html = $renderer->renderRoot($css_render_array);
|
||||
|
||||
$assets->setLibraries([$expected['library_2']])
|
||||
->setAlreadyLoadedLibraries($original_libraries);
|
||||
$js_assets = $asset_resolver->getJsAssets($assets, FALSE)[1];
|
||||
unset($js_assets['drupalSettings']);
|
||||
$js_render_array = $js_collection_renderer->render($js_assets);
|
||||
$expected_js_html = $renderer->renderRoot($js_render_array);
|
||||
|
||||
// Submit the AJAX request without triggering files getting added.
|
||||
$commands = $this->drupalPostAjaxForm(NULL, ['add_files' => FALSE], ['op' => t('Submit')]);
|
||||
$new_settings = $this->getDrupalSettings();
|
||||
$new_libraries = explode(',', $new_settings['ajaxPageState']['libraries']);
|
||||
|
||||
// Verify the setting was not added when not expected.
|
||||
$this->assertTrue(!isset($new_settings[$expected['setting_name']]), format_string('Page still lacks the %setting, as expected.', ['%setting' => $expected['setting_name']]));
|
||||
$this->assertTrue(!in_array($expected['library_1'], $new_libraries), format_string('Page still lacks the %library library, as expected.', ['%library' => $expected['library_1']]));
|
||||
$this->assertTrue(!in_array($expected['library_2'], $new_libraries), format_string('Page still lacks the %library library, as expected.', ['%library' => $expected['library_2']]));
|
||||
// Verify a settings command does not add CSS or scripts to drupalSettings
|
||||
// and no command inserts the corresponding tags on the page.
|
||||
$found_settings_command = FALSE;
|
||||
$found_markup_command = FALSE;
|
||||
foreach ($commands as $command) {
|
||||
if ($command['command'] == 'settings' && (array_key_exists('css', $command['settings']['ajaxPageState']) || array_key_exists('js', $command['settings']['ajaxPageState']))) {
|
||||
$found_settings_command = TRUE;
|
||||
}
|
||||
if (isset($command['data']) && ($command['data'] == $expected_js_html || $command['data'] == $expected_css_html)) {
|
||||
$found_markup_command = TRUE;
|
||||
}
|
||||
}
|
||||
$this->assertFalse($found_settings_command, format_string('Page state still lacks the %library_1 and %library_2 libraries, as expected.', ['%library_1' => $expected['library_1'], '%library_2' => $expected['library_2']]));
|
||||
$this->assertFalse($found_markup_command, format_string('Page still lacks the %library_1 and %library_2 libraries, as expected.', ['%library_1' => $expected['library_1'], '%library_2' => $expected['library_2']]));
|
||||
|
||||
// Submit the AJAX request and trigger adding files.
|
||||
$commands = $this->drupalPostAjaxForm(NULL, ['add_files' => TRUE], ['op' => t('Submit')]);
|
||||
$new_settings = $this->getDrupalSettings();
|
||||
$new_libraries = explode(',', $new_settings['ajaxPageState']['libraries']);
|
||||
|
||||
// Verify the expected setting was added, both to drupalSettings, and as
|
||||
// the first AJAX command.
|
||||
$this->assertIdentical($new_settings[$expected['setting_name']], $expected['setting_value'], format_string('Page now has the %setting.', ['%setting' => $expected['setting_name']]));
|
||||
$expected_command = new SettingsCommand([$expected['setting_name'] => $expected['setting_value']], TRUE);
|
||||
$this->assertCommand(array_slice($commands, 0, 1), $expected_command->render(), 'The settings command was first.');
|
||||
|
||||
// Verify the expected CSS file was added, both to drupalSettings, and as
|
||||
// the second AJAX command for inclusion into the HTML.
|
||||
$this->assertTrue(in_array($expected['library_1'], $new_libraries), format_string('Page state now has the %library library.', ['%library' => $expected['library_1']]));
|
||||
$this->assertCommand(array_slice($commands, 1, 1), ['data' => $expected_css_html], format_string('Page now has the %library library.', ['%library' => $expected['library_1']]));
|
||||
|
||||
// Verify the expected JS file was added, both to drupalSettings, and as
|
||||
// the third AJAX command for inclusion into the HTML. By testing for an
|
||||
// exact HTML string containing the SCRIPT tag, we also ensure that
|
||||
// unexpected JavaScript code, such as a jQuery.extend() that would
|
||||
// potentially clobber rather than properly merge settings, didn't
|
||||
// accidentally get added.
|
||||
$this->assertTrue(in_array($expected['library_2'], $new_libraries), format_string('Page state now has the %library library.', ['%library' => $expected['library_2']]));
|
||||
$this->assertCommand(array_slice($commands, 2, 1), ['data' => $expected_js_html], format_string('Page now has the %library library.', ['%library' => $expected['library_2']]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that drupalSettings.currentPath is not updated on AJAX requests.
|
||||
*/
|
||||
public function testCurrentPathChange() {
|
||||
$commands = $this->drupalPostAjaxForm('ajax_forms_test_lazy_load_form', ['add_files' => FALSE], ['op' => t('Submit')]);
|
||||
foreach ($commands as $command) {
|
||||
if ($command['command'] == 'settings') {
|
||||
$this->assertFalse(isset($command['settings']['currentPath']), 'Value of drupalSettings.currentPath is not updated after an AJAX request.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that overridden CSS files are not added during lazy load.
|
||||
*/
|
||||
public function testLazyLoadOverriddenCSS() {
|
||||
// The test theme overrides js.module.css without an implementation,
|
||||
// thereby removing it.
|
||||
\Drupal::service('theme_handler')->install(['test_theme']);
|
||||
$this->config('system.theme')
|
||||
->set('default', 'test_theme')
|
||||
->save();
|
||||
|
||||
// This gets the form, and emulates an Ajax submission on it, including
|
||||
// adding markup to the HEAD and BODY for any lazy loaded JS/CSS files.
|
||||
$this->drupalPostAjaxForm('ajax_forms_test_lazy_load_form', ['add_files' => TRUE], ['op' => t('Submit')]);
|
||||
|
||||
// Verify that the resulting HTML does not load the overridden CSS file.
|
||||
// We add a "?" to the assertion, because drupalSettings may include
|
||||
// information about the file; we only really care about whether it appears
|
||||
// in a LINK or STYLE tag, for which Drupal always adds a query string for
|
||||
// cache control.
|
||||
$this->assertNoText('js.module.css?', 'Ajax lazy loading does not add overridden CSS files.');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Form;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests that FAPI correctly determines the triggering element.
|
||||
*
|
||||
* @group Form
|
||||
*/
|
||||
class TriggeringElementTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['form_test'];
|
||||
|
||||
/**
|
||||
* Test the determination of the triggering element when no button
|
||||
* information is included in the POST data, as is sometimes the case when
|
||||
* the ENTER key is pressed in a textfield in Internet Explorer.
|
||||
*/
|
||||
public function testNoButtonInfoInPost() {
|
||||
$path = 'form-test/clicked-button';
|
||||
$edit = [];
|
||||
$form_html_id = 'form-test-clicked-button';
|
||||
|
||||
// Ensure submitting a form with no buttons results in no triggering element
|
||||
// and the form submit handler not running.
|
||||
$this->drupalPostForm($path, $edit, NULL, [], [], $form_html_id);
|
||||
$this->assertText('There is no clicked button.', '$form_state->getTriggeringElement() set to NULL.');
|
||||
$this->assertNoText('Submit handler for form_test_clicked_button executed.', 'Form submit handler did not execute.');
|
||||
|
||||
// Ensure submitting a form with one or more submit buttons results in the
|
||||
// triggering element being set to the first one the user has access to. An
|
||||
// argument with 'r' in it indicates a restricted (#access=FALSE) button.
|
||||
$this->drupalPostForm($path . '/s', $edit, NULL, [], [], $form_html_id);
|
||||
$this->assertText('The clicked button is button1.', '$form_state->getTriggeringElement() set to only button.');
|
||||
$this->assertText('Submit handler for form_test_clicked_button executed.', 'Form submit handler executed.');
|
||||
|
||||
$this->drupalPostForm($path . '/s/s', $edit, NULL, [], [], $form_html_id);
|
||||
$this->assertText('The clicked button is button1.', '$form_state->getTriggeringElement() set to first button.');
|
||||
$this->assertText('Submit handler for form_test_clicked_button executed.', 'Form submit handler executed.');
|
||||
|
||||
$this->drupalPostForm($path . '/rs/s', $edit, NULL, [], [], $form_html_id);
|
||||
$this->assertText('The clicked button is button2.', '$form_state->getTriggeringElement() set to first available button.');
|
||||
$this->assertText('Submit handler for form_test_clicked_button executed.', 'Form submit handler executed.');
|
||||
|
||||
// Ensure submitting a form with buttons of different types results in the
|
||||
// triggering element being set to the first button, regardless of type. For
|
||||
// the FAPI 'button' type, this should result in the submit handler not
|
||||
// executing. The types are 's'(ubmit), 'b'(utton), and 'i'(mage_button).
|
||||
$this->drupalPostForm($path . '/s/b/i', $edit, NULL, [], [], $form_html_id);
|
||||
$this->assertText('The clicked button is button1.', '$form_state->getTriggeringElement() set to first button.');
|
||||
$this->assertText('Submit handler for form_test_clicked_button executed.', 'Form submit handler executed.');
|
||||
|
||||
$this->drupalPostForm($path . '/b/s/i', $edit, NULL, [], [], $form_html_id);
|
||||
$this->assertText('The clicked button is button1.', '$form_state->getTriggeringElement() set to first button.');
|
||||
$this->assertNoText('Submit handler for form_test_clicked_button executed.', 'Form submit handler did not execute.');
|
||||
|
||||
$this->drupalPostForm($path . '/i/s/b', $edit, NULL, [], [], $form_html_id);
|
||||
$this->assertText('The clicked button is button1.', '$form_state->getTriggeringElement() set to first button.');
|
||||
$this->assertText('Submit handler for form_test_clicked_button executed.', 'Form submit handler executed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the triggering element does not get set to a button with
|
||||
* #access=FALSE.
|
||||
*/
|
||||
public function testAttemptAccessControlBypass() {
|
||||
$path = 'form-test/clicked-button';
|
||||
$form_html_id = 'form-test-clicked-button';
|
||||
|
||||
// Retrieve a form where 'button1' has #access=FALSE and 'button2' doesn't.
|
||||
$this->drupalGet($path . '/rs/s');
|
||||
|
||||
// Submit the form with 'button1=button1' in the POST data, which someone
|
||||
// trying to get around security safeguards could easily do. We have to do
|
||||
// a little trickery here, to work around the safeguards in drupalPostForm(): by
|
||||
// renaming the text field that is in the form to 'button1', we can get the
|
||||
// data we want into \Drupal::request()->request.
|
||||
$elements = $this->xpath('//form[@id="' . $form_html_id . '"]//input[@name="text"]');
|
||||
$elements[0]['name'] = 'button1';
|
||||
$this->drupalPostForm(NULL, ['button1' => 'button1'], NULL, [], [], $form_html_id);
|
||||
|
||||
// Ensure that the triggering element was not set to the restricted button.
|
||||
// Do this with both a negative and positive assertion, because negative
|
||||
// assertions alone can be brittle. See testNoButtonInfoInPost() for why the
|
||||
// triggering element gets set to 'button2'.
|
||||
$this->assertNoText('The clicked button is button1.', '$form_state->getTriggeringElement() not set to a restricted button.');
|
||||
$this->assertText('The clicked button is button2.', '$form_state->getTriggeringElement() not set to a restricted button.');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Session;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the stacked session handler functionality.
|
||||
*
|
||||
* @group Session
|
||||
*/
|
||||
class StackSessionHandlerIntegrationTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['session_test'];
|
||||
|
||||
/**
|
||||
* Tests a request.
|
||||
*/
|
||||
public function testRequest() {
|
||||
$actual_trace = $this->drupalGetAjax('session-test/trace-handler');
|
||||
$expect_trace = [
|
||||
['BEGIN', 'test_argument', 'open'],
|
||||
['BEGIN', NULL, 'open'],
|
||||
['END', NULL, 'open'],
|
||||
['END', 'test_argument', 'open'],
|
||||
['BEGIN', 'test_argument', 'read', $this->sessionId],
|
||||
['BEGIN', NULL, 'read', $this->sessionId],
|
||||
['END', NULL, 'read', $this->sessionId],
|
||||
['END', 'test_argument', 'read', $this->sessionId],
|
||||
['BEGIN', 'test_argument', 'write', $this->sessionId],
|
||||
['BEGIN', NULL, 'write', $this->sessionId],
|
||||
['END', NULL, 'write', $this->sessionId],
|
||||
['END', 'test_argument', 'write', $this->sessionId],
|
||||
['BEGIN', 'test_argument', 'close'],
|
||||
['BEGIN', NULL, 'close'],
|
||||
['END', NULL, 'close'],
|
||||
['END', 'test_argument', 'close'],
|
||||
];
|
||||
$this->assertEqual($expect_trace, $actual_trace);
|
||||
}
|
||||
|
||||
}
|
|
@ -50,7 +50,7 @@ class Callbacks {
|
|||
*/
|
||||
public function checkboxCallback($form, FormStateInterface $form_state) {
|
||||
$response = new AjaxResponse();
|
||||
$response->addCommand(new HtmlCommand('#ajax_checkbox_value', (int) $form_state->getValue('checkbox')));
|
||||
$response->addCommand(new HtmlCommand('#ajax_checkbox_value', $form_state->getValue('checkbox') ? 'checked' : 'unchecked'));
|
||||
$response->addCommand(new DataCommand('#ajax_checkbox_value', 'form_state_value_select', (int) $form_state->getValue('checkbox')));
|
||||
return $response;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ class AjaxFormsTestSimpleForm extends FormBase {
|
|||
$form['select_' . $key . '_callback'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Test %key callbacks', ['%key' => $key]),
|
||||
'#options' => ['red' => 'red'],
|
||||
'#options' => ['red' => 'red', 'green' => 'green'],
|
||||
'#ajax' => ['callback' => $value],
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\form_test\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Form constructor for testing #type 'file' elements.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class FormTestFileForm extends FormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'form_test_file';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['file'] = [
|
||||
'#type' => 'file',
|
||||
'#multiple' => TRUE,
|
||||
'#attributes' => [
|
||||
'class' => ['cagatio'],
|
||||
],
|
||||
];
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\system\Functional\Ajax;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Core\Ajax\AddCssCommand;
|
||||
use Drupal\Core\Ajax\AlertCommand;
|
||||
use Drupal\Core\Ajax\AppendCommand;
|
||||
use Drupal\Core\Ajax\HtmlCommand;
|
||||
use Drupal\Core\Ajax\PrependCommand;
|
||||
use Drupal\Core\Ajax\SettingsCommand;
|
||||
use Drupal\Core\Asset\AttachedAssets;
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Performs tests on AJAX framework functions.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class FrameworkTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['node', 'ajax_test', 'ajax_forms_test'];
|
||||
|
||||
/**
|
||||
* Verifies the Ajax rendering of a command in the settings.
|
||||
*/
|
||||
public function testAJAXRender() {
|
||||
// Verify that settings command is generated if JavaScript settings exist.
|
||||
$commands = $this->drupalGetAjax('ajax-test/render');
|
||||
$expected = new SettingsCommand(['ajax' => 'test'], TRUE);
|
||||
$this->assertCommand($commands, $expected->render(), 'JavaScript settings command is present.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests AjaxResponse::prepare() AJAX commands ordering.
|
||||
*/
|
||||
public function testOrder() {
|
||||
$expected_commands = [];
|
||||
|
||||
// Expected commands, in a very specific order.
|
||||
$asset_resolver = \Drupal::service('asset.resolver');
|
||||
$css_collection_renderer = \Drupal::service('asset.css.collection_renderer');
|
||||
$js_collection_renderer = \Drupal::service('asset.js.collection_renderer');
|
||||
$renderer = \Drupal::service('renderer');
|
||||
$build['#attached']['library'][] = 'ajax_test/order-css-command';
|
||||
$assets = AttachedAssets::createFromRenderArray($build);
|
||||
$css_render_array = $css_collection_renderer->render($asset_resolver->getCssAssets($assets, FALSE));
|
||||
$expected_commands[1] = new AddCssCommand($renderer->renderRoot($css_render_array));
|
||||
$build['#attached']['library'][] = 'ajax_test/order-header-js-command';
|
||||
$build['#attached']['library'][] = 'ajax_test/order-footer-js-command';
|
||||
$assets = AttachedAssets::createFromRenderArray($build);
|
||||
list($js_assets_header, $js_assets_footer) = $asset_resolver->getJsAssets($assets, FALSE);
|
||||
$js_header_render_array = $js_collection_renderer->render($js_assets_header);
|
||||
$js_footer_render_array = $js_collection_renderer->render($js_assets_footer);
|
||||
$expected_commands[2] = new PrependCommand('head', $js_header_render_array);
|
||||
$expected_commands[3] = new AppendCommand('body', $js_footer_render_array);
|
||||
$expected_commands[4] = new HtmlCommand('body', 'Hello, world!');
|
||||
|
||||
// Load any page with at least one CSS file, at least one JavaScript file
|
||||
// and at least one #ajax-powered element. The latter is an assumption of
|
||||
// drupalPostAjaxForm(), the two former are assumptions of the Ajax
|
||||
// renderer.
|
||||
// @todo refactor AJAX Framework + tests to make less assumptions.
|
||||
$this->drupalGet('ajax_forms_test_lazy_load_form');
|
||||
|
||||
// Verify AJAX command order — this should always be the order:
|
||||
// 1. CSS files
|
||||
// 2. JavaScript files in the header
|
||||
// 3. JavaScript files in the footer
|
||||
// 4. Any other AJAX commands, in whatever order they were added.
|
||||
$commands = $this->drupalGetAjax('ajax-test/order');
|
||||
$this->assertCommand(array_slice($commands, 0, 1), $expected_commands[1]->render());
|
||||
$this->assertCommand(array_slice($commands, 1, 1), $expected_commands[2]->render());
|
||||
$this->assertCommand(array_slice($commands, 2, 1), $expected_commands[3]->render());
|
||||
$this->assertCommand(array_slice($commands, 3, 1), $expected_commands[4]->render());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of an error alert command.
|
||||
*/
|
||||
public function testAJAXRenderError() {
|
||||
// Verify custom error message.
|
||||
$edit = [
|
||||
'message' => 'Custom error message.',
|
||||
];
|
||||
$commands = $this->drupalGetAjax('ajax-test/render-error', ['query' => $edit]);
|
||||
$expected = new AlertCommand($edit['message']);
|
||||
$this->assertCommand($commands, $expected->render(), 'Custom error message is output.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the array of Ajax commands contains the searched command.
|
||||
*
|
||||
* An AjaxResponse object stores an array of Ajax commands. This array
|
||||
* sometimes includes commands automatically provided by the framework in
|
||||
* addition to commands returned by a particular controller. During testing,
|
||||
* we're usually interested that a particular command is present, and don't
|
||||
* care whether other commands precede or follow the one we're interested in.
|
||||
* Additionally, the command we're interested in may include additional data
|
||||
* that we're not interested in. Therefore, this function simply asserts that
|
||||
* one of the commands in $haystack contains all of the keys and values in
|
||||
* $needle. Furthermore, if $needle contains a 'settings' key with an array
|
||||
* value, we simply assert that all keys and values within that array are
|
||||
* present in the command we're checking, and do not consider it a failure if
|
||||
* the actual command contains additional settings that aren't part of
|
||||
* $needle.
|
||||
*
|
||||
* @param $haystack
|
||||
* An array of rendered Ajax commands returned by the server.
|
||||
* @param $needle
|
||||
* Array of info we're expecting in one of those commands.
|
||||
*/
|
||||
protected function assertCommand($haystack, $needle) {
|
||||
$found = FALSE;
|
||||
foreach ($haystack as $command) {
|
||||
// If the command has additional settings that we're not testing for, do
|
||||
// not consider that a failure.
|
||||
if (isset($command['settings']) && is_array($command['settings']) && isset($needle['settings']) && is_array($needle['settings'])) {
|
||||
$command['settings'] = array_intersect_key($command['settings'], $needle['settings']);
|
||||
}
|
||||
// If the command has additional data that we're not testing for, do not
|
||||
// consider that a failure. Also, == instead of ===, because we don't
|
||||
// require the key/value pairs to be in any particular order
|
||||
// (http://php.net/manual/language.operators.array.php).
|
||||
if (array_intersect_key($command, $needle) == $needle) {
|
||||
$found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($found);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests a path or URL in drupal_ajax format and JSON-decodes the response.
|
||||
*
|
||||
* @param \Drupal\Core\Url|string $path
|
||||
* Drupal path or URL to request from.
|
||||
* @param array $options
|
||||
* Array of URL options.
|
||||
* @param array $headers
|
||||
* Array of headers.
|
||||
*
|
||||
* @return array
|
||||
* Decoded JSON.
|
||||
*/
|
||||
protected function drupalGetAjax($path, array $options = [], array $headers = []) {
|
||||
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
||||
if (!isset($options['query'][MainContentViewSubscriber::WRAPPER_FORMAT])) {
|
||||
$options['query'][MainContentViewSubscriber::WRAPPER_FORMAT] = 'drupal_ajax';
|
||||
}
|
||||
return Json::decode($this->drupalGet($path, $options, $headers));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Form;
|
||||
namespace Drupal\Tests\system\Functional\Form;
|
||||
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Tests\system\Functional\Form\StubForm;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the tableselect form element for expected behavior.
|
||||
*
|
||||
* @group Form
|
||||
*/
|
||||
class ElementsTableSelectTest extends WebTestBase {
|
||||
class ElementsTableSelectTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
|
@ -27,35 +26,14 @@ class ElementsTableSelectTest extends WebTestBase {
|
|||
|
||||
$this->drupalGet('form_test/tableselect/multiple-true');
|
||||
|
||||
$this->assertNoText(t('Empty text.'), 'Empty text should not be displayed.');
|
||||
$this->assertSession()->responseNotContains('Empty text.', 'Empty text should not be displayed.');
|
||||
|
||||
// Test for the presence of the Select all rows tableheader.
|
||||
$this->assertFieldByXPath('//th[@class="select-all"]', NULL, 'Presence of the "Select all" checkbox.');
|
||||
$this->assertNotEmpty($this->xpath('//th[@class="select-all"]'), 'Presence of the "Select all" checkbox.');
|
||||
|
||||
$rows = ['row1', 'row2', 'row3'];
|
||||
foreach ($rows as $row) {
|
||||
$this->assertFieldByXPath('//input[@type="checkbox"]', $row, format_string('Checkbox for value @row.', ['@row' => $row]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the presence of ajax functionality for all options.
|
||||
*/
|
||||
public function testAjax() {
|
||||
$rows = ['row1', 'row2', 'row3'];
|
||||
// Test checkboxes (#multiple == TRUE).
|
||||
foreach ($rows as $row) {
|
||||
$element = 'tableselect[' . $row . ']';
|
||||
$edit = [$element => TRUE];
|
||||
$result = $this->drupalPostAjaxForm('form_test/tableselect/multiple-true', $edit, $element);
|
||||
$this->assertFalse(empty($result), t('Ajax triggers on checkbox for @row.', ['@row' => $row]));
|
||||
}
|
||||
// Test radios (#multiple == FALSE).
|
||||
$element = 'tableselect';
|
||||
foreach ($rows as $row) {
|
||||
$edit = [$element => $row];
|
||||
$result = $this->drupalPostAjaxForm('form_test/tableselect/multiple-false', $edit, $element);
|
||||
$this->assertFalse(empty($result), t('Ajax triggers on radio for @row.', ['@row' => $row]));
|
||||
$this->assertNotEmpty($this->xpath('//input[@type="checkbox"]', [$row]), "Checkbox for the value $row.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,40 +43,39 @@ class ElementsTableSelectTest extends WebTestBase {
|
|||
public function testMultipleFalse() {
|
||||
$this->drupalGet('form_test/tableselect/multiple-false');
|
||||
|
||||
$this->assertNoText(t('Empty text.'), 'Empty text should not be displayed.');
|
||||
$this->assertSession()->pageTextNotContains('Empty text.');
|
||||
|
||||
// Test for the absence of the Select all rows tableheader.
|
||||
$this->assertNoFieldByXPath('//th[@class="select-all"]', '', 'Absence of the "Select all" checkbox.');
|
||||
$this->assertFalse($this->xpath('//th[@class="select-all"]'));
|
||||
|
||||
$rows = ['row1', 'row2', 'row3'];
|
||||
foreach ($rows as $row) {
|
||||
$this->assertFieldByXPath('//input[@type="radio"]', $row, format_string('Radio button for value @row.', ['@row' => $row]));
|
||||
$this->assertNotEmpty($this->xpath('//input[@type="radio"]', [$row], "Radio button value: $row"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the display when #colspan is set.
|
||||
*/
|
||||
public function testTableselectColSpan() {
|
||||
public function testTableSelectColSpan() {
|
||||
$this->drupalGet('form_test/tableselect/colspan');
|
||||
|
||||
$this->assertText(t('Three'), 'Presence of the third column');
|
||||
$this->assertNoText(t('Four'), 'Absence of a fourth column');
|
||||
$this->assertSession()->pageTextContains('Three', 'Presence of the third column');
|
||||
$this->assertSession()->pageTextNotContains('Four', 'Absence of a fourth column');
|
||||
|
||||
// There should be three labeled column headers and 1 for the input.
|
||||
$table_head = $this->xpath('//thead');
|
||||
$this->assertEqual(count($table_head[0]->tr->th), 4, 'There are four column headers');
|
||||
$table_head = $this->xpath('//thead/tr/th');
|
||||
$this->assertEquals(count($table_head), 4, 'There are four column headers');
|
||||
|
||||
$table_body = $this->xpath('//tbody');
|
||||
// The first two body rows should each have 5 table cells: One for the
|
||||
// radio, one cell in the first column, one cell in the second column,
|
||||
// and two cells in the third column which has colspan 2.
|
||||
for ($i = 0; $i <= 1; $i++) {
|
||||
$this->assertEqual(count($table_body[0]->tr[$i]->td), 5, format_string('There are five cells in row @row.', ['@row' => $i]));
|
||||
$this->assertEquals(count($this->xpath('//tbody/tr[' . ($i + 1) . ']/td')), 5, 'There are five cells in row ' . $i);
|
||||
}
|
||||
// The third row should have 3 cells, one for the radio, one spanning the
|
||||
// first and second column, and a third in column 3 (which has colspan 3).
|
||||
$this->assertEqual(count($table_body[0]->tr[2]->td), 3, 'There are three cells in row 3.');
|
||||
$this->assertEquals(count($this->xpath('//tbody/tr[3]/td')), 3, 'There are three cells in row 3.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,7 +83,7 @@ class ElementsTableSelectTest extends WebTestBase {
|
|||
*/
|
||||
public function testEmptyText() {
|
||||
$this->drupalGet('form_test/tableselect/empty-text');
|
||||
$this->assertText(t('Empty text.'), 'Empty text should be displayed.');
|
||||
$this->assertSession()->pageTextContains('Empty text.', 'Empty text should be displayed.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,18 +96,19 @@ class ElementsTableSelectTest extends WebTestBase {
|
|||
$edit['tableselect[row1]'] = TRUE;
|
||||
$this->drupalPostForm('form_test/tableselect/multiple-true', $edit, 'Submit');
|
||||
|
||||
$this->assertText(t('Submitted: row1 = row1'), 'Checked checkbox row1');
|
||||
$this->assertText(t('Submitted: row2 = 0'), 'Unchecked checkbox row2.');
|
||||
$this->assertText(t('Submitted: row3 = 0'), 'Unchecked checkbox row3.');
|
||||
$assert_session = $this->assertSession();
|
||||
$assert_session->pageTextContains('Submitted: row1 = row1', 'Checked checkbox row1');
|
||||
$assert_session->pageTextContains('Submitted: row2 = 0', 'Unchecked checkbox row2.');
|
||||
$assert_session->pageTextContains('Submitted: row3 = 0', 'Unchecked checkbox row3.');
|
||||
|
||||
// Test a submission with multiple checkboxes checked.
|
||||
$edit['tableselect[row1]'] = TRUE;
|
||||
$edit['tableselect[row3]'] = TRUE;
|
||||
$this->drupalPostForm('form_test/tableselect/multiple-true', $edit, 'Submit');
|
||||
|
||||
$this->assertText(t('Submitted: row1 = row1'), 'Checked checkbox row1.');
|
||||
$this->assertText(t('Submitted: row2 = 0'), 'Unchecked checkbox row2.');
|
||||
$this->assertText(t('Submitted: row3 = row3'), 'Checked checkbox row3.');
|
||||
$assert_session->pageTextContains('Submitted: row1 = row1', 'Checked checkbox row1.');
|
||||
$assert_session->pageTextContains('Submitted: row2 = 0', 'Unchecked checkbox row2.');
|
||||
$assert_session->pageTextContains('Submitted: row3 = row3', 'Checked checkbox row3.');
|
||||
|
||||
}
|
||||
|
||||
|
@ -140,7 +118,7 @@ class ElementsTableSelectTest extends WebTestBase {
|
|||
public function testMultipleFalseSubmit() {
|
||||
$edit['tableselect'] = 'row1';
|
||||
$this->drupalPostForm('form_test/tableselect/multiple-false', $edit, 'Submit');
|
||||
$this->assertText(t('Submitted: row1'), 'Selected radio button');
|
||||
$this->assertSession()->pageTextContains('Submitted: row1', 'Selected radio button');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,18 +127,18 @@ class ElementsTableSelectTest extends WebTestBase {
|
|||
public function testAdvancedSelect() {
|
||||
// When #multiple = TRUE a Select all checkbox should be displayed by default.
|
||||
$this->drupalGet('form_test/tableselect/advanced-select/multiple-true-default');
|
||||
$this->assertFieldByXPath('//th[@class="select-all"]', NULL, 'Display a "Select all" checkbox by default when #multiple is TRUE.');
|
||||
$this->xpath('//th[@class="select-all"]');
|
||||
|
||||
// When #js_select is set to FALSE, a "Select all" checkbox should not be displayed.
|
||||
$this->drupalGet('form_test/tableselect/advanced-select/multiple-true-no-advanced-select');
|
||||
$this->assertNoFieldByXPath('//th[@class="select-all"]', NULL, 'Do not display a "Select all" checkbox when #js_select is FALSE.');
|
||||
$this->assertFalse($this->xpath('//th[@class="select-all"]'));
|
||||
|
||||
// A "Select all" checkbox never makes sense when #multiple = FALSE, regardless of the value of #js_select.
|
||||
$this->drupalGet('form_test/tableselect/advanced-select/multiple-false-default');
|
||||
$this->assertNoFieldByXPath('//th[@class="select-all"]', NULL, 'Do not display a "Select all" checkbox when #multiple is FALSE.');
|
||||
$this->assertFalse($this->xpath('//th[@class="select-all"]'));
|
||||
|
||||
$this->drupalGet('form_test/tableselect/advanced-select/multiple-false-advanced-select');
|
||||
$this->assertNoFieldByXPath('//th[@class="select-all"]', NULL, 'Do not display a "Select all" checkbox when #multiple is FALSE, even when #js_select is TRUE.');
|
||||
$this->assertFalse($this->xpath('//th[@class="select-all"]'));
|
||||
}
|
||||
|
||||
/**
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\system\Functional\Form;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests functionality of \Drupal\Core\Form\FormBuilderInterface::rebuildForm().
|
||||
*
|
||||
* @group Form
|
||||
*/
|
||||
class RebuildTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'form_test'];
|
||||
|
||||
/**
|
||||
* A user for testing.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $webUser;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
|
||||
$this->webUser = $this->drupalCreateUser(['access content']);
|
||||
$this->drupalLogin($this->webUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests preservation of values.
|
||||
*/
|
||||
public function testRebuildPreservesValues() {
|
||||
$edit = [
|
||||
'checkbox_1_default_off' => TRUE,
|
||||
'checkbox_1_default_on' => FALSE,
|
||||
'text_1' => 'foo',
|
||||
];
|
||||
$this->drupalPostForm('form-test/form-rebuild-preserve-values', $edit, 'Add more');
|
||||
|
||||
$assert_session = $this->assertSession();
|
||||
|
||||
// Verify that initial elements retained their submitted values.
|
||||
$assert_session->checkboxChecked('edit-checkbox-1-default-off');
|
||||
$assert_session->checkboxNotChecked('edit-checkbox-1-default-on');
|
||||
$assert_session->fieldValueEquals('edit-text-1', 'foo');
|
||||
|
||||
// Verify that newly added elements were initialized with their default values.
|
||||
$assert_session->checkboxChecked('edit-checkbox-2-default-on');
|
||||
$assert_session->checkboxNotChecked('edit-checkbox-2-default-off');
|
||||
$assert_session->fieldValueEquals('edit-text-2', 'DEFAULT 2');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Form;
|
||||
namespace Drupal\Tests\system\Functional\Form;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests a multistep form using form storage and makes sure validation and
|
||||
|
@ -16,7 +18,7 @@ use Drupal\simpletest\WebTestBase;
|
|||
*
|
||||
* @group Form
|
||||
*/
|
||||
class StorageTest extends WebTestBase {
|
||||
class StorageTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
|
@ -25,6 +27,9 @@ class StorageTest extends WebTestBase {
|
|||
*/
|
||||
public static $modules = ['form_test', 'dblog'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
|
@ -36,25 +41,27 @@ class StorageTest extends WebTestBase {
|
|||
*/
|
||||
public function testForm() {
|
||||
$this->drupalGet('form_test/form-storage');
|
||||
$this->assertText('Form constructions: 1');
|
||||
|
||||
$assert_session = $this->assertSession();
|
||||
$assert_session->pageTextContains('Form constructions: 1');
|
||||
|
||||
$edit = ['title' => 'new', 'value' => 'value_is_set'];
|
||||
|
||||
// Use form rebuilding triggered by a submit button.
|
||||
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
||||
$this->assertText('Form constructions: 2');
|
||||
$this->assertText('Form constructions: 3');
|
||||
$assert_session->pageTextContains('Form constructions: 2');
|
||||
$assert_session->pageTextContains('Form constructions: 3');
|
||||
|
||||
// Reset the form to the values of the storage, using a form rebuild
|
||||
// triggered by button of type button.
|
||||
$this->drupalPostForm(NULL, ['title' => 'changed'], 'Reset');
|
||||
$this->assertFieldByName('title', 'new', 'Values have been reset.');
|
||||
$assert_session->fieldValueEquals('title', 'new');
|
||||
// After rebuilding, the form has been cached.
|
||||
$this->assertText('Form constructions: 4');
|
||||
$assert_session->pageTextContains('Form constructions: 4');
|
||||
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('Form constructions: 4');
|
||||
$this->assertText('Title: new', 'The form storage has stored the values.');
|
||||
$assert_session->pageTextContains('Form constructions: 4');
|
||||
$assert_session->pageTextContains('Title: new', 'The form storage has stored the values.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,26 +69,26 @@ class StorageTest extends WebTestBase {
|
|||
*/
|
||||
public function testFormCached() {
|
||||
$this->drupalGet('form_test/form-storage', ['query' => ['cache' => 1]]);
|
||||
$this->assertText('Form constructions: 1');
|
||||
$this->assertSession()->pageTextContains('Form constructions: 1');
|
||||
|
||||
$edit = ['title' => 'new', 'value' => 'value_is_set'];
|
||||
|
||||
// Use form rebuilding triggered by a submit button.
|
||||
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
||||
// The first one is for the building of the form.
|
||||
$this->assertText('Form constructions: 2');
|
||||
$this->assertSession()->pageTextContains('Form constructions: 2');
|
||||
// The second one is for the rebuilding of the form.
|
||||
$this->assertText('Form constructions: 3');
|
||||
$this->assertSession()->pageTextContains('Form constructions: 3');
|
||||
|
||||
// Reset the form to the values of the storage, using a form rebuild
|
||||
// triggered by button of type button.
|
||||
$this->drupalPostForm(NULL, ['title' => 'changed'], 'Reset');
|
||||
$this->assertFieldByName('title', 'new', 'Values have been reset.');
|
||||
$this->assertText('Form constructions: 4');
|
||||
$this->assertSession()->fieldValueEquals('title', 'new');
|
||||
$this->assertSession()->pageTextContains('Form constructions: 4');
|
||||
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('Form constructions: 4');
|
||||
$this->assertText('Title: new', 'The form storage has stored the values.');
|
||||
$this->assertSession()->pageTextContains('Form constructions: 4');
|
||||
$this->assertSession()->pageTextContains('Title: new', 'The form storage has stored the values.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,7 +131,7 @@ class StorageTest extends WebTestBase {
|
|||
// validation error. Post again and verify that the rebuilt form contains
|
||||
// the values of the updated form storage.
|
||||
$this->drupalPostForm(NULL, ['title' => 'foo', 'value' => 'bar'], 'Save');
|
||||
$this->assertText("The thing has been changed.", 'The altered form storage value was updated in cache and taken over.');
|
||||
$this->assertSession()->pageTextContains("The thing has been changed.", 'The altered form storage value was updated in cache and taken over.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,27 +142,27 @@ class StorageTest extends WebTestBase {
|
|||
// Request the form with 'cache' query parameter to enable form caching.
|
||||
$this->drupalGet('form_test/form-storage', ['query' => ['cache' => 1, 'immutable' => 1]]);
|
||||
$buildIdFields = $this->xpath('//input[@name="form_build_id"]');
|
||||
$this->assertEqual(count($buildIdFields), 1, 'One form build id field on the page');
|
||||
$buildId = (string) $buildIdFields[0]['value'];
|
||||
$this->assertEquals(count($buildIdFields), 1, 'One form build id field on the page');
|
||||
$buildId = $buildIdFields[0]->getValue();
|
||||
|
||||
// Trigger validation error by submitting an empty title.
|
||||
$edit = ['title' => ''];
|
||||
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
||||
|
||||
// Verify that the build-id did change.
|
||||
$this->assertNoFieldByName('form_build_id', $buildId, 'Build id changes when form validation fails');
|
||||
$this->assertSession()->hiddenFieldValueNotEquals('form_build_id', $buildId);
|
||||
|
||||
// Retrieve the new build-id.
|
||||
$buildIdFields = $this->xpath('//input[@name="form_build_id"]');
|
||||
$this->assertEqual(count($buildIdFields), 1, 'One form build id field on the page');
|
||||
$buildId = (string) $buildIdFields[0]['value'];
|
||||
$this->assertEquals(count($buildIdFields), 1, 'One form build id field on the page');
|
||||
$buildId = (string) $buildIdFields[0]->getValue();
|
||||
|
||||
// Trigger validation error by again submitting an empty title.
|
||||
$edit = ['title' => ''];
|
||||
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
||||
|
||||
// Verify that the build-id does not change the second time.
|
||||
$this->assertFieldByName('form_build_id', $buildId, 'Build id remains the same when form validation fails subsequently');
|
||||
$this->assertSession()->hiddenFieldValueEquals('form_build_id', $buildId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,25 +171,28 @@ class StorageTest extends WebTestBase {
|
|||
public function testImmutableFormLegacyProtection() {
|
||||
$this->drupalGet('form_test/form-storage', ['query' => ['cache' => 1, 'immutable' => 1]]);
|
||||
$build_id_fields = $this->xpath('//input[@name="form_build_id"]');
|
||||
$this->assertEqual(count($build_id_fields), 1, 'One form build id field on the page');
|
||||
$build_id = (string) $build_id_fields[0]['value'];
|
||||
$this->assertEquals(count($build_id_fields), 1, 'One form build id field on the page');
|
||||
$build_id = $build_id_fields[0]->getValue();
|
||||
|
||||
// Try to poison the form cache.
|
||||
$original = $this->drupalGetAjax('form-test/form-storage-legacy/' . $build_id);
|
||||
$this->assertEqual($original['form']['#build_id_old'], $build_id, 'Original build_id was recorded');
|
||||
$this->assertNotEqual($original['form']['#build_id'], $build_id, 'New build_id was generated');
|
||||
$response = $this->drupalGet('form-test/form-storage-legacy/' . $build_id, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']], ['X-Requested-With: XMLHttpRequest']);
|
||||
$original = json_decode($response, TRUE);
|
||||
|
||||
$this->assertEquals($original['form']['#build_id_old'], $build_id, 'Original build_id was recorded');
|
||||
$this->assertNotEquals($original['form']['#build_id'], $build_id, 'New build_id was generated');
|
||||
|
||||
// Assert that a watchdog message was logged by
|
||||
// \Drupal::formBuilder()->setCache().
|
||||
$status = (bool) db_query_range('SELECT 1 FROM {watchdog} WHERE message = :message', 0, 1, [':message' => 'Form build-id mismatch detected while attempting to store a form in the cache.']);
|
||||
$this->assert($status, 'A watchdog message was logged by \Drupal::formBuilder()->setCache');
|
||||
$status = (bool) Database::getConnection()->queryRange('SELECT 1 FROM {watchdog} WHERE message = :message', 0, 1, [':message' => 'Form build-id mismatch detected while attempting to store a form in the cache.']);
|
||||
$this->assertTrue($status, 'A watchdog message was logged by \Drupal::formBuilder()->setCache');
|
||||
|
||||
// Ensure that the form state was not poisoned by the preceding call.
|
||||
$original = $this->drupalGetAjax('form-test/form-storage-legacy/' . $build_id);
|
||||
$this->assertEqual($original['form']['#build_id_old'], $build_id, 'Original build_id was recorded');
|
||||
$this->assertNotEqual($original['form']['#build_id'], $build_id, 'New build_id was generated');
|
||||
$this->assert(empty($original['form']['#poisoned']), 'Original form structure was preserved');
|
||||
$this->assert(empty($original['form_state']['poisoned']), 'Original form state was preserved');
|
||||
$response = $this->drupalGet('form-test/form-storage-legacy/' . $build_id, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']], ['X-Requested-With: XMLHttpRequest']);
|
||||
$original = json_decode($response, TRUE);
|
||||
$this->assertEquals($original['form']['#build_id_old'], $build_id, 'Original build_id was recorded');
|
||||
$this->assertNotEquals($original['form']['#build_id'], $build_id, 'New build_id was generated');
|
||||
$this->assertTrue(empty($original['form']['#poisoned']), 'Original form structure was preserved');
|
||||
$this->assertTrue(empty($original['form_state']['poisoned']), 'Original form state was preserved');
|
||||
}
|
||||
|
||||
}
|
|
@ -107,6 +107,32 @@ class MailTest extends BrowserTestBase {
|
|||
$this->assertEquals('Drépal this is a very long test sentence to te <simpletest@example.com>', Unicode::mimeHeaderDecode($sent_message['headers']['From']), 'From header is correctly encoded.');
|
||||
$this->assertFalse(isset($sent_message['headers']['Reply-to']), 'Message reply-to is not set if not specified.');
|
||||
$this->assertFalse(isset($sent_message['headers']['Errors-To']), 'Errors-to header must not be set, it is deprecated.');
|
||||
|
||||
// Test RFC-2822 rules are respected for 'display-name' component of
|
||||
// 'From:' header. Specials characters are not allowed, so randomly add one
|
||||
// of them to the site name and check the string is wrapped in quotes. Also
|
||||
// hardcode some double-quotes and backslash to validate these are escaped
|
||||
// properly too.
|
||||
$specials = '()<>[]:;@\,."';
|
||||
$site_name = 'Drupal' . $specials[rand(0, strlen($specials) - 1)] . ' "si\te"';
|
||||
$this->config('system.site')->set('name', $site_name)->save();
|
||||
// Send an email and check that the From-header contains the site name
|
||||
// within double-quotes. Also make sure double-quotes and "\" are escaped.
|
||||
\Drupal::service('plugin.manager.mail')->mail('simpletest', 'from_test', 'from_test@example.com', $language);
|
||||
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
|
||||
$sent_message = end($captured_emails);
|
||||
$escaped_site_name = str_replace(['\\', '"'], ['\\\\', '\\"'], $site_name);
|
||||
$this->assertEquals('"' . $escaped_site_name . '" <simpletest@example.com>', $sent_message['headers']['From'], 'From header is correctly quoted.');
|
||||
|
||||
// Make sure display-name is not quoted nor escaped if part on an encoding.
|
||||
$site_name = 'Drépal, "si\te"';
|
||||
$this->config('system.site')->set('name', $site_name)->save();
|
||||
// Send an email and check that the From-header contains the site name.
|
||||
\Drupal::service('plugin.manager.mail')->mail('simpletest', 'from_test', 'from_test@example.com', $language);
|
||||
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
|
||||
$sent_message = end($captured_emails);
|
||||
$this->assertEquals('=?UTF-8?B?RHLDqXBhbCwgInNpXHRlIg==?= <simpletest@example.com>', $sent_message['headers']['From'], 'From header is correctly encoded.');
|
||||
$this->assertEquals($site_name . ' <simpletest@example.com>', Unicode::mimeHeaderDecode($sent_message['headers']['From']), 'From header is correctly encoded.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Routing;
|
||||
namespace Drupal\Tests\system\Functional\Routing;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Symfony\Component\Routing\Exception\RouteNotFoundException;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
|
@ -14,7 +14,7 @@ use Drupal\Core\Url;
|
|||
*
|
||||
* @group Routing
|
||||
*/
|
||||
class RouterTest extends WebTestBase {
|
||||
class RouterTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
|
@ -34,69 +34,72 @@ class RouterTest extends WebTestBase {
|
|||
$this->drupalGet('router_test/test1');
|
||||
$this->assertRaw('test1', 'The correct string was returned because the route was successful.');
|
||||
// Check expected headers from FinishResponseSubscriber.
|
||||
$headers = $this->drupalGetHeaders();
|
||||
$this->assertEqual($headers['x-ua-compatible'], 'IE=edge');
|
||||
$this->assertEqual($headers['content-language'], 'en');
|
||||
$this->assertEqual($headers['x-content-type-options'], 'nosniff');
|
||||
$this->assertEqual($headers['x-frame-options'], 'SAMEORIGIN');
|
||||
$headers = $this->getSession()->getResponseHeaders();
|
||||
|
||||
$this->assertEquals($headers['X-UA-Compatible'], ['IE=edge']);
|
||||
$this->assertEquals($headers['Content-language'], ['en']);
|
||||
$this->assertEquals($headers['X-Content-Type-Options'], ['nosniff']);
|
||||
$this->assertEquals($headers['X-Frame-Options'], ['SAMEORIGIN']);
|
||||
|
||||
$this->drupalGet('router_test/test2');
|
||||
$this->assertRaw('test2', 'The correct string was returned because the route was successful.');
|
||||
// Check expected headers from FinishResponseSubscriber.
|
||||
$headers = $this->drupalGetHeaders();
|
||||
$this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', $expected_cache_contexts));
|
||||
$this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous http_response rendered');
|
||||
$this->assertEqual($headers['X-Drupal-Cache-Contexts'], [implode(' ', $expected_cache_contexts)]);
|
||||
$this->assertEqual($headers['X-Drupal-Cache-Tags'], ['config:user.role.anonymous http_response rendered']);
|
||||
// Confirm that the page wrapping is being added, so we're not getting a
|
||||
// raw body returned.
|
||||
$this->assertRaw('</html>', 'Page markup was found.');
|
||||
// In some instances, the subrequest handling may get confused and render
|
||||
// a page inception style. This test verifies that is not happening.
|
||||
$this->assertNoPattern('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
|
||||
$this->assertSession()->responseNotMatches('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
|
||||
|
||||
// Confirm that route-level access check's cacheability is applied to the
|
||||
// X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags headers.
|
||||
// 1. controller result: render array, globally cacheable route access.
|
||||
$this->drupalGet('router_test/test18');
|
||||
$headers = $this->drupalGetHeaders();
|
||||
$this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url'])));
|
||||
$this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo http_response rendered');
|
||||
$this->assertEqual($headers['X-Drupal-Cache-Contexts'], [implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url']))]);
|
||||
$this->assertEqual($headers['X-Drupal-Cache-Tags'], ['config:user.role.anonymous foo http_response rendered']);
|
||||
// 2. controller result: render array, per-role cacheable route access.
|
||||
$this->drupalGet('router_test/test19');
|
||||
$headers = $this->drupalGetHeaders();
|
||||
$this->assertEqual($headers['x-drupal-cache-contexts'], implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url', 'user.roles'])));
|
||||
$this->assertEqual($headers['x-drupal-cache-tags'], 'config:user.role.anonymous foo http_response rendered');
|
||||
$this->assertEqual($headers['X-Drupal-Cache-Contexts'], [implode(' ', Cache::mergeContexts($renderer_required_cache_contexts, ['url', 'user.roles']))]);
|
||||
$this->assertEqual($headers['X-Drupal-Cache-Tags'], ['config:user.role.anonymous foo http_response rendered']);
|
||||
// 3. controller result: Response object, globally cacheable route access.
|
||||
$this->drupalGet('router_test/test1');
|
||||
$headers = $this->drupalGetHeaders();
|
||||
$this->assertFalse(isset($headers['x-drupal-cache-contexts']));
|
||||
$this->assertFalse(isset($headers['x-drupal-cache-tags']));
|
||||
$this->assertFalse(isset($headers['X-Drupal-Cache-Contexts']));
|
||||
$this->assertFalse(isset($headers['X-Drupal-Cache-Tags']));
|
||||
// 4. controller result: Response object, per-role cacheable route access.
|
||||
$this->drupalGet('router_test/test20');
|
||||
$headers = $this->drupalGetHeaders();
|
||||
$this->assertFalse(isset($headers['x-drupal-cache-contexts']));
|
||||
$this->assertFalse(isset($headers['x-drupal-cache-tags']));
|
||||
$this->assertFalse(isset($headers['X-Drupal-Cache-Contexts']));
|
||||
$this->assertFalse(isset($headers['X-Drupal-Cache-Tags']));
|
||||
// 5. controller result: CacheableResponse object, globally cacheable route access.
|
||||
$this->drupalGet('router_test/test21');
|
||||
$headers = $this->drupalGetHeaders();
|
||||
$this->assertEqual($headers['x-drupal-cache-contexts'], '');
|
||||
$this->assertEqual($headers['x-drupal-cache-tags'], 'http_response');
|
||||
$this->assertEqual($headers['X-Drupal-Cache-Contexts'], ['']);
|
||||
$this->assertEqual($headers['X-Drupal-Cache-Tags'], ['http_response']);
|
||||
// 6. controller result: CacheableResponse object, per-role cacheable route access.
|
||||
$this->drupalGet('router_test/test22');
|
||||
$headers = $this->drupalGetHeaders();
|
||||
$this->assertEqual($headers['x-drupal-cache-contexts'], 'user.roles');
|
||||
$this->assertEqual($headers['x-drupal-cache-tags'], 'http_response');
|
||||
$this->assertEqual($headers['X-Drupal-Cache-Contexts'], ['user.roles']);
|
||||
$this->assertEqual($headers['X-Drupal-Cache-Tags'], ['http_response']);
|
||||
|
||||
// Finally, verify that the X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags
|
||||
// headers are not sent when their container parameter is set to FALSE.
|
||||
$this->drupalGet('router_test/test18');
|
||||
$headers = $this->drupalGetHeaders();
|
||||
$this->assertTrue(isset($headers['x-drupal-cache-contexts']));
|
||||
$this->assertTrue(isset($headers['x-drupal-cache-tags']));
|
||||
$this->setHttpResponseDebugCacheabilityHeaders(FALSE);
|
||||
$this->assertTrue(isset($headers['X-Drupal-Cache-Contexts']));
|
||||
$this->assertTrue(isset($headers['X-Drupal-Cache-Tags']));
|
||||
$this->setContainerParameter('http.response.debug_cacheability_headers', FALSE);
|
||||
$this->rebuildContainer();
|
||||
$this->resetAll();
|
||||
$this->drupalGet('router_test/test18');
|
||||
$headers = $this->drupalGetHeaders();
|
||||
$this->assertFalse(isset($headers['x-drupal-cache-contexts']));
|
||||
$this->assertFalse(isset($headers['x-drupal-cache-tags']));
|
||||
$this->assertFalse(isset($headers['X-Drupal-Cache-Contexts']));
|
||||
$this->assertFalse(isset($headers['X-Drupal-Cache-Tags']));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,7 +148,7 @@ class RouterTest extends WebTestBase {
|
|||
|
||||
// In some instances, the subrequest handling may get confused and render
|
||||
// a page inception style. This test verifies that is not happening.
|
||||
$this->assertNoPattern('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
|
||||
$this->assertSession()->responseNotMatches('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,7 +165,7 @@ class RouterTest extends WebTestBase {
|
|||
|
||||
// In some instances, the subrequest handling may get confused and render
|
||||
// a page inception style. This test verifies that is not happening.
|
||||
$this->assertNoPattern('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
|
||||
$this->assertSession()->responseNotMatches('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,7 +182,7 @@ class RouterTest extends WebTestBase {
|
|||
|
||||
// In some instances, the subrequest handling may get confused and render
|
||||
// a page inception style. This test verifies that is not happening.
|
||||
$this->assertNoPattern('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
|
||||
$this->assertSession()->responseNotMatches('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -208,7 +211,7 @@ class RouterTest extends WebTestBase {
|
|||
|
||||
// In some instances, the subrequest handling may get confused and render
|
||||
// a page inception style. This test verifies that is not happening.
|
||||
$this->assertNoPattern('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
|
||||
$this->assertSession()->responseNotMatches('#</body>.*</body>#s', 'There was no double-page effect from a misrendered subrequest.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -277,7 +280,9 @@ class RouterTest extends WebTestBase {
|
|||
public function testControllerResolutionAjax() {
|
||||
// This will fail with a JSON parse error if the request is not routed to
|
||||
// The correct controller.
|
||||
$this->drupalGetAjax('/router_test/test10');
|
||||
$options['query'][MainContentViewSubscriber::WRAPPER_FORMAT] = 'drupal_ajax';
|
||||
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
||||
$this->drupalGet('/router_test/test10', $options, $headers);
|
||||
|
||||
$this->assertEqual($this->drupalGetHeader('Content-Type'), 'application/json', 'Correct mime content type was returned');
|
||||
|
||||
|
@ -311,21 +316,18 @@ class RouterTest extends WebTestBase {
|
|||
$request = $this->container->get('request_stack')->getCurrentRequest();
|
||||
$url = $request->getUriForPath('//router_test/test1');
|
||||
$this->drupalGet($url);
|
||||
$this->assertEqual(1, $this->redirectCount, $url . " redirected to " . $this->url);
|
||||
$this->assertUrl($request->getUriForPath('/router_test/test1'));
|
||||
|
||||
// It should not matter how many leading slashes are used and query strings
|
||||
// should be preserved.
|
||||
$url = $request->getUriForPath('/////////////////////////////////////////////////router_test/test1') . '?qs=test';
|
||||
$this->drupalGet($url);
|
||||
$this->assertEqual(1, $this->redirectCount, $url . " redirected to " . $this->url);
|
||||
$this->assertUrl($request->getUriForPath('/router_test/test1') . '?qs=test');
|
||||
|
||||
// Ensure that external URLs in destination query params are not redirected
|
||||
// to.
|
||||
$url = $request->getUriForPath('/////////////////////////////////////////////////router_test/test1') . '?qs=test&destination=http://www.example.com%5c@drupal8alt.test';
|
||||
$this->drupalGet($url);
|
||||
$this->assertEqual(1, $this->redirectCount, $url . " redirected to " . $this->url);
|
||||
$this->assertUrl($request->getUriForPath('/router_test/test1') . '?qs=test');
|
||||
}
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Session;
|
||||
namespace Drupal\Tests\system\Functional\Session;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\basic_auth\Tests\BasicAuthTestTrait;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Tests\basic_auth\Traits\BasicAuthTestTrait;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests if sessions are correctly handled when a user authenticates.
|
||||
*
|
||||
* @group Session
|
||||
*/
|
||||
class SessionAuthenticationTest extends WebTestBase {
|
||||
class SessionAuthenticationTest extends BrowserTestBase {
|
||||
|
||||
use BasicAuthTestTrait;
|
||||
|
||||
|
@ -52,20 +52,22 @@ class SessionAuthenticationTest extends WebTestBase {
|
|||
|
||||
// Test that the route is not accessible as an anonymous user.
|
||||
$this->drupalGet($protected_url);
|
||||
$session = $this->getSession();
|
||||
$this->assertResponse(401, 'An anonymous user cannot access a route protected with basic authentication.');
|
||||
|
||||
// We should be able to access the route with basic authentication.
|
||||
$this->basicAuthGet($protected_url, $this->user->getUsername(), $this->user->pass_raw);
|
||||
$this->basicAuthGet($protected_url, $this->user->getAccountName(), $this->user->passRaw);
|
||||
$this->assertResponse(200, 'A route protected with basic authentication can be accessed by an authenticated user.');
|
||||
|
||||
// Check that the correct user is logged in.
|
||||
$this->assertEqual($this->user->id(), json_decode($this->getRawContent())->user, 'The correct user is authenticated on a route with basic authentication.');
|
||||
$this->assertEqual($this->user->id(), json_decode($session->getPage()->getContent())->user, 'The correct user is authenticated on a route with basic authentication.');
|
||||
$session->restart();
|
||||
|
||||
// If we now try to access a page without basic authentication then we
|
||||
// should no longer be logged in.
|
||||
$this->drupalGet($unprotected_url);
|
||||
$this->assertResponse(200, 'An unprotected route can be accessed without basic authentication.');
|
||||
$this->assertFalse(json_decode($this->getRawContent())->user, 'The user is no longer authenticated after visiting a page without basic authentication.');
|
||||
$this->assertFalse(json_decode($session->getPage()->getContent())->user, 'The user is no longer authenticated after visiting a page without basic authentication.');
|
||||
|
||||
// If we access the protected page again without basic authentication we
|
||||
// should get 401 Unauthorized.
|
||||
|
@ -113,20 +115,24 @@ class SessionAuthenticationTest extends WebTestBase {
|
|||
$no_cookie_url = Url::fromRoute('session_test.get_session_basic_auth');
|
||||
|
||||
// A route that is authorized with standard cookie authentication.
|
||||
$cookie_url = '<front>';
|
||||
$cookie_url = 'user/login';
|
||||
|
||||
// If we authenticate with a third party authentication system then no
|
||||
// session cookie should be set, the third party system is responsible for
|
||||
// sustaining the session.
|
||||
$this->basicAuthGet($no_cookie_url, $this->user->getUsername(), $this->user->pass_raw);
|
||||
$this->basicAuthGet($no_cookie_url, $this->user->getAccountName(), $this->user->passRaw);
|
||||
$this->assertResponse(200, 'The user is successfully authenticated using basic authentication.');
|
||||
$this->assertFalse($this->drupalGetHeader('set-cookie', TRUE), 'No cookie is set on a route protected with basic authentication.');
|
||||
$this->assertEmpty($this->getSessionCookies());
|
||||
// Mink stores some information in the session that breaks the next check if
|
||||
// not reset.
|
||||
$this->getSession()->restart();
|
||||
|
||||
// On the other hand, authenticating using Cookie sets a cookie.
|
||||
$edit = ['name' => $this->user->getUsername(), 'pass' => $this->user->pass_raw];
|
||||
$this->drupalGet($cookie_url);
|
||||
$this->assertEmpty($this->getSessionCookies());
|
||||
$edit = ['name' => $this->user->getAccountName(), 'pass' => $this->user->passRaw];
|
||||
$this->drupalPostForm($cookie_url, $edit, t('Log in'));
|
||||
$this->assertResponse(200, 'The user is successfully authenticated using cookie authentication.');
|
||||
$this->assertTrue($this->drupalGetHeader('set-cookie', TRUE), 'A cookie is set on a route protected with cookie authentication.');
|
||||
$this->assertNotEmpty($this->getSessionCookies());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Session;
|
||||
namespace Drupal\Tests\system\Functional\Session;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Drupal session handling tests.
|
||||
*
|
||||
* @group Session
|
||||
*/
|
||||
class SessionTest extends WebTestBase {
|
||||
class SessionTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
|
@ -36,12 +36,15 @@ class SessionTest extends WebTestBase {
|
|||
$user = $this->drupalCreateUser();
|
||||
|
||||
// Enable sessions.
|
||||
$this->sessionReset($user->id());
|
||||
$this->sessionReset();
|
||||
|
||||
// Make sure the session cookie is set as HttpOnly.
|
||||
$this->drupalLogin($user);
|
||||
// Make sure the session cookie is set as HttpOnly. We can only test this in
|
||||
// the header, with the test setup
|
||||
// \GuzzleHttp\Cookie\SetCookie::getHttpOnly() always returns FALSE.
|
||||
// Start a new session by setting a message.
|
||||
$this->drupalGet('session-test/set-message');
|
||||
$this->assertSessionCookie(TRUE);
|
||||
$this->assertTrue(preg_match('/HttpOnly/i', $this->drupalGetHeader('Set-Cookie', TRUE)), 'Session cookie is set as HttpOnly.');
|
||||
$this->drupalLogout();
|
||||
|
||||
// Verify that the session is regenerated if a module calls exit
|
||||
// in hook_user_login().
|
||||
|
@ -49,15 +52,15 @@ class SessionTest extends WebTestBase {
|
|||
$user->save();
|
||||
$this->drupalGet('session-test/id');
|
||||
$matches = [];
|
||||
preg_match('/\s*session_id:(.*)\n/', $this->getRawContent(), $matches);
|
||||
preg_match('/\s*session_id:(.*)\n/', $this->getSession()->getPage()->getContent(), $matches);
|
||||
$this->assertTrue(!empty($matches[1]), 'Found session ID before logging in.');
|
||||
$original_session = $matches[1];
|
||||
|
||||
// We cannot use $this->drupalLogin($user); because we exit in
|
||||
// session_test_user_login() which breaks a normal assertion.
|
||||
$edit = [
|
||||
'name' => $user->getUsername(),
|
||||
'pass' => $user->pass_raw,
|
||||
'name' => $user->getAccountName(),
|
||||
'pass' => $user->passRaw,
|
||||
];
|
||||
$this->drupalPostForm('user/login', $edit, t('Log in'));
|
||||
$this->drupalGet('user');
|
||||
|
@ -66,7 +69,7 @@ class SessionTest extends WebTestBase {
|
|||
|
||||
$this->drupalGet('session-test/id');
|
||||
$matches = [];
|
||||
preg_match('/\s*session_id:(.*)\n/', $this->getRawContent(), $matches);
|
||||
preg_match('/\s*session_id:(.*)\n/', $this->getSession()->getPage()->getContent(), $matches);
|
||||
$this->assertTrue(!empty($matches[1]), 'Found session ID after logging in.');
|
||||
$this->assertTrue($matches[1] != $original_session, 'Session ID changed after login.');
|
||||
}
|
||||
|
@ -91,14 +94,22 @@ class SessionTest extends WebTestBase {
|
|||
// properly, val_1 will still be set.
|
||||
$value_2 = $this->randomMachineName();
|
||||
$this->drupalGet('session-test/no-set/' . $value_2);
|
||||
$session = $this->getSession();
|
||||
$this->assertText($value_2, 'The session value was correctly passed to session-test/no-set.', 'Session');
|
||||
$this->drupalGet('session-test/get');
|
||||
$this->assertText($value_1, 'Session data is not saved for drupal_save_session(FALSE).', 'Session');
|
||||
|
||||
// Switch browser cookie to anonymous user, then back to user 1.
|
||||
$this->sessionReset();
|
||||
$this->sessionReset($user->id());
|
||||
$session_cookie_name = $this->getSessionName();
|
||||
$session_cookie_value = $session->getCookie($session_cookie_name);
|
||||
$session->restart();
|
||||
$this->initFrontPage();
|
||||
// Session restart always resets all the cookies by design, so we need to
|
||||
// add the old session cookie again.
|
||||
$session->setCookie($session_cookie_name, $session_cookie_value);
|
||||
$this->drupalGet('session-test/get');
|
||||
$this->assertText($value_1, 'Session data persists through browser close.', 'Session');
|
||||
$this->mink->setDefaultSessionName('default');
|
||||
|
||||
// Logout the user and make sure the stored value no longer persists.
|
||||
$this->drupalLogout();
|
||||
|
@ -242,8 +253,6 @@ class SessionTest extends WebTestBase {
|
|||
$this->assertEqual($times4->timestamp, $times3->timestamp, 'Sessions table was not updated.');
|
||||
|
||||
// Force updating of users and sessions table once per second.
|
||||
$this->settingsSet('session_write_interval', 0);
|
||||
// Write that value also into the test settings.php file.
|
||||
$settings['settings']['session_write_interval'] = (object) [
|
||||
'value' => 0,
|
||||
'required' => TRUE,
|
||||
|
@ -270,8 +279,7 @@ class SessionTest extends WebTestBase {
|
|||
// Send a blank sid in the session cookie, and the session should no longer
|
||||
// be valid. Closing the curl handler will stop the previous session ID
|
||||
// from persisting.
|
||||
$this->curlClose();
|
||||
$this->additionalCurlOptions[CURLOPT_COOKIE] = rawurlencode($this->getSessionName()) . '=;';
|
||||
$this->mink->resetSessions();
|
||||
$this->drupalGet('session-test/id-from-cookie');
|
||||
$this->assertRaw("session_id:\n", 'Session ID is blank as sent from cookie header.');
|
||||
// Assert that we have an anonymous session now.
|
||||
|
@ -281,19 +289,13 @@ class SessionTest extends WebTestBase {
|
|||
|
||||
/**
|
||||
* Reset the cookie file so that it refers to the specified user.
|
||||
*
|
||||
* @param $uid
|
||||
* User id to set as the active session.
|
||||
*/
|
||||
public function sessionReset($uid = 0) {
|
||||
public function sessionReset() {
|
||||
// Close the internal browser.
|
||||
$this->curlClose();
|
||||
$this->mink->resetSessions();
|
||||
$this->loggedInUser = FALSE;
|
||||
|
||||
// Change cookie file for user.
|
||||
$this->cookieFile = \Drupal::service('stream_wrapper_manager')->getViaScheme('temporary')->getDirectoryPath() . '/cookie.' . $uid . '.txt';
|
||||
$this->additionalCurlOptions[CURLOPT_COOKIEFILE] = $this->cookieFile;
|
||||
$this->additionalCurlOptions[CURLOPT_COOKIESESSION] = TRUE;
|
||||
$this->drupalGet('session-test/get');
|
||||
$this->assertResponse(200, 'Session test module is correctly enabled.', 'Session');
|
||||
}
|
||||
|
@ -303,10 +305,10 @@ class SessionTest extends WebTestBase {
|
|||
*/
|
||||
public function assertSessionCookie($sent) {
|
||||
if ($sent) {
|
||||
$this->assertNotNull($this->sessionId, 'Session cookie was sent.');
|
||||
$this->assertNotEmpty($this->getSessionCookies()->count(), 'Session cookie was sent.');
|
||||
}
|
||||
else {
|
||||
$this->assertNull($this->sessionId, 'Session cookie was not sent.');
|
||||
$this->assertEmpty($this->getSessionCookies()->count(), 'Session cookie was not sent.');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\system\Functional\Session;
|
||||
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the stacked session handler functionality.
|
||||
*
|
||||
* @group Session
|
||||
*/
|
||||
class StackSessionHandlerIntegrationTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['session_test'];
|
||||
|
||||
/**
|
||||
* Tests a request.
|
||||
*/
|
||||
public function testRequest() {
|
||||
$options['query'][MainContentViewSubscriber::WRAPPER_FORMAT] = 'drupal_ajax';
|
||||
$headers[] = 'X-Requested-With: XMLHttpRequest';
|
||||
$actual_trace = json_decode($this->drupalGet('session-test/trace-handler', $options, $headers));
|
||||
$sessionId = $this->getSessionCookies()->getCookieByName($this->getSessionName())->getValue();
|
||||
$expect_trace = [
|
||||
['BEGIN', 'test_argument', 'open'],
|
||||
['BEGIN', NULL, 'open'],
|
||||
['END', NULL, 'open'],
|
||||
['END', 'test_argument', 'open'],
|
||||
['BEGIN', 'test_argument', 'read', $sessionId],
|
||||
['BEGIN', NULL, 'read', $sessionId],
|
||||
['END', NULL, 'read', $sessionId],
|
||||
['END', 'test_argument', 'read', $sessionId],
|
||||
['BEGIN', 'test_argument', 'write', $sessionId],
|
||||
['BEGIN', NULL, 'write', $sessionId],
|
||||
['END', NULL, 'write', $sessionId],
|
||||
['END', 'test_argument', 'write', $sessionId],
|
||||
['BEGIN', 'test_argument', 'close'],
|
||||
['BEGIN', NULL, 'close'],
|
||||
['END', NULL, 'close'],
|
||||
['END', 'test_argument', 'close'],
|
||||
];
|
||||
$this->assertEqual($expect_trace, $actual_trace);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
namespace Drupal\Tests\system\Functional\System;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Performs tests on the Drupal error and exception handler.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class ErrorHandlerTest extends WebTestBase {
|
||||
class ErrorHandlerTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
|
@ -42,17 +42,6 @@ class ErrorHandlerTest extends WebTestBase {
|
|||
'%function' => 'Drupal\error_test\Controller\ErrorTestController->generateWarnings()',
|
||||
'%file' => drupal_get_path('module', 'error_test') . '/error_test.module',
|
||||
];
|
||||
$fatal_error = [
|
||||
'%type' => 'Recoverable fatal error',
|
||||
'%function' => 'Drupal\error_test\Controller\ErrorTestController->Drupal\error_test\Controller\{closure}()',
|
||||
'@message' => 'Argument 1 passed to Drupal\error_test\Controller\ErrorTestController::Drupal\error_test\Controller\{closure}() must be of the type array, string given, called in ' . \Drupal::root() . '/core/modules/system/tests/modules/error_test/src/Controller/ErrorTestController.php on line 62 and defined',
|
||||
];
|
||||
if (version_compare(PHP_VERSION, '7.0.0-dev') >= 0) {
|
||||
// In PHP 7, instead of a recoverable fatal error we get a TypeError.
|
||||
$fatal_error['%type'] = 'TypeError';
|
||||
// The error message also changes in PHP 7.
|
||||
$fatal_error['@message'] = 'Argument 1 passed to Drupal\error_test\Controller\ErrorTestController::Drupal\error_test\Controller\{closure}() must be of the type array, string given, called in ' . \Drupal::root() . '/core/modules/system/tests/modules/error_test/src/Controller/ErrorTestController.php on line 62';
|
||||
}
|
||||
|
||||
// Set error reporting to display verbose notices.
|
||||
$this->config('system.logging')->set('error_level', ERROR_REPORTING_DISPLAY_VERBOSE)->save();
|
||||
|
@ -68,25 +57,6 @@ class ErrorHandlerTest extends WebTestBase {
|
|||
|
||||
// Set error reporting to display verbose notices.
|
||||
$this->config('system.logging')->set('error_level', ERROR_REPORTING_DISPLAY_VERBOSE)->save();
|
||||
$this->drupalGet('error-test/generate-fatals');
|
||||
$this->assertResponse(500, 'Received expected HTTP status code.');
|
||||
$this->assertErrorMessage($fatal_error);
|
||||
$this->assertRaw('<pre class="backtrace">', 'Found pre element with backtrace class.');
|
||||
// Ensure we are escaping but not double escaping.
|
||||
$this->assertRaw(''');
|
||||
$this->assertNoRaw('&#039;');
|
||||
|
||||
// Remove the recoverable fatal error from the assertions, it's wanted here.
|
||||
// Ensure that we just remove this one recoverable fatal error (in PHP 7 this
|
||||
// is a TypeError).
|
||||
foreach ($this->assertions as $key => $assertion) {
|
||||
if (in_array($assertion['message_group'], ['Recoverable fatal error', 'TypeError']) && strpos($assertion['message'], 'Argument 1 passed to Drupal\error_test\Controller\ErrorTestController::Drupal\error_test\Controller\{closure}() must be of the type array, string given, called in') !== FALSE) {
|
||||
unset($this->assertions[$key]);
|
||||
$this->deleteAssert($assertion['message_id']);
|
||||
}
|
||||
}
|
||||
// Drop the single exception.
|
||||
$this->results['#exception']--;
|
||||
|
||||
// Set error reporting to collect notices.
|
||||
$config->set('error_level', ERROR_REPORTING_DISPLAY_ALL)->save();
|
||||
|
@ -96,7 +66,6 @@ class ErrorHandlerTest extends WebTestBase {
|
|||
$this->assertErrorMessage($error_warning);
|
||||
$this->assertErrorMessage($error_user_notice);
|
||||
$this->assertNoRaw('<pre class="backtrace">', 'Did not find pre element with backtrace class.');
|
||||
$this->assertErrorLogged($fatal_error['@message']);
|
||||
|
||||
// Set error reporting to not collect notices.
|
||||
$config->set('error_level', ERROR_REPORTING_DISPLAY_SOME)->save();
|
||||
|
@ -122,9 +91,6 @@ class ErrorHandlerTest extends WebTestBase {
|
|||
* Test the exception handler.
|
||||
*/
|
||||
public function testExceptionHandler() {
|
||||
// Ensure the test error log is empty before these tests.
|
||||
$this->assertNoErrorsLogged();
|
||||
|
||||
$error_exception = [
|
||||
'%type' => 'Exception',
|
||||
'@message' => 'Drupal & awesome',
|
||||
|
@ -148,11 +114,11 @@ class ErrorHandlerTest extends WebTestBase {
|
|||
];
|
||||
|
||||
$this->drupalGet('error-test/trigger-exception');
|
||||
$this->assertTrue(strpos($this->drupalGetHeader(':status'), '500 Service unavailable (with message)'), 'Received expected HTTP status line.');
|
||||
$this->assertSession()->statusCodeEquals(500);
|
||||
$this->assertErrorMessage($error_exception);
|
||||
|
||||
$this->drupalGet('error-test/trigger-pdo-exception');
|
||||
$this->assertTrue(strpos($this->drupalGetHeader(':status'), '500 Service unavailable (with message)'), 'Received expected HTTP status line.');
|
||||
$this->assertSession()->statusCodeEquals(500);
|
||||
// We cannot use assertErrorMessage() since the exact error reported
|
||||
// varies from database to database. Check that the SQL string is displayed.
|
||||
$this->assertText($error_pdo_exception['%type'], format_string('Found %type in error page.', $error_pdo_exception));
|
||||
|
@ -161,7 +127,7 @@ class ErrorHandlerTest extends WebTestBase {
|
|||
$this->assertRaw($error_details, format_string("Found '@message' in error page.", ['@message' => $error_details]));
|
||||
|
||||
$this->drupalGet('error-test/trigger-renderer-exception');
|
||||
$this->assertTrue(strpos($this->drupalGetHeader(':status'), '500 Service unavailable (with message)'), 'Received expected HTTP status line.');
|
||||
$this->assertSession()->statusCodeEquals(500);
|
||||
$this->assertErrorMessage($error_renderer_exception);
|
||||
|
||||
// Disable error reporting, ensure that 5xx responses are not cached.
|
||||
|
@ -172,12 +138,8 @@ class ErrorHandlerTest extends WebTestBase {
|
|||
$this->drupalGet('error-test/trigger-exception');
|
||||
$this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'));
|
||||
$this->assertIdentical(strpos($this->drupalGetHeader('Cache-Control'), 'public'), FALSE, 'Received expected HTTP status line.');
|
||||
$this->assertTrue(strpos($this->drupalGetHeader(':status'), '500 Service unavailable (with message)'), 'Received expected HTTP status line.');
|
||||
$this->assertSession()->statusCodeEquals(500);
|
||||
$this->assertNoErrorMessage($error_exception);
|
||||
|
||||
// The exceptions are expected. Do not interpret them as a test failure.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
|
||||
}
|
||||
|
||||
/**
|
|
@ -94,7 +94,11 @@ class ThemeTest extends BrowserTestBase {
|
|||
$config->set('css.preprocess', 0);
|
||||
$config->save();
|
||||
$this->drupalGet('theme-test/suggestion');
|
||||
$this->assertNoText('js.module.css', 'The theme\'s .info.yml file is able to override a module CSS file from being added to the page.');
|
||||
// We add a "?" to the assertion, because drupalSettings may include
|
||||
// information about the file; we only really care about whether it appears
|
||||
// in a LINK or STYLE tag, for which Drupal always adds a query string for
|
||||
// cache control.
|
||||
$this->assertSession()->responseNotContains('js.module.css?');
|
||||
|
||||
// Also test with aggregation enabled, simply ensuring no PHP errors are
|
||||
// triggered during drupal_build_css_cache() when a source file doesn't
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\system\FunctionalJavascript\Form;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the tableselect form element for expected behavior.
|
||||
*
|
||||
* @group Form
|
||||
*/
|
||||
class ElementsTableSelectTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['form_test'];
|
||||
|
||||
/**
|
||||
* Test the presence of ajax functionality for all options.
|
||||
*/
|
||||
public function testAjax() {
|
||||
// Test checkboxes (#multiple == TRUE).
|
||||
$this->drupalGet('form_test/tableselect/multiple-true');
|
||||
$session = $this->getSession();
|
||||
$page = $session->getPage();
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$row = 'row' . $i;
|
||||
$page->hasUncheckedField($row);
|
||||
$page->checkField($row);
|
||||
$this->assertSession()->assertWaitOnAjaxRequest();
|
||||
// Check current row and previous rows are checked.
|
||||
for ($j = 1; $j <= $i; $j++) {
|
||||
$other_row = 'row' . $j;
|
||||
$page->hasCheckedField($other_row);
|
||||
}
|
||||
}
|
||||
|
||||
// Test radios (#multiple == FALSE).
|
||||
$this->drupalGet('form_test/tableselect/multiple-false');
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
$row = 'input[value="row' . $i . '"]';
|
||||
$page->hasUncheckedField($row);
|
||||
$this->click($row);
|
||||
$this->assertSession()->assertWaitOnAjaxRequest();
|
||||
$page->hasCheckedField($row);
|
||||
// Check other rows are not checked
|
||||
for ($j = 1; $j <= 3; $j++) {
|
||||
if ($j == $i) {
|
||||
continue;
|
||||
}
|
||||
$other_row = 'edit-tableselect-row' . $j;
|
||||
$page->hasUncheckedField($other_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Form;
|
||||
namespace Drupal\Tests\system\FunctionalJavascript\Form;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests functionality of \Drupal\Core\Form\FormBuilderInterface::rebuildForm().
|
||||
|
@ -14,14 +14,12 @@ use Drupal\field\Entity\FieldStorageConfig;
|
|||
* @group Form
|
||||
* @todo Add tests for other aspects of form rebuilding.
|
||||
*/
|
||||
class RebuildTest extends WebTestBase {
|
||||
class RebuildTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node', 'form_test'];
|
||||
protected static $modules = ['node', 'form_test'];
|
||||
|
||||
/**
|
||||
* A user for testing.
|
||||
|
@ -30,6 +28,9 @@ class RebuildTest extends WebTestBase {
|
|||
*/
|
||||
protected $webUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
|
@ -39,28 +40,6 @@ class RebuildTest extends WebTestBase {
|
|||
$this->drupalLogin($this->webUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests preservation of values.
|
||||
*/
|
||||
public function testRebuildPreservesValues() {
|
||||
$edit = [
|
||||
'checkbox_1_default_off' => TRUE,
|
||||
'checkbox_1_default_on' => FALSE,
|
||||
'text_1' => 'foo',
|
||||
];
|
||||
$this->drupalPostForm('form-test/form-rebuild-preserve-values', $edit, 'Add more');
|
||||
|
||||
// Verify that initial elements retained their submitted values.
|
||||
$this->assertFieldChecked('edit-checkbox-1-default-off', 'A submitted checked checkbox retained its checked state during a rebuild.');
|
||||
$this->assertNoFieldChecked('edit-checkbox-1-default-on', 'A submitted unchecked checkbox retained its unchecked state during a rebuild.');
|
||||
$this->assertFieldById('edit-text-1', 'foo', 'A textfield retained its submitted value during a rebuild.');
|
||||
|
||||
// Verify that newly added elements were initialized with their default values.
|
||||
$this->assertFieldChecked('edit-checkbox-2-default-on', 'A newly added checkbox was initialized with a default checked state.');
|
||||
$this->assertNoFieldChecked('edit-checkbox-2-default-off', 'A newly added checkbox was initialized with a default unchecked state.');
|
||||
$this->assertFieldById('edit-text-2', 'DEFAULT 2', 'A newly added textfield was initialized with its default value.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a form's action is retained after an Ajax submission.
|
||||
*
|
||||
|
@ -68,6 +47,7 @@ class RebuildTest extends WebTestBase {
|
|||
* followed by a non-Ajax submission, which triggers a validation error.
|
||||
*/
|
||||
public function testPreserveFormActionAfterAJAX() {
|
||||
$page = $this->getSession()->getPage();
|
||||
// Create a multi-valued field for 'page' nodes to use for Ajax testing.
|
||||
$field_name = 'field_ajax_test';
|
||||
FieldStorageConfig::create([
|
||||
|
@ -81,8 +61,26 @@ class RebuildTest extends WebTestBase {
|
|||
'entity_type' => 'node',
|
||||
'bundle' => 'page',
|
||||
])->save();
|
||||
|
||||
// Also create a file field to test server side validation error.
|
||||
$field_file_name = 'field_file_test';
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => $field_file_name,
|
||||
'entity_type' => 'node',
|
||||
'type' => 'file',
|
||||
'cardinality' => 1,
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'field_name' => $field_file_name,
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'page',
|
||||
'label' => 'Test file',
|
||||
'required' => TRUE,
|
||||
])->save();
|
||||
|
||||
entity_get_form_display('node', 'page', 'default')
|
||||
->setComponent($field_name, ['type' => 'text_textfield'])
|
||||
->setComponent($field_file_name, ['type' => 'file_generic'])
|
||||
->save();
|
||||
|
||||
// Log in a user who can create 'page' nodes.
|
||||
|
@ -93,27 +91,31 @@ class RebuildTest extends WebTestBase {
|
|||
// submission and verify it worked by ensuring the updated page has two text
|
||||
// field items in the field for which we just added an item.
|
||||
$this->drupalGet('node/add/page');
|
||||
$this->drupalPostAjaxForm(NULL, [], ['field_ajax_test_add_more' => t('Add another item')], NULL, [], [], 'node-page-form');
|
||||
$this->assert(count($this->xpath('//div[contains(@class, "field--name-field-ajax-test")]//input[@type="text"]')) == 2, 'AJAX submission succeeded.');
|
||||
$page->find('css', '[value="Add another item"]')->click();
|
||||
$this->assertSession()->assertWaitOnAjaxRequest();
|
||||
$this->assertTrue(count($this->xpath('//div[contains(@class, "field--name-field-ajax-test")]//input[@type="text"]')) == 2, 'AJAX submission succeeded.');
|
||||
|
||||
// Submit the form with the non-Ajax "Save" button, leaving the title field
|
||||
// Submit the form with the non-Ajax "Save" button, leaving the file field
|
||||
// blank to trigger a validation error, and ensure that a validation error
|
||||
// occurred, because this test is for testing what happens when a form is
|
||||
// re-rendered without being re-built, which is what happens when there's
|
||||
// a validation error.
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
$this->assertText('Title field is required.', 'Non-AJAX submission correctly triggered a validation error.');
|
||||
// a server side validation error.
|
||||
$edit = [
|
||||
'title[0][value]' => $this->randomString(),
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertSession()->pageTextContains('Test file field is required.', 'Non-AJAX submission correctly triggered a validation error.');
|
||||
|
||||
// Ensure that the form contains two items in the multi-valued field, so we
|
||||
// know we're testing a form that was correctly retrieved from cache.
|
||||
$this->assert(count($this->xpath('//form[contains(@id, "node-page-form")]//div[contains(@class, "js-form-item-field-ajax-test")]//input[@type="text"]')) == 2, 'Form retained its state from cache.');
|
||||
$this->assertTrue(count($this->xpath('//form[contains(@id, "node-page-form")]//div[contains(@class, "js-form-item-field-ajax-test")]//input[@type="text"]')) == 2, 'Form retained its state from cache.');
|
||||
|
||||
// Ensure that the form's action is correct.
|
||||
$forms = $this->xpath('//form[contains(@class, "node-page-form")]');
|
||||
$this->assertEqual(1, count($forms));
|
||||
$this->assertEquals(1, count($forms));
|
||||
// Strip query params off the action before asserting.
|
||||
$url = parse_url($forms[0]['action'])['path'];
|
||||
$this->assertEqual(Url::fromRoute('node.add', ['node_type' => 'page'])->toString(), $url);
|
||||
$url = parse_url($forms[0]->getAttribute('action'))['path'];
|
||||
$this->assertEquals(Url::fromRoute('node.add', ['node_type' => 'page'])->toString(), $url);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\system\FunctionalJavascript\Form;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests that FAPI correctly determines the triggering element.
|
||||
*
|
||||
* @group Form
|
||||
*/
|
||||
class TriggeringElementTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['form_test'];
|
||||
|
||||
/**
|
||||
* Tests the the triggering element when no button information is included.
|
||||
*
|
||||
* Test the determination of the triggering element when no button
|
||||
* information is included in the POST data, as is sometimes the case when
|
||||
* the ENTER key is pressed in a textfield in Internet Explorer.
|
||||
*/
|
||||
public function testNoButtonInfoInPost() {
|
||||
$path = '/form-test/clicked-button';
|
||||
$form_html_id = 'form-test-clicked-button';
|
||||
|
||||
// Ensure submitting a form with no buttons results in no triggering element
|
||||
// and the form submit handler not running.
|
||||
$this->drupalGet($path);
|
||||
|
||||
$assert_session = $this->assertSession();
|
||||
$this->getSession()->getDriver()->submitForm('//form[@id="' . $form_html_id . '"]');
|
||||
$assert_session->pageTextContains('There is no clicked button.');
|
||||
$assert_session->pageTextNotContains('Submit handler for form_test_clicked_button executed.');
|
||||
|
||||
// Ensure submitting a form with one or more submit buttons results in the
|
||||
// triggering element being set to the first one the user has access to. An
|
||||
// argument with 'r' in it indicates a restricted (#access=FALSE) button.
|
||||
$this->drupalGet($path . '/s');
|
||||
$this->getSession()->getDriver()->submitForm('//form[@id="' . $form_html_id . '"]');
|
||||
$assert_session->pageTextContains('The clicked button is button1.');
|
||||
$assert_session->pageTextContains('Submit handler for form_test_clicked_button executed.');
|
||||
|
||||
$this->drupalGet($path . '/s/s');
|
||||
$this->getSession()->getDriver()->submitForm('//form[@id="' . $form_html_id . '"]');
|
||||
$assert_session->pageTextContains('The clicked button is button1.');
|
||||
$assert_session->pageTextContains('Submit handler for form_test_clicked_button executed.');
|
||||
|
||||
$this->drupalGet($path . '/rs/s');
|
||||
$this->getSession()->getDriver()->submitForm('//form[@id="' . $form_html_id . '"]');
|
||||
$assert_session->pageTextContains('The clicked button is button2.');
|
||||
$assert_session->pageTextContains('Submit handler for form_test_clicked_button executed.');
|
||||
|
||||
// Ensure submitting a form with buttons of different types results in the
|
||||
// triggering element being set to the first button, regardless of type. For
|
||||
// the FAPI 'button' type, this should result in the submit handler not
|
||||
// executing. The types are 's'(ubmit), 'b'(utton), and 'i'(mage_button).
|
||||
$this->drupalGet($path . '/s/b/i');
|
||||
$this->getSession()->getDriver()->submitForm('//form[@id="' . $form_html_id . '"]');
|
||||
$assert_session->pageTextContains('The clicked button is button1.');
|
||||
$assert_session->pageTextContains('Submit handler for form_test_clicked_button executed.');
|
||||
|
||||
$this->drupalGet($path . '/b/s/i');
|
||||
$this->getSession()->getDriver()->submitForm('//form[@id="' . $form_html_id . '"]');
|
||||
$assert_session->pageTextContains('The clicked button is button1.');
|
||||
$assert_session->pageTextNotContains('Submit handler for form_test_clicked_button executed.');
|
||||
|
||||
$this->drupalGet($path . '/i/s/b');
|
||||
$this->getSession()->getDriver()->submitForm('//form[@id="' . $form_html_id . '"]');
|
||||
$assert_session->pageTextContains('The clicked button is button1.');
|
||||
$assert_session->pageTextContains('Submit handler for form_test_clicked_button executed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests attempts to bypass access control.
|
||||
*
|
||||
* Test that the triggering element does not get set to a button with
|
||||
* #access=FALSE.
|
||||
*/
|
||||
public function testAttemptAccessControlBypass() {
|
||||
$path = 'form-test/clicked-button';
|
||||
$form_html_id = 'form-test-clicked-button';
|
||||
|
||||
// Retrieve a form where 'button1' has #access=FALSE and 'button2' doesn't.
|
||||
$this->drupalGet($path . '/rs/s');
|
||||
|
||||
// Submit the form with 'button1=button1' in the POST data, which someone
|
||||
// trying to get around security safeguards could easily do. We have to do
|
||||
// a little trickery here, to work around the safeguards in drupalPostForm()
|
||||
// by renaming the text field and value that is in the form to 'button1',
|
||||
// we can get the data we want into \Drupal::request()->request.
|
||||
$page = $this->getSession()->getPage();
|
||||
$input = $page->find('css', 'input[name="text"]');
|
||||
$this->assertNotNull($input, 'text input located.');
|
||||
|
||||
$input->setValue('name', 'button1');
|
||||
$input->setValue('value', 'button1');
|
||||
$this->xpath('//form[@id="' . $form_html_id . '"]//input[@type="submit"]')[0]->click();
|
||||
|
||||
// Ensure that the triggering element was not set to the restricted button.
|
||||
// Do this with both a negative and positive assertion, because negative
|
||||
// assertions alone can be brittle. See testNoButtonInfoInPost() for why the
|
||||
// triggering element gets set to 'button2'.
|
||||
$this->assertSession()->pageTextNotContains('The clicked button is button1.');
|
||||
$this->assertSession()->pageTextContains('The clicked button is button2.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\system\FunctionalJavascript;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
|
||||
/**
|
||||
* Tests the off-canvas dialog functionality.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class FrameworkTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['node', 'ajax_test', 'ajax_forms_test'];
|
||||
|
||||
/**
|
||||
* Tests that new JavaScript and CSS files are lazy-loaded on an AJAX request.
|
||||
*/
|
||||
public function testLazyLoad() {
|
||||
$expected = [
|
||||
'setting_name' => 'ajax_forms_test_lazy_load_form_submit',
|
||||
'setting_value' => 'executed',
|
||||
'library_1' => 'system/admin',
|
||||
'library_2' => 'system/drupal.system',
|
||||
];
|
||||
|
||||
// Get the base page.
|
||||
$this->drupalGet('ajax_forms_test_lazy_load_form');
|
||||
$page = $this->getSession()->getPage();
|
||||
$assert = $this->assertSession();
|
||||
|
||||
$original_settings = $this->getDrupalSettings();
|
||||
$original_libraries = explode(',', $original_settings['ajaxPageState']['libraries']);
|
||||
|
||||
// Verify that the base page doesn't have the settings and files that are to
|
||||
// be lazy loaded as part of the next requests.
|
||||
$this->assertTrue(!isset($original_settings[$expected['setting_name']]), format_string('Page originally lacks the %setting, as expected.', ['%setting' => $expected['setting_name']]));
|
||||
$this->assertTrue(!in_array($expected['library_1'], $original_libraries), format_string('Page originally lacks the %library library, as expected.', ['%library' => $expected['library_1']]));
|
||||
$this->assertTrue(!in_array($expected['library_2'], $original_libraries), format_string('Page originally lacks the %library library, as expected.', ['%library' => $expected['library_2']]));
|
||||
|
||||
// Submit the AJAX request without triggering files getting added.
|
||||
$page->pressButton('Submit');
|
||||
$assert->assertWaitOnAjaxRequest();
|
||||
$new_settings = $this->getDrupalSettings();
|
||||
$new_libraries = explode(',', $new_settings['ajaxPageState']['libraries']);
|
||||
|
||||
// Verify the setting was not added when not expected.
|
||||
$this->assertTrue(!isset($new_settings[$expected['setting_name']]), format_string('Page still lacks the %setting, as expected.', ['%setting' => $expected['setting_name']]));
|
||||
$this->assertTrue(!in_array($expected['library_1'], $new_libraries), format_string('Page still lacks the %library library, as expected.', ['%library' => $expected['library_1']]));
|
||||
$this->assertTrue(!in_array($expected['library_2'], $new_libraries), format_string('Page still lacks the %library library, as expected.', ['%library' => $expected['library_2']]));
|
||||
|
||||
// Submit the AJAX request and trigger adding files.
|
||||
$page->checkField('add_files');
|
||||
$page->pressButton('Submit');
|
||||
$assert->assertWaitOnAjaxRequest();
|
||||
$new_settings = $this->getDrupalSettings();
|
||||
$new_libraries = explode(',', $new_settings['ajaxPageState']['libraries']);
|
||||
|
||||
// Verify the expected setting was added, both to drupalSettings, and as
|
||||
// the first AJAX command.
|
||||
$this->assertIdentical($new_settings[$expected['setting_name']], $expected['setting_value'], format_string('Page now has the %setting.', ['%setting' => $expected['setting_name']]));
|
||||
|
||||
// Verify the expected CSS file was added, both to drupalSettings, and as
|
||||
// the second AJAX command for inclusion into the HTML.
|
||||
$this->assertTrue(in_array($expected['library_1'], $new_libraries), format_string('Page state now has the %library library.', ['%library' => $expected['library_1']]));
|
||||
|
||||
// Verify the expected JS file was added, both to drupalSettings, and as
|
||||
// the third AJAX command for inclusion into the HTML. By testing for an
|
||||
// exact HTML string containing the SCRIPT tag, we also ensure that
|
||||
// unexpected JavaScript code, such as a jQuery.extend() that would
|
||||
// potentially clobber rather than properly merge settings, didn't
|
||||
// accidentally get added.
|
||||
$this->assertTrue(in_array($expected['library_2'], $new_libraries), format_string('Page state now has the %library library.', ['%library' => $expected['library_2']]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that drupalSettings.currentPath is not updated on AJAX requests.
|
||||
*/
|
||||
public function testCurrentPathChange() {
|
||||
$this->drupalGet('ajax_forms_test_lazy_load_form');
|
||||
$page = $this->getSession()->getPage();
|
||||
$assert = $this->assertSession();
|
||||
|
||||
$old_settings = $this->getDrupalSettings();
|
||||
$page->pressButton('Submit');
|
||||
$assert->assertWaitOnAjaxRequest();
|
||||
$new_settings = $this->getDrupalSettings();
|
||||
$this->assertEquals($old_settings['path']['currentPath'], $new_settings['path']['currentPath']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that overridden CSS files are not added during lazy load.
|
||||
*/
|
||||
public function testLazyLoadOverriddenCSS() {
|
||||
// The test theme overrides js.module.css without an implementation,
|
||||
// thereby removing it.
|
||||
\Drupal::service('theme_handler')->install(['test_theme']);
|
||||
$this->config('system.theme')
|
||||
->set('default', 'test_theme')
|
||||
->save();
|
||||
|
||||
// This gets the form, and does an Ajax submission on it.
|
||||
$this->drupalGet('ajax_forms_test_lazy_load_form');
|
||||
$page = $this->getSession()->getPage();
|
||||
$assert = $this->assertSession();
|
||||
|
||||
$page->checkField('add_files');
|
||||
$page->pressButton('Submit');
|
||||
$assert->assertWaitOnAjaxRequest();
|
||||
|
||||
// Verify that the resulting HTML does not load the overridden CSS file.
|
||||
// We add a "?" to the assertion, because drupalSettings may include
|
||||
// information about the file; we only really care about whether it appears
|
||||
// in a LINK or STYLE tag, for which Drupal always adds a query string for
|
||||
// cache control.
|
||||
$assert->responseNotContains('js.module.css?', 'Ajax lazy loading does not add overridden CSS files.');
|
||||
}
|
||||
|
||||
}
|
|
@ -233,11 +233,11 @@ class ModuleHandlerTest extends KernelTestBase {
|
|||
$result = $this->moduleInstaller()->uninstall([$non_dependency]);
|
||||
$this->assertTrue($result, 'ModuleInstaller::uninstall() returns TRUE.');
|
||||
$this->assertFalse($this->moduleHandler()->moduleExists($non_dependency));
|
||||
$this->assertEquals(drupal_get_installed_schema_version($non_dependency), SCHEMA_UNINSTALLED, "$dependency module was uninstalled.");
|
||||
$this->assertEquals(drupal_get_installed_schema_version($non_dependency), SCHEMA_UNINSTALLED, "$non_dependency module was uninstalled.");
|
||||
|
||||
// Verify that the installation profile itself was not uninstalled.
|
||||
$uninstalled_modules = \Drupal::state()->get('module_test.uninstall_order') ?: [];
|
||||
$this->assertContains($non_dependency, $uninstalled_modules, "$dependency module is in the list of uninstalled modules.");
|
||||
$this->assertContains($non_dependency, $uninstalled_modules, "$non_dependency module is in the list of uninstalled modules.");
|
||||
$this->assertNotContains($profile, $uninstalled_modules, 'The installation profile is not in the list of uninstalled modules.');
|
||||
|
||||
// Try uninstalling the required module.
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\system\Kernel\Form;
|
||||
|
||||
use Drupal\form_test\Form\FormTestFileForm;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests for the 'file' form element.
|
||||
*
|
||||
* @group Form
|
||||
*/
|
||||
class FileElementTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['form_test'];
|
||||
|
||||
/**
|
||||
* Tests that file elements are built and processed correctly.
|
||||
*/
|
||||
public function testFileElement() {
|
||||
$form = $this->container->get('form_builder')
|
||||
->getForm(FormTestFileForm::class);
|
||||
|
||||
$this->assertSame('file', $form['file']['#type']);
|
||||
$this->assertTrue($form['file']['#multiple']);
|
||||
$this->assertContains('cagatio', $form['file']['#attributes']['class']);
|
||||
}
|
||||
|
||||
}
|
|
@ -16,7 +16,7 @@ base theme: classy
|
|||
core: 8.x
|
||||
logo: images/logo2.svg
|
||||
stylesheets-remove:
|
||||
- '@system/css/js.module.css'
|
||||
- '@stable/css/system/components/js.module.css'
|
||||
libraries:
|
||||
- test_theme/global-styling
|
||||
libraries-override:
|
||||
|
|
|
@ -10,3 +10,9 @@ test_theme_settings.settings:
|
|||
sequence:
|
||||
type: integer
|
||||
label: 'fids'
|
||||
multi_file:
|
||||
type: sequence
|
||||
label: 'Multiple file field with all file extensions'
|
||||
sequence:
|
||||
type: integer
|
||||
label: 'fids'
|
||||
|
|
|
@ -24,6 +24,17 @@ function test_theme_settings_form_system_theme_settings_alter(&$form, FormStateI
|
|||
],
|
||||
];
|
||||
|
||||
$form['multi_file'] = [
|
||||
'#type' => 'managed_file',
|
||||
'#title' => t('Multiple file field with all file extensions'),
|
||||
'#multiple' => TRUE,
|
||||
'#default_value' => theme_get_setting('multi_file'),
|
||||
'#upload_location' => 'public://test',
|
||||
'#upload_validators' => [
|
||||
'file_validate_extensions' => [],
|
||||
],
|
||||
];
|
||||
|
||||
$form['#submit'][] = 'test_theme_settings_form_system_theme_settings_submit';
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue