3 namespace Drupal\Tests\system\FunctionalJavascript\Form;
5 use Drupal\Core\Field\FieldStorageDefinitionInterface;
7 use Drupal\field\Entity\FieldConfig;
8 use Drupal\field\Entity\FieldStorageConfig;
9 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
12 * Tests functionality of \Drupal\Core\Form\FormBuilderInterface::rebuildForm().
15 * @todo Add tests for other aspects of form rebuilding.
17 class RebuildTest extends WebDriverTestBase {
22 protected static $modules = ['node', 'form_test'];
27 * @var \Drupal\user\UserInterface
34 protected function setUp() {
37 $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
39 $this->webUser = $this->drupalCreateUser(['access content']);
40 $this->drupalLogin($this->webUser);
44 * Tests that a form's action is retained after an Ajax submission.
46 * The 'action' attribute of a form should not change after an Ajax submission
47 * followed by a non-Ajax submission, which triggers a validation error.
49 public function testPreserveFormActionAfterAJAX() {
50 $page = $this->getSession()->getPage();
51 // Create a multi-valued field for 'page' nodes to use for Ajax testing.
52 $field_name = 'field_ajax_test';
53 FieldStorageConfig::create([
54 'field_name' => $field_name,
55 'entity_type' => 'node',
57 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
60 'field_name' => $field_name,
61 'entity_type' => 'node',
65 // Also create a file field to test server side validation error.
66 $field_file_name = 'field_file_test';
67 FieldStorageConfig::create([
68 'field_name' => $field_file_name,
69 'entity_type' => 'node',
74 'field_name' => $field_file_name,
75 'entity_type' => 'node',
77 'label' => 'Test file',
81 entity_get_form_display('node', 'page', 'default')
82 ->setComponent($field_name, ['type' => 'text_textfield'])
83 ->setComponent($field_file_name, ['type' => 'file_generic'])
86 // Log in a user who can create 'page' nodes.
87 $this->webUser = $this->drupalCreateUser(['create page content']);
88 $this->drupalLogin($this->webUser);
90 // Get the form for adding a 'page' node. Submit an "add another item" Ajax
91 // submission and verify it worked by ensuring the updated page has two text
92 // field items in the field for which we just added an item.
93 $this->drupalGet('node/add/page');
94 $page->find('css', '[value="Add another item"]')->click();
95 $this->assertSession()->assertWaitOnAjaxRequest();
96 $this->assertTrue(count($this->xpath('//div[contains(@class, "field--name-field-ajax-test")]//input[@type="text"]')) == 2, 'AJAX submission succeeded.');
98 // Submit the form with the non-Ajax "Save" button, leaving the file field
99 // blank to trigger a validation error, and ensure that a validation error
100 // occurred, because this test is for testing what happens when a form is
101 // re-rendered without being re-built, which is what happens when there's
102 // a server side validation error.
104 'title[0][value]' => $this->randomString(),
106 $this->drupalPostForm(NULL, $edit, 'Save');
107 $this->assertSession()->pageTextContains('Test file field is required.', 'Non-AJAX submission correctly triggered a validation error.');
109 // Ensure that the form contains two items in the multi-valued field, so we
110 // know we're testing a form that was correctly retrieved from cache.
111 $this->assertTrue(count($this->xpath('//form[contains(@id, "node-page-form")]//div[contains(@class, "js-form-item-field-ajax-test")]//input[@type="text"]')) == 2, 'Form retained its state from cache.');
113 // Ensure that the form's action is correct.
114 $forms = $this->xpath('//form[contains(@class, "node-page-form")]');
115 $this->assertEquals(1, count($forms));
116 // Strip query params off the action before asserting.
117 $url = parse_url($forms[0]->getAttribute('action'))['path'];
118 $this->assertEquals(Url::fromRoute('node.add', ['node_type' => 'page'])->toString(), $url);