3 namespace Drupal\Tests\media_library\FunctionalJavascript;
5 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
6 use Drupal\media\Entity\Media;
7 use Drupal\Tests\TestFileCreationTrait;
8 use Drupal\user\Entity\Role;
9 use Drupal\user\RoleInterface;
12 * Contains Media library integration tests.
14 * @group media_library
16 class MediaLibraryTest extends WebDriverTestBase {
18 use TestFileCreationTrait;
23 protected static $modules = ['block', 'media_library_test'];
28 protected function setUp() {
31 // Create a few example media items for use in selection.
48 foreach ($media as $type => $names) {
49 foreach ($names as $name) {
50 $entity = Media::create(['name' => $name, 'bundle' => $type]);
51 $source_field = $type === 'type_one' ? 'field_media_test' : 'field_media_test_1';
52 $entity->setCreatedTime(++$time);
53 $entity->set($source_field, $name);
58 // Create a user who can use the Media library.
59 $user = $this->drupalCreateUser([
60 'access administration pages',
62 'access media overview',
63 'edit own basic_page content',
64 'create basic_page content',
69 $this->drupalLogin($user);
70 $this->drupalPlaceBlock('local_tasks_block');
71 $this->drupalPlaceBlock('local_actions_block');
75 * Tests that the Media library's administration page works as expected.
77 public function testAdministrationPage() {
78 $session = $this->getSession();
79 $page = $session->getPage();
80 $assert_session = $this->assertSession();
82 // Visit the administration page.
83 $this->drupalGet('admin/content/media');
85 // Verify that the "Add media" link is present.
86 $assert_session->linkExists('Add media');
88 // Verify that media from two separate types is present.
89 $assert_session->pageTextContains('Dog');
90 $assert_session->pageTextContains('Turtle');
92 // Test that users can filter by type.
93 $page->selectFieldOption('Media type', 'Type One');
94 $page->pressButton('Apply Filters');
95 $assert_session->assertWaitOnAjaxRequest();
96 $assert_session->pageTextContains('Dog');
97 $assert_session->pageTextNotContains('Turtle');
98 $page->selectFieldOption('Media type', 'Type Two');
99 $page->pressButton('Apply Filters');
100 $assert_session->assertWaitOnAjaxRequest();
101 $assert_session->pageTextNotContains('Dog');
102 $assert_session->pageTextContains('Turtle');
104 // Test that selecting elements as a part of bulk operations works.
105 $page->selectFieldOption('Media type', '- Any -');
106 $page->pressButton('Apply Filters');
107 $assert_session->assertWaitOnAjaxRequest();
108 // This tests that anchor tags clicked inside the preview are suppressed.
109 $this->getSession()->executeScript('jQuery(".js-click-to-select-trigger a")[0].click()');
110 $this->submitForm([], 'Apply to selected items');
111 $assert_session->pageTextContains('Dog');
112 $assert_session->pageTextNotContains('Cat');
113 $this->submitForm([], 'Delete');
114 $assert_session->pageTextNotContains('Dog');
115 $assert_session->pageTextContains('Cat');
117 // Test 'Select all media'.
118 $this->getSession()->getPage()->checkField('Select all media');
119 $this->getSession()->getPage()->selectFieldOption('Action', 'media_delete_action');
120 $this->submitForm([], 'Apply to selected items');
121 $this->getSession()->getPage()->pressButton('Delete');
123 $assert_session->pageTextNotContains('Cat');
124 $assert_session->pageTextNotContains('Turtle');
125 $assert_session->pageTextNotContains('Snake');
128 $assert_session->pageTextContains('No media available.');
130 // Verify that the "Table" link is present, click it and check address.
131 $assert_session->linkExists('Table');
132 $page->clickLink('Table');
133 $assert_session->addressEquals('admin/content/media-table');
134 // Verify that the "Add media" link is present.
135 $assert_session->linkExists('Add media');
139 * Tests that the Media library's widget works as expected.
141 public function testWidget() {
142 $assert_session = $this->assertSession();
143 $page = $this->getSession()->getPage();
145 // Visit a node create page.
146 $this->drupalGet('node/add/basic_page');
148 // Verify that both media widget instances are present.
149 $assert_session->pageTextContains('Unlimited media');
150 $assert_session->pageTextContains('Twin media');
152 // Add to the unlimited cardinality field.
153 $unlimited_button = $assert_session->elementExists('css', '.media-library-open-button[href*="field_unlimited_media"]');
154 $unlimited_button->click();
155 $assert_session->assertWaitOnAjaxRequest();
156 // Assert that only type_one media items exist, since this field only
157 // accepts items of that type.
158 $assert_session->pageTextContains('Media library');
159 $assert_session->pageTextContains('Dog');
160 $assert_session->pageTextContains('Bear');
161 $assert_session->pageTextNotContains('Turtle');
162 // Ensure that the "Select all" checkbox is not visible.
163 $this->assertFalse($assert_session->elementExists('css', '.media-library-select-all')->isVisible());
164 // Use an exposed filter.
165 $session = $this->getSession();
166 $session->getPage()->fillField('Name', 'Dog');
167 $session->getPage()->pressButton('Apply Filters');
168 $assert_session->assertWaitOnAjaxRequest();
169 $assert_session->pageTextContains('Dog');
170 $assert_session->pageTextNotContains('Bear');
171 // Clear the exposed filter.
172 $session->getPage()->fillField('Name', '');
173 $session->getPage()->pressButton('Apply Filters');
174 $assert_session->assertWaitOnAjaxRequest();
175 // Select the first three media items (should be Dog/Cat/Bear).
176 $checkbox_selector = '.media-library-view .js-click-to-select-checkbox input';
177 $checkboxes = $page->findAll('css', $checkbox_selector);
178 $checkboxes[0]->click();
179 $checkboxes[1]->click();
180 $checkboxes[2]->click();
181 $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Select media');
182 $assert_session->assertWaitOnAjaxRequest();
183 // Ensure that the selection completed successfully.
184 $assert_session->pageTextNotContains('Media library');
185 $assert_session->pageTextContains('Dog');
186 $assert_session->pageTextContains('Cat');
187 $assert_session->pageTextContains('Bear');
188 // Remove "Dog" (happens to be the first remove button on the page).
189 $assert_session->elementExists('css', '.media-library-item__remove')->click();
190 $assert_session->assertWaitOnAjaxRequest();
191 $assert_session->pageTextNotContains('Dog');
192 $assert_session->pageTextContains('Cat');
193 $assert_session->pageTextContains('Bear');
195 // Open another Media library on the same page.
196 $twin_button = $assert_session->elementExists('css', '.media-library-open-button[href*="field_twin_media"]');
197 $twin_button->click();
198 $assert_session->assertWaitOnAjaxRequest();
199 // This field allows both media types.
200 $assert_session->pageTextContains('Media library');
201 $assert_session->pageTextContains('Dog');
202 $assert_session->pageTextContains('Turtle');
203 // Attempt to select three items - the cardinality of this field is two so
204 // the third selection should be disabled.
205 $checkbox_selector = '.media-library-view .js-click-to-select-checkbox input';
206 $checkboxes = $page->findAll('css', $checkbox_selector);
207 $this->assertFalse($checkboxes[5]->hasAttribute('disabled'));
208 $checkboxes[0]->click();
209 $checkboxes[7]->click();
210 $this->assertTrue($checkboxes[5]->hasAttribute('disabled'));
211 $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Select media');
212 $assert_session->assertWaitOnAjaxRequest();
213 // Ensure that the selection completed successfully, and we have only two
214 // media items of two different types.
215 $assert_session->pageTextNotContains('Media library');
216 $assert_session->pageTextContains('Horse');
217 $assert_session->pageTextContains('Turtle');
218 $assert_session->pageTextNotContains('Snake');
220 // Finally, save the form.
221 $assert_session->elementExists('css', '.js-media-library-widget-toggle-weight')->click();
223 'title[0][value]' => 'My page',
224 'field_unlimited_media[selection][0][weight]' => '2',
226 $assert_session->pageTextContains('Basic Page My page has been created');
227 // We removed this item earlier.
228 $assert_session->pageTextNotContains('Dog');
229 // This item should not have been selected due to cardinality constraints.
230 $assert_session->pageTextNotContains('Snake');
231 // "Cat" should come after "Bear", since we changed the weight.
232 $assert_session->elementExists('css', '.field--name-field-unlimited-media > .field__items > .field__item:last-child:contains("Cat")');
233 // Make sure everything that was selected shows up.
234 $assert_session->pageTextContains('Cat');
235 $assert_session->pageTextContains('Bear');
236 $assert_session->pageTextContains('Horse');
237 $assert_session->pageTextContains('Turtle');
239 // Re-edit the content and make a new selection.
240 $this->drupalGet('node/1/edit');
241 $assert_session->pageTextNotContains('Dog');
242 $assert_session->pageTextContains('Cat');
243 $assert_session->pageTextContains('Bear');
244 $assert_session->pageTextContains('Horse');
245 $assert_session->pageTextContains('Turtle');
246 $unlimited_button = $assert_session->elementExists('css', '.media-library-open-button[href*="field_unlimited_media"]');
247 $unlimited_button->click();
248 $assert_session->assertWaitOnAjaxRequest();
249 $assert_session->pageTextContains('Media library');
250 // Select the first media items (should be Dog, again).
251 $checkbox_selector = '.media-library-view .js-click-to-select-checkbox input';
252 $checkboxes = $page->findAll('css', $checkbox_selector);
253 $checkboxes[0]->click();
254 $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Select media');
255 $assert_session->assertWaitOnAjaxRequest();
256 // "Dog" and the existing selection should still exist.
257 $assert_session->pageTextContains('Dog');
258 $assert_session->pageTextContains('Cat');
259 $assert_session->pageTextContains('Bear');
260 $assert_session->pageTextContains('Horse');
261 $assert_session->pageTextContains('Turtle');
265 * Tests that the widget works as expected for anonymous users.
267 public function testWidgetAnonymous() {
268 $assert_session = $this->assertSession();
270 $this->drupalLogout();
272 $role = Role::load(RoleInterface::ANONYMOUS_ID);
273 $role->revokePermission('view media');
276 // Verify that unprivileged users can't access the widget view.
277 $this->drupalGet('admin/content/media-widget');
278 $assert_session->responseContains('Access denied');
280 // Allow the anonymous user to create pages and view media.
281 $this->grantPermissions($role, [
283 'create basic_page content',
287 // Ensure the widget works as an anonymous user.
288 $this->drupalGet('node/add/basic_page');
290 // Add to the unlimited cardinality field.
291 $unlimited_button = $assert_session->elementExists('css', '.media-library-open-button[href*="field_unlimited_media"]');
292 $unlimited_button->click();
293 $assert_session->assertWaitOnAjaxRequest();
295 // Select the first media item (should be Dog).
296 $checkbox_selector = '.media-library-view .js-click-to-select-checkbox input';
297 $checkboxes = $this->getSession()->getPage()->findAll('css', $checkbox_selector);
298 $checkboxes[0]->click();
299 $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Select media');
300 $assert_session->assertWaitOnAjaxRequest();
302 // Ensure that the selection completed successfully.
303 $assert_session->pageTextNotContains('Media library');
304 $assert_session->pageTextContains('Dog');
307 $assert_session->elementExists('css', '.js-media-library-widget-toggle-weight')->click();
309 'title[0][value]' => 'My page',
310 'field_unlimited_media[selection][0][weight]' => '0',
312 $assert_session->pageTextContains('Basic Page My page has been created');
313 $assert_session->pageTextContains('Dog');
317 * Tests that uploads in the Media library's widget works as expected.
319 public function testWidgetUpload() {
320 $assert_session = $this->assertSession();
321 $page = $this->getSession()->getPage();
323 foreach ($this->getTestFiles('image') as $image) {
324 $extension = pathinfo($image->filename, PATHINFO_EXTENSION);
325 if ($extension === 'png') {
328 elseif ($extension === 'jpg') {
333 if (!isset($png_image) || !isset($jpg_image)) {
334 $this->fail('Expected test files not present.');
337 // Visit a node create page.
338 $this->drupalGet('node/add/basic_page');
340 $file_storage = $this->container->get('entity_type.manager')->getStorage('file');
341 /** @var \Drupal\Core\File\FileSystemInterface $file_system */
342 $file_system = $this->container->get('file_system');
344 // Ensure that the add button is not present if no media can be created.
345 $assert_session->elementNotExists('css', '.media-library-add-button[href*="field_noadd_media"]');
347 // Add to the twin media field using the add button directly on the widget.
348 $twin_button = $assert_session->elementExists('css', '.media-library-add-button[href*="field_twin_media"]');
349 $twin_button->click();
350 $assert_session->assertWaitOnAjaxRequest();
352 $page->attachFileToField('Upload', $this->container->get('file_system')->realpath($png_image->uri));
353 $assert_session->assertWaitOnAjaxRequest();
355 // Files are temporary until the form is saved.
356 $files = $file_storage->loadMultiple();
357 $file = array_pop($files);
358 $this->assertSame('public://type-three-dir', $file_system->dirname($file->getFileUri()));
359 $this->assertTrue($file->isTemporary());
361 $this->assertSame($assert_session->fieldExists('Name')->getValue(), $png_image->filename);
362 $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save');
363 $assert_session->assertWaitOnAjaxRequest();
364 $assert_session->pageTextContains('Alternative text field is required');
365 $page->fillField('Alternative text', $this->randomString());
366 $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save');
367 $assert_session->assertWaitOnAjaxRequest();
369 // The file should be permanent now.
370 $files = $file_storage->loadMultiple();
371 $file = array_pop($files);
372 $this->assertFalse($file->isTemporary());
374 // Ensure the media item was added.
375 $assert_session->pageTextNotContains('Media library');
376 $assert_session->pageTextContains($png_image->filename);
378 // Also make sure that we can upload to the unlimited cardinality field.
379 $unlimited_button = $assert_session->elementExists('css', '.media-library-add-button[href*="field_unlimited_media"]');
380 $unlimited_button->click();
381 $assert_session->assertWaitOnAjaxRequest();
383 // Multiple uploads should be allowed.
384 // @todo Add test when https://github.com/minkphp/Mink/issues/358 is closed
385 $this->assertTrue($assert_session->fieldExists('Upload')->hasAttribute('multiple'));
387 $page->attachFileToField('Upload', $this->container->get('file_system')->realpath($png_image->uri));
388 $assert_session->assertWaitOnAjaxRequest();
389 $page->fillField('Name', 'Unlimited Cardinality Image');
390 $page->fillField('Alternative text', $this->randomString());
391 $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save');
392 $assert_session->assertWaitOnAjaxRequest();
394 // Ensure the media item was added.
395 $assert_session->pageTextNotContains('Media library');
396 $assert_session->pageTextContains('Unlimited Cardinality Image');
398 // Open the browser again to test type resolution.
399 $twin_button = $assert_session->elementExists('css', '.media-library-open-button[href*="field_twin_media"]');
400 $twin_button->click();
401 $assert_session->assertWaitOnAjaxRequest();
402 $assert_session->pageTextContains('Media library');
403 $assert_session->elementExists('css', '#drupal-modal')->clickLink('Add media');
404 $assert_session->assertWaitOnAjaxRequest();
406 $page->attachFileToField('Upload', $file_system->realpath($jpg_image->uri));
407 $assert_session->assertWaitOnAjaxRequest();
409 $assert_session->pageTextContains('Select a media type for ' . $jpg_image->filename);
411 // Before the type is determined, the file lives in the default upload
412 // location (temporary://).
413 $files = $file_storage->loadMultiple();
414 $file = array_pop($files);
415 $this->assertSame('temporary', $file_system->uriScheme($file->getFileUri()));
417 // Both the type_three and type_four media types accept jpg images.
418 $assert_session->buttonExists('Type Three');
419 $assert_session->buttonExists('Type Four')->click();
420 $assert_session->assertWaitOnAjaxRequest();
422 // The file should have been moved when the type was selected.
423 $files = $file_storage->loadMultiple();
424 $file = array_pop($files);
425 $this->assertSame('public://type-four-dir', $file_system->dirname($file->getFileUri()));
426 $this->assertSame($assert_session->fieldExists('Name')->getValue(), $jpg_image->filename);
427 $page->fillField('Alternative text', $this->randomString());
429 // The type_four media type has another optional image field.
430 $assert_session->pageTextContains('Extra Image');
431 $page->attachFileToField('Extra Image', $this->container->get('file_system')->realpath($jpg_image->uri));
432 $assert_session->assertWaitOnAjaxRequest();
433 // Ensure that the extra image was uploaded to the correct directory.
434 $files = $file_storage->loadMultiple();
435 $file = array_pop($files);
436 $this->assertSame('public://type-four-extra-dir', $file_system->dirname($file->getFileUri()));
438 $assert_session->elementExists('css', '.ui-dialog-buttonpane')->pressButton('Save');
439 $assert_session->assertWaitOnAjaxRequest();
441 $assert_session->pageTextNotContains('Media library');
442 $assert_session->pageTextContains($jpg_image->filename);