902fa6894ee55a57527fda6b892f9a0b142ad465
[yaffs-website] / web / core / tests / Drupal / FunctionalJavascriptTests / Ajax / MultiFormTest.php
1 <?php
2
3 namespace Drupal\FunctionalJavascriptTests\Ajax;
4
5 use Drupal\Component\Render\FormattableMarkup;
6 use Drupal\Core\Field\FieldStorageDefinitionInterface;
7 use Drupal\field\Entity\FieldConfig;
8 use Drupal\field\Entity\FieldStorageConfig;
9 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
10
11 /**
12  * Tests that AJAX-enabled forms work when multiple instances of the same form
13  * are on a page.
14  *
15  * @group Ajax
16  */
17 class MultiFormTest extends WebDriverTestBase {
18
19   /**
20    * {@inheritdoc}
21    */
22   public static $modules = ['node', 'form_test'];
23
24   /**
25    * {@inheritdoc}
26    */
27   protected function setUp() {
28     parent::setUp();
29
30     $this->drupalCreateContentType(['type' => 'page', 'name' => 'Page']);
31
32     // Create a multi-valued field for 'page' nodes to use for Ajax testing.
33     $field_name = 'field_ajax_test';
34     FieldStorageConfig::create([
35       'entity_type' => 'node',
36       'field_name' => $field_name,
37       'type' => 'text',
38       'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
39     ])->save();
40     FieldConfig::create([
41       'field_name' => $field_name,
42       'entity_type' => 'node',
43       'bundle' => 'page',
44     ])->save();
45     entity_get_form_display('node', 'page', 'default')
46       ->setComponent($field_name, ['type' => 'text_textfield'])
47       ->save();
48
49     // Log in a user who can create 'page' nodes.
50     $this->drupalLogin($this->drupalCreateUser(['create page content']));
51   }
52
53   /**
54    * Tests that pages with the 'node_page_form' included twice work correctly.
55    */
56   public function testMultiForm() {
57     // HTML IDs for elements within the field are potentially modified with
58     // each Ajax submission, but these variables are stable and help target the
59     // desired elements.
60     $field_name = 'field_ajax_test';
61
62     $form_xpath = '//form[starts-with(@id, "node-page-form")]';
63     $field_xpath = '//div[contains(@class, "field--name-field-ajax-test")]';
64     $button_name = $field_name . '_add_more';
65     $button_value = t('Add another item');
66     $button_xpath_suffix = '//input[@name="' . $button_name . '"]';
67     $field_items_xpath_suffix = '//input[@type="text"]';
68
69     // Ensure the initial page contains both node forms and the correct number
70     // of field items and "add more" button for the multi-valued field within
71     // each form.
72     $this->drupalGet('form-test/two-instances-of-same-form');
73
74     // Wait for javascript on the page to prepare the form attributes.
75     $this->assertSession()->assertWaitOnAjaxRequest();
76
77     $session = $this->getSession();
78     $page = $session->getPage();
79     $fields = $page->findAll('xpath', $form_xpath . $field_xpath);
80     $this->assertEqual(count($fields), 2);
81     foreach ($fields as $field) {
82       $this->assertCount(1, $field->findAll('xpath', '.' . $field_items_xpath_suffix), 'Found the correct number of field items on the initial page.');
83       $this->assertFieldsByValue($field->find('xpath', '.' . $button_xpath_suffix), NULL, 'Found the "add more" button on the initial page.');
84     }
85
86     $this->assertNoDuplicateIds();
87
88     // Submit the "add more" button of each form twice. After each corresponding
89     // page update, ensure the same as above.
90
91     for ($i = 0; $i < 2; $i++) {
92       $forms = $page->find('xpath', $form_xpath);
93       foreach ($forms as $offset => $form) {
94         $button = $form->findButton($button_value);
95         $this->assertNotNull($button, 'Add Another Item button exists');
96         $button->press();
97
98         // Wait for page update.
99         $this->assertSession()->assertWaitOnAjaxRequest();
100
101         // After AJAX request and response page will update.
102         $page_updated = $session->getPage();
103         $field = $page_updated->findAll('xpath', '.' . $field_xpath);
104         $this->assertEqual(count($field[0]->find('xpath', '.' . $field_items_xpath_suffix)), $i + 2, 'Found the correct number of field items after an AJAX submission.');
105         $this->assertFieldsByValue($field[0]->find('xpath', '.' . $button_xpath_suffix), NULL, 'Found the "add more" button after an AJAX submission.');
106         $this->assertNoDuplicateIds();
107       }
108     }
109   }
110
111   /**
112    * Asserts that each HTML ID is used for just a single element on the page.
113    *
114    * @param string $message
115    *   (optional) A message to display with the assertion.
116    */
117   protected function assertNoDuplicateIds($message = '') {
118     $args = ['@url' => $this->getUrl()];
119
120     if (!$elements = $this->xpath('//*[@id]')) {
121       $this->fail(new FormattableMarkup('The page @url contains no HTML IDs.', $args));
122       return;
123     }
124
125     $message = $message ?: new FormattableMarkup('The page @url does not contain duplicate HTML IDs', $args);
126
127     $seen_ids = [];
128     foreach ($elements as $element) {
129       $id = $element->getAttribute('id');
130       if (isset($seen_ids[$id])) {
131         $this->fail($message);
132         return;
133       }
134       $seen_ids[$id] = TRUE;
135     }
136     $this->assertTrue(TRUE, $message);
137   }
138
139 }