Chris@0: drupalCreateContentType(['type' => 'article', 'name' => 'Article']); Chris@0: Chris@0: // Log in as a content author who can use Quick Edit and edit Articles. Chris@0: $this->contentAuthorUser = $this->drupalCreateUser([ Chris@0: 'access contextual links', Chris@0: 'access toolbar', Chris@0: 'access in-place editing', Chris@0: 'access content', Chris@0: 'create article content', Chris@0: 'edit any article content', Chris@0: 'delete any article content', Chris@0: ]); Chris@0: $this->drupalLogin($this->contentAuthorUser); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests if an image can be uploaded inline with Quick Edit. Chris@0: */ Chris@0: public function testUpload() { Chris@0: // Create a field with a basic filetype restriction. Chris@0: $field_name = strtolower($this->randomMachineName()); Chris@0: $field_settings = [ Chris@0: 'file_extensions' => 'png', Chris@0: ]; Chris@0: $formatter_settings = [ Chris@0: 'image_style' => 'large', Chris@0: 'image_link' => '', Chris@0: ]; Chris@0: $this->createImageField($field_name, 'article', [], $field_settings, [], $formatter_settings); Chris@0: Chris@0: // Find images that match our field settings. Chris@0: $valid_images = []; Chris@0: foreach ($this->getTestFiles('image') as $image) { Chris@0: // This regex is taken from file_validate_extensions(). Chris@0: $regex = '/\.(' . preg_replace('/ +/', '|', preg_quote($field_settings['file_extensions'])) . ')$/i'; Chris@0: if (preg_match($regex, $image->filename)) { Chris@0: $valid_images[] = $image; Chris@0: } Chris@0: } Chris@0: Chris@0: // Ensure we have at least two valid images. Chris@0: $this->assertGreaterThanOrEqual(2, count($valid_images)); Chris@0: Chris@0: // Create a File entity for the initial image. Chris@0: $file = File::create([ Chris@0: 'uri' => $valid_images[0]->uri, Chris@0: 'uid' => $this->contentAuthorUser->id(), Chris@0: 'status' => FILE_STATUS_PERMANENT, Chris@0: ]); Chris@0: $file->save(); Chris@0: Chris@0: // Use the first valid image to create a new Node. Chris@0: $image_factory = $this->container->get('image.factory'); Chris@0: $image = $image_factory->get($valid_images[0]->uri); Chris@0: $node = $this->drupalCreateNode([ Chris@0: 'type' => 'article', Chris@0: 'title' => t('Test Node'), Chris@0: $field_name => [ Chris@0: 'target_id' => $file->id(), Chris@0: 'alt' => 'Hello world', Chris@0: 'title' => '', Chris@0: 'width' => $image->getWidth(), Chris@0: 'height' => $image->getHeight(), Chris@0: ], Chris@0: ]); Chris@0: Chris@0: // Visit the new Node. Chris@0: $this->drupalGet('node/' . $node->id()); Chris@0: Chris@0: // Assemble common CSS selectors. Chris@0: $entity_selector = '[data-quickedit-entity-id="node/' . $node->id() . '"]'; Chris@0: $field_selector = '[data-quickedit-field-id="node/' . $node->id() . '/' . $field_name . '/' . $node->language()->getId() . '/full"]'; Chris@0: $original_image_selector = 'img[src*="' . $valid_images[0]->filename . '"][alt="Hello world"]'; Chris@0: $new_image_selector = 'img[src*="' . $valid_images[1]->filename . '"][alt="New text"]'; Chris@0: Chris@0: // Assert that the initial image is present. Chris@0: $this->assertSession()->elementExists('css', $entity_selector . ' ' . $field_selector . ' ' . $original_image_selector); Chris@0: Chris@0: // Wait until Quick Edit loads. Chris@0: $condition = "jQuery('" . $entity_selector . " .quickedit').length > 0"; Chris@0: $this->assertJsCondition($condition, 10000); Chris@0: Chris@0: // Initiate Quick Editing. Chris@0: $this->click('.contextual-toolbar-tab button'); Chris@0: $this->click($entity_selector . ' [data-contextual-id] > button'); Chris@0: $this->click($entity_selector . ' [data-contextual-id] .quickedit > a'); Chris@0: $this->click($field_selector); Chris@0: Chris@0: // Wait for the field info to load and set new alt text. Chris@0: $condition = "jQuery('.quickedit-image-field-info').length > 0"; Chris@0: $this->assertJsCondition($condition, 10000); Chris@0: $input = $this->assertSession()->elementExists('css', '.quickedit-image-field-info input[name="alt"]'); Chris@0: $input->setValue('New text'); Chris@0: Chris@0: // Check that our Dropzone element exists. Chris@0: $this->assertSession()->elementExists('css', $field_selector . ' .quickedit-image-dropzone'); Chris@0: Chris@0: // Our headless browser can't drag+drop files, but we can mock the event. Chris@0: // Append a hidden upload element to the DOM. Chris@0: $script = 'jQuery("").appendTo("body")'; Chris@0: $this->getSession()->executeScript($script); Chris@0: Chris@0: // Find the element, and set its value to our new image. Chris@0: $input = $this->assertSession()->elementExists('css', '#quickedit-image-test-input'); Chris@0: $filepath = $this->container->get('file_system')->realpath($valid_images[1]->uri); Chris@0: $input->attachFile($filepath); Chris@0: Chris@0: // Trigger the upload logic with a mock "drop" event. Chris@0: $script = 'var e = jQuery.Event("drop");' Chris@0: . 'e.originalEvent = {dataTransfer: {files: jQuery("#quickedit-image-test-input").get(0).files}};' Chris@0: . 'e.preventDefault = e.stopPropagation = function () {};' Chris@0: . 'jQuery(".quickedit-image-dropzone").trigger(e);'; Chris@0: $this->getSession()->executeScript($script); Chris@0: Chris@0: // Wait for the dropzone element to be removed (i.e. loading is done). Chris@0: $condition = "jQuery('" . $field_selector . " .quickedit-image-dropzone').length == 0"; Chris@0: $this->assertJsCondition($condition, 20000); Chris@0: Chris@0: // To prevent 403s on save, we re-set our request (cookie) state. Chris@0: $this->prepareRequest(); Chris@0: Chris@0: // Save the change. Chris@0: $this->click('.quickedit-button.action-save'); Chris@0: $this->assertSession()->assertWaitOnAjaxRequest(); Chris@0: Chris@0: // Re-visit the page to make sure the edit worked. Chris@0: $this->drupalGet('node/' . $node->id()); Chris@0: Chris@0: // Check that the new image appears as expected. Chris@0: $this->assertSession()->elementNotExists('css', $entity_selector . ' ' . $field_selector . ' ' . $original_image_selector); Chris@0: $this->assertSession()->elementExists('css', $entity_selector . ' ' . $field_selector . ' ' . $new_image_selector); Chris@0: } Chris@0: Chris@0: }