Files
bm/public_html/vendor/facebook/webdriver/lib/AbstractWebDriverCheckboxOrRadio.php
2025-09-24 13:26:28 +02:00

254 lines
7.6 KiB
PHP

<?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();
}
}
}