comparison core/modules/quickedit/tests/src/FunctionalJavascript/QuickEditLoadingTest.php @ 5:12f9dff5fda9 tip

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:34:47 +0100
parents
children
comparison
equal deleted inserted replaced
4:a9cd425dd02b 5:12f9dff5fda9
1 <?php
2
3 namespace Drupal\Tests\quickedit\FunctionalJavascript;
4
5 use Behat\Mink\Session;
6 use Drupal\block_content\Entity\BlockContent;
7 use Drupal\Core\Entity\Entity\EntityViewDisplay;
8 use Drupal\field\Entity\FieldConfig;
9 use Drupal\field\Entity\FieldStorageConfig;
10 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
11 use Drupal\node\Entity\Node;
12 use Drupal\node\Entity\NodeType;
13 use Drupal\filter\Entity\FilterFormat;
14 use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait;
15 use Drupal\Tests\TestFileCreationTrait;
16
17 /**
18 * Tests loading of in-place editing functionality and lazy loading of its
19 * in-place editors.
20 *
21 * @group quickedit
22 */
23 class QuickEditLoadingTest extends WebDriverTestBase {
24
25 use ContextualLinkClickTrait;
26
27 use TestFileCreationTrait {
28 getTestFiles as drupalGetTestFiles;
29 }
30
31 /**
32 * Modules to enable.
33 *
34 * @var array
35 */
36 public static $modules = [
37 'contextual',
38 'quickedit',
39 'filter',
40 'node',
41 'image',
42 ];
43
44 /**
45 * An user with permissions to create and edit articles.
46 *
47 * @var \Drupal\user\UserInterface
48 */
49 protected $authorUser;
50
51 /**
52 * A test node.
53 *
54 * @var \Drupal\node\NodeInterface
55 */
56 protected $testNode;
57
58 /**
59 * A author user with permissions to access in-place editor.
60 *
61 * @var \Drupal\user\UserInterface
62 */
63 protected $editorUser;
64
65 /**
66 * {@inheritdoc}
67 */
68 protected function setUp() {
69 parent::setUp();
70
71 // Create a text format.
72 $filtered_html_format = FilterFormat::create([
73 'format' => 'filtered_html',
74 'name' => 'Filtered HTML',
75 'weight' => 0,
76 'filters' => [],
77 ]);
78 $filtered_html_format->save();
79
80 // Create a node type.
81 $this->drupalCreateContentType([
82 'type' => 'article',
83 'name' => 'Article',
84 ]);
85
86 // Set the node type to initially not have revisions.
87 // Testing with revisions will be done later.
88 $node_type = NodeType::load('article');
89 $node_type->setNewRevision(FALSE);
90 $node_type->save();
91
92 // Create one node of the above node type using the above text format.
93 $this->testNode = $this->drupalCreateNode([
94 'type' => 'article',
95 'body' => [
96 0 => [
97 'value' => '<p>How are you?</p>',
98 'format' => 'filtered_html',
99 ],
100 ],
101 'revision_log' => $this->randomString(),
102 ]);
103
104 // Create 2 users, the only difference being the ability to use in-place
105 // editing
106 $basic_permissions = [
107 'access content',
108 'create article content',
109 'edit any article content',
110 'use text format filtered_html',
111 'access contextual links',
112 ];
113 $this->authorUser = $this->drupalCreateUser($basic_permissions);
114 $this->editorUser = $this->drupalCreateUser(array_merge($basic_permissions, ['access in-place editing']));
115 }
116
117 /**
118 * Test the loading of Quick Edit with different permissions.
119 */
120 public function testUserPermissions() {
121 $assert = $this->assertSession();
122 $this->drupalLogin($this->authorUser);
123 $this->drupalGet('node/1');
124
125 // Library and in-place editors.
126 $this->assertNoRaw('core/modules/quickedit/js/quickedit.js', 'Quick Edit library not loaded.');
127 $this->assertNoRaw('core/modules/quickedit/js/editors/formEditor.js', "'form' in-place editor not loaded.");
128
129 // HTML annotation and title class does not exist for users without
130 // permission to in-place edit.
131 $this->assertNoRaw('data-quickedit-entity-id="node/1"');
132 $this->assertNoRaw('data-quickedit-field-id="node/1/body/en/full"');
133 $this->assertNoFieldByXPath('//h1[contains(@class, "js-quickedit-page-title")]');
134 $assert->linkNotExists('Quick edit');
135
136 // Tests the loading of Quick Edit when a user does have access to it.
137 // Also ensures lazy loading of in-place editors works.
138 $nid = $this->testNode->id();
139 // There should be only one revision so far.
140 $node = Node::load($nid);
141 $vids = \Drupal::entityManager()->getStorage('node')->revisionIds($node);
142 $this->assertCount(1, $vids, 'The node has only one revision.');
143 $original_log = $node->revision_log->value;
144
145 $this->drupalLogin($this->editorUser);
146 $this->drupalGet('node/' . $nid);
147 $page = $this->getSession()->getPage();
148
149 // Wait "Quick edit" button for node.
150 $assert->waitForElement('css', '[data-quickedit-entity-id="node/' . $nid . '"] .contextual .quickedit');
151 // Click by "Quick edit".
152 $this->clickContextualLink('[data-quickedit-entity-id="node/' . $nid . '"]', 'Quick edit');
153 // Switch to body field.
154 $page->find('css', '[data-quickedit-field-id="node/' . $nid . '/body/en/full"]')->click();
155 $assert->assertWaitOnAjaxRequest();
156
157 // Wait and update body field.
158 $body_field_locator = '[name="body[0][value]"]';
159 $body_text = 'Fine thanks.';
160 $assert->waitForElementVisible('css', $body_field_locator)->setValue('<p>' . $body_text . '</p>');
161
162 // Wait and click by "Save" button after body field was changed.
163 $assert->waitForElementVisible('css', '.quickedit-toolgroup.ops [type="submit"][aria-hidden="false"]')->click();
164 $assert->assertWaitOnAjaxRequest();
165
166 $node = Node::load($nid);
167 $vids = \Drupal::entityManager()->getStorage('node')->revisionIds($node);
168 $this->assertCount(1, $vids, 'The node has only one revision.');
169 $this->assertSame($original_log, $node->revision_log->value, 'The revision log message is unchanged.');
170
171 // Ensure that the changes take effect.
172 $assert->responseMatches("|\s*$body_text\s*|");
173
174 // Reload the page and check for updated body.
175 $this->drupalGet('node/' . $nid);
176 $assert->pageTextContains($body_text);
177 }
178
179 /**
180 * Test Quick Edit does not appear for entities with pending revisions.
181 */
182 public function testWithPendingRevision() {
183 $this->drupalLogin($this->editorUser);
184
185 // Verify that the preview is loaded correctly.
186 $this->drupalPostForm('node/add/article', ['title[0][value]' => 'foo'], 'Preview');
187 // Verify that quickedit is not active on preview.
188 $this->assertNoRaw('data-quickedit-entity-id="node/' . $this->testNode->id() . '"');
189 $this->assertNoRaw('data-quickedit-field-id="node/' . $this->testNode->id() . '/title/' . $this->testNode->language()->getId() . '/full"');
190
191 $this->drupalGet('node/' . $this->testNode->id());
192 $this->assertRaw('data-quickedit-entity-id="node/' . $this->testNode->id() . '"');
193 $this->assertRaw('data-quickedit-field-id="node/' . $this->testNode->id() . '/title/' . $this->testNode->language()->getId() . '/full"');
194
195 // Wait for the page to completely load before making any changes to the
196 // node. This allows Quick Edit to fetch the metadata without causing
197 // database locks on SQLite.
198 $this->assertSession()->assertWaitOnAjaxRequest();
199 $this->testNode->title = 'Updated node';
200 $this->testNode->setNewRevision(TRUE);
201 $this->testNode->isDefaultRevision(FALSE);
202 $this->testNode->save();
203
204 $this->drupalGet('node/' . $this->testNode->id());
205 $this->assertNoRaw('data-quickedit-entity-id="node/' . $this->testNode->id() . '"');
206 $this->assertNoRaw('data-quickedit-field-id="node/' . $this->testNode->id() . '/title/' . $this->testNode->language()->getId() . '/full"');
207 }
208
209 /**
210 * Tests the loading of Quick Edit for the title base field.
211 */
212 public function testTitleBaseField() {
213 $page = $this->getSession()->getPage();
214 $assert = $this->assertSession();
215 $nid = $this->testNode->id();
216
217 $this->drupalLogin($this->editorUser);
218 $this->drupalGet('node/' . $nid);
219
220 // Wait "Quick edit" button for node.
221 $assert->waitForElement('css', '[data-quickedit-entity-id="node/' . $nid . '"] .contextual .quickedit');
222 // Click by "Quick edit".
223 $this->clickContextualLink('[data-quickedit-entity-id="node/' . $nid . '"]', 'Quick edit');
224 // Switch to title field.
225 $page->find('css', '[data-quickedit-field-id="node/' . $nid . '/title/en/full"]')->click();
226 $assert->assertWaitOnAjaxRequest();
227
228 // Wait and update title field.
229 $field_locator = '.field--name-title';
230 $text_new = 'Obligatory question';
231 $assert->waitForElementVisible('css', $field_locator)->setValue($text_new);
232
233 // Wait and click by "Save" button after title field was changed.
234 $this->assertSession()->waitForElementVisible('css', '.quickedit-toolgroup.ops [type="submit"][aria-hidden="false"]')->click();
235 $assert->assertWaitOnAjaxRequest();
236
237 // Ensure that the changes take effect.
238 $assert->responseMatches("|\s*$text_new\s*|");
239
240 // Reload the page and check for updated title.
241 $this->drupalGet('node/' . $nid);
242 $assert->pageTextContains($text_new);
243 }
244
245 /**
246 * Tests that Quick Edit doesn't make fields rendered with display options
247 * editable.
248 */
249 public function testDisplayOptions() {
250 $node = Node::load('1');
251 $display_settings = [
252 'label' => 'inline',
253 ];
254 $build = $node->body->view($display_settings);
255 $output = \Drupal::service('renderer')->renderRoot($build);
256 $this->assertFalse(strpos($output, 'data-quickedit-field-id'), 'data-quickedit-field-id attribute not added when rendering field using dynamic display options.');
257 }
258
259 /**
260 * Tests Quick Edit on a node that was concurrently edited on the full node
261 * form.
262 */
263 public function testConcurrentEdit() {
264 $nid = $this->testNode->id();
265 $this->drupalLogin($this->authorUser);
266
267 // Open the edit page in the default session.
268 $this->drupalGet('node/' . $nid . '/edit');
269
270 // Switch to a concurrent session and save a quick edit change.
271 // We need to do some bookkeeping to keep track of the logged in user.
272 $logged_in_user = $this->loggedInUser;
273 $this->loggedInUser = FALSE;
274 // Register a session to preform concurrent editing.
275 $driver = $this->getDefaultDriverInstance();
276 $session = new Session($driver);
277 $this->mink->registerSession('concurrent', $session);
278 $this->mink->setDefaultSessionName('concurrent');
279 $this->initFrontPage();
280 $this->drupalLogin($this->editorUser);
281 $this->drupalGet('node/' . $nid);
282
283 $assert = $this->assertSession();
284 $page = $this->getSession()->getPage();
285
286 // Wait "Quick edit" button for node.
287 $assert->waitForElement('css', '[data-quickedit-entity-id="node/' . $nid . '"] .contextual .quickedit');
288 // Click by "Quick edit".
289 $this->clickContextualLink('[data-quickedit-entity-id="node/' . $nid . '"]', 'Quick edit');
290 // Switch to body field.
291 $page->find('css', '[data-quickedit-field-id="node/' . $nid . '/body/en/full"]')->click();
292 $assert->assertWaitOnAjaxRequest();
293
294 // Wait and update body field.
295 $body_field_locator = '[name="body[0][value]"]';
296 $body_text = 'Fine thanks.';
297 $assert->waitForElementVisible('css', $body_field_locator)->setValue('<p>' . $body_text . '</p>');
298
299 // Wait and click by "Save" button after body field was changed.
300 $assert->waitForElementVisible('css', '.quickedit-toolgroup.ops [type="submit"][aria-hidden="false"]')->click();
301 $assert->assertWaitOnAjaxRequest();
302
303 // Ensure that the changes take effect.
304 $assert->responseMatches("|\s*$body_text\s*|");
305
306 // Switch back to the default session.
307 $this->mink->setDefaultSessionName('default');
308 $this->loggedInUser = $logged_in_user;
309 // Ensure different save timestamps for field editing.
310 sleep(2);
311 $this->drupalPostForm(NULL, ['body[0][value]' => '<p>Concurrent edit!</p>'], 'Save');
312
313 $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.');
314 }
315
316 /**
317 * Tests that Quick Edit's data- attributes are present for content blocks.
318 */
319 public function testContentBlock() {
320 \Drupal::service('module_installer')->install(['block_content']);
321
322 // Create and place a content_block block.
323 $block = BlockContent::create([
324 'info' => $this->randomMachineName(),
325 'type' => 'basic',
326 'langcode' => 'en',
327 ]);
328 $block->save();
329 $this->drupalPlaceBlock('block_content:' . $block->uuid());
330
331 // Check that the data- attribute is present.
332 $this->drupalLogin($this->editorUser);
333 $this->drupalGet('');
334 $this->assertRaw('data-quickedit-entity-id="block_content/1"');
335 }
336
337 /**
338 * Tests that Quick Edit can handle an image field.
339 */
340 public function testImageField() {
341 $page = $this->getSession()->getPage();
342 $assert = $this->assertSession();
343
344 // Add an image field to the content type.
345 FieldStorageConfig::create([
346 'field_name' => 'field_image',
347 'type' => 'image',
348 'entity_type' => 'node',
349 ])->save();
350 FieldConfig::create([
351 'field_name' => 'field_image',
352 'field_type' => 'image',
353 'label' => t('Image'),
354 'entity_type' => 'node',
355 'bundle' => 'article',
356 ])->save();
357 entity_get_form_display('node', 'article', 'default')
358 ->setComponent('field_image', [
359 'type' => 'image_image',
360 ])
361 ->save();
362 $display = EntityViewDisplay::load('node.article.default');
363 $display->setComponent('field_image', [
364 'type' => 'image',
365 ])->save();
366
367 // Add an image to the node.
368 $this->drupalLogin($this->editorUser);
369 $this->drupalGet('node/1/edit');
370 $image = $this->drupalGetTestFiles('image')[0];
371 $image_path = $this->container->get('file_system')->realpath($image->uri);
372 $page->attachFileToField('files[field_image_0]', $image_path);
373 $alt_field = $assert->waitForField('field_image[0][alt]');
374 $this->assertNotEmpty($alt_field);
375 $this->drupalPostForm(NULL, [
376 'field_image[0][alt]' => 'Vivamus aliquet elit',
377 ], t('Save'));
378
379 // The image field form should load normally.
380 // Wait "Quick edit" button for node.
381 $assert->waitForElement('css', '[data-quickedit-entity-id="node/1"] .contextual .quickedit');
382 // Click by "Quick edit".
383 $this->clickContextualLink('[data-quickedit-entity-id="node/1"]', 'Quick edit');
384 // Switch to body field.
385 $assert->waitForElement('css', '[data-quickedit-field-id="node/1/field_image/en/full"]')->click();
386 $assert->assertWaitOnAjaxRequest();
387
388 $field_locator = '.field--name-field-image';
389 $assert->waitForElementVisible('css', $field_locator);
390 }
391
392 }