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