Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Form / EventSubscriber / FormAjaxSubscriberTest.php
1 <?php
2
3 namespace Drupal\Tests\Core\Form\EventSubscriber;
4
5 use Drupal\Core\DependencyInjection\ContainerBuilder;
6 use Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber;
7 use Drupal\Core\Form\Exception\BrokenPostRequestException;
8 use Drupal\Core\Form\FormAjaxException;
9 use Drupal\Core\Form\FormBuilderInterface;
10 use Drupal\Core\Form\FormState;
11 use Drupal\Core\Messenger\MessengerInterface;
12 use Drupal\Tests\UnitTestCase;
13 use Symfony\Component\HttpFoundation\Request;
14 use Symfony\Component\HttpFoundation\Response;
15 use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
16 use Symfony\Component\HttpKernel\Exception\HttpException;
17 use Symfony\Component\HttpKernel\HttpKernelInterface;
18
19 /**
20  * @coversDefaultClass \Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber
21  * @group EventSubscriber
22  */
23 class FormAjaxSubscriberTest extends UnitTestCase {
24
25   /**
26    * @var \Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber
27    */
28   protected $subscriber;
29
30   /**
31    * @var \Drupal\Core\Form\FormAjaxResponseBuilderInterface|\PHPUnit_Framework_MockObject_MockObject
32    */
33   protected $formAjaxResponseBuilder;
34
35   /**
36    * @var \Symfony\Component\HttpKernel\HttpKernelInterface|\PHPUnit_Framework_MockObject_MockObject
37    */
38   protected $httpKernel;
39
40   /**
41    * The mocked string translation.
42    *
43    * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject
44    */
45   protected $stringTranslation;
46
47   /**
48    * The mocked messenger.
49    *
50    * @var \Drupal\Core\Messenger\MessengerInterface|\PHPUnit_Framework_MockObject_MockObject
51    */
52   protected $messenger;
53
54   /**
55    * {@inheritdoc}
56    */
57   protected function setUp() {
58     parent::setUp();
59
60     $this->httpKernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
61     $this->formAjaxResponseBuilder = $this->getMock('Drupal\Core\Form\FormAjaxResponseBuilderInterface');
62     $this->stringTranslation = $this->getStringTranslationStub();
63     $this->messenger = $this->createMock(MessengerInterface::class);
64     $this->subscriber = new FormAjaxSubscriber($this->formAjaxResponseBuilder, $this->stringTranslation, $this->messenger);
65   }
66
67   /**
68    * @covers ::onException
69    */
70   public function testOnException() {
71     $form = ['#type' => 'form', '#build_id' => 'the_build_id'];
72     $expected_form = $form + [
73       '#build_id_old' => 'the_build_id',
74     ];
75     $form_state = new FormState();
76     $exception = new FormAjaxException($form, $form_state);
77
78     $request = new Request([], ['form_build_id' => 'the_build_id']);
79     $commands = [];
80     $response = new Response('');
81
82     $this->formAjaxResponseBuilder->expects($this->once())
83       ->method('buildResponse')
84       ->with($request, $expected_form, $form_state, $commands)
85       ->willReturn($response);
86
87     $event = $this->assertResponseFromException($request, $exception, $response);
88     $this->assertTrue($event->isAllowingCustomResponseCode());
89     $this->assertSame(200, $event->getResponse()->getStatusCode());
90   }
91
92   /**
93    * @covers ::onException
94    */
95   public function testOnExceptionNewBuildId() {
96     $form = ['#type' => 'form', '#build_id' => 'the_build_id'];
97     $expected_form = $form + [
98       '#build_id_old' => 'a_new_build_id',
99     ];
100     $form_state = new FormState();
101     $exception = new FormAjaxException($form, $form_state);
102
103     $request = new Request([], ['form_build_id' => 'a_new_build_id']);
104     $commands = [];
105     $response = new Response('');
106
107     $this->formAjaxResponseBuilder->expects($this->once())
108       ->method('buildResponse')
109       ->with($request, $expected_form, $form_state, $commands)
110       ->willReturn($response);
111
112     $event = $this->assertResponseFromException($request, $exception, $response);
113     $this->assertTrue($event->isAllowingCustomResponseCode());
114     $this->assertSame(200, $event->getResponse()->getStatusCode());
115   }
116
117   /**
118    * @covers ::onException
119    */
120   public function testOnExceptionOtherClass() {
121     $request = new Request();
122     $exception = new \Exception();
123
124     $this->formAjaxResponseBuilder->expects($this->never())
125       ->method('buildResponse');
126
127     $this->assertResponseFromException($request, $exception, NULL);
128   }
129
130   /**
131    * @covers ::onException
132    */
133   public function testOnExceptionResponseBuilderException() {
134     $form = ['#type' => 'form', '#build_id' => 'the_build_id'];
135     $expected_form = $form + [
136       '#build_id_old' => 'the_build_id',
137     ];
138     $form_state = new FormState();
139     $exception = new FormAjaxException($form, $form_state);
140     $request = new Request([], ['form_build_id' => 'the_build_id']);
141     $commands = [];
142
143     $expected_exception = new HttpException(500, 'The specified #ajax callback is empty or not callable.');
144     $this->formAjaxResponseBuilder->expects($this->once())
145       ->method('buildResponse')
146       ->with($request, $expected_form, $form_state, $commands)
147       ->willThrowException($expected_exception);
148
149     $event = $this->assertResponseFromException($request, $exception, NULL);
150     $this->assertSame($expected_exception, $event->getException());
151   }
152
153   /**
154    * @covers ::onException
155    */
156   public function testOnExceptionBrokenPostRequest() {
157     $this->formAjaxResponseBuilder->expects($this->never())
158       ->method('buildResponse');
159
160     $this->messenger->expects($this->once())
161       ->method('addError');
162
163     $this->subscriber = $this->getMockBuilder('\Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber')
164       ->setConstructorArgs([
165         $this->formAjaxResponseBuilder,
166         $this->getStringTranslationStub(),
167         $this->messenger,
168       ])
169       ->setMethods(['formatSize'])
170       ->getMock();
171
172     $this->subscriber->expects($this->once())
173       ->method('formatSize')
174       ->with(32 * 1e6)
175       ->willReturn('32M');
176     $rendered_output = 'the rendered output';
177     // CommandWithAttachedAssetsTrait::getRenderedContent() will call the
178     // renderer service via the container.
179     $renderer = $this->getMock('Drupal\Core\Render\RendererInterface');
180     $renderer->expects($this->once())
181       ->method('renderRoot')
182       ->with()
183       ->willReturnCallback(function (&$elements) use ($rendered_output) {
184         $elements['#attached'] = [];
185         return $rendered_output;
186       });
187     $container = new ContainerBuilder();
188     $container->set('renderer', $renderer);
189     \Drupal::setContainer($container);
190
191     $exception = new BrokenPostRequestException(32 * 1e6);
192     $request = new Request([FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]);
193
194     $event = new GetResponseForExceptionEvent($this->httpKernel, $request, HttpKernelInterface::MASTER_REQUEST, $exception);
195     $this->subscriber->onException($event);
196     $this->assertTrue($event->isAllowingCustomResponseCode());
197     $actual_response = $event->getResponse();
198     $this->assertInstanceOf('\Drupal\Core\Ajax\AjaxResponse', $actual_response);
199     $this->assertSame(200, $actual_response->getStatusCode());
200     $expected_commands[] = [
201       'command' => 'insert',
202       'method' => 'prepend',
203       'selector' => NULL,
204       'data' => $rendered_output,
205       'settings' => NULL,
206     ];
207     $this->assertSame($expected_commands, $actual_response->getCommands());
208   }
209
210   /**
211    * @covers ::onException
212    * @covers ::getFormAjaxException
213    */
214   public function testOnExceptionNestedException() {
215     $form = ['#type' => 'form', '#build_id' => 'the_build_id'];
216     $expected_form = $form + [
217         '#build_id_old' => 'the_build_id',
218       ];
219     $form_state = new FormState();
220     $form_exception = new FormAjaxException($form, $form_state);
221     $exception = new \Exception('', 0, $form_exception);
222
223     $request = new Request([], ['form_build_id' => 'the_build_id']);
224     $commands = [];
225     $response = new Response('');
226
227     $this->formAjaxResponseBuilder->expects($this->once())
228       ->method('buildResponse')
229       ->with($request, $expected_form, $form_state, $commands)
230       ->willReturn($response);
231
232     $this->assertResponseFromException($request, $exception, $response);
233   }
234
235   /**
236    * @covers ::getFormAjaxException
237    */
238   public function testOnExceptionNestedWrongException() {
239     $nested_exception = new \Exception();
240     $exception = new \Exception('', 0, $nested_exception);
241     $request = new Request();
242
243     $this->formAjaxResponseBuilder->expects($this->never())
244       ->method('buildResponse');
245
246     $this->assertResponseFromException($request, $exception, NULL);
247   }
248
249   /**
250    * Asserts that the expected response is derived from the given exception.
251    *
252    * @param \Symfony\Component\HttpFoundation\Request $request
253    *   The request.
254    * @param \Exception $exception
255    *   The exception to pass to the event.
256    * @param \Symfony\Component\HttpFoundation\Response|null $expected_response
257    *   The response expected to be set on the event.
258    *
259    * @return \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent
260    *   The event used to derive the response.
261    */
262   protected function assertResponseFromException(Request $request, \Exception $exception, $expected_response) {
263     $event = new GetResponseForExceptionEvent($this->httpKernel, $request, HttpKernelInterface::MASTER_REQUEST, $exception);
264     $this->subscriber->onException($event);
265
266     $this->assertSame($expected_response, $event->getResponse());
267     return $event;
268   }
269
270 }