3 namespace Drupal\Tests\views\Unit\Controller;
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;
16 * @coversDefaultClass \Drupal\views\Controller\ViewAjaxController
19 class ViewAjaxControllerTest extends UnitTestCase {
22 * The mocked view entity storage.
24 * @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit_Framework_MockObject_MockObject
26 protected $viewStorage;
29 * The mocked executable factory.
31 * @var \Drupal\views\ViewExecutableFactory|\PHPUnit_Framework_MockObject_MockObject
33 protected $executableFactory;
36 * The tested views ajax controller.
38 * @var \Drupal\views\Controller\ViewAjaxController
40 protected $viewAjaxController;
43 * The mocked current path.
45 * @var \Drupal\Core\Path\CurrentPathStack|\PHPUnit_Framework_MockObject_MockObject
47 protected $currentPath;
50 * The redirect destination.
52 * @var \Drupal\Core\Routing\RedirectDestinationInterface|\PHPUnit_Framework_MockObject_MockObject
54 protected $redirectDestination;
59 * @var \Drupal\Core\Render\RendererInterface|\PHPUnit_Framework_MockObject_MockObject
66 protected function setUp() {
67 $this->viewStorage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
68 $this->executableFactory = $this->getMockBuilder('Drupal\views\ViewExecutableFactory')
69 ->disableOriginalConstructor()
71 $this->renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
72 $this->renderer->expects($this->any())
74 ->will($this->returnCallback(function(array &$elements) {
75 $elements['#attached'] = [];
76 return isset($elements['#markup']) ? $elements['#markup'] : '';
78 $this->renderer->expects($this->any())
79 ->method('executeInRenderContext')
80 ->willReturnCallback(function (RenderContext $context, callable $callable) {
83 $this->currentPath = $this->getMockBuilder('Drupal\Core\Path\CurrentPathStack')
84 ->disableOriginalConstructor()
86 $this->redirectDestination = $this->getMock('\Drupal\Core\Routing\RedirectDestinationInterface');
88 $this->viewAjaxController = new ViewAjaxController($this->viewStorage, $this->executableFactory, $this->renderer, $this->currentPath, $this->redirectDestination);
90 $element_info_manager = $this->getMock('\Drupal\Core\Render\ElementInfoManagerInterface');
91 $request_stack = new RequestStack();
92 $request_stack->push(new Request());
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'),
101 'required_cache_contexts' => [
102 'languages:language_interface',
107 $this->renderer = $this->getMockBuilder('Drupal\Core\Render\Renderer')
108 ->setConstructorArgs($args)
111 $container = new ContainerBuilder();
112 $container->set('renderer', $this->renderer);
113 \Drupal::setContainer($container);
117 * Tests missing view_name and view_display_id
119 public function testMissingViewName() {
120 $request = new Request();
121 $this->setExpectedException(NotFoundHttpException::class);
122 $this->viewAjaxController->ajaxView($request);
126 * Tests with view_name and view_display_id but not existing view.
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');
133 $this->viewStorage->expects($this->once())
136 ->will($this->returnValue(FALSE));
138 $this->setExpectedException(NotFoundHttpException::class);
139 $this->viewAjaxController->ajaxView($request);
143 * Tests a view without having access to it.
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');
150 $view = $this->getMockBuilder('Drupal\views\Entity\View')
151 ->disableOriginalConstructor()
154 $this->viewStorage->expects($this->once())
157 ->will($this->returnValue($view));
159 $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
160 ->disableOriginalConstructor()
162 $executable->expects($this->once())
164 ->will($this->returnValue(FALSE));
166 $this->executableFactory->expects($this->once())
169 ->will($this->returnValue($executable));
171 $this->setExpectedException(AccessDeniedHttpException::class);
172 $this->viewAjaxController->ajaxView($request);
176 * Tests a valid view without arguments pagers etc.
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');
187 list($view, $executable) = $this->setupValidMocks();
189 $display_handler = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
190 ->disableOriginalConstructor()
192 // Ensure that the pager element is not set.
193 $display_handler->expects($this->never())
194 ->method('setOption');
196 $display_collection = $this->getMockBuilder('Drupal\views\DisplayPluginCollection')
197 ->disableOriginalConstructor()
199 $display_collection->expects($this->any())
202 ->will($this->returnValue($display_handler));
204 $executable->displayHandlers = $display_collection;
206 $this->redirectDestination->expects($this->atLeastOnce())
208 ->with('/test-page?type=article');
210 $response = $this->viewAjaxController->ajaxView($request);
211 $this->assertTrue($response instanceof ViewAjaxResponse);
213 $this->assertSame($response->getView(), $executable);
215 $this->assertViewResultCommand($response);
219 * Tests a valid view with arguments.
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');
227 list($view, $executable) = $this->setupValidMocks();
228 $executable->expects($this->once())
230 ->with('page_1', ['arg1', 'arg2']);
232 $response = $this->viewAjaxController->ajaxView($request);
233 $this->assertTrue($response instanceof ViewAjaxResponse);
235 $this->assertViewResultCommand($response);
239 * Tests a valid view with arguments.
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/');
248 list($view, $executable) = $this->setupValidMocks();
249 $executable->expects($this->once())
251 ->with('page_1', $this->identicalTo(['arg1', NULL]));
253 $response = $this->viewAjaxController->ajaxView($request);
254 $this->assertTrue($response instanceof ViewAjaxResponse);
256 $this->assertViewResultCommand($response);
260 * Tests a valid view with a pager.
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');
270 list($view, $executable) = $this->setupValidMocks();
272 $display_handler = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
273 ->disableOriginalConstructor()
275 $display_handler->expects($this->once())
276 ->method('setOption', '0')
277 ->with($this->equalTo('pager_element'));
279 $display_collection = $this->getMockBuilder('Drupal\views\DisplayPluginCollection')
280 ->disableOriginalConstructor()
282 $display_collection->expects($this->any())
285 ->will($this->returnValue($display_handler));
286 $executable->displayHandlers = $display_collection;
288 $response = $this->viewAjaxController->ajaxView($request);
289 $this->assertTrue($response instanceof ViewAjaxResponse);
291 $commands = $this->getCommands($response);
292 $this->assertEquals('viewsScrollTop', $commands[0]['command']);
293 $this->assertEquals('.js-view-dom-id-' . $dom_id, $commands[0]['selector']);
295 $this->assertViewResultCommand($response, 1);
299 * Sets up a bunch of valid mocks like the view entity and executable.
301 protected function setupValidMocks() {
302 $view = $this->getMockBuilder('Drupal\views\Entity\View')
303 ->disableOriginalConstructor()
306 $this->viewStorage->expects($this->once())
309 ->will($this->returnValue($view));
311 $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
312 ->disableOriginalConstructor()
314 $executable->expects($this->once())
316 ->will($this->returnValue(TRUE));
317 $executable->expects($this->once())
319 ->will($this->returnValue(['#markup' => 'View result']));
321 $this->executableFactory->expects($this->once())
324 ->will($this->returnValue($executable));
326 return [$view, $executable];
330 * Gets the commands entry from the response object.
332 * @param \Drupal\views\Ajax\ViewAjaxResponse $response
333 * The views ajax response object.
336 * Returns the commands.
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);
346 * Ensures that the main view content command is added.
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.
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']);