Chris@17: drupalCreateContentType(['type' => 'page', 'name' => 'Page']); Chris@17: Chris@17: // Create a multi-valued field for 'page' nodes to use for Ajax testing. Chris@17: $field_name = 'field_ajax_test'; Chris@17: FieldStorageConfig::create([ Chris@17: 'entity_type' => 'node', Chris@17: 'field_name' => $field_name, Chris@17: 'type' => 'text', Chris@17: 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, Chris@17: ])->save(); Chris@17: FieldConfig::create([ Chris@17: 'field_name' => $field_name, Chris@17: 'entity_type' => 'node', Chris@17: 'bundle' => 'page', Chris@17: ])->save(); Chris@17: entity_get_form_display('node', 'page', 'default') Chris@17: ->setComponent($field_name, ['type' => 'text_textfield']) Chris@17: ->save(); Chris@17: Chris@17: // Log in a user who can create 'page' nodes. Chris@17: $this->drupalLogin($this->drupalCreateUser(['create page content'])); Chris@17: } Chris@17: Chris@17: /** Chris@17: * Tests that pages with the 'node_page_form' included twice work correctly. Chris@17: */ Chris@17: public function testMultiForm() { Chris@17: // HTML IDs for elements within the field are potentially modified with Chris@17: // each Ajax submission, but these variables are stable and help target the Chris@17: // desired elements. Chris@17: $field_name = 'field_ajax_test'; Chris@17: Chris@17: $form_xpath = '//form[starts-with(@id, "node-page-form")]'; Chris@17: $field_xpath = '//div[contains(@class, "field--name-field-ajax-test")]'; Chris@17: $button_name = $field_name . '_add_more'; Chris@17: $button_value = t('Add another item'); Chris@17: $button_xpath_suffix = '//input[@name="' . $button_name . '"]'; Chris@17: $field_items_xpath_suffix = '//input[@type="text"]'; Chris@17: Chris@17: // Ensure the initial page contains both node forms and the correct number Chris@17: // of field items and "add more" button for the multi-valued field within Chris@17: // each form. Chris@17: $this->drupalGet('form-test/two-instances-of-same-form'); Chris@17: Chris@17: // Wait for javascript on the page to prepare the form attributes. Chris@17: $this->assertSession()->assertWaitOnAjaxRequest(); Chris@17: Chris@17: $session = $this->getSession(); Chris@17: $page = $session->getPage(); Chris@17: $fields = $page->findAll('xpath', $form_xpath . $field_xpath); Chris@17: $this->assertEqual(count($fields), 2); Chris@17: foreach ($fields as $field) { Chris@17: $this->assertCount(1, $field->findAll('xpath', '.' . $field_items_xpath_suffix), 'Found the correct number of field items on the initial page.'); Chris@17: $this->assertFieldsByValue($field->find('xpath', '.' . $button_xpath_suffix), NULL, 'Found the "add more" button on the initial page.'); Chris@17: } Chris@17: Chris@17: $this->assertNoDuplicateIds(); Chris@17: Chris@17: // Submit the "add more" button of each form twice. After each corresponding Chris@17: // page update, ensure the same as above. Chris@17: Chris@17: for ($i = 0; $i < 2; $i++) { Chris@17: $forms = $page->find('xpath', $form_xpath); Chris@17: foreach ($forms as $offset => $form) { Chris@17: $button = $form->findButton($button_value); Chris@17: $this->assertNotNull($button, 'Add Another Item button exists'); Chris@17: $button->press(); Chris@17: Chris@17: // Wait for page update. Chris@17: $this->assertSession()->assertWaitOnAjaxRequest(); Chris@17: Chris@17: // After AJAX request and response page will update. Chris@17: $page_updated = $session->getPage(); Chris@17: $field = $page_updated->findAll('xpath', '.' . $field_xpath); Chris@17: $this->assertEqual(count($field[0]->find('xpath', '.' . $field_items_xpath_suffix)), $i + 2, 'Found the correct number of field items after an AJAX submission.'); Chris@17: $this->assertFieldsByValue($field[0]->find('xpath', '.' . $button_xpath_suffix), NULL, 'Found the "add more" button after an AJAX submission.'); Chris@17: $this->assertNoDuplicateIds(); Chris@17: } Chris@17: } Chris@17: } Chris@17: Chris@17: /** Chris@17: * Asserts that each HTML ID is used for just a single element on the page. Chris@17: * Chris@17: * @param string $message Chris@17: * (optional) A message to display with the assertion. Chris@17: */ Chris@17: protected function assertNoDuplicateIds($message = '') { Chris@17: $args = ['@url' => $this->getUrl()]; Chris@17: Chris@17: if (!$elements = $this->xpath('//*[@id]')) { Chris@17: $this->fail(new FormattableMarkup('The page @url contains no HTML IDs.', $args)); Chris@17: return; Chris@17: } Chris@17: Chris@17: $message = $message ?: new FormattableMarkup('The page @url does not contain duplicate HTML IDs', $args); Chris@17: Chris@17: $seen_ids = []; Chris@17: foreach ($elements as $element) { Chris@17: $id = $element->getAttribute('id'); Chris@17: if (isset($seen_ids[$id])) { Chris@17: $this->fail($message); Chris@17: return; Chris@17: } Chris@17: $seen_ids[$id] = TRUE; Chris@17: } Chris@17: $this->assertTrue(TRUE, $message); Chris@17: } Chris@17: Chris@17: }