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