Core and composer updates
This commit is contained in:
parent
a82634bb98
commit
62cac30480
1118 changed files with 21770 additions and 6306 deletions
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalJavascriptTests\Ajax;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||
|
||||
/**
|
||||
* Performs tests on AJAX forms in cached pages.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxFormPageCacheTest extends JavascriptTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['ajax_test', 'ajax_forms_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$config = $this->config('system.performance');
|
||||
$config->set('cache.page.max_age', 300);
|
||||
$config->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the build id of the current form.
|
||||
*/
|
||||
protected function getFormBuildId() {
|
||||
$build_id_fields = $this->xpath('//input[@name="form_build_id"]');
|
||||
$this->assertEquals(count($build_id_fields), 1, 'One form build id field on the page');
|
||||
return $build_id_fields[0]->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simple form, then submit the form via AJAX to change to it.
|
||||
*/
|
||||
public function testSimpleAJAXFormValue() {
|
||||
$this->drupalGet('ajax_forms_test_get_form');
|
||||
$this->assertEquals($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
|
||||
$build_id_initial = $this->getFormBuildId();
|
||||
|
||||
// Changing the value of a select input element, triggers a AJAX
|
||||
// request/response. The callback on the form responds with three AJAX
|
||||
// commands:
|
||||
// - UpdateBuildIdCommand
|
||||
// - HtmlCommand
|
||||
// - DataCommand
|
||||
$session = $this->getSession();
|
||||
$session->getPage()->selectFieldOption('select', 'green');
|
||||
|
||||
// Wait for the DOM to update. The HtmlCommand will update
|
||||
// #ajax_selected_color to reflect the color change.
|
||||
$green_div = $this->assertSession()->waitForElement('css', "#ajax_selected_color div:contains('green')");
|
||||
$this->assertNotNull($green_div, 'DOM update: The selected color DIV is green.');
|
||||
|
||||
// Confirm the operation of the UpdateBuildIdCommand.
|
||||
$build_id_first_ajax = $this->getFormBuildId();
|
||||
$this->assertNotEquals($build_id_initial, $build_id_first_ajax, 'Build id is changed in the form_build_id element on first AJAX submission');
|
||||
|
||||
// Changing the value of a select input element, triggers a AJAX
|
||||
// request/response.
|
||||
$session->getPage()->selectFieldOption('select', 'red');
|
||||
|
||||
// Wait for the DOM to update.
|
||||
$red_div = $this->assertSession()->waitForElement('css', "#ajax_selected_color div:contains('red')");
|
||||
$this->assertNotNull($red_div, 'DOM update: The selected color DIV is red.');
|
||||
|
||||
// Confirm the operation of the UpdateBuildIdCommand.
|
||||
$build_id_second_ajax = $this->getFormBuildId();
|
||||
$this->assertNotEquals($build_id_first_ajax, $build_id_second_ajax, 'Build id changes on subsequent AJAX submissions');
|
||||
|
||||
// Emulate a push of the reload button and then repeat the test sequence
|
||||
// this time with a page loaded from the cache.
|
||||
$session->reload();
|
||||
$this->assertEquals($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
|
||||
$build_id_from_cache_initial = $this->getFormBuildId();
|
||||
$this->assertEquals($build_id_initial, $build_id_from_cache_initial, 'Build id is the same as on the first request');
|
||||
|
||||
// Changing the value of a select input element, triggers a AJAX
|
||||
// request/response.
|
||||
$session->getPage()->selectFieldOption('select', 'green');
|
||||
|
||||
// Wait for the DOM to update.
|
||||
$green_div2 = $this->assertSession()->waitForElement('css', "#ajax_selected_color div:contains('green')");
|
||||
$this->assertNotNull($green_div2, 'DOM update: After reload - the selected color DIV is green.');
|
||||
|
||||
$build_id_from_cache_first_ajax = $this->getFormBuildId();
|
||||
$this->assertNotEquals($build_id_from_cache_initial, $build_id_from_cache_first_ajax, 'Build id is changed in the simpletest-DOM on first AJAX submission');
|
||||
$this->assertNotEquals($build_id_first_ajax, $build_id_from_cache_first_ajax, 'Build id from first user is not reused');
|
||||
|
||||
// Changing the value of a select input element, triggers a AJAX
|
||||
// request/response.
|
||||
$session->getPage()->selectFieldOption('select', 'red');
|
||||
|
||||
// Wait for the DOM to update.
|
||||
$red_div2 = $this->assertSession()->waitForElement('css', "#ajax_selected_color div:contains('red')");
|
||||
$this->assertNotNull($red_div2, 'DOM update: After reload - the selected color DIV is red.');
|
||||
|
||||
$build_id_from_cache_second_ajax = $this->getFormBuildId();
|
||||
$this->assertNotEquals($build_id_from_cache_first_ajax, $build_id_from_cache_second_ajax, 'Build id changes on subsequent AJAX submissions');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that updating the text field trigger an AJAX request/response.
|
||||
*
|
||||
* @see \Drupal\system\Tests\Ajax\ElementValidationTest::testAjaxElementValidation()
|
||||
*/
|
||||
public function testAjaxElementValidation() {
|
||||
$this->drupalGet('ajax_validation_test');
|
||||
// Changing the value of the textfield will trigger an AJAX
|
||||
// request/response.
|
||||
$this->getSession()->getPage()->fillField('drivertext', 'some dumb text');
|
||||
|
||||
// When the AJAX command updates the DOM a <ul> unsorted list
|
||||
// "message__list" structure will appear on the page echoing back the
|
||||
// "some dumb text" message.
|
||||
$placeholder = $this->assertSession()->waitForElement('css', "ul.messages__list li.messages__item em:contains('some dumb text')");
|
||||
$this->assertNotNull($placeholder, 'Message structure containing input data located.');
|
||||
}
|
||||
|
||||
}
|
|
@ -152,9 +152,9 @@ class BrowserTestBaseTest extends BrowserTestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests legacy field asserts.
|
||||
* Tests legacy field asserts which use xpath directly.
|
||||
*/
|
||||
public function testLegacyFieldAsserts() {
|
||||
public function testLegacyXpathAsserts() {
|
||||
$this->drupalGet('test-field-xpath');
|
||||
$this->assertFieldsByValue($this->xpath("//h1[@class = 'page-title']"), NULL);
|
||||
$this->assertFieldsByValue($this->xpath('//table/tbody/tr[2]/td[1]'), 'one');
|
||||
|
@ -168,6 +168,73 @@ class BrowserTestBaseTest extends BrowserTestBase {
|
|||
$this->assertNoFieldByXPath('//notexisting');
|
||||
$this->assertNoFieldByXPath("//input[@id = 'edit-name']", 'wrong value');
|
||||
|
||||
// Test that the assertion fails correctly.
|
||||
try {
|
||||
$this->assertFieldByXPath("//input[@id = 'notexisting']");
|
||||
$this->fail('The "notexisting" field was found.');
|
||||
}
|
||||
catch (\PHPUnit_Framework_ExpectationFailedException $e) {
|
||||
$this->pass('assertFieldByXPath correctly failed. The "notexisting" field was not found.');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->assertNoFieldByXPath("//input[@id = 'edit-name']");
|
||||
$this->fail('The "edit-name" field was not found.');
|
||||
}
|
||||
catch (\PHPUnit_Framework_ExpectationFailedException $e) {
|
||||
$this->pass('assertNoFieldByXPath correctly failed. The "edit-name" field was found.');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->assertFieldsByValue($this->xpath("//input[@id = 'edit-name']"), 'not the value');
|
||||
$this->fail('The "edit-name" field is found with the value "not the value".');
|
||||
}
|
||||
catch (\PHPUnit_Framework_ExpectationFailedException $e) {
|
||||
$this->pass('The "edit-name" field is not found with the value "not the value".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests legacy field asserts using textfields.
|
||||
*/
|
||||
public function testLegacyFieldAssertsWithTextfields() {
|
||||
$this->drupalGet('test-field-xpath');
|
||||
|
||||
// *** 1. assertNoField().
|
||||
$this->assertNoField('invalid_name_and_id');
|
||||
|
||||
// Test that the assertion fails correctly when searching by name.
|
||||
try {
|
||||
$this->assertNoField('name');
|
||||
$this->fail('The "name" field was not found based on name.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('assertNoField correctly failed. The "name" field was found by name.');
|
||||
}
|
||||
|
||||
// Test that the assertion fails correctly when searching by id.
|
||||
try {
|
||||
$this->assertNoField('edit-name');
|
||||
$this->fail('The "name" field was not found based on id.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('assertNoField correctly failed. The "name" field was found by id.');
|
||||
}
|
||||
|
||||
// *** 2. assertField().
|
||||
$this->assertField('name');
|
||||
$this->assertField('edit-name');
|
||||
|
||||
// Test that the assertion fails correctly if the field does not exist.
|
||||
try {
|
||||
$this->assertField('invalid_name_and_id');
|
||||
$this->fail('The "invalid_name_and_id" field was found.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('assertField correctly failed. The "invalid_name_and_id" field was not found.');
|
||||
}
|
||||
|
||||
// *** 3. assertNoFieldById().
|
||||
$this->assertNoFieldById('name');
|
||||
$this->assertNoFieldById('name', 'not the value');
|
||||
$this->assertNoFieldById('notexisting');
|
||||
|
@ -191,6 +258,7 @@ class BrowserTestBaseTest extends BrowserTestBase {
|
|||
$this->pass('The "name" field was found.');
|
||||
}
|
||||
|
||||
// *** 4. assertFieldById().
|
||||
$this->assertFieldById('edit-name', NULL);
|
||||
$this->assertFieldById('edit-name', 'Test name');
|
||||
$this->assertFieldById('edit-description', NULL);
|
||||
|
@ -205,15 +273,16 @@ class BrowserTestBaseTest extends BrowserTestBase {
|
|||
$this->pass('The "edit-name" field with no value was not found.');
|
||||
}
|
||||
|
||||
// Test that the assertion fails correctly if NULL is passed in.
|
||||
// Test that the assertion fails correctly if the wrong value is passed in.
|
||||
try {
|
||||
$this->assertFieldById('name', NULL);
|
||||
$this->fail('The "name" field was found.');
|
||||
$this->assertFieldById('edit-name', 'not the value');
|
||||
$this->fail('The "name" field was found, using the wrong value.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('The "name" field was not found.');
|
||||
catch (\PHPUnit_Framework_ExpectationFailedException $e) {
|
||||
$this->pass('The "name" field was not found, using the wrong value.');
|
||||
}
|
||||
|
||||
// *** 5. assertNoFieldByName().
|
||||
$this->assertNoFieldByName('name');
|
||||
$this->assertNoFieldByName('name', 'not the value');
|
||||
$this->assertNoFieldByName('notexisting');
|
||||
|
@ -237,6 +306,40 @@ class BrowserTestBaseTest extends BrowserTestBase {
|
|||
$this->pass('The "name" field was found.');
|
||||
}
|
||||
|
||||
// *** 6. assertFieldByName().
|
||||
$this->assertFieldByName('name');
|
||||
$this->assertFieldByName('name', NULL);
|
||||
$this->assertFieldByName('name', 'Test name');
|
||||
$this->assertFieldByName('description');
|
||||
$this->assertFieldByName('description', '');
|
||||
$this->assertFieldByName('description', NULL);
|
||||
|
||||
// Test that the assertion fails correctly if given the wrong name.
|
||||
try {
|
||||
$this->assertFieldByName('non-existing-name');
|
||||
$this->fail('The "non-existing-name" field was found.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('The "non-existing-name" field was not found');
|
||||
}
|
||||
|
||||
// Test that the assertion fails correctly if given the wrong value.
|
||||
try {
|
||||
$this->assertFieldByName('name', 'not the value');
|
||||
$this->fail('The "name" field with incorrect value was found.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('assertFieldByName correctly failed. The "name" field with incorrect value was not found.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests legacy field asserts on other types of field.
|
||||
*/
|
||||
public function testLegacyFieldAssertsWithNonTextfields() {
|
||||
$this->drupalGet('test-field-xpath');
|
||||
|
||||
// Option field type.
|
||||
$this->assertOptionByText('options', 'one');
|
||||
try {
|
||||
$this->assertOptionByText('options', 'four');
|
||||
|
@ -246,6 +349,42 @@ class BrowserTestBaseTest extends BrowserTestBase {
|
|||
$this->pass($e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertOption('options', 1);
|
||||
try {
|
||||
$this->assertOption('options', 4);
|
||||
$this->fail('The select option "4" was found.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass($e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertNoOption('options', 'non-existing');
|
||||
try {
|
||||
$this->assertNoOption('options', 'one');
|
||||
$this->fail('The select option "one" was not found.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass($e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertOptionSelected('options', 2);
|
||||
try {
|
||||
$this->assertOptionSelected('options', 4);
|
||||
$this->fail('The select option "4" was selected.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass($e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$this->assertOptionSelected('options', 1);
|
||||
$this->fail('The select option "1" was selected.');
|
||||
}
|
||||
catch (\PHPUnit_Framework_ExpectationFailedException $e) {
|
||||
$this->pass($e->getMessage());
|
||||
}
|
||||
|
||||
// Button field type.
|
||||
$this->assertFieldById('edit-save', NULL);
|
||||
// Test that the assertion fails correctly if the field value is passed in
|
||||
// rather than the id.
|
||||
|
@ -267,6 +406,81 @@ class BrowserTestBaseTest extends BrowserTestBase {
|
|||
catch (ExpectationException $e) {
|
||||
$this->pass($e->getMessage());
|
||||
}
|
||||
|
||||
// Checkbox field type.
|
||||
// Test that checkboxes are found/not found correctly by name, when using
|
||||
// TRUE or FALSE to match their 'checked' state.
|
||||
$this->assertFieldByName('checkbox_enabled', TRUE);
|
||||
$this->assertFieldByName('checkbox_disabled', FALSE);
|
||||
$this->assertNoFieldByName('checkbox_enabled', FALSE);
|
||||
$this->assertNoFieldByName('checkbox_disabled', TRUE);
|
||||
|
||||
// Test that checkboxes are found by name when using NULL to ignore the
|
||||
// 'checked' state.
|
||||
$this->assertFieldByName('checkbox_enabled', NULL);
|
||||
$this->assertFieldByName('checkbox_disabled', NULL);
|
||||
|
||||
// Test that checkboxes are found/not found correctly by ID, when using
|
||||
// TRUE or FALSE to match their 'checked' state.
|
||||
$this->assertFieldById('edit-checkbox-enabled', TRUE);
|
||||
$this->assertFieldById('edit-checkbox-disabled', FALSE);
|
||||
$this->assertNoFieldById('edit-checkbox-enabled', FALSE);
|
||||
$this->assertNoFieldById('edit-checkbox-disabled', TRUE);
|
||||
|
||||
// Test that checkboxes are found by by ID, when using NULL to ignore the
|
||||
// 'checked' state.
|
||||
$this->assertFieldById('edit-checkbox-enabled', NULL);
|
||||
$this->assertFieldById('edit-checkbox-disabled', NULL);
|
||||
|
||||
// Test that the assertion fails correctly when using NULL to ignore state.
|
||||
try {
|
||||
$this->assertNoFieldByName('checkbox_enabled', NULL);
|
||||
$this->fail('The "checkbox_enabled" field was not found by name, using NULL value.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('assertNoFieldByName failed correctly. The "checkbox_enabled" field was found using NULL value.');
|
||||
}
|
||||
|
||||
// Test that the assertion fails correctly when using NULL to ignore state.
|
||||
try {
|
||||
$this->assertNoFieldById('edit-checkbox-disabled', NULL);
|
||||
$this->fail('The "edit-checkbox-disabled" field was not found by ID, using NULL value.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('assertNoFieldById failed correctly. The "edit-checkbox-disabled" field was found by ID using NULL value.');
|
||||
}
|
||||
|
||||
// Test the specific 'checked' assertions.
|
||||
$this->assertFieldChecked('edit-checkbox-enabled');
|
||||
$this->assertNoFieldChecked('edit-checkbox-disabled');
|
||||
|
||||
// Test that the assertion fails correctly with non-existant field id.
|
||||
try {
|
||||
$this->assertNoFieldChecked('incorrect_checkbox_id');
|
||||
$this->fail('The "incorrect_checkbox_id" field was found');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('assertNoFieldChecked correctly failed. The "incorrect_checkbox_id" field was not found.');
|
||||
}
|
||||
|
||||
// Test that the assertion fails correctly for a checkbox that is checked.
|
||||
try {
|
||||
$this->assertNoFieldChecked('edit-checkbox-enabled');
|
||||
$this->fail('The "edit-checkbox-enabled" field was not found in a checked state.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('assertNoFieldChecked correctly failed. The "edit-checkbox-enabled" field was found in a checked state.');
|
||||
}
|
||||
|
||||
// Test that the assertion fails correctly for a checkbox that is not
|
||||
// checked.
|
||||
try {
|
||||
$this->assertFieldChecked('edit-checkbox-disabled');
|
||||
$this->fail('The "edit-checkbox-disabled" field was found and checked.');
|
||||
}
|
||||
catch (ExpectationException $e) {
|
||||
$this->pass('assertFieldChecked correctly failed. The "edit-checkbox-disabled" field was not found in a checked state.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\FunctionalTests\HttpKernel;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests CORS provided by Drupal.
|
||||
*
|
||||
* @see sites/default/default.services.yml
|
||||
* @see \Asm89\Stack\Cors
|
||||
* @see \Asm89\Stack\CorsService
|
||||
*
|
||||
* @group Http
|
||||
*/
|
||||
class CorsIntegrationTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['system', 'test_page_test', 'page_cache'];
|
||||
|
||||
public function testCrossSiteRequest() {
|
||||
// Test default parameters.
|
||||
$cors_config = $this->container->getParameter('cors.config');
|
||||
$this->assertSame(FALSE, $cors_config['enabled']);
|
||||
$this->assertSame([], $cors_config['allowedHeaders']);
|
||||
$this->assertSame([], $cors_config['allowedMethods']);
|
||||
$this->assertSame(['*'], $cors_config['allowedOrigins']);
|
||||
|
||||
$this->assertSame(FALSE, $cors_config['exposedHeaders']);
|
||||
$this->assertSame(FALSE, $cors_config['maxAge']);
|
||||
$this->assertSame(FALSE, $cors_config['supportsCredentials']);
|
||||
|
||||
// Enable CORS with the default options.
|
||||
$cors_config['enabled'] = TRUE;
|
||||
|
||||
$this->setContainerParameter('cors.config', $cors_config);
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Fire off a request.
|
||||
$this->drupalGet('/test-page', [], ['Origin' => 'http://example.com']);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'MISS');
|
||||
$this->assertSession()->responseHeaderEquals('Access-Control-Allow-Origin', 'http://example.com');
|
||||
|
||||
// Fire the same exact request. This time it should be cached.
|
||||
$this->drupalGet('/test-page', [], ['Origin' => 'http://example.com']);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
|
||||
$this->assertSession()->responseHeaderEquals('Access-Control-Allow-Origin', 'http://example.com');
|
||||
|
||||
// Fire a request for a different origin. Verify the CORS header.
|
||||
$this->drupalGet('/test-page', [], ['Origin' => 'http://example.org']);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->responseHeaderEquals('X-Drupal-Cache', 'HIT');
|
||||
$this->assertSession()->responseHeaderEquals('Access-Control-Allow-Origin', 'http://example.org');
|
||||
|
||||
// Configure the CORS stack to allow a specific set of origins.
|
||||
$cors_config['allowedOrigins'] = ['http://example.com'];
|
||||
|
||||
$this->setContainerParameter('cors.config', $cors_config);
|
||||
$this->rebuildContainer();
|
||||
|
||||
// Fire a request from an origin that isn't allowed.
|
||||
/** @var \Symfony\Component\HttpFoundation\Response $response */
|
||||
$this->drupalGet('/test-page', [], ['Origin' => 'http://non-valid.com']);
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
$this->assertSession()->pageTextContains('Not allowed.');
|
||||
|
||||
// Specify a valid origin.
|
||||
$this->drupalGet('/test-page', [], ['Origin' => 'http://example.com']);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->responseHeaderEquals('Access-Control-Allow-Origin', 'http://example.com');
|
||||
}
|
||||
|
||||
}
|
|
@ -202,6 +202,15 @@ class ConfigInstallTest extends KernelTestBase {
|
|||
$this->assertEqual($e->getConfigObjects(), ['config_test.dynamic.other_module_test_with_dependency' => ['config_other_module_config_test', 'config_test.dynamic.dotted.english']]);
|
||||
$this->assertEqual($e->getMessage(), 'Configuration objects provided by <em class="placeholder">config_install_dependency_test</em> have unmet dependencies: <em class="placeholder">config_test.dynamic.other_module_test_with_dependency (config_other_module_config_test, config_test.dynamic.dotted.english)</em>');
|
||||
}
|
||||
try {
|
||||
$this->installModules(['config_install_double_dependency_test']);
|
||||
$this->fail('Expected UnmetDependenciesException not thrown.');
|
||||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
$this->assertEquals('config_install_double_dependency_test', $e->getExtension());
|
||||
$this->assertEquals(['config_test.dynamic.other_module_test_with_dependency' => ['config_other_module_config_test', 'config_test.dynamic.dotted.english']], $e->getConfigObjects());
|
||||
$this->assertEquals('Configuration objects provided by <em class="placeholder">config_install_double_dependency_test</em> have unmet dependencies: <em class="placeholder">config_test.dynamic.other_module_test_with_dependency (config_other_module_config_test, config_test.dynamic.dotted.english)</em>', $e->getMessage());
|
||||
}
|
||||
$this->installModules(['config_test_language']);
|
||||
try {
|
||||
$this->installModules(['config_install_dependency_test']);
|
||||
|
|
|
@ -221,6 +221,12 @@ class ConnectionUnitTest extends KernelTestBase {
|
|||
$reflection = new \ReflectionObject($connection);
|
||||
$connection_property = $reflection->getProperty('connection');
|
||||
$connection_property->setAccessible(TRUE);
|
||||
// Skip this test when a database driver does not implement PDO.
|
||||
// An alternative database driver that does not implement PDO
|
||||
// should implement its own connection test.
|
||||
if (get_class($connection_property->getValue($connection)) !== 'PDO') {
|
||||
$this->markTestSkipped('Ignored PDO connection unit test for this driver because it does not implement PDO.');
|
||||
}
|
||||
$error_mode = $connection_property->getValue($connection)
|
||||
->getAttribute(\PDO::ATTR_ERRMODE);
|
||||
$this->assertEqual($error_mode, \PDO::ERRMODE_EXCEPTION, 'Ensure the default error mode is set to exception.');
|
||||
|
|
|
@ -251,4 +251,87 @@ class ContentEntityCloneTest extends EntityKernelTestBase {
|
|||
$this->assertEquals('clone', $clone->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests changing the default revision flag.
|
||||
*/
|
||||
public function testDefaultRevision() {
|
||||
// Create a test entity with a translation, which will internally trigger
|
||||
// entity cloning for the new translation and create references for some of
|
||||
// the entity properties.
|
||||
$entity = EntityTestMulRev::create([
|
||||
'name' => 'original',
|
||||
'language' => 'en',
|
||||
]);
|
||||
$entity->addTranslation('de');
|
||||
$entity->save();
|
||||
|
||||
// Assert that the entity is in the default revision.
|
||||
$this->assertTrue($entity->isDefaultRevision());
|
||||
|
||||
// Clone the entity and modify its default revision flag.
|
||||
$clone = clone $entity;
|
||||
$clone->isDefaultRevision(FALSE);
|
||||
|
||||
// Assert that the clone is not in default revision, but the original entity
|
||||
// is still in the default revision.
|
||||
$this->assertFalse($clone->isDefaultRevision());
|
||||
$this->assertTrue($entity->isDefaultRevision());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests references of entity properties after entity cloning.
|
||||
*/
|
||||
public function testEntityPropertiesModifications() {
|
||||
// Create a test entity with a translation, which will internally trigger
|
||||
// entity cloning for the new translation and create references for some of
|
||||
// the entity properties.
|
||||
$entity = EntityTestMulRev::create([
|
||||
'name' => 'original',
|
||||
'language' => 'en',
|
||||
]);
|
||||
$translation = $entity->addTranslation('de');
|
||||
$entity->save();
|
||||
|
||||
// Clone the entity.
|
||||
$clone = clone $entity;
|
||||
|
||||
// Retrieve the entity properties.
|
||||
$reflection = new \ReflectionClass($entity);
|
||||
$properties = $reflection->getProperties(~\ReflectionProperty::IS_STATIC);
|
||||
$translation_unique_properties = ['activeLangcode', 'translationInitialize', 'fieldDefinitions', 'languages', 'langcodeKey', 'defaultLangcode', 'defaultLangcodeKey', 'validated', 'validationRequired', 'entityTypeId', 'typedData', 'cacheContexts', 'cacheTags', 'cacheMaxAge', '_serviceIds'];
|
||||
|
||||
foreach ($properties as $property) {
|
||||
// Modify each entity property on the clone and assert that the change is
|
||||
// not propagated to the original entity.
|
||||
$property->setAccessible(TRUE);
|
||||
$property->setValue($entity, 'default-value');
|
||||
$property->setValue($translation, 'default-value');
|
||||
$property->setValue($clone, 'test-entity-cloning');
|
||||
$this->assertEquals('default-value', $property->getValue($entity), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
|
||||
$this->assertEquals('default-value', $property->getValue($translation), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
|
||||
$this->assertEquals('test-entity-cloning', $property->getValue($clone), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
|
||||
|
||||
// Modify each entity property on the translation entity object and assert
|
||||
// that the change is propagated to the default translation entity object
|
||||
// except for the properties that are unique for each entity translation
|
||||
// object.
|
||||
$property->setValue($translation, 'test-translation-cloning');
|
||||
// Using assertEquals or assertNotEquals here is dangerous as if the
|
||||
// assertion fails and the property for some reasons contains the entity
|
||||
// object e.g. the "typedData" property then the property will be
|
||||
// serialized, but this will cause exceptions because the entity is
|
||||
// modified in a non-consistent way and ContentEntityBase::__sleep() will
|
||||
// not be able to properly access all properties and this will cause
|
||||
// exceptions without a proper backtrace.
|
||||
if (in_array($property->getName(), $translation_unique_properties)) {
|
||||
$this->assertEquals('default-value', $property->getValue($entity), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
|
||||
$this->assertEquals('test-translation-cloning', $property->getValue($translation), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
|
||||
}
|
||||
else {
|
||||
$this->assertEquals('test-translation-cloning', $property->getValue($entity), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
|
||||
$this->assertEquals('test-translation-cloning', $property->getValue($translation), (string) new FormattableMarkup('Entity property %property_name is not cloned properly.', ['%property_name' => $property->getName()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -101,6 +101,9 @@ class EntityApiTest extends EntityKernelTestBase {
|
|||
if ($revision_table = $definition->getRevisionTable()) {
|
||||
$this->assertEqual(0, db_query('SELECT COUNT(*) FROM {' . $revision_table . '}')->fetchField(), 'Data table was emptied');
|
||||
}
|
||||
if ($revision_data_table = $definition->getRevisionDataTable()) {
|
||||
$this->assertEqual(0, db_query('SELECT COUNT(*) FROM {' . $revision_data_table . '}')->fetchField(), 'Data table was emptied');
|
||||
}
|
||||
|
||||
// Test deleting a list of entities not indexed by entity id.
|
||||
$entities = [];
|
||||
|
@ -126,6 +129,9 @@ class EntityApiTest extends EntityKernelTestBase {
|
|||
if ($revision_table = $definition->getRevisionTable()) {
|
||||
$this->assertEqual(0, db_query('SELECT COUNT(*) FROM {' . $revision_table . '}')->fetchField(), 'Data table was emptied');
|
||||
}
|
||||
if ($revision_data_table = $definition->getRevisionDataTable()) {
|
||||
$this->assertEqual(0, db_query('SELECT COUNT(*) FROM {' . $revision_data_table . '}')->fetchField(), 'Data table was emptied');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -132,4 +132,29 @@ class EntityRevisionTranslationTest extends EntityKernelTestBase {
|
|||
$this->assertEquals($forward_revision->getTranslation('de')->name->value, 'forward revision - de');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests changing the default revision flag is propagated to all translations.
|
||||
*/
|
||||
public function testDefaultRevision() {
|
||||
// Create a test entity with a translation, which will internally trigger
|
||||
// entity cloning for the new translation and create references for some of
|
||||
// the entity properties.
|
||||
$entity = EntityTestMulRev::create([
|
||||
'name' => 'original',
|
||||
'language' => 'en',
|
||||
]);
|
||||
$translation = $entity->addTranslation('de');
|
||||
$entity->save();
|
||||
|
||||
// Assert that the entity is in the default revision.
|
||||
$this->assertTrue($entity->isDefaultRevision());
|
||||
$this->assertTrue($translation->isDefaultRevision());
|
||||
|
||||
// Change the default revision flag on one of the entity translations and
|
||||
// assert that the change is propagated to all entity translation objects.
|
||||
$translation->isDefaultRevision(FALSE);
|
||||
$this->assertFalse($entity->isDefaultRevision());
|
||||
$this->assertFalse($translation->isDefaultRevision());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ class UnmanagedCopyTest extends FileTestBase {
|
|||
public function testNonExistent() {
|
||||
// Copy non-existent file
|
||||
$desired_filepath = $this->randomMachineName();
|
||||
$this->assertFalse(file_exists($desired_filepath), "Randomly named file doesn't exists.");
|
||||
$this->assertFalse(file_exists($desired_filepath), "Randomly named file doesn't exist.");
|
||||
$new_filepath = file_unmanaged_copy($desired_filepath, $this->randomMachineName());
|
||||
$this->assertFalse($new_filepath, 'Copying a missing file fails.');
|
||||
}
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\KernelTests\Core\HttpKernel;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Tests CORS provided by Drupal.
|
||||
*
|
||||
* @see sites/default/default.services.yml
|
||||
* @see \Asm89\Stack\Cors
|
||||
* @see \Asm89\Stack\CorsService
|
||||
*
|
||||
* @group Http
|
||||
*/
|
||||
class CorsIntegrationTest extends KernelTestBase implements ServiceModifierInterface {
|
||||
|
||||
/**
|
||||
* The cors container configuration.
|
||||
*
|
||||
* @var null|array
|
||||
*/
|
||||
protected $corsConfig = NULL;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['system', 'test_page_test'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installSchema('system', 'router');
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
}
|
||||
|
||||
public function testCrossSiteRequest() {
|
||||
|
||||
// Test default parameters.
|
||||
$cors_config = $this->container->getParameter('cors.config');
|
||||
$this->assertSame(FALSE, $cors_config['enabled']);
|
||||
$this->assertSame([], $cors_config['allowedHeaders']);
|
||||
$this->assertSame([], $cors_config['allowedMethods']);
|
||||
$this->assertSame(['*'], $cors_config['allowedOrigins']);
|
||||
|
||||
$this->assertSame(FALSE, $cors_config['exposedHeaders']);
|
||||
$this->assertSame(FALSE, $cors_config['maxAge']);
|
||||
$this->assertSame(FALSE, $cors_config['supportsCredentials']);
|
||||
|
||||
// Configure the CORS stack to allow a specific set of origins, but don't
|
||||
// specify an origin header.
|
||||
$request = Request::create('/test-page');
|
||||
$request->headers->set('Origin', '');
|
||||
$cors_config['enabled'] = TRUE;
|
||||
$cors_config['allowedOrigins'] = ['http://example.com'];
|
||||
|
||||
$this->corsConfig = $cors_config;
|
||||
$this->container->get('kernel')->rebuildContainer();
|
||||
|
||||
/** @var \Symfony\Component\HttpFoundation\Response $response */
|
||||
$response = $this->container->get('http_kernel')->handle($request);
|
||||
$this->assertEquals(Response::HTTP_FORBIDDEN, $response->getStatusCode());
|
||||
$this->assertEquals('Not allowed.', $response->getContent());
|
||||
|
||||
// Specify a valid origin.
|
||||
$request->headers->set('Origin', 'http://example.com');
|
||||
$response = $this->container->get('http_kernel')->handle($request);
|
||||
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function alter(ContainerBuilder $container) {
|
||||
if (isset($this->corsConfig)) {
|
||||
$container->setParameter('cors.config', $this->corsConfig);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -69,8 +69,10 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Kernel tests are run in separate processes to prevent collisions between
|
||||
* code that may be loaded by tests.
|
||||
* Kernel tests are run in separate processes because they allow autoloading
|
||||
* of code from extensions. Running the test in a separate process isolates
|
||||
* this behavior from other tests. Subclasses should not override this
|
||||
* property.
|
||||
*/
|
||||
protected $runTestInSeparateProcess = TRUE;
|
||||
|
||||
|
@ -130,11 +132,6 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\DependencyInjection\ContainerBuilder
|
||||
*/
|
||||
private static $initialContainerBuilder;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
|
@ -343,23 +340,13 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
// PHPUnit's @test annotations are intentionally ignored/not supported.
|
||||
return strpos($method->getName(), 'test') === 0;
|
||||
}));
|
||||
if ($test_method_count > 1 && !$this->isTestInIsolation()) {
|
||||
// Clone a precompiled, empty ContainerBuilder instance for each test.
|
||||
$container = $this->getCompiledContainerBuilder($modules);
|
||||
}
|
||||
|
||||
// Bootstrap the kernel. Do not use createFromRequest() to retain Settings.
|
||||
$kernel = new DrupalKernel('testing', $this->classLoader, FALSE);
|
||||
$kernel->setSitePath($this->siteDirectory);
|
||||
// Boot the precompiled container. The kernel will enhance it with synthetic
|
||||
// services.
|
||||
if (isset($container)) {
|
||||
$kernel->setContainer($container);
|
||||
unset($container);
|
||||
}
|
||||
// Boot a new one-time container from scratch. Ensure to set the module list
|
||||
// upfront to avoid a subsequent rebuild.
|
||||
elseif ($modules && $extensions = $this->getExtensionsForModules($modules)) {
|
||||
if ($modules && $extensions = $this->getExtensionsForModules($modules)) {
|
||||
$kernel->updateModules($extensions, $extensions);
|
||||
}
|
||||
// DrupalKernel::boot() is not sufficient as it does not invoke preHandle(),
|
||||
|
@ -469,68 +456,6 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
return $connection_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a precompiled ContainerBuilder for all tests of this class.
|
||||
*
|
||||
* Avoids repetitive calls to ContainerBuilder::compile(), which is very slow.
|
||||
*
|
||||
* Based on the (always identical) list of $modules to enable, an initial
|
||||
* container is compiled, all instantiated services are reset/removed, and
|
||||
* this precompiled container is stored in a static class property. (Static,
|
||||
* because PHPUnit instantiates a new class instance for each test *method*.)
|
||||
*
|
||||
* This method is not invoked if there is only a single test method. It is
|
||||
* also not invoked for tests running in process isolation (since each test
|
||||
* method runs in a separate process).
|
||||
*
|
||||
* The ContainerBuilder is not dumped into the filesystem (which would yield
|
||||
* an actually compiled Container class), because
|
||||
*
|
||||
* 1. PHP code cannot be unloaded, so e.g. 900 tests would load 900 different,
|
||||
* full Container classes into memory, quickly exceeding any sensible
|
||||
* memory consumption (GigaBytes).
|
||||
* 2. Dumping a Container class requires to actually write to the system's
|
||||
* temporary directory. This is not really easy with vfs, because vfs
|
||||
* doesn't support yet "include 'vfs://container.php'.". Maybe we could fix
|
||||
* that upstream.
|
||||
* 3. PhpDumper is very slow on its own.
|
||||
*
|
||||
* @param string[] $modules
|
||||
* The list of modules to enable.
|
||||
*
|
||||
* @return \Drupal\Core\DependencyInjection\ContainerBuilder
|
||||
* A clone of the precompiled, empty service container.
|
||||
*/
|
||||
private function getCompiledContainerBuilder(array $modules) {
|
||||
if (!isset(self::$initialContainerBuilder)) {
|
||||
$kernel = new DrupalKernel('testing', $this->classLoader, FALSE);
|
||||
$kernel->setSitePath($this->siteDirectory);
|
||||
if ($modules && $extensions = $this->getExtensionsForModules($modules)) {
|
||||
$kernel->updateModules($extensions, $extensions);
|
||||
}
|
||||
$kernel->boot();
|
||||
self::$initialContainerBuilder = $kernel->getContainer();
|
||||
|
||||
// Remove all instantiated services, so the container is safe for cloning.
|
||||
// Technically, ContainerBuilder::set($id, NULL) removes each definition,
|
||||
// but the container is compiled/frozen already.
|
||||
foreach (self::$initialContainerBuilder->getServiceIds() as $id) {
|
||||
self::$initialContainerBuilder->set($id, NULL);
|
||||
}
|
||||
|
||||
// Destruct and trigger garbage collection.
|
||||
\Drupal::unsetContainer();
|
||||
$kernel->shutdown();
|
||||
$kernel = NULL;
|
||||
// @see register()
|
||||
$this->container = NULL;
|
||||
}
|
||||
|
||||
$container = clone self::$initialContainerBuilder;
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the FileCache component.
|
||||
*
|
||||
|
@ -749,15 +674,6 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function tearDownAfterClass() {
|
||||
// Free up memory: Precompiled container.
|
||||
self::$initialContainerBuilder = NULL;
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs default configuration for a given list of modules.
|
||||
*
|
||||
|
@ -1072,13 +988,20 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns whether the current test runs in isolation.
|
||||
* Returns whether the current test method is running in a separate process.
|
||||
*
|
||||
* Note that KernelTestBase will run in a separate process by default.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @see \Drupal\KernelTests\KernelTestBase::$runTestInSeparateProcess
|
||||
* @see https://github.com/sebastianbergmann/phpunit/pull/1350
|
||||
*
|
||||
* @deprecated in Drupal 8.4.x, for removal before the Drupal 9.0.0 release.
|
||||
* KernelTestBase tests are always run in isolated processes.
|
||||
*/
|
||||
protected function isTestInIsolation() {
|
||||
@trigger_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated in Drupal 8.4.x, for removal before the Drupal 9.0.0 release. KernelTestBase tests are always run in isolated processes.', E_USER_DEPRECATED);
|
||||
return function_exists('__phpunit_run_isolated_test');
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ use org\bovigo\vfs\visitor\vfsStreamStructureVisitor;
|
|||
/**
|
||||
* @coversDefaultClass \Drupal\KernelTests\KernelTestBase
|
||||
* @group PHPUnit
|
||||
* @group Test
|
||||
* @group KernelTests
|
||||
*/
|
||||
class KernelTestBaseTest extends KernelTestBase {
|
||||
|
||||
|
@ -137,22 +139,21 @@ class KernelTestBaseTest extends KernelTestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* @covers ::getCompiledContainerBuilder
|
||||
* Tests whether the fixture allows us to install modules and configuration.
|
||||
*
|
||||
* The point of this test is to have integration level testing.
|
||||
* @see ::testSubsequentContainerIsolation()
|
||||
*/
|
||||
public function testCompiledContainer() {
|
||||
public function testContainerIsolation() {
|
||||
$this->enableModules(['system', 'user']);
|
||||
$this->assertNull($this->installConfig('user'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getCompiledContainerBuilder
|
||||
* @depends testCompiledContainer
|
||||
* Tests whether the fixture can re-install modules and configuration.
|
||||
*
|
||||
* The point of this test is to have integration level testing.
|
||||
* @depends testContainerIsolation
|
||||
*/
|
||||
public function testCompiledContainerIsDestructed() {
|
||||
public function testSubsequentContainerIsolation() {
|
||||
$this->enableModules(['system', 'user']);
|
||||
$this->assertNull($this->installConfig('user'));
|
||||
}
|
||||
|
|
|
@ -246,6 +246,20 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
*/
|
||||
protected $originalShutdownCallbacks = [];
|
||||
|
||||
/**
|
||||
* The number of meta refresh redirects to follow, or NULL if unlimited.
|
||||
*
|
||||
* @var null|int
|
||||
*/
|
||||
protected $maximumMetaRefreshCount = NULL;
|
||||
|
||||
/**
|
||||
* The number of meta refresh redirects followed during ::drupalGet().
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $metaRefreshCount = 0;
|
||||
|
||||
/**
|
||||
* Initializes Mink sessions.
|
||||
*/
|
||||
|
@ -637,6 +651,13 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
// Ensure that any changes to variables in the other thread are picked up.
|
||||
$this->refreshVariables();
|
||||
|
||||
// Replace original page output with new output from redirected page(s).
|
||||
if ($new = $this->checkForMetaRefresh()) {
|
||||
$out = $new;
|
||||
// We are finished with all meta refresh redirects, so reset the counter.
|
||||
$this->metaRefreshCount = 0;
|
||||
}
|
||||
|
||||
// Log only for JavascriptTestBase tests because for Goutte we log with
|
||||
// ::getResponseLogHandler.
|
||||
if ($this->htmlOutputEnabled && !($this->getSession()->getDriver() instanceof GoutteDriver)) {
|
||||
|
@ -810,6 +831,12 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
// Ensure that any changes to variables in the other thread are picked up.
|
||||
$this->refreshVariables();
|
||||
|
||||
// Check if there are any meta refresh redirects (like Batch API pages).
|
||||
if ($this->checkForMetaRefresh()) {
|
||||
// We are finished with all meta refresh redirects, so reset the counter.
|
||||
$this->metaRefreshCount = 0;
|
||||
}
|
||||
|
||||
// Log only for JavascriptTestBase tests because for Goutte we log with
|
||||
// ::getResponseLogHandler.
|
||||
if ($this->htmlOutputEnabled && !($this->getSession()->getDriver() instanceof GoutteDriver)) {
|
||||
|
@ -1369,4 +1396,26 @@ abstract class BrowserTestBase extends \PHPUnit_Framework_TestCase {
|
|||
return $caller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for meta refresh tag and if found call drupalGet() recursively.
|
||||
*
|
||||
* This function looks for the http-equiv attribute to be set to "Refresh" and
|
||||
* is case-sensitive.
|
||||
*
|
||||
* @return string|false
|
||||
* Either the new page content or FALSE.
|
||||
*/
|
||||
protected function checkForMetaRefresh() {
|
||||
$refresh = $this->cssSelect('meta[http-equiv="Refresh"]');
|
||||
if (!empty($refresh) && (!isset($this->maximumMetaRefreshCount) || $this->metaRefreshCount < $this->maximumMetaRefreshCount)) {
|
||||
// Parse the content attribute of the meta tag for the format:
|
||||
// "[delay]: URL=[page_to_redirect_to]".
|
||||
if (preg_match('/\d+;\s*URL=(?<url>.*)/i', $refresh[0]->getAttribute('content'), $match)) {
|
||||
$this->metaRefreshCount++;
|
||||
return $this->drupalGet($this->getAbsoluteUrl(Html::decodeEntities($match['url'])));
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,16 @@ class YamlPeclTest extends YamlTestBase {
|
|||
$this->assertEquals($data, YamlPecl::decode(YamlPecl::encode($data)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that php object support is disabled.
|
||||
*/
|
||||
public function testObjectSupportDisabled() {
|
||||
$object = new \stdClass();
|
||||
$object->foo = 'bar';
|
||||
$this->assertEquals(['O:8:"stdClass":1:{s:3:"foo";s:3:"bar";}'], YamlPecl::decode(YamlPecl::encode([$object])));
|
||||
$this->assertEquals(0, ini_get('yaml.decode_php'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests decoding YAML node anchors.
|
||||
*
|
||||
|
|
|
@ -63,4 +63,16 @@ class YamlSymfonyTest extends YamlTestBase {
|
|||
YamlSymfony::decode('foo: [ads');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that php object support is disabled.
|
||||
*
|
||||
* @covers ::encode
|
||||
*/
|
||||
public function testObjectSupportDisabled() {
|
||||
$this->setExpectedException(InvalidDataTypeException::class, 'Object support when dumping a YAML file has been disabled.');
|
||||
$object = new \stdClass();
|
||||
$object->foo = 'bar';
|
||||
YamlSymfony::encode([$object]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -76,6 +76,23 @@ class YamlTest extends UnitTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that decoding php objects is similar for PECL and Symfony.
|
||||
*
|
||||
* @requires extension yaml
|
||||
*/
|
||||
public function testObjectSupportDisabled() {
|
||||
$object = new \stdClass();
|
||||
$object->foo = 'bar';
|
||||
// In core all Yaml encoding is done via Symfony and it does not support
|
||||
// objects so in order to encode an object we hace to use the PECL
|
||||
// extension.
|
||||
// @see \Drupal\Component\Serialization\Yaml::encode()
|
||||
$yaml = YamlPecl::encode([$object]);
|
||||
$this->assertEquals(['O:8:"stdClass":1:{s:3:"foo";s:3:"bar";}'], YamlPecl::decode($yaml));
|
||||
$this->assertEquals(['!php/object "O:8:\"stdClass\":1:{s:3:\"foo\";s:3:\"bar\";}"'], YamlSymfony::decode($yaml));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider that lists all YAML files in core.
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\Tests\Component\Utility;
|
||||
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\Component\Render\MarkupTrait;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
|
@ -87,7 +89,12 @@ class HtmlTest extends UnitTestCase {
|
|||
*/
|
||||
public function testHtmlClass() {
|
||||
// Verify Drupal coding standards are enforced.
|
||||
$this->assertSame(Html::getClass('CLASS NAME_[Ü]'), 'class-name--ü', 'Enforce Drupal coding standards.');
|
||||
$this->assertSame('class-name--ü', Html::getClass('CLASS NAME_[Ü]'), 'Enforce Drupal coding standards.');
|
||||
|
||||
// Test Html::getClass() handles Drupal\Component\Render\MarkupInterface
|
||||
// input.
|
||||
$markup = HtmlTestMarkup::create('CLASS_FROM_OBJECT');
|
||||
$this->assertSame('class-from-object', Html::getClass($markup), 'Markup object is converted to CSS class.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -390,3 +397,11 @@ class HtmlTest extends UnitTestCase {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks an object's __toString() method as returning markup.
|
||||
*/
|
||||
class HtmlTestMarkup implements MarkupInterface {
|
||||
use MarkupTrait;
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class UrlHelperTest extends UnitTestCase {
|
|||
[['a' => ' &#//+%20@۞'], 'a=%20%26%23//%2B%2520%40%DB%9E', 'Value was properly encoded.'],
|
||||
[[' &#//+%20@۞' => 'a'], '%20%26%23%2F%2F%2B%2520%40%DB%9E=a', 'Key was properly encoded.'],
|
||||
[['a' => '1', 'b' => '2', 'c' => '3'], 'a=1&b=2&c=3', 'Multiple values were properly concatenated.'],
|
||||
[['a' => ['b' => '2', 'c' => '3'], 'd' => 'foo'], 'a[b]=2&a[c]=3&d=foo', 'Nested array was properly encoded.'],
|
||||
[['a' => ['b' => '2', 'c' => '3'], 'd' => 'foo'], 'a%5Bb%5D=2&a%5Bc%5D=3&d=foo', 'Nested array was properly encoded.'],
|
||||
[['foo' => NULL], 'foo', 'Simple parameters are properly added.'],
|
||||
];
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ use Drupal\Core\Ajax\CloseModalDialogCommand;
|
|||
use Drupal\Core\Ajax\SetDialogOptionCommand;
|
||||
use Drupal\Core\Ajax\SetDialogTitleCommand;
|
||||
use Drupal\Core\Ajax\RedirectCommand;
|
||||
use Drupal\Core\Ajax\UpdateBuildIdCommand;
|
||||
|
||||
/**
|
||||
* Test coverage for various classes in the \Drupal\Core\Ajax namespace.
|
||||
|
@ -429,4 +430,20 @@ class AjaxCommandsTest extends UnitTestCase {
|
|||
$this->assertEquals($expected, $command->render());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Drupal\Core\Ajax\UpdateBuildIdCommand
|
||||
*/
|
||||
public function testUpdateBuildIdCommand() {
|
||||
$old = 'ThisStringisOld';
|
||||
$new = 'ThisStringIsNew';
|
||||
$command = new UpdateBuildIdCommand($old, $new);
|
||||
$expected = [
|
||||
'command' => 'update_build_id',
|
||||
'old' => $old,
|
||||
'new' => $new,
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, $command->render());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
34
web/core/tests/Drupal/Tests/Core/Test/KernelTestBaseTest.php
Normal file
34
web/core/tests/Drupal/Tests/Core/Test/KernelTestBaseTest.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\Core\Test;
|
||||
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* @group Test
|
||||
* @group legacy
|
||||
*
|
||||
* @coversDefaultClass \Drupal\KernelTests\KernelTestBase
|
||||
*/
|
||||
class KernelTestBaseTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @expectedDeprecation Drupal\KernelTests\KernelTestBase::isTestInIsolation() is deprecated in Drupal 8.4.x, for removal before the Drupal 9.0.0 release. KernelTestBase tests are always run in isolated processes.
|
||||
*
|
||||
* @covers ::isTestInIsolation
|
||||
*/
|
||||
public function testDeprecatedIsTestInIsolation() {
|
||||
$kernel_test = $this->getMockBuilder(KernelTestBase::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMockForAbstractClass();
|
||||
|
||||
$is_isolated = new \ReflectionMethod($kernel_test, 'isTestInIsolation');
|
||||
$is_isolated->setAccessible(TRUE);
|
||||
|
||||
// Assert that the return value is a bool, because this unit test might or
|
||||
// might not be running in process isolation.
|
||||
$this->assertInternalType('bool', $is_isolated->invoke($kernel_test));
|
||||
}
|
||||
|
||||
}
|
|
@ -736,6 +736,7 @@ class UrlTest extends UnitTestCase {
|
|||
['/?page=1000'],
|
||||
['?page=1000'],
|
||||
['?breed=bengal&page=1000'],
|
||||
['?referrer=https://kittenfacts'],
|
||||
// Paths with various token formats but no leading slash.
|
||||
['/[duckies]'],
|
||||
['/%bunnies'],
|
||||
|
|
71
web/core/tests/Drupal/Tests/EntityViewTrait.php
Normal file
71
web/core/tests/Drupal/Tests/EntityViewTrait.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
|
||||
/**
|
||||
* Provides helper methods to deal with building entity views in tests.
|
||||
*/
|
||||
trait EntityViewTrait {
|
||||
|
||||
/**
|
||||
* Builds the renderable view of an entity.
|
||||
*
|
||||
* Entities postpone the composition of their renderable arrays to #pre_render
|
||||
* functions in order to maximize cache efficacy. This means that the full
|
||||
* renderable array for an entity is constructed in drupal_render(). Some
|
||||
* tests require the complete renderable array for an entity outside of the
|
||||
* drupal_render process in order to verify the presence of specific values.
|
||||
* This method isolates the steps in the render process that produce an
|
||||
* entity's renderable array.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity to prepare a renderable array for.
|
||||
* @param string $view_mode
|
||||
* (optional) The view mode that should be used to build the entity.
|
||||
* @param null $langcode
|
||||
* (optional) For which language the entity should be prepared, defaults to
|
||||
* the current content language.
|
||||
* @param bool $reset
|
||||
* (optional) Whether to clear the cache for this entity.
|
||||
* @return array
|
||||
*
|
||||
* @see drupal_render()
|
||||
*/
|
||||
protected function buildEntityView(EntityInterface $entity, $view_mode = 'full', $langcode = NULL, $reset = FALSE) {
|
||||
$ensure_fully_built = function(&$elements) use (&$ensure_fully_built) {
|
||||
// If the default values for this element have not been loaded yet, populate
|
||||
// them.
|
||||
if (isset($elements['#type']) && empty($elements['#defaults_loaded'])) {
|
||||
$elements += \Drupal::service('element_info')->getInfo($elements['#type']);
|
||||
}
|
||||
|
||||
// Make any final changes to the element before it is rendered. This means
|
||||
// that the $element or the children can be altered or corrected before the
|
||||
// element is rendered into the final text.
|
||||
if (isset($elements['#pre_render'])) {
|
||||
foreach ($elements['#pre_render'] as $callable) {
|
||||
$elements = call_user_func($callable, $elements);
|
||||
}
|
||||
}
|
||||
|
||||
// And recurse.
|
||||
$children = Element::children($elements, TRUE);
|
||||
foreach ($children as $key) {
|
||||
$ensure_fully_built($elements[$key]);
|
||||
}
|
||||
};
|
||||
|
||||
$render_controller = $this->container->get('entity.manager')->getViewBuilder($entity->getEntityTypeId());
|
||||
if ($reset) {
|
||||
$render_controller->resetCache([$entity->id()]);
|
||||
}
|
||||
$build = $render_controller->view($entity, $view_mode, $langcode);
|
||||
$ensure_fully_built($build);
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\Traits\Core;
|
||||
|
||||
/**
|
||||
* Adds ability to convert a list of parameters into a stack of permutations.
|
||||
*/
|
||||
trait GeneratePermutationsTrait {
|
||||
|
||||
/**
|
||||
* Converts a list of possible parameters into a stack of permutations.
|
||||
*
|
||||
* Takes a list of parameters containing possible values, and converts all of
|
||||
* them into a list of items containing every possible permutation.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* $parameters = [
|
||||
* 'one' => [0, 1],
|
||||
* 'two' => [2, 3],
|
||||
* ];
|
||||
* $permutations = $this->generatePermutations($parameters);
|
||||
* // Result:
|
||||
* $permutations == [
|
||||
* ['one' => 0, 'two' => 2],
|
||||
* ['one' => 1, 'two' => 2],
|
||||
* ['one' => 0, 'two' => 3],
|
||||
* ['one' => 1, 'two' => 3],
|
||||
* ]
|
||||
* @endcode
|
||||
*
|
||||
* @param array $parameters
|
||||
* An associative array of parameters, keyed by parameter name, and whose
|
||||
* values are arrays of parameter values.
|
||||
*
|
||||
* @return array[]
|
||||
* A list of permutations, which is an array of arrays. Each inner array
|
||||
* contains the full list of parameters that have been passed, but with a
|
||||
* single value only.
|
||||
*/
|
||||
public static function generatePermutations(array $parameters) {
|
||||
$all_permutations = [[]];
|
||||
foreach ($parameters as $parameter => $values) {
|
||||
$new_permutations = [];
|
||||
// Iterate over all values of the parameter.
|
||||
foreach ($values as $value) {
|
||||
// Iterate over all existing permutations.
|
||||
foreach ($all_permutations as $permutation) {
|
||||
// Add the new parameter value to existing permutations.
|
||||
$new_permutations[] = $permutation + [$parameter => $value];
|
||||
}
|
||||
}
|
||||
// Replace the old permutations with the new permutations.
|
||||
$all_permutations = $new_permutations;
|
||||
}
|
||||
return $all_permutations;
|
||||
}
|
||||
|
||||
}
|
|
@ -18,9 +18,9 @@ Note: functional tests have to be invoked with a user in the same group as the
|
|||
web server user. You can either configure Apache (or nginx) to run as your own
|
||||
system user or run tests as a privileged user instead.
|
||||
|
||||
To develop locally, a straigtforward - but also less secure - approach is to run
|
||||
tests as your own system user. To achieve that, change the default Apache user
|
||||
to run as your system user. Typically, you'd need to modify
|
||||
To develop locally, a straightforward - but also less secure - approach is to
|
||||
run tests as your own system user. To achieve that, change the default Apache
|
||||
user to run as your system user. Typically, you'd need to modify
|
||||
`/etc/apache2/envvars` on Linux or `/etc/apache2/httpd.conf` on Mac.
|
||||
|
||||
Example for Linux:
|
||||
|
|
Reference in a new issue