050d74526508767bac2f0e1c5dd49255b30bb354
[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->assertSame(200, $event->getResponse()->headers->get('X-Status-Code'));
80   }
81
82   /**
83    * @covers ::onException
84    */
85   public function testOnExceptionNewBuildId() {
86     $form = ['#type' => 'form', '#build_id' => 'the_build_id'];
87     $expected_form = $form + [
88       '#build_id_old' => 'a_new_build_id',
89     ];
90     $form_state = new FormState();
91     $exception = new FormAjaxException($form, $form_state);
92
93     $request = new Request([], ['form_build_id' => 'a_new_build_id']);
94     $commands = [];
95     $response = new Response('');
96
97     $this->formAjaxResponseBuilder->expects($this->once())
98       ->method('buildResponse')
99       ->with($request, $expected_form, $form_state, $commands)
100       ->willReturn($response);
101
102     $event = $this->assertResponseFromException($request, $exception, $response);
103     $this->assertSame(200, $event->getResponse()->headers->get('X-Status-Code'));
104   }
105
106   /**
107    * @covers ::onException
108    */
109   public function testOnExceptionOtherClass() {
110     $request = new Request();
111     $exception = new \Exception();
112
113     $this->formAjaxResponseBuilder->expects($this->never())
114       ->method('buildResponse');
115
116     $this->assertResponseFromException($request, $exception, NULL);
117   }
118
119   /**
120    * @covers ::onException
121    */
122   public function testOnExceptionResponseBuilderException() {
123     $form = ['#type' => 'form', '#build_id' => 'the_build_id'];
124     $expected_form = $form + [
125       '#build_id_old' => 'the_build_id',
126     ];
127     $form_state = new FormState();
128     $exception = new FormAjaxException($form, $form_state);
129     $request = new Request([], ['form_build_id' => 'the_build_id']);
130     $commands = [];
131
132     $expected_exception = new HttpException(500, 'The specified #ajax callback is empty or not callable.');
133     $this->formAjaxResponseBuilder->expects($this->once())
134       ->method('buildResponse')
135       ->with($request, $expected_form, $form_state, $commands)
136       ->willThrowException($expected_exception);
137
138     $event = $this->assertResponseFromException($request, $exception, NULL);
139     $this->assertSame($expected_exception, $event->getException());
140   }
141
142   /**
143    * @covers ::onException
144    */
145   public function testOnExceptionBrokenPostRequest() {
146     $this->formAjaxResponseBuilder->expects($this->never())
147       ->method('buildResponse');
148     $this->subscriber = $this->getMockBuilder('\Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber')
149       ->setConstructorArgs([$this->formAjaxResponseBuilder, $this->getStringTranslationStub()])
150       ->setMethods(['drupalSetMessage', 'formatSize'])
151       ->getMock();
152     $this->subscriber->expects($this->once())
153       ->method('drupalSetMessage')
154       ->willReturn('asdf');
155     $this->subscriber->expects($this->once())
156       ->method('formatSize')
157       ->with(32 * 1e6)
158       ->willReturn('32M');
159     $rendered_output = 'the rendered output';
160     // CommandWithAttachedAssetsTrait::getRenderedContent() will call the
161     // renderer service via the container.
162     $renderer = $this->getMock('Drupal\Core\Render\RendererInterface');
163     $renderer->expects($this->once())
164       ->method('renderRoot')
165       ->with()
166       ->willReturnCallback(function (&$elements) use ($rendered_output) {
167         $elements['#attached'] = [];
168         return $rendered_output;
169       });
170     $container = new ContainerBuilder();
171     $container->set('renderer', $renderer);
172     \Drupal::setContainer($container);
173
174     $exception = new BrokenPostRequestException(32 * 1e6);
175     $request = new Request([FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]);
176
177     $event = new GetResponseForExceptionEvent($this->httpKernel, $request, HttpKernelInterface::MASTER_REQUEST, $exception);
178     $this->subscriber->onException($event);
179     $actual_response = $event->getResponse();
180     $this->assertInstanceOf('\Drupal\Core\Ajax\AjaxResponse', $actual_response);
181     $this->assertSame(200, $actual_response->headers->get('X-Status-Code'));
182     $expected_commands[] = [
183       'command' => 'insert',
184       'method' => 'replaceWith',
185       'selector' => NULL,
186       'data' => $rendered_output,
187       'settings' => NULL,
188     ];
189     $this->assertSame($expected_commands, $actual_response->getCommands());
190   }
191
192   /**
193    * @covers ::onException
194    * @covers ::getFormAjaxException
195    */
196   public function testOnExceptionNestedException() {
197     $form = ['#type' => 'form', '#build_id' => 'the_build_id'];
198     $expected_form = $form + [
199         '#build_id_old' => 'the_build_id',
200       ];
201     $form_state = new FormState();
202     $form_exception = new FormAjaxException($form, $form_state);
203     $exception = new \Exception('', 0, $form_exception);
204
205     $request = new Request([], ['form_build_id' => 'the_build_id']);
206     $commands = [];
207     $response = new Response('');
208
209     $this->formAjaxResponseBuilder->expects($this->once())
210       ->method('buildResponse')
211       ->with($request, $expected_form, $form_state, $commands)
212       ->willReturn($response);
213
214     $this->assertResponseFromException($request, $exception, $response);
215   }
216
217   /**
218    * @covers ::getFormAjaxException
219    */
220   public function testOnExceptionNestedWrongException() {
221     $nested_exception = new \Exception();
222     $exception = new \Exception('', 0, $nested_exception);
223     $request = new Request();
224
225     $this->formAjaxResponseBuilder->expects($this->never())
226       ->method('buildResponse');
227
228     $this->assertResponseFromException($request, $exception, NULL);
229   }
230
231   /**
232    * Asserts that the expected response is derived from the given exception.
233    *
234    * @param \Symfony\Component\HttpFoundation\Request $request
235    *   The request.
236    * @param \Exception $exception
237    *   The exception to pass to the event.
238    * @param \Symfony\Component\HttpFoundation\Response|null $expected_response
239    *   The response expected to be set on the event.
240    *
241    * @return \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent
242    *   The event used to derive the response.
243    */
244   protected function assertResponseFromException(Request $request, \Exception $exception, $expected_response) {
245     $event = new GetResponseForExceptionEvent($this->httpKernel, $request, HttpKernelInterface::MASTER_REQUEST, $exception);
246     $this->subscriber->onException($event);
247
248     $this->assertSame($expected_response, $event->getResponse());
249     return $event;
250   }
251
252 }