/** * Extends WebTestBase::drupalPostAjaxForm() to replace additional content * on the page after an ajax submission. * * WebTestBase::drupalPostAjaxForm() will only process ajax insertions which * don't have a 'selector' attribute, because it's not easy to convert from a * jQuery selector to an XPath. However, Ubercart uses many simple, id-based * selectors, and these can be converted easily * (eg: '#my-identifier' => '//*[@id="my-identifier"]'). * * This helper method post-processes the command array returned by * drupalPostAjaxForm() to perform these insertions. * * @see WebTestBase::drupalPostAjaxForm() */ protected function ucPostAjax($path, $edit, $triggering_element, $ajax_path = NULL, array $options = [], array $headers = [], $form_html_id = NULL, $ajax_settings = NULL) { $commands = parent::drupalPostAjaxForm($path, $edit, $triggering_element, $ajax_path, $options, $headers, $form_html_id, $ajax_settings); $dom = new \DOMDocument(); @$dom->loadHTML($this->getRawContent()); foreach ($commands as $command) { if ($command['command'] == 'insert' && isset($command['selector']) && preg_match('/^\\#-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/', $command['selector'])) { $xpath = new \DOMXPath($dom); $wrapperNode = $xpath->query('//*[@id="' . substr($command['selector'], 1) . '"]')->item(0); if ($wrapperNode) { // ajax.js adds an enclosing DIV to work around a Safari bug. $newDom = new \DOMDocument(); @$newDom->loadHTML('<div>' . $command['data'] . '</div>'); $newNode = $dom->importNode($newDom->documentElement->firstChild->firstChild, TRUE); $method = isset($command['method']) ? $command['method'] : $ajax_settings['method']; // The "method" is a jQuery DOM manipulation function. Emulate // each one using PHP's DOMNode API. switch ($method) { case 'replaceWith': $wrapperNode->parentNode->replaceChild($newNode, $wrapperNode); break; case 'append': $wrapperNode->appendChild($newNode); break; case 'prepend': // If no firstChild, insertBefore() falls back to // appendChild(). $wrapperNode->insertBefore($newNode, $wrapperNode->firstChild); break; case 'before': $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode); break; case 'after': // If no nextSibling, insertBefore() falls back to // appendChild(). $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode->nextSibling); break; case 'html': foreach ($wrapperNode->childNodes as $childNode) { $wrapperNode->removeChild($childNode); } $wrapperNode->appendChild($newNode); break; } } } } $content = $dom->saveHTML(); $this->setRawContent($content); $this->verbose('Page content after ajax submission:<hr />' . $this->content); return $commands; }