3 namespace Drupal\Tests\entity_browser\Kernel\Extension;
5 use Drupal\Component\FileCache\FileCacheFactory;
6 use Drupal\Component\Plugin\Exception\PluginException;
7 use Drupal\Core\Config\Entity\ConfigEntityStorage;
8 use Drupal\Core\Entity\EntityMalformedException;
9 use Drupal\Core\Form\FormState;
10 use Drupal\entity_browser\DisplayInterface;
11 use Drupal\entity_browser\EntityBrowserInterface;
12 use Drupal\entity_browser\WidgetInterface;
13 use Drupal\entity_browser\WidgetSelectorInterface;
14 use Drupal\entity_browser\SelectionDisplayInterface;
15 use Drupal\KernelTests\KernelTestBase;
16 use Drupal\user\Entity\User;
17 use Drupal\views\Entity\View;
20 * Tests the entity_browser config entity.
22 * @group entity_browser
24 class EntityBrowserTest extends KernelTestBase {
31 public static $modules = [
38 'entity_browser_test',
42 * The entity browser storage.
44 * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
46 protected $controller;
53 protected $widgetUUID;
56 * Route provider service.
58 * @var \Drupal\Core\Routing\RouteProviderInterface
60 protected $routeProvider;
65 protected function setUp() {
66 FileCacheFactory::setPrefix($this->randomString(4));
69 $this->controller = $this->container->get('entity.manager')->getStorage('entity_browser');
70 $this->widgetUUID = $this->container->get('uuid')->generate();
71 $this->routeProvider = $this->container->get('router.route_provider');
73 $this->installSchema('system', ['router', 'key_value_expire', 'sequences']);
74 View::create(['id' => 'test_view'])->save();
78 * Tests CRUD operations.
80 public function testEntityBrowserCrud() {
81 $this->assertTrue($this->controller instanceof ConfigEntityStorage, 'The entity_browser storage is loaded.');
83 // Run each test method in the same installation.
90 * Tests the creation of entity_browser.
92 protected function createTests() {
94 'name' => 'test_browser',
95 'label' => 'Testing entity browser instance',
96 'display' => 'standalone',
97 'display_configuration' => ['path' => 'test-browser-test'],
98 'selection_display' => 'no_display',
99 'selection_display_configuration' => [],
100 'widget_selector' => 'single',
101 'widget_selector_configuration' => [],
103 $this->widgetUUID => [
105 'label' => 'View widget',
106 'uuid' => $this->widgetUUID,
109 'view' => 'test_view',
110 'view_display' => 'test_display',
117 'display' => 'getDisplay',
118 'selection_display' => 'getSelectionDisplay',
119 'widget_selector' => 'getWidgetSelector',
120 ] as $plugin_type => $function_name) {
121 $current_plugin = $plugin;
122 unset($current_plugin[$plugin_type]);
124 // Attempt to create an entity_browser without required plugin.
126 $entity = $this->controller->create($current_plugin);
127 $entity->{$function_name}();
128 $this->fail('An entity browser without required ' . $plugin_type . ' created with no exception thrown.');
130 catch (PluginException $e) {
131 $this->assertEquals('The "" plugin does not exist.', $e->getMessage(), 'An exception was thrown when an entity_browser was created without a ' . $plugin_type . ' plugin.');
135 // Try to create an entity browser w/o the ID.
136 $current_plugin = $plugin;
137 unset($current_plugin['name']);
139 $entity = $this->controller->create($current_plugin);
141 $this->fail('An entity browser without required name created with no exception thrown.');
143 catch (EntityMalformedException $e) {
144 $this->assertEquals('The entity does not have an ID.', $e->getMessage(), 'An exception was thrown when an entity_browser was created without a name.');
147 // Create an entity_browser with required values.
148 $entity = $this->controller->create($plugin);
151 $this->assertTrue($entity instanceof EntityBrowserInterface, 'The newly created entity is an Entity browser.');
153 // Verify all of the properties.
154 $actual_properties = $this->container->get('config.factory')
155 ->get('entity_browser.browser.test_browser')
158 $this->assertTrue(!empty($actual_properties['uuid']), 'The entity browser UUID is set.');
159 unset($actual_properties['uuid']);
161 // Ensure that default values are filled in.
162 $expected_properties = [
163 'langcode' => $this->container->get('language_manager')->getDefaultLanguage()->getId(),
166 'config' => ['views.view.test_view'],
167 'module' => ['views'],
169 'name' => 'test_browser',
170 'label' => 'Testing entity browser instance',
171 'display' => 'standalone',
172 'display_configuration' => ['path' => 'test-browser-test'],
173 'selection_display' => 'no_display',
174 'selection_display_configuration' => [],
175 'widget_selector' => 'single',
176 'widget_selector_configuration' => [],
178 $this->widgetUUID => [
180 'label' => 'View widget',
181 'uuid' => $this->widgetUUID,
184 'view' => 'test_view',
185 'view_display' => 'test_display',
186 'submit_text' => 'Select entities',
187 'auto_select' => FALSE,
193 $this->assertEquals($actual_properties, $expected_properties, 'Actual config properties are structured as expected.');
195 // Ensure that rebuilding routes works.
196 $route = $this->routeProvider->getRoutesByPattern('/test-browser-test');
197 $this->assertTrue($route, 'Route exists.');
201 * Tests the loading of entity browser.
203 protected function loadTests() {
204 /** @var \Drupal\entity_browser\EntityBrowserInterface $entity */
205 $entity = $this->controller->load('test_browser');
207 $this->assertTrue($entity instanceof EntityBrowserInterface, 'The loaded entity is an entity browser.');
209 // Verify several properties of the entity browser.
210 $this->assertEquals($entity->label(), 'Testing entity browser instance');
211 $this->assertTrue($entity->uuid());
212 $plugin = $entity->getDisplay();
213 $this->assertTrue($plugin instanceof DisplayInterface, 'Testing display plugin.');
214 $this->assertEquals($plugin->getPluginId(), 'standalone');
215 $plugin = $entity->getSelectionDisplay();
216 $this->assertTrue($plugin instanceof SelectionDisplayInterface, 'Testing selection display plugin.');
217 $this->assertEquals($plugin->getPluginId(), 'no_display');
218 $plugin = $entity->getWidgetSelector();
219 $this->assertTrue($plugin instanceof WidgetSelectorInterface, 'Testing widget selector plugin.');
220 $this->assertEquals($plugin->getPluginId(), 'single');
221 $plugin = $entity->getWidget($this->widgetUUID);
222 $this->assertTrue($plugin instanceof WidgetInterface, 'Testing widget plugin.');
223 $this->assertEquals($plugin->getPluginId(), 'view');
227 * Tests the deleting of entity browser.
229 protected function deleteTests() {
230 $entity = $this->controller->load('test_browser');
232 // Ensure that the storage isn't currently empty.
233 $config_storage = $this->container->get('config.storage');
234 $config = $config_storage->listAll('entity_browser.browser.');
235 $this->assertFalse(empty($config), 'There are entity browsers in config storage.');
237 // Delete the entity browser.
240 // Ensure that the storage is now empty.
241 $config = $config_storage->listAll('entity_browser.browser.');
242 $this->assertTrue(empty($config), 'There are no entity browsers in config storage.');
246 * Tests dynamic routes.
248 public function testDynamicRoutes() {
249 $this->installConfig(['entity_browser_test']);
250 $this->container->get('router.builder')->rebuild();
252 /** @var \Drupal\entity_browser\EntityBrowserInterface $entity */
253 $entity = $this->controller->load('test');
254 $route = $entity->route();
256 $this->assertEquals($route->getPath(), '/entity-browser/test', 'Dynamic path matches.');
257 $this->assertEquals($route->getDefault('entity_browser_id'), $entity->id(), 'Entity browser ID matches.');
258 $this->assertEquals($route->getDefault('_controller'), 'Drupal\entity_browser\Controllers\EntityBrowserFormController::getContentResult', 'Controller matches.');
259 $this->assertEquals($route->getDefault('_title_callback'), 'Drupal\entity_browser\Controllers\EntityBrowserFormController::title', 'Title callback matches.');
260 $this->assertEquals($route->getRequirement('_permission'), 'access ' . $entity->id() . ' entity browser pages', 'Permission matches.');
263 $registered_route = $this->routeProvider->getRouteByName('entity_browser.' . $entity->id());
265 catch (\Exception $e) {
266 $this->fail(t('Expected route not found: @message', ['@message' => $e->getMessage()]));
270 $this->assertEquals($registered_route->getPath(), '/entity-browser/test', 'Dynamic path matches.');
271 $this->assertEquals($registered_route->getDefault('entity_browser_id'), $entity->id(), 'Entity browser ID matches.');
272 $this->assertEquals($registered_route->getDefault('_controller'), 'Drupal\entity_browser\Controllers\EntityBrowserFormController::getContentResult', 'Controller matches.');
273 $this->assertEquals($registered_route->getDefault('_title_callback'), 'Drupal\entity_browser\Controllers\EntityBrowserFormController::title', 'Title callback matches.');
274 $this->assertEquals($registered_route->getRequirement('_permission'), 'access ' . $entity->id() . ' entity browser pages', 'Permission matches.');
278 * Tests dynamically generated permissions.
280 public function testDynamicPermissions() {
281 $this->installConfig(['entity_browser_test']);
282 $permissions = $this->container->get('user.permissions')->getPermissions();
284 /** @var \Drupal\entity_browser\EntityBrowserInterface $entity */
285 $entity = $this->controller->load('test');
287 $expected_permission_name = 'access ' . $entity->id() . ' entity browser pages';
288 $expected_permission = [
289 'title' => $this->container->get('string_translation')
290 ->translate('Access @name pages', ['@name' => $entity->label()])
292 'description' => $this->container->get('string_translation')
293 ->translate('Access pages that %browser uses to operate.', ['%browser' => $entity->label()])
295 'provider' => 'entity_browser',
298 $this->assertSame($permissions[$expected_permission_name]['title']->render(), $expected_permission['title'], 'Dynamically generated permission title found.');
299 $this->assertSame($permissions[$expected_permission_name]['description']->render(), $expected_permission['description'], 'Dynamically generated permission description found.');
300 $this->assertSame($permissions[$expected_permission_name]['provider'], $expected_permission['provider'], 'Dynamically generated permission provider found.');
304 * Tests default widget selector.
306 public function testDefaultWidget() {
307 $this->installConfig(['entity_browser_test']);
309 /** @var \Drupal\entity_browser\EntityBrowserInterface $entity */
310 $entity = $this->controller->load('test');
312 /** @var \Drupal\entity_browser\EntityBrowserFormInterface $form_object */
313 $form_object = $entity->getFormObject();
314 $form_object->setEntityBrowser($entity);
315 $form_state = new FormState();
318 $form = $form_object->buildForm($form, $form_state);
319 $this->assertEquals($form['widget']['#markup'], 'Number one', 'First widget is active.');
321 // Change weight and expect second widget to become first.
322 $entity->getWidget($entity->getFirstWidget())->setWeight(3);
323 $form_state->set('entity_browser_current_widget', NULL);
324 $entity->getWidgets()->sort();
327 $form = $form_object->buildForm($form, $form_state);
328 $this->assertEquals($form['widget']['#markup'], 'Number two', 'Second widget is active after changing widgets.');
332 * Test selected event dispatch.
334 public function testSelectedEvent() {
335 $this->installConfig(['entity_browser_test']);
337 /** @var \Drupal\entity_browser\EntityBrowserInterface $entity */
338 $entity = $this->controller->load('dummy_widget');
340 /** @var \Drupal\entity_browser\EntityBrowserFormInterface $form_object */
341 $form_object = $entity->getFormObject();
342 $form_object->setEntityBrowser($entity);
344 $form_state = new FormState();
345 $entity->getWidgets()->get($entity->getFirstWidget())->entity = $entity;
347 $this->container->get('form_builder')->buildForm($form_object, $form_state);
348 $this->assertEquals(0, count($form_state->get([
351 ])), 'Correct number of entities was propagated.');
353 $this->container->get('form_builder')->submitForm($form_object, $form_state);
355 // Event should be dispatched from widget and added to list of selected
357 $selected_entities = $form_state->get([
361 $this->assertEquals($selected_entities, [$entity], 'Expected selected entities detected.');
365 * Tests propagation of existing selection.
367 public function testExistingSelection() {
368 $this->installConfig(['entity_browser_test']);
369 $this->installEntitySchema('user');
371 /** @var \Drupal\entity_browser\EntityBrowserInterface $entity */
372 $entity = $this->controller->load('test');
374 /** @var \Drupal\user\UserInterface $user */
375 $user = $this->container->get('entity_type.manager')
378 'name' => $this->randomString(),
379 'mail' => 'info@example.com',
383 /** @var \Symfony\Component\HttpFoundation\Request $request */
384 $uuid = $this->container->get('uuid')->generate();
385 $this->container->get('request_stack')
386 ->getCurrentRequest()
388 ->set('uuid', $uuid);
389 $this->container->get('entity_browser.selection_storage')->setWithExpire($uuid, ['selected_entities' => [$user]], 21600);
391 /** @var \Drupal\entity_browser\EntityBrowserFormInterface $form_object */
392 $form_object = $entity->getFormObject();
393 $form_object->setEntityBrowser($entity);
394 $form_state = new FormState();
397 $form_object->buildForm($form, $form_state);
398 $propagated_entities = $form_state->get([
402 $this->assertEquals(1, count($propagated_entities), 'Correct number of entities was propagated.');
403 $this->assertEquals($user->id(), $propagated_entities[0]->id(), 'Propagated entity ID is correct.');
404 $this->assertEquals($user->getAccountName(), $propagated_entities[0]->getAccountName(), 'Propagated entity name is correct.');
405 $this->assertEquals($user->getEmail(), $propagated_entities[0]->getEmail(), 'Propagated entity name is correct.');
411 public function testValidators() {
412 $this->installConfig(['entity_browser_test']);
413 $this->installEntitySchema('user');
415 /** @var \Drupal\entity_browser\EntityBrowserInterface $entity */
416 $entity = $this->controller->load('test');
418 /** @var \Drupal\user\UserInterface $user */
419 $user = $this->container->get('entity_type.manager')
422 'name' => $this->randomString(),
423 'mail' => 'info@example.com',
427 /** @var \Symfony\Component\HttpFoundation\Request $request */
428 $uuid = $this->container->get('uuid')->generate();
429 $this->container->get('request_stack')
430 ->getCurrentRequest()
432 ->set('uuid', $uuid);
436 'entity_type' => ['type' => 'user'],
439 $this->container->get('entity_browser.selection_storage')->setWithExpire($uuid, $storage, 21600);
441 /** @var \Drupal\entity_browser\EntityBrowserFormInterface $form_object */
442 $form_object = $entity->getFormObject();
443 $form_object->setEntityBrowser($entity);
444 $form_state = new FormState();
446 $form = $form_object->buildForm([], $form_state);
447 $validators = $form_state->get(['entity_browser', 'validators']);
448 $this->assertSame($validators, $storage['validators'], 'Correct validators were passed to form');
450 // Set a valid triggering element
451 // (see \Drupal\entity_browser\WidgetBase::validate())
453 '#array_parents' => ['submit'],
455 $form_state->setTriggeringElement($element);
457 // Use an entity that we know will fail validation.
458 $form_state->setValue('dummy_entities', [$entity]);
459 $form_object->validateForm($form, $form_state);
461 $this->assertNotEmpty($form_state->getErrors(), t('Validation failed where expected'));
463 // Use an entity that we know will pass validation.
464 $form_state->clearErrors();
465 $form_state->setValue('dummy_entities', [$user]);
466 $form_object->validateForm($form, $form_state);
468 $this->assertEmpty($form_state->getErrors(), t('Validation succeeded where expected'));
472 * Tests view widget access.
474 public function testViewWidgetAccess() {
475 $this->installConfig(['entity_browser_test']);
476 $this->installEntitySchema('user');
477 $this->installEntitySchema('user_role');
479 /** @var \Drupal\entity_browser\EntityBrowserInterface $entity */
480 $entity = $this->controller->load('test_entity_browser_file');
482 $this->assertFalse($entity->getWidget('774798f1-5ec5-4b63-84bd-124cd51ec07d')->access()->isAllowed());
484 // Create a user that has permission to access the view and try with it.
485 /** @var \Drupal\user\RoleInterface $role */
486 $role = $this->container->get('entity_type.manager')
487 ->getStorage('user_role')
489 'name' => $this->randomString(),
490 'id' => $this->randomMachineName(),
492 $role->grantPermission('access content');
495 $user = $this->container->get('entity_type.manager')
498 'name' => $this->randomString(),
499 'mail' => 'info@example.com',
500 'roles' => $role->id(),
503 \Drupal::currentUser()->setAccount($user);
505 $this->assertTrue($entity->getWidget('774798f1-5ec5-4b63-84bd-124cd51ec07d')->access()->isAllowed());