Issue #1987716 by pfrenssen, tim.plunkett, kgoel: Provide a FormTestBase class to allow PHPUnit form tests.
parent
aa15f0ca32
commit
eacd8a50b1
|
@ -620,7 +620,7 @@ class FormBuilder implements FormBuilderInterface {
|
||||||
// possibly ending execution. We make sure we do not react to the batch
|
// possibly ending execution. We make sure we do not react to the batch
|
||||||
// that is already being processed (if a batch operation performs a
|
// that is already being processed (if a batch operation performs a
|
||||||
// self::submitForm).
|
// self::submitForm).
|
||||||
if ($batch =& batch_get() && !isset($batch['current_set'])) {
|
if ($batch = &$this->batchGet() && !isset($batch['current_set'])) {
|
||||||
// Store $form_state information in the batch definition.
|
// Store $form_state information in the batch definition.
|
||||||
// We need the full $form_state when either:
|
// We need the full $form_state when either:
|
||||||
// - Some submit handlers were saved to be called during batch
|
// - Some submit handlers were saved to be called during batch
|
||||||
|
@ -1195,7 +1195,7 @@ class FormBuilder implements FormBuilderInterface {
|
||||||
// Check if a previous _submit handler has set a batch, but make sure we
|
// Check if a previous _submit handler has set a batch, but make sure we
|
||||||
// do not react to a batch that is already being processed (for instance
|
// do not react to a batch that is already being processed (for instance
|
||||||
// if a batch operation performs a self::submitForm()).
|
// if a batch operation performs a self::submitForm()).
|
||||||
if ($type == 'submit' && ($batch =& batch_get()) && !isset($batch['id'])) {
|
if ($type == 'submit' && ($batch = &$this->batchGet()) && !isset($batch['id'])) {
|
||||||
// Some previous submit handler has set a batch. To ensure correct
|
// Some previous submit handler has set a batch. To ensure correct
|
||||||
// execution order, store the call in a special 'control' batch set.
|
// execution order, store the call in a special 'control' batch set.
|
||||||
// See _batch_next_set().
|
// See _batch_next_set().
|
||||||
|
@ -1837,4 +1837,11 @@ class FormBuilder implements FormBuilderInterface {
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps batch_get().
|
||||||
|
*/
|
||||||
|
protected function &batchGet() {
|
||||||
|
return batch_get();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -656,17 +656,6 @@ class FormTest extends WebTestBase {
|
||||||
$this->assertTrue(!empty($element), 'The textarea has the proper required attribute.');
|
$this->assertTrue(!empty($element), 'The textarea has the proper required attribute.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests error border of multiple fields with same name in a page.
|
|
||||||
*/
|
|
||||||
function testMultiFormSameNameErrorClass() {
|
|
||||||
$this->drupalGet('form-test/double-form');
|
|
||||||
$edit = array();
|
|
||||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
|
||||||
$this->assertFieldByXpath('//input[@id="edit-name" and contains(@class, "error")]', NULL, 'Error input form element class found for first element.');
|
|
||||||
$this->assertNoFieldByXpath('//input[@id="edit-name--2" and contains(@class, "error")]', NULL, 'No error input form element class found for second element.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests a form with a form state storing a database connection.
|
* Tests a form with a form state storing a database connection.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Definition of Drupal\system\Tests\Form\HTMLIdTest.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Drupal\system\Tests\Form;
|
|
||||||
|
|
||||||
use Drupal\simpletest\WebTestBase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests uniqueness of generated HTML IDs.
|
|
||||||
*/
|
|
||||||
class HTMLIdTest extends WebTestBase {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modules to enable.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public static $modules = array('form_test');
|
|
||||||
|
|
||||||
public static function getInfo() {
|
|
||||||
return array(
|
|
||||||
'name' => 'Unique HTML IDs',
|
|
||||||
'description' => 'Tests functionality of drupal_html_id().',
|
|
||||||
'group' => 'Form API',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that HTML IDs do not get duplicated when form validation fails.
|
|
||||||
*/
|
|
||||||
function testHTMLId() {
|
|
||||||
$this->drupalGet('form-test/double-form');
|
|
||||||
$this->assertNoDuplicateIds('There are no duplicate IDs');
|
|
||||||
|
|
||||||
// Submit second form with empty title.
|
|
||||||
$edit = array();
|
|
||||||
$this->drupalPostForm(NULL, $edit, 'Save', array(), array(), 'form-test-html-id--2');
|
|
||||||
$this->assertNoDuplicateIds('There are no duplicate IDs');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -2056,34 +2056,6 @@ function form_test_required_attribute($form, &$form_state) {
|
||||||
return $form;
|
return $form;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Menu callback returns two instances of the same form.
|
|
||||||
*
|
|
||||||
* @deprecated \Drupal\form_test\Controller\FormTestController::doubleForm()
|
|
||||||
*/
|
|
||||||
function form_test_double_form() {
|
|
||||||
return array(
|
|
||||||
'form1' => drupal_get_form('form_test_html_id'),
|
|
||||||
'form2' => drupal_get_form('form_test_html_id'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a simple form to test duplicate HTML IDs.
|
|
||||||
*/
|
|
||||||
function form_test_html_id($form, &$form_state) {
|
|
||||||
$form['name'] = array(
|
|
||||||
'#type' => 'textfield',
|
|
||||||
'#title' => 'name',
|
|
||||||
'#required' => TRUE,
|
|
||||||
);
|
|
||||||
$form['submit'] = array(
|
|
||||||
'#type' => 'submit',
|
|
||||||
'#value' => 'Save',
|
|
||||||
);
|
|
||||||
return $form;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a simple form to test form button classes.
|
* Builds a simple form to test form button classes.
|
||||||
*
|
*
|
||||||
|
|
|
@ -77,14 +77,6 @@ form_test.wrapper:
|
||||||
requirements:
|
requirements:
|
||||||
_access: 'TRUE'
|
_access: 'TRUE'
|
||||||
|
|
||||||
form_test.double_form:
|
|
||||||
path: '/form-test/double-form'
|
|
||||||
defaults:
|
|
||||||
_title: 'Double form test'
|
|
||||||
_content: '\Drupal\form_test\Controller\FormTestController::doubleForm'
|
|
||||||
requirements:
|
|
||||||
_access: 'TRUE'
|
|
||||||
|
|
||||||
form_test.alter_form:
|
form_test.alter_form:
|
||||||
path: '/form-test/alter'
|
path: '/form-test/alter'
|
||||||
defaults:
|
defaults:
|
||||||
|
|
|
@ -42,11 +42,4 @@ class FormTestController extends ControllerBase {
|
||||||
return form_test_wrapper_callback($form_id);
|
return form_test_wrapper_callback($form_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo Remove form_test_double_form().
|
|
||||||
*/
|
|
||||||
public function doubleForm() {
|
|
||||||
return form_test_double_form();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,68 +8,17 @@
|
||||||
namespace Drupal\Tests\Core\Form {
|
namespace Drupal\Tests\Core\Form {
|
||||||
|
|
||||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||||
use Drupal\Core\Form\FormBuilder;
|
|
||||||
use Drupal\Core\Form\FormInterface;
|
use Drupal\Core\Form\FormInterface;
|
||||||
use Drupal\Core\Session\AccountInterface;
|
|
||||||
use Drupal\Tests\UnitTestCase;
|
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the form builder.
|
* Tests the form builder.
|
||||||
|
*
|
||||||
|
* @group Drupal
|
||||||
|
* @group Form
|
||||||
*/
|
*/
|
||||||
class FormBuilderTest extends UnitTestCase {
|
class FormBuilderTest extends FormTestBase {
|
||||||
|
|
||||||
/**
|
|
||||||
* The form builder being tested.
|
|
||||||
*
|
|
||||||
* @var \Drupal\Core\Form\FormBuilder
|
|
||||||
*/
|
|
||||||
protected $formBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mocked URL generator.
|
|
||||||
*
|
|
||||||
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Routing\UrlGeneratorInterface
|
|
||||||
*/
|
|
||||||
protected $urlGenerator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mocked module handler.
|
|
||||||
*
|
|
||||||
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Extension\ModuleHandlerInterface
|
|
||||||
*/
|
|
||||||
protected $moduleHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The expirable key value store used by form cache.
|
|
||||||
*
|
|
||||||
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
|
|
||||||
*/
|
|
||||||
protected $formCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The expirable key value store used by form state cache.
|
|
||||||
*
|
|
||||||
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
|
|
||||||
*/
|
|
||||||
protected $formStateCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current user.
|
|
||||||
*
|
|
||||||
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Session\AccountInterface
|
|
||||||
*/
|
|
||||||
protected $account;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The CSRF token generator.
|
|
||||||
*
|
|
||||||
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Access\CsrfTokenGenerator
|
|
||||||
*/
|
|
||||||
protected $csrfToken;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
@ -82,39 +31,6 @@ class FormBuilderTest extends UnitTestCase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUp() {
|
|
||||||
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
|
|
||||||
|
|
||||||
$this->formCache = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface');
|
|
||||||
$this->formStateCache = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface');
|
|
||||||
$key_value_expirable_factory = $this->getMockBuilder('\Drupal\Core\KeyValueStore\KeyValueExpirableFactory')
|
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
$key_value_expirable_factory->expects($this->any())
|
|
||||||
->method('get')
|
|
||||||
->will($this->returnValueMap(array(
|
|
||||||
array('form', $this->formCache),
|
|
||||||
array('form_state', $this->formStateCache),
|
|
||||||
)));
|
|
||||||
|
|
||||||
$event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
|
||||||
$this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
|
|
||||||
$translation_manager = $this->getStringTranslationStub();
|
|
||||||
$this->csrfToken = $this->getMockBuilder('Drupal\Core\Access\CsrfTokenGenerator')
|
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
$http_kernel = $this->getMockBuilder('Drupal\Core\HttpKernel')
|
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$this->formBuilder = new TestFormBuilder($this->moduleHandler, $key_value_expirable_factory, $event_dispatcher, $this->urlGenerator, $translation_manager, $this->csrfToken, $http_kernel);
|
|
||||||
$this->formBuilder->setRequest(new Request());
|
|
||||||
|
|
||||||
$this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
|
|
||||||
$this->formBuilder->setCurrentUser($this->account);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the getFormId() method with a string based form ID.
|
* Tests the getFormId() method with a string based form ID.
|
||||||
*/
|
*/
|
||||||
|
@ -729,147 +645,6 @@ class FormBuilderTest extends UnitTestCase {
|
||||||
$this->formBuilder->buildForm($form_arg, $form_state);
|
$this->formBuilder->buildForm($form_arg, $form_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a mocked form object.
|
|
||||||
*
|
|
||||||
* @param string $form_id
|
|
||||||
* (optional) The form ID to be used. If none is provided, the form will be
|
|
||||||
* set with no expectation about getFormId().
|
|
||||||
* @param mixed $expected_form
|
|
||||||
* (optional) If provided, the expected form response for buildForm() to
|
|
||||||
* return. Defaults to NULL.
|
|
||||||
* @param int $count
|
|
||||||
* (optional) The number of times the form is expected to be built. Defaults
|
|
||||||
* to 1.
|
|
||||||
*
|
|
||||||
* @return \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Form\FormInterface
|
|
||||||
* The mocked form object.
|
|
||||||
*/
|
|
||||||
protected function getMockForm($form_id, $expected_form = NULL, $count = 1) {
|
|
||||||
$form = $this->getMock('Drupal\Core\Form\FormInterface');
|
|
||||||
$form->expects($this->once())
|
|
||||||
->method('getFormId')
|
|
||||||
->will($this->returnValue($form_id));
|
|
||||||
|
|
||||||
if ($expected_form) {
|
|
||||||
$form->expects($this->exactly($count))
|
|
||||||
->method('buildForm')
|
|
||||||
->will($this->returnValue($expected_form));
|
|
||||||
}
|
|
||||||
return $form;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts that the expected form structure is found in a form for a given key.
|
|
||||||
*
|
|
||||||
* @param array $expected_form
|
|
||||||
* The expected form structure.
|
|
||||||
* @param array $actual_form
|
|
||||||
* The actual form.
|
|
||||||
* @param string|null $form_key
|
|
||||||
* (optional) The form key to look in. Otherwise the entire form will be
|
|
||||||
* compared.
|
|
||||||
*/
|
|
||||||
protected function assertFormElement(array $expected_form, array $actual_form, $form_key = NULL) {
|
|
||||||
$expected_element = $form_key ? $expected_form[$form_key] : $expected_form;
|
|
||||||
$actual_element = $form_key ? $actual_form[$form_key] : $actual_form;
|
|
||||||
$this->assertSame(array_intersect_key($expected_element, $actual_element), $expected_element);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a test form builder class.
|
|
||||||
*/
|
|
||||||
class TestFormBuilder extends FormBuilder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
protected function sendResponse(Response $response) {
|
|
||||||
parent::sendResponse($response);
|
|
||||||
// Throw an exception instead of exiting.
|
|
||||||
throw new \Exception('exit');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param \Drupal\Core\Session\AccountInterface $account
|
|
||||||
*/
|
|
||||||
public function setCurrentUser(AccountInterface $account) {
|
|
||||||
$this->currentUser = $account;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
protected function getElementInfo($type) {
|
|
||||||
$types['token'] = array(
|
|
||||||
'#input' => TRUE,
|
|
||||||
);
|
|
||||||
$types['value'] = array(
|
|
||||||
'#input' => TRUE,
|
|
||||||
);
|
|
||||||
$types['select'] = array(
|
|
||||||
'#input' => TRUE,
|
|
||||||
'#multiple' => FALSE,
|
|
||||||
'#empty_value' => '',
|
|
||||||
);
|
|
||||||
$types['radios'] = array(
|
|
||||||
'#input' => TRUE,
|
|
||||||
);
|
|
||||||
$types['textfield'] = array(
|
|
||||||
'#input' => TRUE,
|
|
||||||
);
|
|
||||||
$types['submit'] = array(
|
|
||||||
'#input' => TRUE,
|
|
||||||
'#name' => 'op',
|
|
||||||
'#is_button' => TRUE,
|
|
||||||
);
|
|
||||||
if (!isset($types[$type])) {
|
|
||||||
$types[$type] = array();
|
|
||||||
}
|
|
||||||
return $types[$type];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
protected function drupalInstallationAttempted() {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
protected function drupalSetMessage($message = NULL, $type = 'status', $repeat = FALSE) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
protected function watchdog($type, $message, array $variables = NULL, $severity = WATCHDOG_NOTICE, $link = NULL) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
protected function drupalHtmlClass($class) {
|
|
||||||
return $class;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
protected function drupalHtmlId($id) {
|
|
||||||
return $id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
protected function drupalStaticReset($name = NULL) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestForm implements FormInterface {
|
class TestForm implements FormInterface {
|
||||||
|
@ -892,48 +667,9 @@ class TestFormInjected extends TestForm implements ContainerInjectionInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
function test_form_id() {
|
|
||||||
$form['test'] = array(
|
|
||||||
'#type' => 'textfield',
|
|
||||||
'#title' => 'Test',
|
|
||||||
);
|
|
||||||
$form['select'] = array(
|
|
||||||
'#type' => 'select',
|
|
||||||
'#options' => array(
|
|
||||||
'foo' => 'foo',
|
|
||||||
'bar' => 'bar',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
$form['options'] = array(
|
|
||||||
'#type' => 'radios',
|
|
||||||
'#options' => array(
|
|
||||||
'foo' => 'foo',
|
|
||||||
'bar' => 'bar',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
$form['value'] = array(
|
|
||||||
'#type' => 'value',
|
|
||||||
'#value' => 'bananas',
|
|
||||||
);
|
|
||||||
$form['actions'] = array(
|
|
||||||
'#type' => 'actions',
|
|
||||||
);
|
|
||||||
$form['actions']['submit'] = array(
|
|
||||||
'#type' => 'submit',
|
|
||||||
'#value' => 'Submit',
|
|
||||||
);
|
|
||||||
return $form;
|
|
||||||
}
|
|
||||||
function test_form_id_custom_submit(array &$form, array &$form_state) {
|
function test_form_id_custom_submit(array &$form, array &$form_state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defined('WATCHDOG_ERROR')) {
|
if (!defined('WATCHDOG_ERROR')) {
|
||||||
define('WATCHDOG_ERROR', 3);
|
define('WATCHDOG_ERROR', 3);
|
||||||
}
|
}
|
||||||
if (!function_exists('batch_get')) {
|
|
||||||
function &batch_get() {
|
|
||||||
$batch = array();
|
|
||||||
return $batch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,366 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\Tests\Core\Form\FormTestBase.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\Tests\Core\Form {
|
||||||
|
|
||||||
|
use Drupal\Core\Form\FormBuilder;
|
||||||
|
use Drupal\Core\Form\FormInterface;
|
||||||
|
use Drupal\Core\Session\AccountInterface;
|
||||||
|
use Drupal\Tests\UnitTestCase;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a base class for testing form functionality.
|
||||||
|
*
|
||||||
|
* @see \Drupal\Core\Form\FormBuilder
|
||||||
|
*/
|
||||||
|
abstract class FormTestBase extends UnitTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form builder being tested.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Form\FormBuilderInterface
|
||||||
|
*/
|
||||||
|
protected $formBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mocked URL generator.
|
||||||
|
*
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Routing\UrlGeneratorInterface
|
||||||
|
*/
|
||||||
|
protected $urlGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mocked module handler.
|
||||||
|
*
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Extension\ModuleHandlerInterface
|
||||||
|
*/
|
||||||
|
protected $moduleHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The expirable key value store used by form cache.
|
||||||
|
*
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
|
||||||
|
*/
|
||||||
|
protected $formCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The expirable key value store used by form state cache.
|
||||||
|
*
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
|
||||||
|
*/
|
||||||
|
protected $formStateCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current user.
|
||||||
|
*
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Session\AccountInterface
|
||||||
|
*/
|
||||||
|
protected $account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CSRF token generator.
|
||||||
|
*
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Access\CsrfTokenGenerator
|
||||||
|
*/
|
||||||
|
protected $csrfToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The request.
|
||||||
|
*
|
||||||
|
* @var \Symfony\Component\HttpFoundation\Request
|
||||||
|
*/
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event dispatcher.
|
||||||
|
*
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject|\Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||||
|
*/
|
||||||
|
protected $eventDispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The expirable key value factory.
|
||||||
|
*
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\KeyValueStore\KeyValueExpirableFactory
|
||||||
|
*/
|
||||||
|
protected $keyValueExpirableFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\StringTranslation\TranslationInterface
|
||||||
|
*/
|
||||||
|
protected $translationManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\HttpKernel
|
||||||
|
*/
|
||||||
|
protected $httpKernel;
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
|
||||||
|
|
||||||
|
$this->formCache = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface');
|
||||||
|
$this->formStateCache = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface');
|
||||||
|
$this->keyValueExpirableFactory = $this->getMockBuilder('Drupal\Core\KeyValueStore\KeyValueExpirableFactory')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$this->keyValueExpirableFactory->expects($this->any())
|
||||||
|
->method('get')
|
||||||
|
->will($this->returnValueMap(array(
|
||||||
|
array('form', $this->formCache),
|
||||||
|
array('form_state', $this->formStateCache),
|
||||||
|
)));
|
||||||
|
|
||||||
|
$this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||||
|
$this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
|
||||||
|
$this->translationManager = $this->getStringTranslationStub();
|
||||||
|
$this->csrfToken = $this->getMockBuilder('Drupal\Core\Access\CsrfTokenGenerator')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$this->httpKernel = $this->getMockBuilder('Drupal\Core\HttpKernel')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$this->request = new Request();
|
||||||
|
$this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
|
||||||
|
|
||||||
|
$this->setupFormBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function tearDown() {
|
||||||
|
$this->formBuilder->drupalStaticReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a new form builder object to test.
|
||||||
|
*/
|
||||||
|
protected function setupFormBuilder() {
|
||||||
|
$this->formBuilder = new TestFormBuilder($this->moduleHandler, $this->keyValueExpirableFactory, $this->eventDispatcher, $this->urlGenerator, $this->translationManager, $this->csrfToken, $this->httpKernel);
|
||||||
|
$this->formBuilder->setRequest($this->request);
|
||||||
|
$this->formBuilder->setCurrentUser($this->account);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a mocked form object.
|
||||||
|
*
|
||||||
|
* @param string $form_id
|
||||||
|
* (optional) The form ID to be used. If none is provided, the form will be
|
||||||
|
* set with no expectation about getFormId().
|
||||||
|
* @param mixed $expected_form
|
||||||
|
* (optional) If provided, the expected form response for buildForm() to
|
||||||
|
* return. Defaults to NULL.
|
||||||
|
* @param int $count
|
||||||
|
* (optional) The number of times the form is expected to be built. Defaults
|
||||||
|
* to 1.
|
||||||
|
*
|
||||||
|
* @return \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Form\FormInterface
|
||||||
|
* The mocked form object.
|
||||||
|
*/
|
||||||
|
protected function getMockForm($form_id, $expected_form = NULL, $count = 1) {
|
||||||
|
$form = $this->getMock('Drupal\Core\Form\FormInterface');
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('getFormId')
|
||||||
|
->will($this->returnValue($form_id));
|
||||||
|
|
||||||
|
if ($expected_form) {
|
||||||
|
$form->expects($this->exactly($count))
|
||||||
|
->method('buildForm')
|
||||||
|
->will($this->returnValue($expected_form));
|
||||||
|
}
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulates a form submission within a request, bypassing submitForm().
|
||||||
|
*
|
||||||
|
* Calling submitForm() will reset the form builder, if two forms were on the
|
||||||
|
* same page, they will be submitted simultaneously.
|
||||||
|
*
|
||||||
|
* @param string $form_id
|
||||||
|
* The unique string identifying the form.
|
||||||
|
* @param \Drupal\Core\Form\FormInterface $form_arg
|
||||||
|
* The form object.
|
||||||
|
* @param array $form_state
|
||||||
|
* An associative array containing the current state of the form.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* The built form.
|
||||||
|
*/
|
||||||
|
protected function simulateFormSubmission($form_id, FormInterface $form_arg, array &$form_state) {
|
||||||
|
$form_state['build_info']['callback_object'] = $form_arg;
|
||||||
|
$form_state['build_info']['args'] = array();
|
||||||
|
$form_state['input']['op'] = 'Submit';
|
||||||
|
$form_state['programmed'] = TRUE;
|
||||||
|
$form_state['submitted'] = TRUE;
|
||||||
|
return $this->formBuilder->buildForm($form_id, $form_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the expected form structure is found in a form for a given key.
|
||||||
|
*
|
||||||
|
* @param array $expected_form
|
||||||
|
* The expected form structure.
|
||||||
|
* @param array $actual_form
|
||||||
|
* The actual form.
|
||||||
|
* @param string|null $form_key
|
||||||
|
* (optional) The form key to look in. Otherwise the entire form will be
|
||||||
|
* compared.
|
||||||
|
*/
|
||||||
|
protected function assertFormElement(array $expected_form, array $actual_form, $form_key = NULL) {
|
||||||
|
$expected_element = $form_key ? $expected_form[$form_key] : $expected_form;
|
||||||
|
$actual_element = $form_key ? $actual_form[$form_key] : $actual_form;
|
||||||
|
$this->assertSame(array_intersect_key($expected_element, $actual_element), $expected_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a test form builder class.
|
||||||
|
*/
|
||||||
|
class TestFormBuilder extends FormBuilder {
|
||||||
|
protected static $seenIds = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function sendResponse(Response $response) {
|
||||||
|
parent::sendResponse($response);
|
||||||
|
// Throw an exception instead of exiting.
|
||||||
|
throw new \Exception('exit');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Drupal\Core\Session\AccountInterface $account
|
||||||
|
*/
|
||||||
|
public function setCurrentUser(AccountInterface $account) {
|
||||||
|
$this->currentUser = $account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getElementInfo($type) {
|
||||||
|
$types['token'] = array(
|
||||||
|
'#input' => TRUE,
|
||||||
|
);
|
||||||
|
$types['value'] = array(
|
||||||
|
'#input' => TRUE,
|
||||||
|
);
|
||||||
|
$types['radios'] = array(
|
||||||
|
'#input' => TRUE,
|
||||||
|
);
|
||||||
|
$types['textfield'] = array(
|
||||||
|
'#input' => TRUE,
|
||||||
|
);
|
||||||
|
$types['submit'] = array(
|
||||||
|
'#input' => TRUE,
|
||||||
|
'#name' => 'op',
|
||||||
|
'#is_button' => TRUE,
|
||||||
|
);
|
||||||
|
if (!isset($types[$type])) {
|
||||||
|
$types[$type] = array();
|
||||||
|
}
|
||||||
|
return $types[$type];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function drupalInstallationAttempted() {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function menuGetItem() {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function drupalSetMessage($message = NULL, $type = 'status', $repeat = FALSE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function watchdog($type, $message, array $variables = NULL, $severity = WATCHDOG_NOTICE, $link = NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function drupalHtmlClass($class) {
|
||||||
|
return $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function drupalHtmlId($id) {
|
||||||
|
if (isset(static::$seenIds[$id])) {
|
||||||
|
$id = $id . '--' . ++static::$seenIds[$id];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
static::$seenIds[$id] = 1;
|
||||||
|
}
|
||||||
|
return $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function drupalStaticReset($name = NULL) {
|
||||||
|
static::$seenIds = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function &batchGet() {
|
||||||
|
$batch = array();
|
||||||
|
return $batch;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
function test_form_id() {
|
||||||
|
$form['test'] = array(
|
||||||
|
'#type' => 'textfield',
|
||||||
|
'#title' => 'Test',
|
||||||
|
);
|
||||||
|
$form['options'] = array(
|
||||||
|
'#type' => 'radios',
|
||||||
|
'#options' => array(
|
||||||
|
'foo' => 'foo',
|
||||||
|
'bar' => 'bar',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$form['value'] = array(
|
||||||
|
'#type' => 'value',
|
||||||
|
'#value' => 'bananas',
|
||||||
|
);
|
||||||
|
$form['actions'] = array(
|
||||||
|
'#type' => 'actions',
|
||||||
|
);
|
||||||
|
$form['actions']['submit'] = array(
|
||||||
|
'#type' => 'submit',
|
||||||
|
'#value' => 'Submit',
|
||||||
|
);
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\Tests\Core\Form\FormValidationTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\Tests\Core\Form;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests various form element validation mechanisms.
|
||||||
|
*
|
||||||
|
* @group Drupal
|
||||||
|
* @group Form
|
||||||
|
*/
|
||||||
|
class FormValidationTest extends FormTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function getInfo() {
|
||||||
|
return array(
|
||||||
|
'name' => 'Form element validation',
|
||||||
|
'description' => 'Tests various form element validation mechanisms.',
|
||||||
|
'group' => 'Form API',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNoDuplicateErrorsForIdenticalForm() {
|
||||||
|
$form_id = 'test_form_id';
|
||||||
|
$expected_form = $form_id();
|
||||||
|
$expected_form['test']['#required'] = TRUE;
|
||||||
|
|
||||||
|
// Mock a form object that will be built three times.
|
||||||
|
$form_arg = $this->getMockForm($form_id, $expected_form, 3);
|
||||||
|
|
||||||
|
// The first form will have errors.
|
||||||
|
$form_state = array();
|
||||||
|
$this->formBuilder->getFormId($form_arg, $form_state);
|
||||||
|
$this->simulateFormSubmission($form_id, $form_arg, $form_state);
|
||||||
|
$errors = $this->formBuilder->getErrors($form_state);
|
||||||
|
$this->assertNotEmpty($errors['test']);
|
||||||
|
|
||||||
|
// The second form will not have errors.
|
||||||
|
$form_state = array();
|
||||||
|
$this->simulateFormSubmission($form_id, $form_arg, $form_state);
|
||||||
|
$errors = $this->formBuilder->getErrors($form_state);
|
||||||
|
$this->assertEmpty($errors);
|
||||||
|
|
||||||
|
// Reset the form builder.
|
||||||
|
$this->setupFormBuilder();
|
||||||
|
|
||||||
|
// On a new request, the first form will have errors again.
|
||||||
|
$form_state = array();
|
||||||
|
$this->simulateFormSubmission($form_id, $form_arg, $form_state);
|
||||||
|
$errors = $this->formBuilder->getErrors($form_state);
|
||||||
|
$this->assertNotEmpty($errors['test']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUniqueHtmlId() {
|
||||||
|
$form_id = 'test_form_id';
|
||||||
|
$expected_form = $form_id();
|
||||||
|
$expected_form['test']['#required'] = TRUE;
|
||||||
|
|
||||||
|
// Mock a form object that will be built three times.
|
||||||
|
$form_arg = $this->getMockForm($form_id, $expected_form, 2);
|
||||||
|
|
||||||
|
$form_state = array();
|
||||||
|
$this->formBuilder->getFormId($form_arg, $form_state);
|
||||||
|
$form = $this->simulateFormSubmission($form_id, $form_arg, $form_state);
|
||||||
|
$this->assertSame($form_id, $form['#id']);
|
||||||
|
|
||||||
|
$form_state = array();
|
||||||
|
$form = $this->simulateFormSubmission($form_id, $form_arg, $form_state);
|
||||||
|
$this->assertSame("$form_id--2", $form['#id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue