Newer
Older
Alex Pott
committed
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Form\FormBuilderTest.
*/
namespace Drupal\Tests\Core\Form {
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\FormInterface;
Dries Buytaert
committed
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
Alex Pott
committed
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
Angie Byron
committed
* @coversDefaultClass \Drupal\Core\Form\FormBuilder
Angie Byron
committed
* @group Form
Alex Pott
committed
*/
Angie Byron
committed
class FormBuilderTest extends FormTestBase {
Alex Pott
committed
/**
* Tests the getFormId() method with a string based form ID.
*
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The form argument foo is not a valid form.
Alex Pott
committed
*/
public function testGetFormIdWithString() {
$form_arg = 'foo';
Dries Buytaert
committed
$clean_form_state = new FormState();
$form_state = new FormState();
Alex Pott
committed
$form_id = $this->formBuilder->getFormId($form_arg, $form_state);
$this->assertSame($form_arg, $form_id);
Dries Buytaert
committed
$this->assertSame($clean_form_state, $form_state);
Alex Pott
committed
}
/**
* Tests the getFormId() method with a class name form ID.
*/
public function testGetFormIdWithClassName() {
$form_arg = 'Drupal\Tests\Core\Form\TestForm';
Dries Buytaert
committed
$form_state = new FormState();
Alex Pott
committed
$form_id = $this->formBuilder->getFormId($form_arg, $form_state);
$this->assertSame('test_form', $form_id);
$this->assertSame($form_arg, get_class($form_state['build_info']['callback_object']));
}
/**
* Tests the getFormId() method with an injected class name form ID.
*/
public function testGetFormIdWithInjectedClassName() {
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
\Drupal::setContainer($container);
$form_arg = 'Drupal\Tests\Core\Form\TestFormInjected';
Dries Buytaert
committed
$form_state = new FormState();
Alex Pott
committed
$form_id = $this->formBuilder->getFormId($form_arg, $form_state);
$this->assertSame('test_form', $form_id);
$this->assertSame($form_arg, get_class($form_state['build_info']['callback_object']));
}
/**
* Tests the getFormId() method with a form object.
*/
public function testGetFormIdWithObject() {
$expected_form_id = 'my_module_form_id';
Angie Byron
committed
$form_arg = $this->getMockForm($expected_form_id);
Alex Pott
committed
Dries Buytaert
committed
$form_state = new FormState();
Alex Pott
committed
$form_id = $this->formBuilder->getFormId($form_arg, $form_state);
$this->assertSame($expected_form_id, $form_id);
$this->assertSame($form_arg, $form_state['build_info']['callback_object']);
}
/**
* Tests the getFormId() method with a base form object.
*/
public function testGetFormIdWithBaseForm() {
$expected_form_id = 'my_module_form_id';
$base_form_id = 'my_module';
$form_arg = $this->getMock('Drupal\Core\Form\BaseFormIdInterface');
$form_arg->expects($this->once())
->method('getFormId')
->will($this->returnValue($expected_form_id));
$form_arg->expects($this->once())
->method('getBaseFormId')
->will($this->returnValue($base_form_id));
Dries Buytaert
committed
$form_state = new FormState();
Alex Pott
committed
$form_id = $this->formBuilder->getFormId($form_arg, $form_state);
$this->assertSame($expected_form_id, $form_id);
$this->assertSame($form_arg, $form_state['build_info']['callback_object']);
$this->assertSame($base_form_id, $form_state['build_info']['base_form_id']);
}
Alex Pott
committed
/**
* Tests the handling of FormStateInterface::$response.
Alex Pott
committed
*
* @dataProvider formStateResponseProvider
*/
public function testHandleFormStateResponse($class, $form_state_key) {
$form_id = 'test_form_id';
$expected_form = $form_id();
$response = $this->getMockBuilder($class)
->disableOriginalConstructor()
->getMock();
$response->expects($this->any())
->method('prepare')
->will($this->returnValue($response));
$form_arg = $this->getMockForm($form_id, $expected_form);
$form_arg->expects($this->any())
->method('submitForm')
Dries Buytaert
committed
->will($this->returnCallback(function ($form, FormStateInterface $form_state) use ($response, $form_state_key) {
Angie Byron
committed
$form_state->set($form_state_key, $response);
Alex Pott
committed
}));
Dries Buytaert
committed
$form_state = new FormState();
Alex Pott
committed
try {
Angie Byron
committed
$input['form_id'] = $form_id;
$form_state->setUserInput($input);
Alex Pott
committed
$this->simulateFormSubmission($form_id, $form_arg, $form_state, FALSE);
$this->fail('TestFormBuilder::sendResponse() was not triggered.');
}
catch (\Exception $e) {
$this->assertSame('exit', $e->getMessage());
}
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $form_state->get('response'));
Alex Pott
committed
}
/**
* Provides test data for testHandleFormStateResponse().
*/
public function formStateResponseProvider() {
return array(
array('Symfony\Component\HttpFoundation\Response', 'response'),
array('Symfony\Component\HttpFoundation\RedirectResponse', 'redirect'),
);
}
/**
* Tests the handling of a redirect when FormStateInterface::$response exists.
Alex Pott
committed
*/
public function testHandleRedirectWithResponse() {
$form_id = 'test_form_id';
$expected_form = $form_id();
// Set up a response that will be used.
$response = $this->getMockBuilder('Symfony\Component\HttpFoundation\Response')
->disableOriginalConstructor()
->getMock();
$response->expects($this->once())
->method('prepare')
->will($this->returnValue($response));
// Set up a redirect that will not be called.
$redirect = $this->getMockBuilder('Symfony\Component\HttpFoundation\RedirectResponse')
->disableOriginalConstructor()
->getMock();
$redirect->expects($this->never())
->method('prepare');
$form_arg = $this->getMockForm($form_id, $expected_form);
$form_arg->expects($this->any())
->method('submitForm')
Dries Buytaert
committed
->will($this->returnCallback(function ($form, FormStateInterface $form_state) use ($response, $redirect) {
Alex Pott
committed
// Set both the response and the redirect.
$form_state->setResponse($response);
$form_state->set('redirect', $redirect);
Alex Pott
committed
}));
Dries Buytaert
committed
$form_state = new FormState();
Alex Pott
committed
try {
Angie Byron
committed
$input['form_id'] = $form_id;
$form_state->setUserInput($input);
Alex Pott
committed
$this->simulateFormSubmission($form_id, $form_arg, $form_state, FALSE);
$this->fail('TestFormBuilder::sendResponse() was not triggered.');
}
catch (\Exception $e) {
$this->assertSame('exit', $e->getMessage());
}
$this->assertSame($response, $form_state->get('response'));
Alex Pott
committed
}
Alex Pott
committed
/**
* Tests the getForm() method with a string based form ID.
*
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The form argument test_form_id is not a valid form.
Alex Pott
committed
*/
public function testGetFormWithString() {
$form_id = 'test_form_id';
$expected_form = $form_id();
$form = $this->formBuilder->getForm($form_id);
$this->assertFormElement($expected_form, $form, 'test');
$this->assertSame($form_id, $form['#id']);
}
/**
* Tests the getForm() method with a form object.
*/
public function testGetFormWithObject() {
$form_id = 'test_form_id';
$expected_form = $form_id();
Angie Byron
committed
$form_arg = $this->getMockForm($form_id, $expected_form);
Alex Pott
committed
$form = $this->formBuilder->getForm($form_arg);
$this->assertFormElement($expected_form, $form, 'test');
$this->assertSame($form_id, $form['#id']);
}
/**
Angie Byron
committed
* Tests the getForm() method with a class name based form ID.
Alex Pott
committed
*/
Angie Byron
committed
public function testGetFormWithClassString() {
$form_id = '\Drupal\Tests\Core\Form\TestForm';
$object = new TestForm();
$form = array();
Dries Buytaert
committed
$form_state = new FormState();
Angie Byron
committed
$expected_form = $object->buildForm($form, $form_state);
$form = $this->formBuilder->getForm($form_id);
$this->assertFormElement($expected_form, $form, 'test');
$this->assertSame('test_form', $form['#id']);
}
/**
* Tests the buildForm() method with a string based form ID.
*
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The form argument test_form_id is not a valid form.
Angie Byron
committed
*/
public function testBuildFormWithString() {
Alex Pott
committed
$form_id = 'test_form_id';
$expected_form = $form_id();
Angie Byron
committed
$form = $this->formBuilder->getForm($form_id);
$this->assertFormElement($expected_form, $form, 'test');
$this->assertSame($form_id, $form['#id']);
}
Alex Pott
committed
Angie Byron
committed
/**
* Tests the buildForm() method with a class name based form ID.
*/
public function testBuildFormWithClassString() {
$form_id = '\Drupal\Tests\Core\Form\TestForm';
$object = new TestForm();
$form = array();
Dries Buytaert
committed
$form_state = new FormState();
Angie Byron
committed
$expected_form = $object->buildForm($form, $form_state);
Alex Pott
committed
$form = $this->formBuilder->buildForm($form_id, $form_state);
$this->assertFormElement($expected_form, $form, 'test');
Angie Byron
committed
$this->assertSame('test_form', $form['#id']);
}
/**
* Tests the buildForm() method with a form object.
*/
public function testBuildFormWithObject() {
$form_id = 'test_form_id';
$expected_form = $form_id();
$form_arg = $this->getMockForm($form_id, $expected_form);
Dries Buytaert
committed
$form_state = new FormState();
Angie Byron
committed
$form = $this->formBuilder->buildForm($form_arg, $form_state);
$this->assertFormElement($expected_form, $form, 'test');
Alex Pott
committed
$this->assertSame($form_id, $form_state['build_info']['form_id']);
$this->assertSame($form_id, $form['#id']);
}
/**
* Tests the rebuildForm() method.
*/
public function testRebuildForm() {
$form_id = 'test_form_id';
$expected_form = $form_id();
Angie Byron
committed
// The form will be built four times.
Angie Byron
committed
$form_arg = $this->getMock('Drupal\Core\Form\FormInterface');
$form_arg->expects($this->exactly(2))
->method('getFormId')
->will($this->returnValue($form_id));
$form_arg->expects($this->exactly(4))
->method('buildForm')
->will($this->returnValue($expected_form));
Alex Pott
committed
// Do an initial build of the form and track the build ID.
Dries Buytaert
committed
$form_state = new FormState();
Angie Byron
committed
$form = $this->formBuilder->buildForm($form_arg, $form_state);
Alex Pott
committed
$original_build_id = $form['#build_id'];
// Rebuild the form, and assert that the build ID has not changed.
$form_state['rebuild'] = TRUE;
Angie Byron
committed
$input['form_id'] = $form_id;
$form_state->setUserInput($input);
Alex Pott
committed
$form_state['rebuild_info']['copy']['#build_id'] = TRUE;
$this->formBuilder->processForm($form_id, $form, $form_state);
$this->assertSame($original_build_id, $form['#build_id']);
// Rebuild the form again, and assert that there is a new build ID.
$form_state['rebuild_info'] = array();
Angie Byron
committed
$form = $this->formBuilder->buildForm($form_arg, $form_state);
Alex Pott
committed
$this->assertNotSame($original_build_id, $form['#build_id']);
}
/**
* Tests the getCache() method.
*/
public function testGetCache() {
$form_id = 'test_form_id';
$expected_form = $form_id();
Angie Byron
committed
$expected_form['#token'] = FALSE;
Alex Pott
committed
Angie Byron
committed
// FormBuilder::buildForm() will be called twice, but the form object will
// only be called once due to caching.
$form_arg = $this->getMock('Drupal\Core\Form\FormInterface');
$form_arg->expects($this->exactly(2))
->method('getFormId')
->will($this->returnValue($form_id));
$form_arg->expects($this->once())
->method('buildForm')
->will($this->returnValue($expected_form));
Alex Pott
committed
// Do an initial build of the form and track the build ID.
Dries Buytaert
committed
$form_state = new FormState();
Alex Pott
committed
$form_state['build_info']['args'] = array();
$form_state['build_info']['files'] = array(array('module' => 'node', 'type' => 'pages.inc'));
$form_state['cache'] = TRUE;
Angie Byron
committed
$form = $this->formBuilder->buildForm($form_arg, $form_state);
Alex Pott
committed
$cached_form = $form;
$cached_form['#cache_token'] = 'csrf_token';
// The form cache, form_state cache, and CSRF token validation will only be
// called on the cached form.
Angie Byron
committed
$this->formCache->expects($this->once())
Angie Byron
committed
->method('getCache')
->willReturn($form);
Alex Pott
committed
// The final form build will not trigger any actual form building, but will
// use the form cache.
Dries Buytaert
committed
$form_state['executed'] = TRUE;
Angie Byron
committed
$input['form_id'] = $form_id;
$input['form_build_id'] = $form['#build_id'];
$form_state->setUserInput($input);
$this->formBuilder->buildForm($form_arg, $form_state);
Alex Pott
committed
$this->assertEmpty($form_state['errors']);
Alex Pott
committed
}
Angie Byron
committed
/**
* Tests the sendResponse() method.
*
* @expectedException \Exception
*/
public function testSendResponse() {
$form_id = 'test_form_id';
$expected_form = $this->getMockBuilder('Symfony\Component\HttpFoundation\Response')
->disableOriginalConstructor()
->getMock();
$expected_form->expects($this->once())
->method('prepare')
->will($this->returnValue($expected_form));
Angie Byron
committed
$form_arg = $this->getMockForm($form_id, $expected_form);
Angie Byron
committed
// Do an initial build of the form and track the build ID.
Dries Buytaert
committed
$form_state = new FormState();
Angie Byron
committed
$this->formBuilder->buildForm($form_arg, $form_state);
Angie Byron
committed
}
Alex Pott
committed
/**
* Tests that HTML IDs are unique when rebuilding a form with errors.
*/
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 two times.
$form_arg = $this->getMock('Drupal\Core\Form\FormInterface');
$form_arg->expects($this->exactly(2))
->method('getFormId')
->will($this->returnValue($form_id));
Alex Pott
committed
$form_arg->expects($this->exactly(2))
->method('buildForm')
->will($this->returnValue($expected_form));
Dries Buytaert
committed
$form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
->setMethods(array('drupalSetMessage'))
->getMock();
Alex Pott
committed
$form = $this->simulateFormSubmission($form_id, $form_arg, $form_state);
$this->assertSame($form_id, $form['#id']);
Dries Buytaert
committed
$form_state = $this->getMockBuilder('Drupal\Core\Form\FormState')
->setMethods(array('drupalSetMessage'))
->getMock();
Alex Pott
committed
$form = $this->simulateFormSubmission($form_id, $form_arg, $form_state);
$this->assertSame("$form_id--2", $form['#id']);
}
Alex Pott
committed
}
class TestForm implements FormInterface {
public function getFormId() {
return 'test_form';
}
Dries Buytaert
committed
public function buildForm(array $form, FormStateInterface $form_state) {
Angie Byron
committed
return test_form_id();
}
Dries Buytaert
committed
public function validateForm(array &$form, FormStateInterface $form_state) { }
public function submitForm(array &$form, FormStateInterface $form_state) { }
Alex Pott
committed
}
class TestFormInjected extends TestForm implements ContainerInjectionInterface {
public static function create(ContainerInterface $container) {
return new static();
}
}
}
namespace {
Dries Buytaert
committed
use Drupal\Core\Form\FormStateInterface;
function test_form_id_custom_submit(array &$form, FormStateInterface $form_state) {
Angie Byron
committed
}