annotate core/modules/image/tests/src/FunctionalJavascript/QuickEditImageTest.php @ 3:e11175134f4e

Attempt to introduce editable version of theme
author Chris Cannam
date Tue, 05 Dec 2017 11:25:38 +0000
parents 4c8ae668cc8c
children 129ea1e6d783
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Tests\image\FunctionalJavascript;
Chris@0 4
Chris@0 5 use Drupal\file\Entity\File;
Chris@0 6 use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
Chris@0 7 use Drupal\Tests\image\Kernel\ImageFieldCreationTrait;
Chris@0 8 use Drupal\Tests\TestFileCreationTrait;
Chris@0 9
Chris@0 10 /**
Chris@0 11 * Tests the JavaScript functionality of the "image" in-place editor.
Chris@0 12 *
Chris@0 13 * @group image
Chris@0 14 */
Chris@0 15 class QuickEditImageTest extends JavascriptTestBase {
Chris@0 16
Chris@0 17 use ImageFieldCreationTrait;
Chris@0 18 use TestFileCreationTrait;
Chris@0 19
Chris@0 20 /**
Chris@0 21 * {@inheritdoc}
Chris@0 22 */
Chris@0 23 public static $modules = ['node', 'image', 'field_ui', 'contextual', 'quickedit', 'toolbar'];
Chris@0 24
Chris@0 25 /**
Chris@0 26 * A user with permissions to edit Articles and use Quick Edit.
Chris@0 27 *
Chris@0 28 * @var \Drupal\user\UserInterface
Chris@0 29 */
Chris@0 30 protected $contentAuthorUser;
Chris@0 31
Chris@0 32 /**
Chris@0 33 * {@inheritdoc}
Chris@0 34 */
Chris@0 35 protected function setUp() {
Chris@0 36 parent::setUp();
Chris@0 37
Chris@0 38 // Create the Article node type.
Chris@0 39 $this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
Chris@0 40
Chris@0 41 // Log in as a content author who can use Quick Edit and edit Articles.
Chris@0 42 $this->contentAuthorUser = $this->drupalCreateUser([
Chris@0 43 'access contextual links',
Chris@0 44 'access toolbar',
Chris@0 45 'access in-place editing',
Chris@0 46 'access content',
Chris@0 47 'create article content',
Chris@0 48 'edit any article content',
Chris@0 49 'delete any article content',
Chris@0 50 ]);
Chris@0 51 $this->drupalLogin($this->contentAuthorUser);
Chris@0 52 }
Chris@0 53
Chris@0 54 /**
Chris@0 55 * Tests if an image can be uploaded inline with Quick Edit.
Chris@0 56 */
Chris@0 57 public function testUpload() {
Chris@0 58 // Create a field with a basic filetype restriction.
Chris@0 59 $field_name = strtolower($this->randomMachineName());
Chris@0 60 $field_settings = [
Chris@0 61 'file_extensions' => 'png',
Chris@0 62 ];
Chris@0 63 $formatter_settings = [
Chris@0 64 'image_style' => 'large',
Chris@0 65 'image_link' => '',
Chris@0 66 ];
Chris@0 67 $this->createImageField($field_name, 'article', [], $field_settings, [], $formatter_settings);
Chris@0 68
Chris@0 69 // Find images that match our field settings.
Chris@0 70 $valid_images = [];
Chris@0 71 foreach ($this->getTestFiles('image') as $image) {
Chris@0 72 // This regex is taken from file_validate_extensions().
Chris@0 73 $regex = '/\.(' . preg_replace('/ +/', '|', preg_quote($field_settings['file_extensions'])) . ')$/i';
Chris@0 74 if (preg_match($regex, $image->filename)) {
Chris@0 75 $valid_images[] = $image;
Chris@0 76 }
Chris@0 77 }
Chris@0 78
Chris@0 79 // Ensure we have at least two valid images.
Chris@0 80 $this->assertGreaterThanOrEqual(2, count($valid_images));
Chris@0 81
Chris@0 82 // Create a File entity for the initial image.
Chris@0 83 $file = File::create([
Chris@0 84 'uri' => $valid_images[0]->uri,
Chris@0 85 'uid' => $this->contentAuthorUser->id(),
Chris@0 86 'status' => FILE_STATUS_PERMANENT,
Chris@0 87 ]);
Chris@0 88 $file->save();
Chris@0 89
Chris@0 90 // Use the first valid image to create a new Node.
Chris@0 91 $image_factory = $this->container->get('image.factory');
Chris@0 92 $image = $image_factory->get($valid_images[0]->uri);
Chris@0 93 $node = $this->drupalCreateNode([
Chris@0 94 'type' => 'article',
Chris@0 95 'title' => t('Test Node'),
Chris@0 96 $field_name => [
Chris@0 97 'target_id' => $file->id(),
Chris@0 98 'alt' => 'Hello world',
Chris@0 99 'title' => '',
Chris@0 100 'width' => $image->getWidth(),
Chris@0 101 'height' => $image->getHeight(),
Chris@0 102 ],
Chris@0 103 ]);
Chris@0 104
Chris@0 105 // Visit the new Node.
Chris@0 106 $this->drupalGet('node/' . $node->id());
Chris@0 107
Chris@0 108 // Assemble common CSS selectors.
Chris@0 109 $entity_selector = '[data-quickedit-entity-id="node/' . $node->id() . '"]';
Chris@0 110 $field_selector = '[data-quickedit-field-id="node/' . $node->id() . '/' . $field_name . '/' . $node->language()->getId() . '/full"]';
Chris@0 111 $original_image_selector = 'img[src*="' . $valid_images[0]->filename . '"][alt="Hello world"]';
Chris@0 112 $new_image_selector = 'img[src*="' . $valid_images[1]->filename . '"][alt="New text"]';
Chris@0 113
Chris@0 114 // Assert that the initial image is present.
Chris@0 115 $this->assertSession()->elementExists('css', $entity_selector . ' ' . $field_selector . ' ' . $original_image_selector);
Chris@0 116
Chris@0 117 // Wait until Quick Edit loads.
Chris@0 118 $condition = "jQuery('" . $entity_selector . " .quickedit').length > 0";
Chris@0 119 $this->assertJsCondition($condition, 10000);
Chris@0 120
Chris@0 121 // Initiate Quick Editing.
Chris@0 122 $this->click('.contextual-toolbar-tab button');
Chris@0 123 $this->click($entity_selector . ' [data-contextual-id] > button');
Chris@0 124 $this->click($entity_selector . ' [data-contextual-id] .quickedit > a');
Chris@0 125 $this->click($field_selector);
Chris@0 126
Chris@0 127 // Wait for the field info to load and set new alt text.
Chris@0 128 $condition = "jQuery('.quickedit-image-field-info').length > 0";
Chris@0 129 $this->assertJsCondition($condition, 10000);
Chris@0 130 $input = $this->assertSession()->elementExists('css', '.quickedit-image-field-info input[name="alt"]');
Chris@0 131 $input->setValue('New text');
Chris@0 132
Chris@0 133 // Check that our Dropzone element exists.
Chris@0 134 $this->assertSession()->elementExists('css', $field_selector . ' .quickedit-image-dropzone');
Chris@0 135
Chris@0 136 // Our headless browser can't drag+drop files, but we can mock the event.
Chris@0 137 // Append a hidden upload element to the DOM.
Chris@0 138 $script = 'jQuery("<input id=\"quickedit-image-test-input\" type=\"file\" />").appendTo("body")';
Chris@0 139 $this->getSession()->executeScript($script);
Chris@0 140
Chris@0 141 // Find the element, and set its value to our new image.
Chris@0 142 $input = $this->assertSession()->elementExists('css', '#quickedit-image-test-input');
Chris@0 143 $filepath = $this->container->get('file_system')->realpath($valid_images[1]->uri);
Chris@0 144 $input->attachFile($filepath);
Chris@0 145
Chris@0 146 // Trigger the upload logic with a mock "drop" event.
Chris@0 147 $script = 'var e = jQuery.Event("drop");'
Chris@0 148 . 'e.originalEvent = {dataTransfer: {files: jQuery("#quickedit-image-test-input").get(0).files}};'
Chris@0 149 . 'e.preventDefault = e.stopPropagation = function () {};'
Chris@0 150 . 'jQuery(".quickedit-image-dropzone").trigger(e);';
Chris@0 151 $this->getSession()->executeScript($script);
Chris@0 152
Chris@0 153 // Wait for the dropzone element to be removed (i.e. loading is done).
Chris@0 154 $condition = "jQuery('" . $field_selector . " .quickedit-image-dropzone').length == 0";
Chris@0 155 $this->assertJsCondition($condition, 20000);
Chris@0 156
Chris@0 157 // To prevent 403s on save, we re-set our request (cookie) state.
Chris@0 158 $this->prepareRequest();
Chris@0 159
Chris@0 160 // Save the change.
Chris@0 161 $this->click('.quickedit-button.action-save');
Chris@0 162 $this->assertSession()->assertWaitOnAjaxRequest();
Chris@0 163
Chris@0 164 // Re-visit the page to make sure the edit worked.
Chris@0 165 $this->drupalGet('node/' . $node->id());
Chris@0 166
Chris@0 167 // Check that the new image appears as expected.
Chris@0 168 $this->assertSession()->elementNotExists('css', $entity_selector . ' ' . $field_selector . ' ' . $original_image_selector);
Chris@0 169 $this->assertSession()->elementExists('css', $entity_selector . ' ' . $field_selector . ' ' . $new_image_selector);
Chris@0 170 }
Chris@0 171
Chris@0 172 }