| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 | <?php// Copyright 2004-present Facebook. All Rights Reserved.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////     http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.namespace Facebook\WebDriver;use Facebook\WebDriver\Exception\NoSuchElementException;use Facebook\WebDriver\Exception\UnexpectedTagNameException;use Facebook\WebDriver\Exception\WebDriverException;use Facebook\WebDriver\Support\XPathEscaper;/** * Provides helper methods for checkboxes and radio buttons. */abstract class AbstractWebDriverCheckboxOrRadio implements WebDriverSelectInterface{    /** @var WebDriverElement */    protected $element;    /** @var string */    protected $type;    /** @var string */    protected $name;    public function __construct(WebDriverElement $element)    {        $tagName = $element->getTagName();        if ($tagName !== 'input') {            throw new UnexpectedTagNameException('input', $tagName);        }        $this->name = $element->getAttribute('name');        if ($this->name === null) {            throw new WebDriverException('The input does not have a "name" attribute.');        }        $this->element = $element;    }    public function getOptions()    {        return $this->getRelatedElements();    }    public function getAllSelectedOptions()    {        $selectedElement = [];        foreach ($this->getRelatedElements() as $element) {            if ($element->isSelected()) {                $selectedElement[] = $element;                if (!$this->isMultiple()) {                    return $selectedElement;                }            }        }        return $selectedElement;    }    public function getFirstSelectedOption()    {        foreach ($this->getRelatedElements() as $element) {            if ($element->isSelected()) {                return $element;            }        }        throw new NoSuchElementException(            sprintf('No %s are selected', 'radio' === $this->type ? 'radio buttons' : 'checkboxes')        );    }    public function selectByIndex($index)    {        $this->byIndex($index);    }    public function selectByValue($value)    {        $this->byValue($value);    }    public function selectByVisibleText($text)    {        $this->byVisibleText($text);    }    public function selectByVisiblePartialText($text)    {        $this->byVisibleText($text, true);    }    /**     * Selects or deselects a checkbox or a radio button by its value.     *     * @param string $value     * @param bool $select     * @throws NoSuchElementException     */    protected function byValue($value, $select = true)    {        $matched = false;        foreach ($this->getRelatedElements($value) as $element) {            $select ? $this->selectOption($element) : $this->deselectOption($element);            if (!$this->isMultiple()) {                return;            }            $matched = true;        }        if (!$matched) {            throw new NoSuchElementException(                sprintf('Cannot locate %s with value: %s', $this->type, $value)            );        }    }    /**     * Selects or deselects a checkbox or a radio button by its index.     *     * @param int $index     * @param bool $select     * @throws NoSuchElementException     */    protected function byIndex($index, $select = true)    {        $elements = $this->getRelatedElements();        if (!isset($elements[$index])) {            throw new NoSuchElementException(sprintf('Cannot locate %s with index: %d', $this->type, $index));        }        $select ? $this->selectOption($elements[$index]) : $this->deselectOption($elements[$index]);    }    /**     * Selects or deselects a checkbox or a radio button by its visible text.     *     * @param string $text     * @param bool $partial     * @param bool $select     */    protected function byVisibleText($text, $partial = false, $select = true)    {        foreach ($this->getRelatedElements() as $element) {            $normalizeFilter = sprintf(                $partial ? 'contains(normalize-space(.), %s)' : 'normalize-space(.) = %s',                XPathEscaper::escapeQuotes($text)            );            $xpath = 'ancestor::label';            $xpathNormalize = sprintf('%s[%s]', $xpath, $normalizeFilter);            $id = $element->getAttribute('id');            if ($id !== null) {                $idFilter = sprintf('@for = %s', XPathEscaper::escapeQuotes($id));                $xpath .= sprintf(' | //label[%s]', $idFilter);                $xpathNormalize .= sprintf(' | //label[%s and %s]', $idFilter, $normalizeFilter);            }            try {                $element->findElement(WebDriverBy::xpath($xpathNormalize));            } catch (NoSuchElementException $e) {                if ($partial) {                    continue;                }                try {                    // Since the mechanism of getting the text in xpath is not the same as                    // webdriver, use the expensive getText() to check if nothing is matched.                    if ($text !== $element->findElement(WebDriverBy::xpath($xpath))->getText()) {                        continue;                    }                } catch (NoSuchElementException $e) {                    continue;                }            }            $select ? $this->selectOption($element) : $this->deselectOption($element);            if (!$this->isMultiple()) {                return;            }        }    }    /**     * Gets checkboxes or radio buttons with the same name.     *     * @param string|null $value     * @return WebDriverElement[]     */    protected function getRelatedElements($value = null)    {        $valueSelector = $value ? sprintf(' and @value = %s', XPathEscaper::escapeQuotes($value)) : '';        $formId = $this->element->getAttribute('form');        if ($formId === null) {            $form = $this->element->findElement(WebDriverBy::xpath('ancestor::form'));            $formId = $form->getAttribute('id');            if ($formId === '') {                return $form->findElements(WebDriverBy::xpath(                    sprintf('.//input[@name = %s%s]', XPathEscaper::escapeQuotes($this->name), $valueSelector)                ));            }        }        // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#form        return $this->element->findElements(            WebDriverBy::xpath(sprintf(                '//form[@id = %1$s]//input[@name = %2$s%3$s'                . ' and ((boolean(@form) = true() and @form = %1$s) or boolean(@form) = false())]'                . ' | //input[@form = %1$s and @name = %2$s%3$s]',                XPathEscaper::escapeQuotes($formId),                XPathEscaper::escapeQuotes($this->name),                $valueSelector            ))        );    }    /**     * Selects a checkbox or a radio button.     */    protected function selectOption(WebDriverElement $element)    {        if (!$element->isSelected()) {            $element->click();        }    }    /**     * Deselects a checkbox or a radio button.     */    protected function deselectOption(WebDriverElement $element)    {        if ($element->isSelected()) {            $element->click();        }    }}
 |