Issue #2900291 by martin107, Lendude, RytoEX, vijaycs85, borisson_, jibran, dawehner: Form: Convert system functional tests to phpunit Part 2
parent
9df150e1ab
commit
47d067a16b
|
@ -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,17 +1,16 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Drupal\system\Tests\Form;
|
namespace Drupal\Tests\system\Functional\Form;
|
||||||
|
|
||||||
use Drupal\Core\Form\FormState;
|
use Drupal\Core\Form\FormState;
|
||||||
use Drupal\simpletest\WebTestBase;
|
use Drupal\Tests\BrowserTestBase;
|
||||||
use Drupal\Tests\system\Functional\Form\StubForm;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the tableselect form element for expected behavior.
|
* Tests the tableselect form element for expected behavior.
|
||||||
*
|
*
|
||||||
* @group Form
|
* @group Form
|
||||||
*/
|
*/
|
||||||
class ElementsTableSelectTest extends WebTestBase {
|
class ElementsTableSelectTest extends BrowserTestBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modules to enable.
|
* Modules to enable.
|
||||||
|
@ -27,35 +26,14 @@ class ElementsTableSelectTest extends WebTestBase {
|
||||||
|
|
||||||
$this->drupalGet('form_test/tableselect/multiple-true');
|
$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.
|
// 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'];
|
$rows = ['row1', 'row2', 'row3'];
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
$this->assertFieldByXPath('//input[@type="checkbox"]', $row, format_string('Checkbox for value @row.', ['@row' => $row]));
|
$this->assertNotEmpty($this->xpath('//input[@type="checkbox"]', [$row]), "Checkbox for the value $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]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,40 +43,39 @@ class ElementsTableSelectTest extends WebTestBase {
|
||||||
public function testMultipleFalse() {
|
public function testMultipleFalse() {
|
||||||
$this->drupalGet('form_test/tableselect/multiple-false');
|
$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.
|
// 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'];
|
$rows = ['row1', 'row2', 'row3'];
|
||||||
foreach ($rows as $row) {
|
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.
|
* Tests the display when #colspan is set.
|
||||||
*/
|
*/
|
||||||
public function testTableselectColSpan() {
|
public function testTableSelectColSpan() {
|
||||||
$this->drupalGet('form_test/tableselect/colspan');
|
$this->drupalGet('form_test/tableselect/colspan');
|
||||||
|
|
||||||
$this->assertText(t('Three'), 'Presence of the third column');
|
$this->assertSession()->pageTextContains('Three', 'Presence of the third column');
|
||||||
$this->assertNoText(t('Four'), 'Absence of a fourth column');
|
$this->assertSession()->pageTextNotContains('Four', 'Absence of a fourth column');
|
||||||
|
|
||||||
// There should be three labeled column headers and 1 for the input.
|
// There should be three labeled column headers and 1 for the input.
|
||||||
$table_head = $this->xpath('//thead');
|
$table_head = $this->xpath('//thead/tr/th');
|
||||||
$this->assertEqual(count($table_head[0]->tr->th), 4, 'There are four column headers');
|
$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
|
// 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,
|
// radio, one cell in the first column, one cell in the second column,
|
||||||
// and two cells in the third column which has colspan 2.
|
// and two cells in the third column which has colspan 2.
|
||||||
for ($i = 0; $i <= 1; $i++) {
|
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
|
// 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).
|
// 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() {
|
public function testEmptyText() {
|
||||||
$this->drupalGet('form_test/tableselect/empty-text');
|
$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;
|
$edit['tableselect[row1]'] = TRUE;
|
||||||
$this->drupalPostForm('form_test/tableselect/multiple-true', $edit, 'Submit');
|
$this->drupalPostForm('form_test/tableselect/multiple-true', $edit, 'Submit');
|
||||||
|
|
||||||
$this->assertText(t('Submitted: row1 = row1'), 'Checked checkbox row1');
|
$assert_session = $this->assertSession();
|
||||||
$this->assertText(t('Submitted: row2 = 0'), 'Unchecked checkbox row2.');
|
$assert_session->pageTextContains('Submitted: row1 = row1', 'Checked checkbox row1');
|
||||||
$this->assertText(t('Submitted: row3 = 0'), 'Unchecked checkbox row3.');
|
$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.
|
// Test a submission with multiple checkboxes checked.
|
||||||
$edit['tableselect[row1]'] = TRUE;
|
$edit['tableselect[row1]'] = TRUE;
|
||||||
$edit['tableselect[row3]'] = TRUE;
|
$edit['tableselect[row3]'] = TRUE;
|
||||||
$this->drupalPostForm('form_test/tableselect/multiple-true', $edit, 'Submit');
|
$this->drupalPostForm('form_test/tableselect/multiple-true', $edit, 'Submit');
|
||||||
|
|
||||||
$this->assertText(t('Submitted: row1 = row1'), 'Checked checkbox row1.');
|
$assert_session->pageTextContains('Submitted: row1 = row1', 'Checked checkbox row1.');
|
||||||
$this->assertText(t('Submitted: row2 = 0'), 'Unchecked checkbox row2.');
|
$assert_session->pageTextContains('Submitted: row2 = 0', 'Unchecked checkbox row2.');
|
||||||
$this->assertText(t('Submitted: row3 = row3'), 'Checked checkbox row3.');
|
$assert_session->pageTextContains('Submitted: row3 = row3', 'Checked checkbox row3.');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +118,7 @@ class ElementsTableSelectTest extends WebTestBase {
|
||||||
public function testMultipleFalseSubmit() {
|
public function testMultipleFalseSubmit() {
|
||||||
$edit['tableselect'] = 'row1';
|
$edit['tableselect'] = 'row1';
|
||||||
$this->drupalPostForm('form_test/tableselect/multiple-false', $edit, 'Submit');
|
$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() {
|
public function testAdvancedSelect() {
|
||||||
// When #multiple = TRUE a Select all checkbox should be displayed by default.
|
// When #multiple = TRUE a Select all checkbox should be displayed by default.
|
||||||
$this->drupalGet('form_test/tableselect/advanced-select/multiple-true-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.
|
// 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->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.
|
// 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->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->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,9 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Drupal\system\Tests\Form;
|
namespace Drupal\Tests\system\Functional\Form;
|
||||||
|
|
||||||
use Drupal\Core\Database\Database;
|
use Drupal\Core\Database\Database;
|
||||||
use Drupal\simpletest\WebTestBase;
|
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||||
|
use Drupal\Tests\BrowserTestBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests a multistep form using form storage and makes sure validation and
|
* Tests a multistep form using form storage and makes sure validation and
|
||||||
|
@ -17,7 +18,7 @@ use Drupal\simpletest\WebTestBase;
|
||||||
*
|
*
|
||||||
* @group Form
|
* @group Form
|
||||||
*/
|
*/
|
||||||
class StorageTest extends WebTestBase {
|
class StorageTest extends BrowserTestBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modules to enable.
|
* Modules to enable.
|
||||||
|
@ -26,6 +27,9 @@ class StorageTest extends WebTestBase {
|
||||||
*/
|
*/
|
||||||
public static $modules = ['form_test', 'dblog'];
|
public static $modules = ['form_test', 'dblog'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
protected function setUp() {
|
protected function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
@ -37,25 +41,27 @@ class StorageTest extends WebTestBase {
|
||||||
*/
|
*/
|
||||||
public function testForm() {
|
public function testForm() {
|
||||||
$this->drupalGet('form_test/form-storage');
|
$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'];
|
$edit = ['title' => 'new', 'value' => 'value_is_set'];
|
||||||
|
|
||||||
// Use form rebuilding triggered by a submit button.
|
// Use form rebuilding triggered by a submit button.
|
||||||
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
||||||
$this->assertText('Form constructions: 2');
|
$assert_session->pageTextContains('Form constructions: 2');
|
||||||
$this->assertText('Form constructions: 3');
|
$assert_session->pageTextContains('Form constructions: 3');
|
||||||
|
|
||||||
// Reset the form to the values of the storage, using a form rebuild
|
// Reset the form to the values of the storage, using a form rebuild
|
||||||
// triggered by button of type button.
|
// triggered by button of type button.
|
||||||
$this->drupalPostForm(NULL, ['title' => 'changed'], 'Reset');
|
$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.
|
// After rebuilding, the form has been cached.
|
||||||
$this->assertText('Form constructions: 4');
|
$assert_session->pageTextContains('Form constructions: 4');
|
||||||
|
|
||||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||||
$this->assertText('Form constructions: 4');
|
$assert_session->pageTextContains('Form constructions: 4');
|
||||||
$this->assertText('Title: new', 'The form storage has stored the values.');
|
$assert_session->pageTextContains('Title: new', 'The form storage has stored the values.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,26 +69,26 @@ class StorageTest extends WebTestBase {
|
||||||
*/
|
*/
|
||||||
public function testFormCached() {
|
public function testFormCached() {
|
||||||
$this->drupalGet('form_test/form-storage', ['query' => ['cache' => 1]]);
|
$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'];
|
$edit = ['title' => 'new', 'value' => 'value_is_set'];
|
||||||
|
|
||||||
// Use form rebuilding triggered by a submit button.
|
// Use form rebuilding triggered by a submit button.
|
||||||
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
||||||
// The first one is for the building of the form.
|
// 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.
|
// 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
|
// Reset the form to the values of the storage, using a form rebuild
|
||||||
// triggered by button of type button.
|
// triggered by button of type button.
|
||||||
$this->drupalPostForm(NULL, ['title' => 'changed'], 'Reset');
|
$this->drupalPostForm(NULL, ['title' => 'changed'], 'Reset');
|
||||||
$this->assertFieldByName('title', 'new', 'Values have been reset.');
|
$this->assertSession()->fieldValueEquals('title', 'new');
|
||||||
$this->assertText('Form constructions: 4');
|
$this->assertSession()->pageTextContains('Form constructions: 4');
|
||||||
|
|
||||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||||
$this->assertText('Form constructions: 4');
|
$this->assertSession()->pageTextContains('Form constructions: 4');
|
||||||
$this->assertText('Title: new', 'The form storage has stored the values.');
|
$this->assertSession()->pageTextContains('Title: new', 'The form storage has stored the values.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -125,7 +131,7 @@ class StorageTest extends WebTestBase {
|
||||||
// validation error. Post again and verify that the rebuilt form contains
|
// validation error. Post again and verify that the rebuilt form contains
|
||||||
// the values of the updated form storage.
|
// the values of the updated form storage.
|
||||||
$this->drupalPostForm(NULL, ['title' => 'foo', 'value' => 'bar'], 'Save');
|
$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.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -136,27 +142,27 @@ class StorageTest extends WebTestBase {
|
||||||
// Request the form with 'cache' query parameter to enable form caching.
|
// Request the form with 'cache' query parameter to enable form caching.
|
||||||
$this->drupalGet('form_test/form-storage', ['query' => ['cache' => 1, 'immutable' => 1]]);
|
$this->drupalGet('form_test/form-storage', ['query' => ['cache' => 1, 'immutable' => 1]]);
|
||||||
$buildIdFields = $this->xpath('//input[@name="form_build_id"]');
|
$buildIdFields = $this->xpath('//input[@name="form_build_id"]');
|
||||||
$this->assertEqual(count($buildIdFields), 1, 'One form build id field on the page');
|
$this->assertEquals(count($buildIdFields), 1, 'One form build id field on the page');
|
||||||
$buildId = (string) $buildIdFields[0]['value'];
|
$buildId = $buildIdFields[0]->getValue();
|
||||||
|
|
||||||
// Trigger validation error by submitting an empty title.
|
// Trigger validation error by submitting an empty title.
|
||||||
$edit = ['title' => ''];
|
$edit = ['title' => ''];
|
||||||
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
||||||
|
|
||||||
// Verify that the build-id did change.
|
// 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.
|
// Retrieve the new build-id.
|
||||||
$buildIdFields = $this->xpath('//input[@name="form_build_id"]');
|
$buildIdFields = $this->xpath('//input[@name="form_build_id"]');
|
||||||
$this->assertEqual(count($buildIdFields), 1, 'One form build id field on the page');
|
$this->assertEquals(count($buildIdFields), 1, 'One form build id field on the page');
|
||||||
$buildId = (string) $buildIdFields[0]['value'];
|
$buildId = (string) $buildIdFields[0]->getValue();
|
||||||
|
|
||||||
// Trigger validation error by again submitting an empty title.
|
// Trigger validation error by again submitting an empty title.
|
||||||
$edit = ['title' => ''];
|
$edit = ['title' => ''];
|
||||||
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
$this->drupalPostForm(NULL, $edit, 'Continue submit');
|
||||||
|
|
||||||
// Verify that the build-id does not change the second time.
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,25 +171,28 @@ class StorageTest extends WebTestBase {
|
||||||
public function testImmutableFormLegacyProtection() {
|
public function testImmutableFormLegacyProtection() {
|
||||||
$this->drupalGet('form_test/form-storage', ['query' => ['cache' => 1, 'immutable' => 1]]);
|
$this->drupalGet('form_test/form-storage', ['query' => ['cache' => 1, 'immutable' => 1]]);
|
||||||
$build_id_fields = $this->xpath('//input[@name="form_build_id"]');
|
$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');
|
$this->assertEquals(count($build_id_fields), 1, 'One form build id field on the page');
|
||||||
$build_id = (string) $build_id_fields[0]['value'];
|
$build_id = $build_id_fields[0]->getValue();
|
||||||
|
|
||||||
// Try to poison the form cache.
|
// Try to poison the form cache.
|
||||||
$original = $this->drupalGetAjax('form-test/form-storage-legacy/' . $build_id);
|
$response = $this->drupalGet('form-test/form-storage-legacy/' . $build_id, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']], ['X-Requested-With: XMLHttpRequest']);
|
||||||
$this->assertEqual($original['form']['#build_id_old'], $build_id, 'Original build_id was recorded');
|
$original = json_decode($response, TRUE);
|
||||||
$this->assertNotEqual($original['form']['#build_id'], $build_id, 'New build_id was generated');
|
|
||||||
|
$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
|
// Assert that a watchdog message was logged by
|
||||||
// \Drupal::formBuilder()->setCache().
|
// \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.']);
|
$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->assert($status, 'A watchdog message was logged by \Drupal::formBuilder()->setCache');
|
$this->assertTrue($status, 'A watchdog message was logged by \Drupal::formBuilder()->setCache');
|
||||||
|
|
||||||
// Ensure that the form state was not poisoned by the preceding call.
|
// Ensure that the form state was not poisoned by the preceding call.
|
||||||
$original = $this->drupalGetAjax('form-test/form-storage-legacy/' . $build_id);
|
$response = $this->drupalGet('form-test/form-storage-legacy/' . $build_id, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']], ['X-Requested-With: XMLHttpRequest']);
|
||||||
$this->assertEqual($original['form']['#build_id_old'], $build_id, 'Original build_id was recorded');
|
$original = json_decode($response, TRUE);
|
||||||
$this->assertNotEqual($original['form']['#build_id'], $build_id, 'New build_id was generated');
|
$this->assertEquals($original['form']['#build_id_old'], $build_id, 'Original build_id was recorded');
|
||||||
$this->assert(empty($original['form']['#poisoned']), 'Original form structure was preserved');
|
$this->assertNotEquals($original['form']['#build_id'], $build_id, 'New build_id was generated');
|
||||||
$this->assert(empty($original['form_state']['poisoned']), 'Original form state was preserved');
|
$this->assertTrue(empty($original['form']['#poisoned']), 'Original form structure was preserved');
|
||||||
|
$this->assertTrue(empty($original['form_state']['poisoned']), 'Original form state was preserved');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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
|
<?php
|
||||||
|
|
||||||
namespace Drupal\system\Tests\Form;
|
namespace Drupal\Tests\system\FunctionalJavascript\Form;
|
||||||
|
|
||||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||||
use Drupal\Core\Url;
|
use Drupal\Core\Url;
|
||||||
use Drupal\field\Entity\FieldConfig;
|
use Drupal\field\Entity\FieldConfig;
|
||||||
use Drupal\simpletest\WebTestBase;
|
|
||||||
use Drupal\field\Entity\FieldStorageConfig;
|
use Drupal\field\Entity\FieldStorageConfig;
|
||||||
|
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests functionality of \Drupal\Core\Form\FormBuilderInterface::rebuildForm().
|
* Tests functionality of \Drupal\Core\Form\FormBuilderInterface::rebuildForm().
|
||||||
|
@ -14,14 +14,12 @@ use Drupal\field\Entity\FieldStorageConfig;
|
||||||
* @group Form
|
* @group Form
|
||||||
* @todo Add tests for other aspects of form rebuilding.
|
* @todo Add tests for other aspects of form rebuilding.
|
||||||
*/
|
*/
|
||||||
class RebuildTest extends WebTestBase {
|
class RebuildTest extends WebDriverTestBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modules to enable.
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
public static $modules = ['node', 'form_test'];
|
protected static $modules = ['node', 'form_test'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user for testing.
|
* A user for testing.
|
||||||
|
@ -30,6 +28,9 @@ class RebuildTest extends WebTestBase {
|
||||||
*/
|
*/
|
||||||
protected $webUser;
|
protected $webUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
protected function setUp() {
|
protected function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
@ -39,28 +40,6 @@ class RebuildTest extends WebTestBase {
|
||||||
$this->drupalLogin($this->webUser);
|
$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.
|
* 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.
|
* followed by a non-Ajax submission, which triggers a validation error.
|
||||||
*/
|
*/
|
||||||
public function testPreserveFormActionAfterAJAX() {
|
public function testPreserveFormActionAfterAJAX() {
|
||||||
|
$page = $this->getSession()->getPage();
|
||||||
// Create a multi-valued field for 'page' nodes to use for Ajax testing.
|
// Create a multi-valued field for 'page' nodes to use for Ajax testing.
|
||||||
$field_name = 'field_ajax_test';
|
$field_name = 'field_ajax_test';
|
||||||
FieldStorageConfig::create([
|
FieldStorageConfig::create([
|
||||||
|
@ -81,8 +61,26 @@ class RebuildTest extends WebTestBase {
|
||||||
'entity_type' => 'node',
|
'entity_type' => 'node',
|
||||||
'bundle' => 'page',
|
'bundle' => 'page',
|
||||||
])->save();
|
])->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')
|
entity_get_form_display('node', 'page', 'default')
|
||||||
->setComponent($field_name, ['type' => 'text_textfield'])
|
->setComponent($field_name, ['type' => 'text_textfield'])
|
||||||
|
->setComponent($field_file_name, ['type' => 'file_generic'])
|
||||||
->save();
|
->save();
|
||||||
|
|
||||||
// Log in a user who can create 'page' nodes.
|
// 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
|
// 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.
|
// field items in the field for which we just added an item.
|
||||||
$this->drupalGet('node/add/page');
|
$this->drupalGet('node/add/page');
|
||||||
$this->drupalPostAjaxForm(NULL, [], ['field_ajax_test_add_more' => t('Add another item')], NULL, [], [], 'node-page-form');
|
$page->find('css', '[value="Add another item"]')->click();
|
||||||
$this->assert(count($this->xpath('//div[contains(@class, "field--name-field-ajax-test")]//input[@type="text"]')) == 2, 'AJAX submission succeeded.');
|
$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
|
// 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
|
// 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
|
// re-rendered without being re-built, which is what happens when there's
|
||||||
// a validation error.
|
// a server side validation error.
|
||||||
$this->drupalPostForm(NULL, [], t('Save'));
|
$edit = [
|
||||||
$this->assertText('Title field is required.', 'Non-AJAX submission correctly triggered a validation error.');
|
'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
|
// 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.
|
// 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.
|
// Ensure that the form's action is correct.
|
||||||
$forms = $this->xpath('//form[contains(@class, "node-page-form")]');
|
$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.
|
// Strip query params off the action before asserting.
|
||||||
$url = parse_url($forms[0]['action'])['path'];
|
$url = parse_url($forms[0]->getAttribute('action'))['path'];
|
||||||
$this->assertEqual(Url::fromRoute('node.add', ['node_type' => 'page'])->toString(), $url);
|
$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.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue