FormTestBase.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <?php
  2. namespace Drupal\Tests\Core\Form;
  3. use Drupal\Component\Utility\Html;
  4. use Drupal\Core\Form\FormBuilder;
  5. use Drupal\Core\Form\FormInterface;
  6. use Drupal\Core\Form\FormState;
  7. use Drupal\Core\Form\FormStateInterface;
  8. use Drupal\Tests\UnitTestCase;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\HttpFoundation\RequestStack;
  11. /**
  12. * Provides a base class for testing form functionality.
  13. *
  14. * @see \Drupal\Core\Form\FormBuilder
  15. */
  16. abstract class FormTestBase extends UnitTestCase {
  17. /**
  18. * The form builder being tested.
  19. *
  20. * @var \Drupal\Core\Form\FormBuilderInterface
  21. */
  22. protected $formBuilder;
  23. /**
  24. * @var \Drupal\Core\Form\FormValidatorInterface|\PHPUnit\Framework\MockObject\MockObject
  25. */
  26. protected $formValidator;
  27. /**
  28. * @var \Drupal\Core\Form\FormSubmitterInterface|\PHPUnit\Framework\MockObject\MockObject
  29. */
  30. protected $formSubmitter;
  31. /**
  32. * The mocked URL generator.
  33. *
  34. * @var \Drupal\Core\Routing\UrlGeneratorInterface|\PHPUnit\Framework\MockObject\MockObject
  35. */
  36. protected $urlGenerator;
  37. /**
  38. * The mocked module handler.
  39. *
  40. * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
  41. */
  42. protected $moduleHandler;
  43. /**
  44. * The form cache.
  45. *
  46. * @var \Drupal\Core\Form\FormCacheInterface|\PHPUnit\Framework\MockObject\MockObject
  47. */
  48. protected $formCache;
  49. /**
  50. * The cache backend to use.
  51. *
  52. * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit\Framework\MockObject\MockObject
  53. */
  54. protected $cache;
  55. /**
  56. * The current user.
  57. *
  58. * @var \Drupal\Core\Session\AccountInterface|\PHPUnit\Framework\MockObject\MockObject
  59. */
  60. protected $account;
  61. /**
  62. * The controller resolver.
  63. *
  64. * @var \Drupal\Core\Controller\ControllerResolverInterface|\PHPUnit\Framework\MockObject\MockObject
  65. */
  66. protected $controllerResolver;
  67. /**
  68. * The CSRF token generator.
  69. *
  70. * @var \Drupal\Core\Access\CsrfTokenGenerator|\PHPUnit\Framework\MockObject\MockObject
  71. */
  72. protected $csrfToken;
  73. /**
  74. * The request.
  75. *
  76. * @var \Symfony\Component\HttpFoundation\Request
  77. */
  78. protected $request;
  79. /**
  80. * The request stack.
  81. *
  82. * @var \Symfony\Component\HttpFoundation\RequestStack
  83. */
  84. protected $requestStack;
  85. /**
  86. * The class results.
  87. *
  88. * @var \Drupal\Core\DependencyInjection\ClassResolverInterface|\PHPUnit\Framework\MockObject\MockObject
  89. */
  90. protected $classResolver;
  91. /**
  92. * The element info manager.
  93. *
  94. * @var \Drupal\Core\Render\ElementInfoManagerInterface
  95. */
  96. protected $elementInfo;
  97. /**
  98. * The event dispatcher.
  99. *
  100. * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject
  101. */
  102. protected $eventDispatcher;
  103. /**
  104. * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit\Framework\MockObject\MockObject
  105. */
  106. protected $translationManager;
  107. /**
  108. * @var \Drupal\Core\DrupalKernelInterface|\PHPUnit\Framework\MockObject\MockObject
  109. */
  110. protected $kernel;
  111. /**
  112. * @var \PHPUnit\Framework\MockObject\MockObject|\Psr\Log\LoggerInterface
  113. */
  114. protected $logger;
  115. /**
  116. * The mocked theme manager.
  117. *
  118. * @var \Drupal\Core\Theme\ThemeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
  119. */
  120. protected $themeManager;
  121. /**
  122. * {@inheritdoc}
  123. */
  124. protected function setUp() {
  125. parent::setUp();
  126. // Add functions to the global namespace for testing.
  127. require_once __DIR__ . '/fixtures/form_base_test.inc';
  128. $this->moduleHandler = $this->createMock('Drupal\Core\Extension\ModuleHandlerInterface');
  129. $this->formCache = $this->createMock('Drupal\Core\Form\FormCacheInterface');
  130. $this->cache = $this->createMock('Drupal\Core\Cache\CacheBackendInterface');
  131. $this->urlGenerator = $this->createMock('Drupal\Core\Routing\UrlGeneratorInterface');
  132. $this->classResolver = $this->getClassResolverStub();
  133. $this->elementInfo = $this->getMockBuilder('\Drupal\Core\Render\ElementInfoManagerInterface')
  134. ->disableOriginalConstructor()
  135. ->getMock();
  136. $this->elementInfo->expects($this->any())
  137. ->method('getInfo')
  138. ->will($this->returnCallback([$this, 'getInfo']));
  139. $this->csrfToken = $this->getMockBuilder('Drupal\Core\Access\CsrfTokenGenerator')
  140. ->disableOriginalConstructor()
  141. ->getMock();
  142. $this->kernel = $this->getMockBuilder('\Drupal\Core\DrupalKernel')
  143. ->disableOriginalConstructor()
  144. ->getMock();
  145. $this->account = $this->createMock('Drupal\Core\Session\AccountInterface');
  146. $this->themeManager = $this->createMock('Drupal\Core\Theme\ThemeManagerInterface');
  147. $this->request = Request::createFromGlobals();
  148. $this->eventDispatcher = $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
  149. $this->requestStack = new RequestStack();
  150. $this->requestStack->push($this->request);
  151. $this->logger = $this->createMock('Drupal\Core\Logger\LoggerChannelInterface');
  152. $form_error_handler = $this->createMock('Drupal\Core\Form\FormErrorHandlerInterface');
  153. $this->formValidator = $this->getMockBuilder('Drupal\Core\Form\FormValidator')
  154. ->setConstructorArgs([$this->requestStack, $this->getStringTranslationStub(), $this->csrfToken, $this->logger, $form_error_handler])
  155. ->setMethods(NULL)
  156. ->getMock();
  157. $this->formSubmitter = $this->getMockBuilder('Drupal\Core\Form\FormSubmitter')
  158. ->setConstructorArgs([$this->requestStack, $this->urlGenerator])
  159. ->setMethods(['batchGet', 'drupalInstallationAttempted'])
  160. ->getMock();
  161. $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
  162. $this->formBuilder = new FormBuilder($this->formValidator, $this->formSubmitter, $this->formCache, $this->moduleHandler, $this->eventDispatcher, $this->requestStack, $this->classResolver, $this->elementInfo, $this->themeManager, $this->csrfToken);
  163. }
  164. /**
  165. * {@inheritdoc}
  166. */
  167. protected function tearDown() {
  168. Html::resetSeenIds();
  169. (new FormState())->clearErrors();
  170. }
  171. /**
  172. * Provides a mocked form object.
  173. *
  174. * @param string $form_id
  175. * The form ID to be used.
  176. * @param mixed $expected_form
  177. * (optional) If provided, the expected form response for buildForm() to
  178. * return. Defaults to NULL.
  179. * @param int $count
  180. * (optional) The number of times the form is expected to be built. Defaults
  181. * to 1.
  182. *
  183. * @return \PHPUnit\Framework\MockObject\MockObject|\Drupal\Core\Form\FormInterface
  184. * The mocked form object.
  185. */
  186. protected function getMockForm($form_id, $expected_form = NULL, $count = 1) {
  187. $form = $this->createMock('Drupal\Core\Form\FormInterface');
  188. $form->expects($this->once())
  189. ->method('getFormId')
  190. ->will($this->returnValue($form_id));
  191. if ($expected_form) {
  192. $form->expects($this->exactly($count))
  193. ->method('buildForm')
  194. ->will($this->returnValue($expected_form));
  195. }
  196. return $form;
  197. }
  198. /**
  199. * Simulates a form submission within a request, bypassing submitForm().
  200. *
  201. * Calling submitForm() will reset the form builder, if two forms were on the
  202. * same page, they will be submitted simultaneously.
  203. *
  204. * @param string $form_id
  205. * The unique string identifying the form.
  206. * @param \Drupal\Core\Form\FormInterface $form_arg
  207. * The form object.
  208. * @param \Drupal\Core\Form\FormStateInterface $form_state
  209. * The current state of the form.
  210. * @param bool $programmed
  211. * Whether $form_state->setProgrammed() should be passed TRUE or not. If it
  212. * is not set to TRUE, you must provide additional data in $form_state for
  213. * the submission to take place.
  214. *
  215. * @return array
  216. * The built form.
  217. */
  218. protected function simulateFormSubmission($form_id, FormInterface $form_arg, FormStateInterface $form_state, $programmed = TRUE) {
  219. $input = $form_state->getUserInput();
  220. $input['op'] = 'Submit';
  221. $form_state
  222. ->setUserInput($input)
  223. ->setProgrammed($programmed)
  224. ->setSubmitted();
  225. return $this->formBuilder->buildForm($form_arg, $form_state);
  226. }
  227. /**
  228. * Asserts that the expected form structure is found in a form for a given key.
  229. *
  230. * @param array $expected_form
  231. * The expected form structure.
  232. * @param array $actual_form
  233. * The actual form.
  234. * @param string|null $form_key
  235. * (optional) The form key to look in. Otherwise the entire form will be
  236. * compared.
  237. */
  238. protected function assertFormElement(array $expected_form, array $actual_form, $form_key = NULL) {
  239. $expected_element = $form_key ? $expected_form[$form_key] : $expected_form;
  240. $actual_element = $form_key ? $actual_form[$form_key] : $actual_form;
  241. $this->assertSame(array_intersect_key($expected_element, $actual_element), $expected_element);
  242. }
  243. /**
  244. * A stub method returning properties for the defined element type.
  245. *
  246. * @param string $type
  247. * The machine name of an element type plugin.
  248. *
  249. * @return array
  250. * An array with dummy values to be used in tests. Defaults to an empty
  251. * array.
  252. */
  253. public function getInfo($type) {
  254. $types['hidden'] = [
  255. '#input' => TRUE,
  256. ];
  257. $types['token'] = [
  258. '#input' => TRUE,
  259. ];
  260. $types['value'] = [
  261. '#input' => TRUE,
  262. ];
  263. $types['radios'] = [
  264. '#input' => TRUE,
  265. ];
  266. $types['textfield'] = [
  267. '#input' => TRUE,
  268. ];
  269. $types['submit'] = [
  270. '#input' => TRUE,
  271. '#name' => 'op',
  272. '#is_button' => TRUE,
  273. ];
  274. if (!isset($types[$type])) {
  275. $types[$type] = [];
  276. }
  277. return $types[$type];
  278. }
  279. }