diff core/modules/quickedit/tests/src/FunctionalJavascript/QuickEditLoadingTest.php @ 18:af1871eacc83

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:33:08 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/quickedit/tests/src/FunctionalJavascript/QuickEditLoadingTest.php	Thu May 09 15:33:08 2019 +0100
@@ -0,0 +1,392 @@
+<?php
+
+namespace Drupal\Tests\quickedit\FunctionalJavascript;
+
+use Behat\Mink\Session;
+use Drupal\block_content\Entity\BlockContent;
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\node\Entity\Node;
+use Drupal\node\Entity\NodeType;
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait;
+use Drupal\Tests\TestFileCreationTrait;
+
+/**
+ * Tests loading of in-place editing functionality and lazy loading of its
+ * in-place editors.
+ *
+ * @group quickedit
+ */
+class QuickEditLoadingTest extends WebDriverTestBase {
+
+  use ContextualLinkClickTrait;
+
+  use TestFileCreationTrait {
+    getTestFiles as drupalGetTestFiles;
+  }
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'contextual',
+    'quickedit',
+    'filter',
+    'node',
+    'image',
+  ];
+
+  /**
+   * An user with permissions to create and edit articles.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $authorUser;
+
+  /**
+   * A test node.
+   *
+   * @var \Drupal\node\NodeInterface
+   */
+  protected $testNode;
+
+  /**
+   * A author user with permissions to access in-place editor.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $editorUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Create a text format.
+    $filtered_html_format = FilterFormat::create([
+      'format' => 'filtered_html',
+      'name' => 'Filtered HTML',
+      'weight' => 0,
+      'filters' => [],
+    ]);
+    $filtered_html_format->save();
+
+    // Create a node type.
+    $this->drupalCreateContentType([
+      'type' => 'article',
+      'name' => 'Article',
+    ]);
+
+    // Set the node type to initially not have revisions.
+    // Testing with revisions will be done later.
+    $node_type = NodeType::load('article');
+    $node_type->setNewRevision(FALSE);
+    $node_type->save();
+
+    // Create one node of the above node type using the above text format.
+    $this->testNode = $this->drupalCreateNode([
+      'type' => 'article',
+      'body' => [
+        0 => [
+          'value' => '<p>How are you?</p>',
+          'format' => 'filtered_html',
+        ],
+      ],
+      'revision_log' => $this->randomString(),
+    ]);
+
+    // Create 2 users, the only difference being the ability to use in-place
+    // editing
+    $basic_permissions = [
+      'access content',
+      'create article content',
+      'edit any article content',
+      'use text format filtered_html',
+      'access contextual links',
+    ];
+    $this->authorUser = $this->drupalCreateUser($basic_permissions);
+    $this->editorUser = $this->drupalCreateUser(array_merge($basic_permissions, ['access in-place editing']));
+  }
+
+  /**
+   * Test the loading of Quick Edit with different permissions.
+   */
+  public function testUserPermissions() {
+    $assert = $this->assertSession();
+    $this->drupalLogin($this->authorUser);
+    $this->drupalGet('node/1');
+
+    // Library and in-place editors.
+    $this->assertNoRaw('core/modules/quickedit/js/quickedit.js', 'Quick Edit library not loaded.');
+    $this->assertNoRaw('core/modules/quickedit/js/editors/formEditor.js', "'form' in-place editor not loaded.");
+
+    // HTML annotation and title class does not exist for users without
+    // permission to in-place edit.
+    $this->assertNoRaw('data-quickedit-entity-id="node/1"');
+    $this->assertNoRaw('data-quickedit-field-id="node/1/body/en/full"');
+    $this->assertNoFieldByXPath('//h1[contains(@class, "js-quickedit-page-title")]');
+    $assert->linkNotExists('Quick edit');
+
+    // Tests the loading of Quick Edit when a user does have access to it.
+    // Also ensures lazy loading of in-place editors works.
+    $nid = $this->testNode->id();
+    // There should be only one revision so far.
+    $node = Node::load($nid);
+    $vids = \Drupal::entityManager()->getStorage('node')->revisionIds($node);
+    $this->assertCount(1, $vids, 'The node has only one revision.');
+    $original_log = $node->revision_log->value;
+
+    $this->drupalLogin($this->editorUser);
+    $this->drupalGet('node/' . $nid);
+    $page = $this->getSession()->getPage();
+
+    // Wait "Quick edit" button for node.
+    $assert->waitForElement('css', '[data-quickedit-entity-id="node/' . $nid . '"] .contextual .quickedit');
+    // Click by "Quick edit".
+    $this->clickContextualLink('[data-quickedit-entity-id="node/' . $nid . '"]', 'Quick edit');
+    // Switch to body field.
+    $page->find('css', '[data-quickedit-field-id="node/' . $nid . '/body/en/full"]')->click();
+    $assert->assertWaitOnAjaxRequest();
+
+    // Wait and update body field.
+    $body_field_locator = '[name="body[0][value]"]';
+    $body_text = 'Fine thanks.';
+    $assert->waitForElementVisible('css', $body_field_locator)->setValue('<p>' . $body_text . '</p>');
+
+    // Wait and click by "Save" button after body field was changed.
+    $assert->waitForElementVisible('css', '.quickedit-toolgroup.ops [type="submit"][aria-hidden="false"]')->click();
+    $assert->assertWaitOnAjaxRequest();
+
+    $node = Node::load($nid);
+    $vids = \Drupal::entityManager()->getStorage('node')->revisionIds($node);
+    $this->assertCount(1, $vids, 'The node has only one revision.');
+    $this->assertSame($original_log, $node->revision_log->value, 'The revision log message is unchanged.');
+
+    // Ensure that the changes take effect.
+    $assert->responseMatches("|\s*$body_text\s*|");
+
+    // Reload the page and check for updated body.
+    $this->drupalGet('node/' . $nid);
+    $assert->pageTextContains($body_text);
+  }
+
+  /**
+   * Test Quick Edit does not appear for entities with pending revisions.
+   */
+  public function testWithPendingRevision() {
+    $this->drupalLogin($this->editorUser);
+
+    // Verify that the preview is loaded correctly.
+    $this->drupalPostForm('node/add/article', ['title[0][value]' => 'foo'], 'Preview');
+    // Verify that quickedit is not active on preview.
+    $this->assertNoRaw('data-quickedit-entity-id="node/' . $this->testNode->id() . '"');
+    $this->assertNoRaw('data-quickedit-field-id="node/' . $this->testNode->id() . '/title/' . $this->testNode->language()->getId() . '/full"');
+
+    $this->drupalGet('node/' . $this->testNode->id());
+    $this->assertRaw('data-quickedit-entity-id="node/' . $this->testNode->id() . '"');
+    $this->assertRaw('data-quickedit-field-id="node/' . $this->testNode->id() . '/title/' . $this->testNode->language()->getId() . '/full"');
+
+    // Wait for the page to completely load before making any changes to the
+    // node. This allows Quick Edit to fetch the metadata without causing
+    // database locks on SQLite.
+    $this->assertSession()->assertWaitOnAjaxRequest();
+    $this->testNode->title = 'Updated node';
+    $this->testNode->setNewRevision(TRUE);
+    $this->testNode->isDefaultRevision(FALSE);
+    $this->testNode->save();
+
+    $this->drupalGet('node/' . $this->testNode->id());
+    $this->assertNoRaw('data-quickedit-entity-id="node/' . $this->testNode->id() . '"');
+    $this->assertNoRaw('data-quickedit-field-id="node/' . $this->testNode->id() . '/title/' . $this->testNode->language()->getId() . '/full"');
+  }
+
+  /**
+   * Tests the loading of Quick Edit for the title base field.
+   */
+  public function testTitleBaseField() {
+    $page = $this->getSession()->getPage();
+    $assert = $this->assertSession();
+    $nid = $this->testNode->id();
+
+    $this->drupalLogin($this->editorUser);
+    $this->drupalGet('node/' . $nid);
+
+    // Wait "Quick edit" button for node.
+    $assert->waitForElement('css', '[data-quickedit-entity-id="node/' . $nid . '"] .contextual .quickedit');
+    // Click by "Quick edit".
+    $this->clickContextualLink('[data-quickedit-entity-id="node/' . $nid . '"]', 'Quick edit');
+    // Switch to title field.
+    $page->find('css', '[data-quickedit-field-id="node/' . $nid . '/title/en/full"]')->click();
+    $assert->assertWaitOnAjaxRequest();
+
+    // Wait and update title field.
+    $field_locator = '.field--name-title';
+    $text_new = 'Obligatory question';
+    $assert->waitForElementVisible('css', $field_locator)->setValue($text_new);
+
+    // Wait and click by "Save" button after title field was changed.
+    $this->assertSession()->waitForElementVisible('css', '.quickedit-toolgroup.ops [type="submit"][aria-hidden="false"]')->click();
+    $assert->assertWaitOnAjaxRequest();
+
+    // Ensure that the changes take effect.
+    $assert->responseMatches("|\s*$text_new\s*|");
+
+    // Reload the page and check for updated title.
+    $this->drupalGet('node/' . $nid);
+    $assert->pageTextContains($text_new);
+  }
+
+  /**
+   * Tests that Quick Edit doesn't make fields rendered with display options
+   * editable.
+   */
+  public function testDisplayOptions() {
+    $node = Node::load('1');
+    $display_settings = [
+      'label' => 'inline',
+    ];
+    $build = $node->body->view($display_settings);
+    $output = \Drupal::service('renderer')->renderRoot($build);
+    $this->assertFalse(strpos($output, 'data-quickedit-field-id'), 'data-quickedit-field-id attribute not added when rendering field using dynamic display options.');
+  }
+
+  /**
+   * Tests Quick Edit on a node that was concurrently edited on the full node
+   * form.
+   */
+  public function testConcurrentEdit() {
+    $nid = $this->testNode->id();
+    $this->drupalLogin($this->authorUser);
+
+    // Open the edit page in the default session.
+    $this->drupalGet('node/' . $nid . '/edit');
+
+    // Switch to a concurrent session and save a quick edit change.
+    // We need to do some bookkeeping to keep track of the logged in user.
+    $logged_in_user = $this->loggedInUser;
+    $this->loggedInUser = FALSE;
+    // Register a session to preform concurrent editing.
+    $driver = $this->getDefaultDriverInstance();
+    $session = new Session($driver);
+    $this->mink->registerSession('concurrent', $session);
+    $this->mink->setDefaultSessionName('concurrent');
+    $this->initFrontPage();
+    $this->drupalLogin($this->editorUser);
+    $this->drupalGet('node/' . $nid);
+
+    $assert = $this->assertSession();
+    $page = $this->getSession()->getPage();
+
+    // Wait "Quick edit" button for node.
+    $assert->waitForElement('css', '[data-quickedit-entity-id="node/' . $nid . '"] .contextual .quickedit');
+    // Click by "Quick edit".
+    $this->clickContextualLink('[data-quickedit-entity-id="node/' . $nid . '"]', 'Quick edit');
+    // Switch to body field.
+    $page->find('css', '[data-quickedit-field-id="node/' . $nid . '/body/en/full"]')->click();
+    $assert->assertWaitOnAjaxRequest();
+
+    // Wait and update body field.
+    $body_field_locator = '[name="body[0][value]"]';
+    $body_text = 'Fine thanks.';
+    $assert->waitForElementVisible('css', $body_field_locator)->setValue('<p>' . $body_text . '</p>');
+
+    // Wait and click by "Save" button after body field was changed.
+    $assert->waitForElementVisible('css', '.quickedit-toolgroup.ops [type="submit"][aria-hidden="false"]')->click();
+    $assert->assertWaitOnAjaxRequest();
+
+    // Ensure that the changes take effect.
+    $assert->responseMatches("|\s*$body_text\s*|");
+
+    // Switch back to the default session.
+    $this->mink->setDefaultSessionName('default');
+    $this->loggedInUser = $logged_in_user;
+    // Ensure different save timestamps for field editing.
+    sleep(2);
+    $this->drupalPostForm(NULL, ['body[0][value]' => '<p>Concurrent edit!</p>'], 'Save');
+
+    $this->getSession()->getPage()->hasContent('The content has either been modified by another user, or you have already submitted modifications. As a result, your changes cannot be saved.');
+  }
+
+  /**
+   * Tests that Quick Edit's data- attributes are present for content blocks.
+   */
+  public function testContentBlock() {
+    \Drupal::service('module_installer')->install(['block_content']);
+
+    // Create and place a content_block block.
+    $block = BlockContent::create([
+      'info' => $this->randomMachineName(),
+      'type' => 'basic',
+      'langcode' => 'en',
+    ]);
+    $block->save();
+    $this->drupalPlaceBlock('block_content:' . $block->uuid());
+
+    // Check that the data- attribute is present.
+    $this->drupalLogin($this->editorUser);
+    $this->drupalGet('');
+    $this->assertRaw('data-quickedit-entity-id="block_content/1"');
+  }
+
+  /**
+   * Tests that Quick Edit can handle an image field.
+   */
+  public function testImageField() {
+    $page = $this->getSession()->getPage();
+    $assert = $this->assertSession();
+
+    // Add an image field to the content type.
+    FieldStorageConfig::create([
+      'field_name' => 'field_image',
+      'type' => 'image',
+      'entity_type' => 'node',
+    ])->save();
+    FieldConfig::create([
+      'field_name' => 'field_image',
+      'field_type' => 'image',
+      'label' => t('Image'),
+      'entity_type' => 'node',
+      'bundle' => 'article',
+    ])->save();
+    entity_get_form_display('node', 'article', 'default')
+      ->setComponent('field_image', [
+        'type' => 'image_image',
+      ])
+      ->save();
+    $display = EntityViewDisplay::load('node.article.default');
+    $display->setComponent('field_image', [
+      'type' => 'image',
+    ])->save();
+
+    // Add an image to the node.
+    $this->drupalLogin($this->editorUser);
+    $this->drupalGet('node/1/edit');
+    $image = $this->drupalGetTestFiles('image')[0];
+    $image_path = $this->container->get('file_system')->realpath($image->uri);
+    $page->attachFileToField('files[field_image_0]', $image_path);
+    $alt_field = $assert->waitForField('field_image[0][alt]');
+    $this->assertNotEmpty($alt_field);
+    $this->drupalPostForm(NULL, [
+      'field_image[0][alt]' => 'Vivamus aliquet elit',
+    ], t('Save'));
+
+    // The image field form should load normally.
+    // Wait "Quick edit" button for node.
+    $assert->waitForElement('css', '[data-quickedit-entity-id="node/1"] .contextual .quickedit');
+    // Click by "Quick edit".
+    $this->clickContextualLink('[data-quickedit-entity-id="node/1"]', 'Quick edit');
+    // Switch to body field.
+    $assert->waitForElement('css', '[data-quickedit-field-id="node/1/field_image/en/full"]')->click();
+    $assert->assertWaitOnAjaxRequest();
+
+    $field_locator = '.field--name-field-image';
+    $assert->waitForElementVisible('css', $field_locator);
+  }
+
+}