Version 1
[yaffs-website] / web / core / modules / views / tests / src / Unit / Controller / ViewAjaxControllerTest.php
1 <?php
2
3 namespace Drupal\Tests\views\Unit\Controller;
4
5 use Drupal\Core\Render\RenderContext;
6 use Drupal\Tests\UnitTestCase;
7 use Drupal\views\Ajax\ViewAjaxResponse;
8 use Drupal\views\Controller\ViewAjaxController;
9 use Symfony\Component\HttpFoundation\Request;
10 use Symfony\Component\DependencyInjection\ContainerBuilder;
11 use Symfony\Component\HttpFoundation\RequestStack;
12 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
13 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
14
15 /**
16  * @coversDefaultClass \Drupal\views\Controller\ViewAjaxController
17  * @group views
18  */
19 class ViewAjaxControllerTest extends UnitTestCase {
20
21   /**
22    * The mocked view entity storage.
23    *
24    * @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit_Framework_MockObject_MockObject
25    */
26   protected $viewStorage;
27
28   /**
29    * The mocked executable factory.
30    *
31    * @var \Drupal\views\ViewExecutableFactory|\PHPUnit_Framework_MockObject_MockObject
32    */
33   protected $executableFactory;
34
35   /**
36    * The tested views ajax controller.
37    *
38    * @var \Drupal\views\Controller\ViewAjaxController
39    */
40   protected $viewAjaxController;
41
42   /**
43    * The mocked current path.
44    *
45    * @var \Drupal\Core\Path\CurrentPathStack|\PHPUnit_Framework_MockObject_MockObject
46    */
47   protected $currentPath;
48
49   /**
50    * The redirect destination.
51    *
52    * @var \Drupal\Core\Routing\RedirectDestinationInterface|\PHPUnit_Framework_MockObject_MockObject
53    */
54   protected $redirectDestination;
55
56   /**
57    * The renderer.
58    *
59    * @var \Drupal\Core\Render\RendererInterface|\PHPUnit_Framework_MockObject_MockObject
60    */
61   protected $renderer;
62
63   /**
64    * {@inheritdoc}
65    */
66   protected function setUp() {
67     $this->viewStorage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
68     $this->executableFactory = $this->getMockBuilder('Drupal\views\ViewExecutableFactory')
69       ->disableOriginalConstructor()
70       ->getMock();
71     $this->renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
72     $this->renderer->expects($this->any())
73       ->method('render')
74       ->will($this->returnCallback(function(array &$elements) {
75         $elements['#attached'] = [];
76         return isset($elements['#markup']) ? $elements['#markup'] : '';
77       }));
78     $this->renderer->expects($this->any())
79       ->method('executeInRenderContext')
80       ->willReturnCallback(function (RenderContext $context, callable $callable) {
81         return $callable();
82       });
83     $this->currentPath = $this->getMockBuilder('Drupal\Core\Path\CurrentPathStack')
84       ->disableOriginalConstructor()
85       ->getMock();
86     $this->redirectDestination = $this->getMock('\Drupal\Core\Routing\RedirectDestinationInterface');
87
88     $this->viewAjaxController = new ViewAjaxController($this->viewStorage, $this->executableFactory, $this->renderer, $this->currentPath, $this->redirectDestination);
89
90     $element_info_manager = $this->getMock('\Drupal\Core\Render\ElementInfoManagerInterface');
91     $request_stack = new RequestStack();
92     $request_stack->push(new Request());
93     $args = [
94       $this->getMock('\Drupal\Core\Controller\ControllerResolverInterface'),
95       $this->getMock('\Drupal\Core\Theme\ThemeManagerInterface'),
96       $element_info_manager,
97       $this->getMock('\Drupal\Core\Render\PlaceholderGeneratorInterface'),
98       $this->getMock('\Drupal\Core\Render\RenderCacheInterface'),
99       $request_stack,
100       [
101         'required_cache_contexts' => [
102           'languages:language_interface',
103           'theme',
104         ],
105       ],
106     ];
107     $this->renderer = $this->getMockBuilder('Drupal\Core\Render\Renderer')
108       ->setConstructorArgs($args)
109       ->setMethods(NULL)
110       ->getMock();
111     $container = new ContainerBuilder();
112     $container->set('renderer', $this->renderer);
113     \Drupal::setContainer($container);
114   }
115
116   /**
117    * Tests missing view_name and view_display_id
118    */
119   public function testMissingViewName() {
120     $request = new Request();
121     $this->setExpectedException(NotFoundHttpException::class);
122     $this->viewAjaxController->ajaxView($request);
123   }
124
125   /**
126    * Tests with view_name and view_display_id but not existing view.
127    */
128   public function testMissingView() {
129     $request = new Request();
130     $request->request->set('view_name', 'test_view');
131     $request->request->set('view_display_id', 'page_1');
132
133     $this->viewStorage->expects($this->once())
134       ->method('load')
135       ->with('test_view')
136       ->will($this->returnValue(FALSE));
137
138     $this->setExpectedException(NotFoundHttpException::class);
139     $this->viewAjaxController->ajaxView($request);
140   }
141
142   /**
143    * Tests a view without having access to it.
144    */
145   public function testAccessDeniedView() {
146     $request = new Request();
147     $request->request->set('view_name', 'test_view');
148     $request->request->set('view_display_id', 'page_1');
149
150     $view = $this->getMockBuilder('Drupal\views\Entity\View')
151       ->disableOriginalConstructor()
152       ->getMock();
153
154     $this->viewStorage->expects($this->once())
155       ->method('load')
156       ->with('test_view')
157       ->will($this->returnValue($view));
158
159     $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
160       ->disableOriginalConstructor()
161       ->getMock();
162     $executable->expects($this->once())
163       ->method('access')
164       ->will($this->returnValue(FALSE));
165
166     $this->executableFactory->expects($this->once())
167       ->method('get')
168       ->with($view)
169       ->will($this->returnValue($executable));
170
171     $this->setExpectedException(AccessDeniedHttpException::class);
172     $this->viewAjaxController->ajaxView($request);
173   }
174
175   /**
176    * Tests a valid view without arguments pagers etc.
177    */
178   public function testAjaxView() {
179     $request = new Request();
180     $request->request->set('view_name', 'test_view');
181     $request->request->set('view_display_id', 'page_1');
182     $request->request->set('view_path', '/test-page');
183     $request->request->set('_wrapper_format', 'ajax');
184     $request->request->set('ajax_page_state', 'drupal.settings[]');
185     $request->request->set('type', 'article');
186
187     list($view, $executable) = $this->setupValidMocks();
188
189     $display_handler = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
190       ->disableOriginalConstructor()
191       ->getMock();
192     // Ensure that the pager element is not set.
193     $display_handler->expects($this->never())
194       ->method('setOption');
195
196     $display_collection = $this->getMockBuilder('Drupal\views\DisplayPluginCollection')
197       ->disableOriginalConstructor()
198       ->getMock();
199     $display_collection->expects($this->any())
200       ->method('get')
201       ->with('page_1')
202       ->will($this->returnValue($display_handler));
203
204     $executable->displayHandlers = $display_collection;
205
206     $this->redirectDestination->expects($this->atLeastOnce())
207       ->method('set')
208       ->with('/test-page?type=article');
209
210     $response = $this->viewAjaxController->ajaxView($request);
211     $this->assertTrue($response instanceof ViewAjaxResponse);
212
213     $this->assertSame($response->getView(), $executable);
214
215     $this->assertViewResultCommand($response);
216   }
217
218   /**
219    * Tests a valid view with arguments.
220    */
221   public function testAjaxViewWithArguments() {
222     $request = new Request();
223     $request->request->set('view_name', 'test_view');
224     $request->request->set('view_display_id', 'page_1');
225     $request->request->set('view_args', 'arg1/arg2');
226
227     list($view, $executable) = $this->setupValidMocks();
228     $executable->expects($this->once())
229       ->method('preview')
230       ->with('page_1', ['arg1', 'arg2']);
231
232     $response = $this->viewAjaxController->ajaxView($request);
233     $this->assertTrue($response instanceof ViewAjaxResponse);
234
235     $this->assertViewResultCommand($response);
236   }
237
238   /**
239    * Tests a valid view with arguments.
240    */
241   public function testAjaxViewWithEmptyArguments() {
242     $request = new Request();
243     $request->request->set('view_name', 'test_view');
244     $request->request->set('view_display_id', 'page_1');
245     // Simulate a request that has a second, empty argument.
246     $request->request->set('view_args', 'arg1/');
247
248     list($view, $executable) = $this->setupValidMocks();
249     $executable->expects($this->once())
250       ->method('preview')
251       ->with('page_1', $this->identicalTo(['arg1', NULL]));
252
253     $response = $this->viewAjaxController->ajaxView($request);
254     $this->assertTrue($response instanceof ViewAjaxResponse);
255
256     $this->assertViewResultCommand($response);
257   }
258
259   /**
260    * Tests a valid view with a pager.
261    */
262   public function testAjaxViewWithPager() {
263     $request = new Request();
264     $request->request->set('view_name', 'test_view');
265     $request->request->set('view_display_id', 'page_1');
266     $dom_id = $this->randomMachineName(20);
267     $request->request->set('view_dom_id', $dom_id);
268     $request->request->set('pager_element', '0');
269
270     list($view, $executable) = $this->setupValidMocks();
271
272     $display_handler = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
273       ->disableOriginalConstructor()
274       ->getMock();
275     $display_handler->expects($this->once())
276       ->method('setOption', '0')
277       ->with($this->equalTo('pager_element'));
278
279     $display_collection = $this->getMockBuilder('Drupal\views\DisplayPluginCollection')
280       ->disableOriginalConstructor()
281       ->getMock();
282     $display_collection->expects($this->any())
283       ->method('get')
284       ->with('page_1')
285       ->will($this->returnValue($display_handler));
286     $executable->displayHandlers = $display_collection;
287
288     $response = $this->viewAjaxController->ajaxView($request);
289     $this->assertTrue($response instanceof ViewAjaxResponse);
290
291     $commands = $this->getCommands($response);
292     $this->assertEquals('viewsScrollTop', $commands[0]['command']);
293     $this->assertEquals('.js-view-dom-id-' . $dom_id, $commands[0]['selector']);
294
295     $this->assertViewResultCommand($response, 1);
296   }
297
298   /**
299    * Sets up a bunch of valid mocks like the view entity and executable.
300    */
301   protected function setupValidMocks() {
302     $view = $this->getMockBuilder('Drupal\views\Entity\View')
303       ->disableOriginalConstructor()
304       ->getMock();
305
306     $this->viewStorage->expects($this->once())
307       ->method('load')
308       ->with('test_view')
309       ->will($this->returnValue($view));
310
311     $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
312       ->disableOriginalConstructor()
313       ->getMock();
314     $executable->expects($this->once())
315       ->method('access')
316       ->will($this->returnValue(TRUE));
317     $executable->expects($this->once())
318       ->method('preview')
319       ->will($this->returnValue(['#markup' => 'View result']));
320
321     $this->executableFactory->expects($this->once())
322       ->method('get')
323       ->with($view)
324       ->will($this->returnValue($executable));
325
326     return [$view, $executable];
327   }
328
329   /**
330    * Gets the commands entry from the response object.
331    *
332    * @param \Drupal\views\Ajax\ViewAjaxResponse $response
333    *   The views ajax response object.
334    *
335    * @return mixed
336    *   Returns the commands.
337    */
338   protected function getCommands(ViewAjaxResponse $response) {
339     $reflection_property = new \ReflectionProperty('Drupal\views\Ajax\ViewAjaxResponse', 'commands');
340     $reflection_property->setAccessible(TRUE);
341     $commands = $reflection_property->getValue($response);
342     return $commands;
343   }
344
345   /**
346    * Ensures that the main view content command is added.
347    *
348    * @param \Drupal\views\Ajax\ViewAjaxResponse $response
349    *   The response object.
350    * @param int $position
351    *   The position where the view content command is expected.
352    */
353   protected function assertViewResultCommand(ViewAjaxResponse $response, $position = 0) {
354     $commands = $this->getCommands($response);
355     $this->assertEquals('insert', $commands[$position]['command']);
356     $this->assertEquals('View result', $commands[$position]['data']);
357   }
358
359 }