Escaped characters are: quotes (") and apostrophe (').
Examples:
echo Crawler::xpathLiteral('foo " bar');
prints 'foo " bar'
echo Crawler::xpathLiteral("foo ' bar");
prints "foo ' bar"
echo Crawler::xpathLiteral('a\'b"c');
prints concat('a', "'", 'b"c')
public static xpathLiteral ( string $s ) : string | ||
$s | string | String to be escaped |
return | string | Converted string |
/** * Adds form elements related to this form. * * Creates an internal copy of the submitted 'button' element and * the form node or the entire document depending on whether we need * to find non-descendant elements through HTML5 'form' attribute. */ private function initialize() { $this->fields = new FormFieldRegistry(); $xpath = new \DOMXPath($this->node->ownerDocument); // add submitted button if it has a valid name if ('form' !== $this->button->nodeName && $this->button->hasAttribute('name') && $this->button->getAttribute('name')) { if ('input' == $this->button->nodeName && 'image' == strtolower($this->button->getAttribute('type'))) { $name = $this->button->getAttribute('name'); $this->button->setAttribute('value', '0'); // temporarily change the name of the input node for the x coordinate $this->button->setAttribute('name', $name . '.x'); $this->set(new Field\InputFormField($this->button)); // temporarily change the name of the input node for the y coordinate $this->button->setAttribute('name', $name . '.y'); $this->set(new Field\InputFormField($this->button)); // restore the original name of the input node $this->button->setAttribute('name', $name); } else { $this->set(new Field\InputFormField($this->button)); } } // find form elements corresponding to the current form if ($this->node->hasAttribute('id')) { // corresponding elements are either descendants or have a matching HTML5 form attribute $formId = Crawler::xpathLiteral($this->node->getAttribute('id')); $fieldNodes = $xpath->query(sprintf('descendant::input[@form=%s] | descendant::button[@form=%s] | descendant::textarea[@form=%s] | descendant::select[@form=%s] | //form[@id=%s]//input[not(@form)] | //form[@id=%s]//button[not(@form)] | //form[@id=%s]//textarea[not(@form)] | //form[@id=%s]//select[not(@form)]', $formId, $formId, $formId, $formId, $formId, $formId, $formId, $formId)); foreach ($fieldNodes as $node) { $this->addField($node); } } else { // do the xpath query with $this->node as the context node, to only find descendant elements // however, descendant elements with form attribute are not part of this form $fieldNodes = $xpath->query('descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)]', $this->node); foreach ($fieldNodes as $node) { $this->addField($node); } } if ($this->baseHref && '' !== $this->node->getAttribute('action')) { $this->currentUri = $this->baseHref; } }
/** * @param $context * @param $radioOrCheckbox * @param bool $byValue * @return mixed|null */ protected function findCheckable($context, $radioOrCheckbox, $byValue = false) { if ($radioOrCheckbox instanceof WebDriverElement) { return $radioOrCheckbox; } if (is_array($radioOrCheckbox) or $radioOrCheckbox instanceof WebDriverBy) { return $this->matchFirstOrFail($this->webDriver, $radioOrCheckbox); } $locator = Crawler::xpathLiteral($radioOrCheckbox); if ($context instanceof WebDriverElement && $context->getTagName() === 'input') { $contextType = $context->getAttribute('type'); if (!in_array($contextType, ['checkbox', 'radio'], true)) { return null; } $nameLiteral = Crawler::xPathLiteral($context->getAttribute('name')); $typeLiteral = Crawler::xPathLiteral($contextType); $inputLocatorFragment = "input[@type = {$typeLiteral}][@name = {$nameLiteral}]"; $xpath = Locator::combine("ancestor::form//{$inputLocatorFragment}[(@id = ancestor::form//label[contains(normalize-space(string(.)), {$locator})]/@for) or @placeholder = {$locator}]", "ancestor::form//label[contains(normalize-space(string(.)), {$locator})]//{$inputLocatorFragment}"); if ($byValue) { $xpath = Locator::combine($xpath, "ancestor::form//{$inputLocatorFragment}[@value = {$locator}]"); } } else { $xpath = Locator::combine("//input[@type = 'checkbox' or @type = 'radio'][(@id = //label[contains(normalize-space(string(.)), {$locator})]/@for) or @placeholder = {$locator}]", "//label[contains(normalize-space(string(.)), {$locator})]//input[@type = 'radio' or @type = 'checkbox']"); if ($byValue) { $xpath = Locator::combine($xpath, "//input[@type = 'checkbox' or @type = 'radio'][@value = {$locator}]"); } } $els = $context->findElements(WebDriverBy::xpath($xpath)); if (count($els)) { return reset($els); } $els = $context->findElements(WebDriverBy::xpath(str_replace('ancestor::form', '', $xpath))); if (count($els)) { return reset($els); } $els = $this->match($context, $radioOrCheckbox); if (count($els)) { return reset($els); } return null; }
/** * Adds form elements related to this form. * * Creates an internal copy of the submitted 'button' element and * the form node or the entire document depending on whether we need * to find non-descendant elements through HTML5 'form' attribute. */ private function initialize() { $this->fields = new FormFieldRegistry(); $document = new \DOMDocument('1.0', 'UTF-8'); $xpath = new \DOMXPath($document); $root = $document->appendChild($document->createElement('_root')); // add submitted button if it has a valid name if ($this->button->hasAttribute('name') && $this->button->getAttribute('name')) { $this->set(new Field\InputFormField($document->importNode($this->button, true))); } // find form elements corresponding to the current form if ($this->node->hasAttribute('id')) { // traverse through the whole document $node = $document->importNode($this->node->ownerDocument->documentElement, true); $root->appendChild($node); // corresponding elements are either descendants or have a matching HTML5 form attribute $formId = Crawler::xpathLiteral($this->node->getAttribute('id')); $fieldNodes = $xpath->query(sprintf('descendant::input[@form=%s] | descendant::button[@form=%s] | descendant::textarea[@form=%s] | descendant::select[@form=%s] | //form[@id=%s]//input[not(@form)] | //form[@id=%s]//button[not(@form)] | //form[@id=%s]//textarea[not(@form)] | //form[@id=%s]//select[not(@form)]', $formId, $formId, $formId, $formId, $formId, $formId, $formId, $formId), $root); foreach ($fieldNodes as $node) { $this->addField($node); } } else { // parent form has no id, add descendant elements only $node = $document->importNode($this->node, true); $root->appendChild($node); // descendant elements with form attribute are not part of this form $fieldNodes = $xpath->query('descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)]', $root); foreach ($fieldNodes as $node) { $this->addField($node); } } }
/** * @param array $by * @throws TestRuntime * @return Crawler */ protected function strictMatch(array $by) { $type = key($by); $locator = $by[$type]; switch ($type) { case 'id': return $this->crawler->filter("#{$locator}"); case 'name': return @$this->crawler->filterXPath(sprintf('.//*[@name=%s]', Crawler::xpathLiteral($locator))); case 'css': return $this->crawler->filter($locator); case 'xpath': return @$this->crawler->filterXPath($locator); case 'link': return @$this->crawler->filterXPath(sprintf('.//a[.=%s]', Crawler::xpathLiteral($locator))); case 'class': return $this->crawler->filter(".{$locator}"); default: throw new TestRuntime("Locator type '{$by}' is not defined. Use either: xpath, css, id, link, class, name"); } }
public function dontSeeLink($text, $url = null) { $links = $this->crawler->selectLink($text); if ($url) { $links = $links->filterXPath(sprintf('descendant-or-self::a[contains(@href, %s)]', Crawler::xpathLiteral($this->escape($url)))); } $this->assertDomNotContains($links, 'a'); }
/** * @param $context * @param $radio_or_checkbox * @param bool $byValue * @return mixed|null */ protected function findCheckable($context, $radio_or_checkbox, $byValue = false) { if ($radio_or_checkbox instanceof \WebDriverElement) { return $radio_or_checkbox; } if (is_array($radio_or_checkbox) or $radio_or_checkbox instanceof \WebDriverBy) { return $this->matchFirstOrFail($this->webDriver, $radio_or_checkbox); } $locator = Crawler::xpathLiteral($radio_or_checkbox); $xpath = Locator::combine("//input[./@type = 'checkbox'][(./@id = //label[contains(normalize-space(string(.)), {$locator})]/@for) or ./@placeholder = {$locator}]", "//label[contains(normalize-space(string(.)), {$locator})]//.//input[./@type = 'checkbox']", "//input[./@type = 'radio'][(./@id = //label[contains(normalize-space(string(.)), {$locator})]/@for) or ./@placeholder = {$locator}]", "//label[contains(normalize-space(string(.)), {$locator})]//.//input[./@type = 'radio']"); if ($byValue) { $xpath = Locator::combine($xpath, "//input[./@type = 'checkbox'][./@value = {$locator}]", "//input[./@type = 'radio'][./@value = {$locator}]"); } /** @var $context \WebDriverElement * */ $els = $context->findElements(\WebDriverBy::xpath($xpath)); if (count($els)) { return reset($els); } $els = $this->match($context, $radio_or_checkbox); if (count($els)) { return reset($els); } return null; }
private function initialize() { $this->fields = new FormFieldRegistry(); $document = new \DOMDocument('1.0', 'UTF-8'); $node = $document->importNode($this->node, true); $button = $document->importNode($this->button, true); $root = $document->appendChild($document->createElement('_root')); $root->appendChild($node); $root->appendChild($button); $xpath = new \DOMXPath($document); // add descendant elements to the form $fieldNodes = $xpath->query('descendant::input | descendant::button | descendant::textarea | descendant::select', $root); foreach ($fieldNodes as $node) { $this->addField($node, $button); } // find form elements corresponding to the current form by the HTML5 form attribute if ($this->node->hasAttribute('id')) { $formId = Crawler::xpathLiteral($this->node->getAttribute('id')); $xpath = new \DOMXPath($this->node->ownerDocument); $fieldNodes = $xpath->query(sprintf('descendant::input[@form=%s] | descendant::button[@form=%s] | descendant::textarea[@form=%s] | descendant::select[@form=%s]', $formId, $formId, $formId, $formId)); foreach ($fieldNodes as $node) { $this->addField($node, $button); } } }
public function dontSeeLink($text, $url = null) { $links = $this->crawler->selectLink($this->escape($text)); if (!$url) { \PHPUnit_Framework_Assert::assertEquals(0, $links->count(), "'{$text}' on page"); } $links->filterXPath(sprintf('descendant-or-self::a[contains(@href, "%s")]', Crawler::xpathLiteral(' ' . $this->escape($url) . ' '))); \PHPUnit_Framework_Assert::assertEquals(0, $links->count()); }