3 namespace Drupal\inline_entity_form\Tests;
5 use Drupal\node\Entity\Node;
8 * IEF complex field widget tests.
10 * @group inline_entity_form
12 class ComplexWidgetWebTest extends InlineEntityFormTestBase {
19 public static $modules = [
20 'inline_entity_form_test',
26 * URL to add new content.
30 protected $formContentAddUrl;
33 * Entity form display storage.
35 * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
37 protected $entityFormDisplayStorage;
40 * Prepares environment for
42 protected function setUp() {
45 $this->user = $this->createUser([
46 'create ief_reference_type content',
47 'edit any ief_reference_type content',
48 'delete any ief_reference_type content',
49 'create ief_test_complex content',
50 'edit any ief_test_complex content',
51 'delete any ief_test_complex content',
52 'edit any ief_test_nested1 content',
53 'edit any ief_test_nested2 content',
54 'edit any ief_test_nested3 content',
55 'view own unpublished content',
56 'administer content types',
58 $this->drupalLogin($this->user);
60 $this->formContentAddUrl = 'node/add/ief_test_complex';
61 $this->entityFormDisplayStorage = $this->container->get('entity_type.manager')->getStorage('entity_form_display');
65 * Tests if form behaves correctly when field is empty.
67 public function testEmptyFieldIEF() {
68 // Don't allow addition of existing nodes.
69 $this->updateSetting('allow_existing', FALSE);
70 $this->drupalGet($this->formContentAddUrl);
72 $this->assertFieldByName('multi[form][inline_entity_form][title][0][value]', NULL, 'Title field on inline form exists.');
73 $this->assertFieldByName('multi[form][inline_entity_form][first_name][0][value]', NULL, 'First name field on inline form exists.');
74 $this->assertFieldByName('multi[form][inline_entity_form][last_name][0][value]', NULL, 'Last name field on inline form exists.');
75 $this->assertFieldByXpath('//input[@type="submit" and @value="Create node"]', NULL, 'Found "Create node" submit button');
77 // Allow addition of existing nodes.
78 $this->updateSetting('allow_existing', TRUE);
79 $this->drupalGet($this->formContentAddUrl);
81 $this->assertNoFieldByName('multi[form][inline_entity_form][title][0][value]', NULL, 'Title field does not appear.');
82 $this->assertNoFieldByName('multi[form][inline_entity_form][first_name][0][value]', NULL, 'First name field does not appear.');
83 $this->assertNoFieldByName('multi[form][inline_entity_form][last_name][0][value]', NULL, 'Last name field does not appear.');
84 $this->assertFieldByXpath('//input[@type="submit" and @value="Add new node"]', NULL, 'Found "Add new node" submit button');
85 $this->assertFieldByXpath('//input[@type="submit" and @value="Add existing node"]', NULL, 'Found "Add existing node" submit button');
87 // Now submit 'Add new node' button.
88 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Add new node" and @data-drupal-selector="edit-multi-actions-ief-add"]'));
90 $this->assertFieldByName('multi[form][inline_entity_form][title][0][value]', NULL, 'Title field on inline form exists.');
91 $this->assertFieldByName('multi[form][inline_entity_form][first_name][0][value]', NULL, 'First name field on inline form exists.');
92 $this->assertFieldByName('multi[form][inline_entity_form][last_name][0][value]', NULL, 'Second name field on inline form exists.');
93 $this->assertFieldByXpath('//input[@type="submit" and @value="Create node"]', NULL, 'Found "Create node" submit button');
94 $this->assertFieldByXpath('//input[@type="submit" and @value="Cancel"]', NULL, 'Found "Cancel" submit button');
96 // Now submit 'Add Existing node' button.
97 $this->drupalGet($this->formContentAddUrl);
98 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Add existing node" and @data-drupal-selector="edit-multi-actions-ief-add-existing"]'));
100 $this->assertFieldByName('multi[form][entity_id]', NULL, 'Existing entity reference autocomplete field found.');
101 $this->assertFieldByXpath('//input[@type="submit" and @value="Add node"]', NULL, 'Found "Add node" submit button');
102 $this->assertFieldByXpath('//input[@type="submit" and @value="Cancel"]', NULL, 'Found "Cancel" submit button');
106 * Tests creation of entities.
108 public function testEntityCreation() {
109 // Allow addition of existing nodes.
110 $this->updateSetting('allow_existing', TRUE);
111 $this->drupalGet($this->formContentAddUrl);
113 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Add new node" and @data-drupal-selector="edit-multi-actions-ief-add"]'));
114 $this->assertResponse(200, 'Opening new inline form was successful.');
116 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Create node" and @data-drupal-selector="edit-multi-form-inline-entity-form-actions-ief-add-save"]'));
117 $this->assertResponse(200, 'Submitting empty form was successful.');
118 $this->assertText('First name field is required.', 'Validation failed for empty "First name" field.');
119 $this->assertText('Last name field is required.', 'Validation failed for empty "Last name" field.');
120 $this->assertText('Title field is required.', 'Validation failed for empty "Title" field.');
122 // Create ief_reference_type node in IEF.
123 $this->drupalGet($this->formContentAddUrl);
124 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Add new node" and @data-drupal-selector="edit-multi-actions-ief-add"]'));
125 $this->assertResponse(200, 'Opening new inline form was successful.');
128 'multi[form][inline_entity_form][title][0][value]' => 'Some reference',
129 'multi[form][inline_entity_form][first_name][0][value]' => 'John',
130 'multi[form][inline_entity_form][last_name][0][value]' => 'Doe',
132 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Create node" and @data-drupal-selector="edit-multi-form-inline-entity-form-actions-ief-add-save"]'));
133 $this->assertResponse(200, 'Creating node via inline form was successful.');
135 // Tests if correct fields appear in the table.
136 $this->assertTrue((bool) $this->xpath('//td[@class="inline-entity-form-node-label" and contains(.,"Some reference")]'), 'Node title field appears in the table');
137 $this->assertTrue((bool) $this->xpath('//td[@class="inline-entity-form-node-status" and ./div[contains(.,"Published")]]'), 'Node status field appears in the table');
139 // Tests if edit and remove buttons appear.
140 $this->assertTrue((bool) $this->xpath('//input[@type="submit" and @value="Edit"]'), 'Edit button appears in the table.');
141 $this->assertTrue((bool) $this->xpath('//input[@type="submit" and @value="Remove"]'), 'Remove button appears in the table.');
143 // Test edit functionality.
144 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Edit"]'));
146 'multi[form][inline_entity_form][entities][0][form][title][0][value]' => 'Some changed reference',
148 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Update node"]'));
149 $this->assertTrue((bool) $this->xpath('//td[@class="inline-entity-form-node-label" and contains(.,"Some changed reference")]'), 'Node title field appears in the table');
150 $this->assertTrue((bool) $this->xpath('//td[@class="inline-entity-form-node-status" and ./div[contains(.,"Published")]]'), 'Node status field appears in the table');
152 // Make sure unrelated AJAX submit doesn't save the referenced entity.
153 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Upload"]'));
154 $node = $this->drupalGetNodeByTitle('Some changed reference');
155 $this->assertFalse($node, 'Referenced node was not saved during unrelated AJAX submit.');
157 // Create ief_test_complex node.
158 $edit = ['title[0][value]' => 'Some title'];
159 $this->drupalPostForm(NULL, $edit, t('Save'));
160 $this->assertResponse(200, 'Saving parent entity was successful.');
162 // Checks values of created entities.
163 $node = $this->drupalGetNodeByTitle('Some changed reference');
164 $this->assertTrue($node, 'Created ief_reference_type node ' . $node->label());
165 $this->assertTrue($node->get('first_name')->value == 'John', 'First name in reference node set to John');
166 $this->assertTrue($node->get('last_name')->value == 'Doe', 'Last name in reference node set to Doe');
168 $parent_node = $this->drupalGetNodeByTitle('Some title');
169 $this->assertTrue($parent_node, 'Created ief_test_complex node ' . $parent_node->label());
170 $this->assertTrue($parent_node->multi->target_id == $node->id(), 'Refererence node id set to ' . $node->id());
174 * Tests the entity creation with different bundles nested in each other.
176 * ief_test_nested1 -> ief_test_nested2 -> ief_test_nested3
178 public function testNestedEntityCreationWithDifferentBundlesAjaxSubmit() {
179 $required_possibilities = [
183 foreach ($required_possibilities as $required) {
184 $this->setupNestedComplexForm($required);
186 $nested3_title = 'nested3 title steps ' . ($required ? 'required' : 'not required');
187 $nested2_title = 'nested2 title steps ' . ($required ? 'required' : 'not required');
188 $nested1_title = 'nested1 title steps ' . ($required ? 'required' : 'not required');
190 'test_ref_nested1[form][inline_entity_form][test_ref_nested2][form][inline_entity_form][title][0][value]' => $nested3_title,
192 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Create node 3"]'));
193 $this->assertText($nested3_title, 'Title of second nested node found.');
194 $this->assertNoNodeByTitle($nested3_title, 'Second nested entity is not saved yet.');
197 'test_ref_nested1[form][inline_entity_form][title][0][value]' => $nested2_title,
199 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Create node 2"]'));
200 $this->assertText($nested2_title, 'Title of first nested node found.');
201 $this->assertNoNodeByTitle($nested2_title, 'First nested entity is not saved yet.');
204 'title[0][value]' => $nested1_title,
206 $this->drupalPostForm(NULL, $edit, t('Save'));
207 $this->checkNestedNodes($nested1_title, $nested2_title, $nested3_title);
212 * Checks that nested IEF entity references can be edit and saved.
214 * @param \Drupal\node\Entity\Node $node
215 * Top level node of type ief_test_nested1 to check.
216 * @param bool $ajax_submit
217 * Whether IEF form widgets should be submitted via AJAX or left open.
219 protected function checkNestedEntityEditing(Node $node, $ajax_submit = TRUE) {
220 $this->drupalGet("node/{$node->id()}/edit");
221 /** @var \Drupal\node\Entity\Node $level_1_node */
222 $level_1_node = $node->test_ref_nested1->entity;
223 /** @var \Drupal\node\Entity\Node $level_2_node */
224 $level_2_node = $node->test_ref_nested1->entity->test_ref_nested2->entity;
225 $level_2_node_update_title = $level_2_node->getTitle() . ' - updated';
226 // edit-test-ref-nested1-entities-0-actions-ief-entity-edit
227 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-test-ref-nested1-entities-0-actions-ief-entity-edit"]'));
228 // edit-test-ref-nested1-form-inline-entity-form-entities-0-form-test-ref-nested2-entities-0-actions-ief-entity-edit
229 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-test-ref-nested1-form-inline-entity-form-entities-0-form-test-ref-nested2-entities-0-actions-ief-entity-edit"]'));
230 $edit['test_ref_nested1[form][inline_entity_form][entities][0][form][test_ref_nested2][form][inline_entity_form][entities][0][form][title][0][value]'] = $level_2_node_update_title;
232 // Close IEF Forms with AJAX posts
233 // edit-test-ref-nested1-form-inline-entity-form-entities-0-form-test-ref-nested2-form-inline-entity-form-entities-0-form-actions-ief-edit-save
234 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-test-ref-nested1-form-inline-entity-form-entities-0-form-test-ref-nested2-form-inline-entity-form-entities-0-form-actions-ief-edit-save"]'));
235 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-test-ref-nested1-form-inline-entity-form-entities-0-form-actions-ief-edit-save"]'));
236 $this->drupalPostForm(NULL, [], t('Save'));
239 $this->drupalPostForm(NULL, $edit, t('Save'));
241 $this->nodeStorage->resetCache([$level_2_node->id()]);
242 $level_2_node = $this->nodeStorage->load($level_2_node->id());
243 $this->assertEqual($level_2_node_update_title, $level_2_node->getTitle());
247 * Tests the entity creation with different bundles nested in each other.
249 * ief_test_nested1 -> ief_test_nested2 -> ief_test_nested3
251 public function testNestedEntityCreationWithDifferentBundlesNoAjaxSubmit() {
252 $required_possibilities = [
257 foreach ($required_possibilities as $required) {
258 $this->setupNestedComplexForm($required);
260 $nested3_title = 'nested3 title single ' . ($required ? 'required' : 'not required');
261 $nested2_title = 'nested2 title single ' . ($required ? 'required' : 'not required');
262 $nested1_title = 'nested1 title single ' . ($required ? 'required' : 'not required');
265 'title[0][value]' => $nested1_title,
266 'test_ref_nested1[form][inline_entity_form][title][0][value]' => $nested2_title,
267 'test_ref_nested1[form][inline_entity_form][test_ref_nested2][form][inline_entity_form][title][0][value]' => $nested3_title,
269 $this->drupalPostForm(NULL, $edit, t('Save'));
270 $this->checkNestedNodes($nested1_title, $nested2_title, $nested3_title);
275 * Tests if editing and removing entities work.
277 public function testEntityEditingAndRemoving() {
278 // Allow addition of existing nodes.
279 $this->updateSetting('allow_existing', TRUE);
281 // Create three ief_reference_type entities.
282 $referenceNodes = $this->createReferenceContent(3);
283 $this->drupalCreateNode([
284 'type' => 'ief_test_complex',
285 'title' => 'Some title',
286 'multi' => array_values($referenceNodes),
288 /** @var \Drupal\node\NodeInterface $node */
289 $parent_node = $this->drupalGetNodeByTitle('Some title');
291 // Edit the second entity.
292 $this->drupalGet('node/' . $parent_node->id() . '/edit');
293 $cell = $this->xpath('//table[@id="ief-entity-table-edit-multi-entities"]/tbody/tr[@class="ief-row-entity draggable even"]/td[@class="inline-entity-form-node-label"]');
294 $title = (string) $cell[0];
296 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @id="edit-multi-entities-1-actions-ief-entity-edit"]'));
297 $this->assertResponse(200, 'Opening inline edit form was successful.');
300 'multi[form][inline_entity_form][entities][1][form][first_name][0][value]' => 'John',
301 'multi[form][inline_entity_form][entities][1][form][last_name][0][value]' => 'Doe',
303 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-multi-form-inline-entity-form-entities-1-form-actions-ief-edit-save"]'));
304 $this->assertResponse(200, 'Saving inline edit form was successful.');
306 // Save the ief_test_complex node.
307 $this->drupalPostForm(NULL, [], t('Save'));
308 $this->assertResponse(200, 'Saving parent entity was successful.');
310 // Checks values of changed entities.
311 $node = $this->drupalGetNodeByTitle($title, TRUE);
312 $this->assertTrue($node->first_name->value == 'John', 'First name in reference node changed to John');
313 $this->assertTrue($node->last_name->value == 'Doe', 'Last name in reference node changed to Doe');
315 // Delete the second entity.
316 $this->drupalGet('node/' . $parent_node->id() . '/edit');
317 $cell = $this->xpath('//table[@id="ief-entity-table-edit-multi-entities"]/tbody/tr[@class="ief-row-entity draggable even"]/td[@class="inline-entity-form-node-label"]');
318 $title = (string) $cell[0];
320 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @id="edit-multi-entities-1-actions-ief-entity-remove"]'));
321 $this->assertResponse(200, 'Opening inline remove confirm form was successful.');
322 $this->assertText('Are you sure you want to remove', 'Remove warning message is displayed.');
324 $this->drupalPostAjaxForm(NULL, ['multi[form][entities][1][form][delete]' => TRUE], $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-multi-form-entities-1-form-actions-ief-remove-confirm"]'));
325 $this->assertResponse(200, 'Removing inline entity was successful.');
326 $this->assertNoText($title, 'Deleted inline entity is not present on the page.');
328 // Save the ief_test_complex node.
329 $this->drupalPostForm(NULL, [], t('Save'));
330 $this->assertResponse(200, 'Saving parent node was successful.');
332 $deleted_node = $this->drupalGetNodeByTitle($title);
333 $this->assertTrue(empty($deleted_node), 'The inline entity was deleted from the site.');
335 // Checks that entity does nor appear in IEF.
336 $this->drupalGet('node/' . $parent_node->id() . '/edit');
337 $this->assertNoText($title, 'Deleted inline entity is not present on the page after saving parent.');
339 // Delete the third entity reference only, don't delete the node. The third
340 // entity now is second referenced entity because the second one was deleted
342 $this->drupalGet('node/' . $parent_node->id() . '/edit');
343 $cell = $this->xpath('//table[@id="ief-entity-table-edit-multi-entities"]/tbody/tr[@class="ief-row-entity draggable even"]/td[@class="inline-entity-form-node-label"]');
344 $title = (string) $cell[0];
346 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @id="edit-multi-entities-1-actions-ief-entity-remove"]'));
347 $this->assertResponse(200, 'Opening inline remove confirm form was successful.');
349 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-multi-form-entities-1-form-actions-ief-remove-confirm"]'));
350 $this->assertResponse(200, 'Removing inline entity was successful.');
352 // Save the ief_test_complex node.
353 $this->drupalPostForm(NULL, [], t('Save'));
354 $this->assertResponse(200, 'Saving parent node was successful.');
356 // Checks that entity does nor appear in IEF.
357 $this->drupalGet('node/' . $parent_node->id() . '/edit');
358 $this->assertNoText($title, 'Deleted inline entity is not present on the page after saving parent.');
360 // Checks that entity is not deleted.
361 $node = $this->drupalGetNodeByTitle($title, TRUE);
362 $this->assertTrue($node, 'Reference node not deleted');
366 * Tests if referencing existing entities work.
368 public function testReferencingExistingEntities() {
369 // Allow addition of existing nodes.
370 $this->updateSetting('allow_existing', TRUE);
372 // Create three ief_reference_type entities.
373 $referenceNodes = $this->createReferenceContent(3);
375 // Create a node for every bundle available.
376 $bundle_nodes = $this->createNodeForEveryBundle();
378 // Create ief_test_complex node with first ief_reference_type node and first
379 // node from bundle nodes.
380 $this->drupalCreateNode([
381 'type' => 'ief_test_complex',
382 'title' => 'Some title',
384 'all_bundles' => key($bundle_nodes),
386 // Remove first node since we already added it.
387 unset($bundle_nodes[key($bundle_nodes)]);
389 $parent_node = $this->drupalGetNodeByTitle('Some title', TRUE);
391 // Add remaining existing reference nodes.
392 $this->drupalGet('node/' . $parent_node->id() . '/edit');
393 for ($i = 2; $i <= 3; $i++) {
394 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Add existing node" and @data-drupal-selector="edit-multi-actions-ief-add-existing"]'));
395 $this->assertResponse(200, 'Opening reference form was successful.');
396 $title = 'Some reference ' . $i;
398 'multi[form][entity_id]' => $title . ' (' . $referenceNodes[$title] . ')',
400 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-multi-form-actions-ief-reference-save"]'));
401 $this->assertResponse(200, 'Adding new referenced entity was successful.');
403 // Add all remaining nodes from all bundles.
404 foreach ($bundle_nodes as $id => $title) {
405 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Add existing node" and @data-drupal-selector="edit-all-bundles-actions-ief-add-existing"]'));
406 $this->assertResponse(200, 'Opening reference form was successful.');
408 'all_bundles[form][entity_id]' => $title . ' (' . $id . ')',
410 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-all-bundles-form-actions-ief-reference-save"]'));
411 $this->assertResponse(200, 'Adding new referenced entity was successful.');
414 $this->drupalPostForm(NULL, [], t('Save'));
415 $this->assertResponse(200, 'Saving parent for was successful.');
417 // Check if entities are referenced.
418 $this->drupalGet('node/' . $parent_node->id() . '/edit');
419 for ($i = 2; $i <= 3; $i++) {
420 $cell = $this->xpath('//table[@id="ief-entity-table-edit-multi-entities"]/tbody/tr[' . $i . ']/td[@class="inline-entity-form-node-label"]');
421 $this->assertTrue($cell[0] == 'Some reference ' . $i, 'Found reference node title "Some reference ' . $i . '" in the IEF table.');
423 // Check if all remaining nodes from all bundles are referenced.
425 foreach ($bundle_nodes as $id => $title) {
426 $cell = $this->xpath('//table[@id="ief-entity-table-edit-all-bundles-entities"]/tbody/tr[' . $count . ']/td[@class="inline-entity-form-node-label"]');
427 $this->assertTrue($cell[0] == $title, 'Found reference node title "' . $title . '" in the IEF table.');
433 * Test if invalid values get correct validation messages in reference existing entity form.
435 * Also checks if existing entity reference form can be canceled.
437 public function testReferenceExistingValidation() {
438 $this->updateSetting('allow_existing', TRUE);
440 $this->drupalGet('node/add/ief_test_complex');
441 $this->checkExistingValidationExpectation('', 'Node field is required.');
442 $this->checkExistingValidationExpectation('Fake Title', "There are no entities matching \"Fake Title\"");
443 // Check adding nodes that cannot be referenced by this field.
444 $bundle_nodes = $this->createNodeForEveryBundle();
445 foreach ($bundle_nodes as $id => $title) {
446 $node = $this->nodeStorage->load($id);
447 if ($node->bundle() != 'ief_reference_type') {
448 $this->checkExistingValidationExpectation("$title ($id)", "The referenced entity (node: $id) does not exist.");
452 $nodes = $this->createReferenceContent(2);
453 foreach ($nodes as $title => $id) {
454 $this->openMultiExistingForm();
456 'multi[form][entity_id]' => "$title ($id)",
458 // Add a node successfully.
459 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-multi-form-actions-ief-reference-save"]'));
460 $this->assertNoFieldByName('multi[form][entity_id]', NULL, 'Existing entity reference autocomplete field removed.');
461 // Try to add the same node again.
462 $this->checkExistingValidationExpectation("$title ($id)", 'The selected node has already been added.');
467 * Tests if duplicating entities works.
469 public function testDuplicatingEntities() {
470 $this->updateSetting('allow_duplicate', TRUE);
472 $referenceNodes = $this->createReferenceContent(2);
473 $this->drupalCreateNode([
474 'type' => 'ief_test_complex',
475 'title' => 'Some title',
476 'multi' => array_values($referenceNodes),
478 /** @var \Drupal\node\NodeInterface $node */
479 $parent_node = $this->drupalGetNodeByTitle('Some title');
481 $this->drupalGet('node/' . $parent_node->id() . '/edit');
482 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @id="edit-multi-entities-0-actions-ief-entity-duplicate"]'));
483 $this->assertResponse(200, 'Opening inline duplicate form was successful.');
486 'multi[form][inline_entity_form][entities][0][form][title][0][value]' => 'Duplicate!',
487 'multi[form][inline_entity_form][entities][0][form][first_name][0][value]' => 'Bojan',
489 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-multi-form-inline-entity-form-entities-0-form-actions-ief-duplicate-save"]'));
490 $this->assertResponse(200, 'Saving inline duplicate form was successful.');
492 $this->assertText('Some reference 1');
493 $this->assertText('Some reference 2');
494 $this->assertText('Duplicate!');
495 $this->drupalPostForm(NULL, [], t('Save'));
496 $this->assertResponse(200, 'Saving parent entity was successful.');
498 // Confirm a duplicate was made.
499 $duplicate = Node::load(4);
500 $this->assertEqual($duplicate->label(), 'Duplicate!');
501 $this->assertEqual($duplicate->first_name->value, 'Bojan');
505 * Tests if a referenced content can be edited while the referenced content is
506 * newer than the referencing parent node.
508 public function testEditedInlineEntityValidation() {
509 $this->updateSetting('allow_existing', TRUE);
511 // Create referenced content.
512 $referenced_nodes = $this->createReferenceContent(1);
514 // Create first referencing node.
515 $this->drupalCreateNode([
516 'type' => 'ief_test_complex',
517 'title' => 'First referencing node',
518 'multi' => array_values($referenced_nodes),
520 $first_node = $this->drupalGetNodeByTitle('First referencing node');
522 // Create second referencing node.
523 $this->drupalCreateNode([
524 'type' => 'ief_test_complex',
525 'title' => 'Second referencing node',
526 'multi' => array_values($referenced_nodes),
528 $second_node = $this->drupalGetNodeByTitle('Second referencing node');
530 // Edit referenced content in first node.
531 $this->drupalGet('node/' . $first_node->id() . '/edit');
533 // Edit referenced node.
534 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Edit" and @data-drupal-selector="edit-multi-entities-0-actions-ief-entity-edit"]'));
536 'multi[form][inline_entity_form][entities][0][form][title][0][value]' => 'Some reference updated',
538 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Update node" and @data-drupal-selector="edit-multi-form-inline-entity-form-entities-0-form-actions-ief-edit-save"]'));
540 // Save the first node after editing the reference.
541 $edit = ['title[0][value]' => 'First node updated'];
542 $this->drupalPostForm(NULL, $edit, t('Save'));
544 // The changed value of the referenced content is now newer than the
545 // changed value of the second node.
547 // Edit referenced content in second node.
548 $this->drupalGet('node/' . $second_node->id() . '/edit');
550 // Edit referenced node.
551 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Edit" and @data-drupal-selector="edit-multi-entities-0-actions-ief-entity-edit"]'));
553 'multi[form][inline_entity_form][entities][0][form][title][0][value]' => 'Some reference updated the second time',
555 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Update node" and @data-drupal-selector="edit-multi-form-inline-entity-form-entities-0-form-actions-ief-edit-save"]'));
557 // Save the second node after editing the reference.
558 $edit = ['title[0][value]' => 'Second node updated'];
559 $this->drupalPostForm(NULL, $edit, t('Save'));
561 // Check if the referenced content could be edited.
562 $this->assertNoText('The content has either been modified by another user, or you have already submitted modifications. As a result, your changes cannot be saved.', 'The referenced content could be edited.');
566 * Creates ief_reference_type nodes which shall serve as reference nodes.
568 * @param int $numNodes
569 * The number of nodes to create
571 * Array of created node ids keyed by labels.
573 protected function createReferenceContent($numNodes = 3) {
575 for ($i = 1; $i <= $numNodes; $i++) {
576 $this->drupalCreateNode([
577 'type' => 'ief_reference_type',
578 'title' => 'Some reference ' . $i,
579 'first_name' => 'First Name ' . $i,
580 'last_name' => 'Last Name ' . $i,
582 $node = $this->drupalGetNodeByTitle('Some reference ' . $i);
583 $this->assertTrue($node, 'Created ief_reference_type node "' . $node->label() . '"');
584 $retval[$node->label()] = $node->id();
590 * Updates an IEF setting and saves the underlying entity display.
592 * @param string $name
593 * The name of the setting.
594 * @param mixed $value
597 protected function updateSetting($name, $value) {
598 /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $display */
599 $display = $this->entityFormDisplayStorage->load('node.ief_test_complex.default');
600 $component = $display->getComponent('multi');
601 $component['settings'][$name] = $value;
602 $display->setComponent('multi', $component)->save();
606 * Creates a node for every node bundle.
609 * Array of node titles keyed by ids.
611 protected function createNodeForEveryBundle() {
613 $bundles = $this->container->get('entity.manager')->getBundleInfo('node');
614 foreach ($bundles as $id => $value) {
615 $this->drupalCreateNode(['type' => $id, 'title' => $value['label']]);
616 $node = $this->drupalGetNodeByTitle($value['label']);
617 $this->assertTrue($node, 'Created node "' . $node->label() . '"');
618 $retval[$node->id()] = $value['label'];
624 * Set up the ief_test_nested1 node add form.
626 * Sets the nested fields' required settings.
628 * Opens the inline entity forms if they are not required.
630 * @param bool $required
631 * Whether the fields are required.
632 * @param array $permissions
633 * (optional) Permissions to sign testing user in with. You may pass in an
634 * empty array (default) to use the all the permissions necessary create and
635 * edit nodes on the form.
637 protected function setupNestedComplexForm($required, $permissions = []) {
638 /** @var \Drupal\Core\Field\FieldConfigInterface $ief_test_nested1 */
639 $ief_test_nested1 = $this->fieldConfigStorage->load('node.ief_test_nested1.test_ref_nested1');
640 $ief_test_nested1->setRequired($required);
641 $ief_test_nested1->save();
642 /** @var \Drupal\Core\Field\FieldConfigInterface $ief_test_nested2 */
643 $ief_test_nested2 = $this->fieldConfigStorage->load('node.ief_test_nested2.test_ref_nested2');
644 $ief_test_nested2->setRequired($required);
645 $ief_test_nested2->save();
649 'create ief_test_nested1 content',
650 'create ief_test_nested2 content',
651 'create ief_test_nested3 content',
652 'edit any ief_test_nested1 content',
653 'edit any ief_test_nested2 content',
654 'edit any ief_test_nested3 content',
657 $this->user = $this->createUser($permissions);
658 $this->drupalLogin($this->user);
660 $this->drupalGet('node/add/ief_test_nested1');
663 // Open inline forms if not required.
664 if (in_array('create ief_test_nested2 content', $permissions)) {
665 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Add new node 2"]'));
667 if (in_array('create ief_test_nested3 content', $permissions)) {
668 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Add new node 3"]'));
674 * Closes the existing node form on the "multi" field.
676 protected function cancelExistingMultiForm($edit) {
677 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-multi-form-actions-ief-reference-cancel"]'));
678 $this->assertNoFieldByName('multi[form][entity_id]', NULL, 'Existing entity reference autocomplete field removed.');
682 * Opens the existing node form on the "multi" field.
684 protected function openMultiExistingForm() {
685 $this->drupalPostAjaxForm(NULL, [], $this->getButtonName('//input[@type="submit" and @value="Add existing node" and @data-drupal-selector="edit-multi-actions-ief-add-existing"]'));
686 $this->assertResponse(200, 'Opening reference form was successful.');
687 $this->assertFieldByName('multi[form][entity_id]', NULL, 'Existing entity reference autocomplete field found.');
691 * Checks that an invalid value for an existing node will be display the expected error.
693 * @param $existing_node_text
694 * The text to enter into the existing node text field.
695 * @param $expected_error
696 * The error message that is expected to be shown.
698 protected function checkExistingValidationExpectation($existing_node_text, $expected_error) {
700 'multi[form][entity_id]' => $existing_node_text,
702 $this->openMultiExistingForm();
704 $this->drupalPostAjaxForm(NULL, $edit, $this->getButtonName('//input[@type="submit" and @data-drupal-selector="edit-multi-form-actions-ief-reference-save"]'));
705 $this->assertText($expected_error);
706 $this->cancelExistingMultiForm($edit);
710 * Tests entity create access is correct on nested IEF forms.
712 public function testNestedEntityCreateAccess() {
714 'create ief_test_nested1 content',
715 'create ief_test_nested2 content',
717 $this->setupNestedComplexForm(TRUE, $permissions);
718 $this->assertFieldByName('title[0][value]');
719 $this->assertFieldByName('test_ref_nested1[form][inline_entity_form][title][0][value]');
720 $this->assertNoFieldByName('test_ref_nested1[form][inline_entity_form][test_ref_nested2][form][inline_entity_form][title][0][value]', NULL);
722 $this->setupNestedComplexForm(FALSE, $permissions);
723 $this->assertNoFieldByXPath('//input[@type="submit" and @value="Add new node 3"]');
727 * Tests create access on IEF Complex content type.
729 public function testComplexEntityCreate() {
730 $user = $this->createUser([
731 'create ief_test_complex content',
733 $this->drupalLogin($user);
735 $this->drupalGet('node/add/ief_test_complex');
736 $this->assertNoFieldByName('all_bundles[actions][bundle]', NULL, 'Bundle select is not shown when only one bundle is available.');
737 $this->assertNoFieldByName('multi[form][inline_entity_form][title][0][value]', NULL);
739 $user = $this->createUser([
740 'create ief_test_complex content',
741 'create ief_reference_type content'
743 $this->drupalLogin($user);
745 $this->drupalGet('node/add/ief_test_complex');
746 $this->assertFieldByName('all_bundles[actions][bundle]', NULL, 'Bundle select is shown when more than one bundle is available.');
747 $this->assertOption('edit-all-bundles-actions-bundle', 'ief_reference_type');
748 $this->assertOption('edit-all-bundles-actions-bundle', 'ief_test_complex');
749 $this->assertFieldByName('multi[form][inline_entity_form][title][0][value]');
753 * Checks if nested nodes for ief_test_nested1 content were created correctly.
755 * @param $nested1_title
756 * Expected title of top level node of the type ief_test_nested1
757 * @param $nested2_title
758 * Expected title of second level node
759 * @param $nested3_title
760 * Expected title of third level node
762 protected function checkNestedNodes($nested1_title, $nested2_title, $nested3_title) {
763 $nested1_node = $this->drupalGetNodeByTitle($nested1_title);
764 $this->assertEqual($nested1_title, $nested1_node->label(), "First node's title looks correct.");
765 $this->assertEqual('ief_test_nested1', $nested1_node->bundle(), "First node's type looks correct.");
766 if ($this->assertNotNull($nested1_node->test_ref_nested1->entity, 'Second node was created.')) {
767 $this->assertEqual($nested1_node->test_ref_nested1->count(), 1, 'Only 1 node created at first level.');
768 $this->assertEqual($nested2_title, $nested1_node->test_ref_nested1->entity->label(), "Second node's title looks correct.");
769 $this->assertEqual('ief_test_nested2', $nested1_node->test_ref_nested1->entity->bundle(), "Second node's type looks correct.");
770 if ($this->assertNotNull($nested1_node->test_ref_nested1->entity->test_ref_nested2->entity, 'Third node was created')) {
771 $this->assertEqual($nested1_node->test_ref_nested1->entity->test_ref_nested2->count(), 1, 'Only 1 node created at second level.');
772 $this->assertEqual($nested3_title, $nested1_node->test_ref_nested1->entity->test_ref_nested2->entity->label(), "Third node's title looks correct.");
773 $this->assertEqual('ief_test_nested3', $nested1_node->test_ref_nested1->entity->test_ref_nested2->entity->bundle(), "Third node's type looks correct.");
775 $this->checkNestedEntityEditing($nested1_node, TRUE);