razielsd/phpSelenide

View on GitHub
lib/Selenide/ElementsCollection.php

Summary

Maintainability
C
1 day
Test Coverage
<?php

namespace Selenide;

use ArrayAccess;
use Countable;
use Iterator;

class ElementsCollection implements Iterator, Countable, ArrayAccess
{
    const MODE_SINGLE_ELEMENT = 1;
    const MODE_COLLECTION_ELEMENT = 2;

    /**
     * @var Selenide;
     */
    protected $selenide = null;
    /**
     * @var Driver
     */
    protected $driver = null;
    /**
     * @var SelectorList
     */
    protected $selectorList = [];

    protected $selectorMode = self::MODE_COLLECTION_ELEMENT;

    protected $description = '';
    protected $elementCache = null;

    /**
     * @var int Current position for Iterator interface.
     */
    protected $index = 0;


    public function __construct(Selenide $selenide, SelectorList $selectorList)
    {
        $this->selenide = $selenide;
        $this->driver = $selenide->getDriver();
        $this->selectorList = $selectorList;
    }


    /**
     * Set element description
     *
     * @param $description
     * @return $this
     */
    public function description($description)
    {
        $this->description = $description;
        return $this;
    }


    /**
     * Find single element
     *
     * @param $locator
     * @return ElementsCollection
     */
    public function find(By $locator)
    {
        $this->clearCache();
        $selector = new Selector_Locator($locator);
        $this->selectorList->add($selector);
        $this->selectorMode = self::MODE_SINGLE_ELEMENT;
        return $this;
    }


    /**
     * Find elements collection
     *
     * @param $locator
     * @return ElementsCollection
     */
    public function findAll(By $locator)
    {
        $this->clearCache();
        $selector = new Selector_Locator($locator);
        $this->selectorList->add($selector);
        $this->selectorMode = self::MODE_COLLECTION_ELEMENT;
        return $this;
    }


    /**
     * Filter by condition
     *
     * @param Condition_Rule $condition
     * @return ElementsCollection
     */
    public function should(Condition_Rule $condition)
    {
        $this->clearCache();
        $selector = new Selector_Condition($condition);
        $this->selectorList->add($selector);
        return $this;
    }


    /**
     * Filter by Not Condition
     *
     * @param Condition_Rule $condition
     * @return ElementsCollection
     */
    public function shouldNot(Condition_Rule $condition)
    {
        $this->clearCache();
        $selector = new Selector_Condition($condition, false);
        $this->selectorList->add($selector);
        return $this;
    }


    /**
     * Assert condition
     *
     * @param Condition_Rule $condition
     * @return $this
     * @throws Exception_ElementNotFound
     */
    public function assert(Condition_Rule $condition)
    {
        $collection = $this->getWebdriverCollection();
        $collection = $this->prepareResult($collection, true);
        $this->selenide->getListener()->beforeAssert($condition, $this->getLocator());
        try {
            $condition->applyAssert($collection);
        } catch (Exception_ElementNotFound $e) {
            throw new Exception_ElementNotFound(
                $this->description .
                ': Not found element ' . $this->getLocator() . ' with condition ' .
                $condition->getLocator(),
                0,
                $e);
        }

        return $this;
    }


    /**
     * Assert not condition
     *
     * @param Condition_Rule $condition
     * @return $this
     */
    public function assertNot(Condition_Rule $condition)
    {
        $collection = $this->getWebdriverCollection();
        $collection = $this->prepareResult($collection, true);
        $this->selenide->getListener()->beforeAssertNot($condition, $this->getLocator());
        $condition->applyAssertNegative($collection);
        return $this;
    }


    public function wait(Condition_Rule $condition, $waitTimeout = null)
    {
        $this->clearCache();
        $selectorList = $this->selectorList;
        $waitTimeout = $waitTimeout ?? $this->selenide->configuration()->waitTimeout;
        $this->should($condition);
        try {
            $timeout = $this->selenide->configuration()->timeout;
            $this->selenide->configuration()->timeout = $waitTimeout;
            $collection = $this->getWebdriverCollection();
            if (count($collection) === 0) {
                throw new Exception(
                    'Unable wait condition: ' . $condition->getName() . 'for ' . $this->getLocator()
                );
            }
        } finally {
            $this->selenide->configuration()->timeout = $timeout;
            $this->selectorList = $selectorList;
        }
        return $this;
    }


    /**
     * @param int $index
     * @return SelenideElement
     * @throws Exception_ElementNotFound
     */
    public function get($index = 0)
    {
        $collection = $this->getCollectionNotEmpty();
        if (!isset($collection[$index])) {
            throw new Exception_ElementNotFound(
                $this->description . ': Not found element ' . $this->getLocator()
            );
        }
        return $collection[$index];
    }


    public function length()
    {
        return count($this->getCollection());
    }


    /**
     * Set element value
     *
     * @param $value
     * @return $this
     */
    public function setValue($value)
    {
        $collection = $this->getCollectionNotEmpty();
        foreach ($collection as $idx => $element) {
            $this->selenide->getListener()->beforeSetValue(
                $element,
                $value,
                $this->getLocator().'[' . $idx . ']',
                $this->description
            );
            $element->setValue($value);
        }
        return $this;
    }


    /**
     * Press key enter
     *
     * @return $this
     */
    public function pressEnter()
    {
        $collection = $this->getCollectionNotEmpty();
        foreach ($collection as $element) {
            $element->pressEnter();
        }
        return $this;
    }


    /**
     * Check all elements visible
     *
     * @return bool
     */
    public function isDisplayed()
    {
        $collection = $this->getCollection();
        $counter = 0;
        foreach ($collection as $element) {
            $counter += $element->isDisplayed() ? 1 : 0;
        }
        return ((count($collection) == $counter) && ($counter > 0));
    }


    /**
     * Click all elements
     *
     * @return $this
     */
    public function click()
    {
        $collection = $this->getCollectionNotEmpty();
        foreach ($collection as $idx => $element) {
            $this->selenide->getListener()->beforeClick(
                $element,
                $this->getLocator().'[' . $idx . ']',
                $this->description
            );
            $element->click();
        }
        return $this;
    }


    /**
     * DoubleClick all elements
     *
     * @return $this
     */
    public function doubleClick()
    {
        $collection = $this->getCollectionNotEmpty();
        foreach ($collection as $element) {
            $element->dbclick();
        }
        return $this;
    }


    /**
     * Check all elements exists
     *
     * @return bool
     */
    public function exists()
    {
        $collection = $this->getCollection();
        $counter = 0;
        foreach ($collection as $element) {
            $counter += $element->exists() ? 1 : 0;
        }
        return (count($collection) == $counter) && ($counter > 0);
    }


    /**
     * Check all elements checked
     *
     * @return bool
     */
    public function checked()
    {
        $collection = $this->getCollectionNotEmpty();
        $counter = 0;
        foreach ($collection as $element) {
            $counter += $element->checked() ? 1 : 0;
        }
        return (count($collection) == $counter) && ($counter > 0);
    }


    /**
     * Get element list values
     *
     * @return string|string[]
     */
    public function val()
    {
        $collection = $this->getCollectionNotEmpty();
        $this->selenide->getReport()->addChildEvent('Read value');
        $valueList = [];
        foreach ($collection as $element) {
            $valueList[] = $element->val();
        }
        return $this->prepareResult($valueList);
    }



    /**
     * Get all elements attribute with name
     *
     * @return string|string[]
     */
    public function attribute($name)
    {
        $collection = $this->getCollectionNotEmpty();
        $attrList = [];
        foreach ($collection as $element) {
            $attrList[] = $element->attribute($name);
        }
        return $this->prepareResult($attrList);
    }


    /**
     * Get element list values
     *
     * @return string|string[]
     */
    public function text()
    {
        $collection = $this->getCollectionNotEmpty();
        $this->selenide->getReport()->addChildEvent('Read value');
        $valueList = [];
        foreach ($collection as $element) {
            $valueList[] = $element->text();
        }
        return $this->prepareResult($valueList);
    }


    /**
     * Execute javascript for elements collection
     *
     * @param $script
     * @return mixed
     */
    public function execute($script)
    {
        return $this->selenide->execute($script, $this->getCollection());
    }


    public function source()
    {
        return $this->execute('return arguments[0].outerHTML;');
    }


    /**
     * Get path for element
     *
     * @return string
     */
    public function getLocator()
    {
        return $this->selectorList->getLocator();
    }


    /**
     * @return \WebDriver_Element[]
     */
    protected function getWebdriverCollection()
    {
        if ($this->elementCache === null) {
            $elementList = $this->driver->search($this->selectorList);
            $stateText = empty($elementList) ?
                'Not found elements' : ('Found elements ' . count($elementList));
            $this->selenide->getReport()->addChildEvent($stateText);
            $this->elementCache = $elementList;
        }
        return $this->elementCache;
    }


    /**
     * @return SelenideElement[]
     */
    public function getCollection()
    {
        $elementList = $this->getWebdriverCollection();
        $resultList = [];
        foreach ($elementList as $wdElement) {
            $resultList[] = new SelenideElement($this->selenide, $wdElement);
        }
        return $resultList;
    }


    /**
     * Alias for getCollection with check for not empty
     *
     * @return SelenideElement[]
     * @throws Exception_ElementNotFound
     */
    public function getCollectionNotEmpty()
    {
        $collection = $this->getCollection();
        $collection = $this->prepareResult($collection, true);
        if (empty($collection)) {
            throw new Exception_ElementNotFound(
                $this->description .
                ': Not found element ' . $this->getLocator()
            );
        }
        return $collection;
    }


    protected function clearCache()
    {
        $this->elementCache = null;
    }


    protected function prepareResult(array $result, $asArray = false)
    {
        if ($this->selectorMode == self::MODE_SINGLE_ELEMENT) {
            $result = $result[0] ?? null;
            if ($asArray) {
                $result = $result ? [$result] : [];
            }
        }
        return $result;
    }


    /**
     * @return SelenideElement
     */
    public function current(): SelenideElement
    {
        return $this->get($this->index);
    }


    /**
     * @return void
     */
    public function next()
    {
        $this->index++;
    }


    /**
     * @return int
     */
    public function key()
    {
        return $this->index;
    }


    /**
     * @return boolean
     */
    public function valid()
    {
        return array_key_exists($this->index, $this->getCollection());
    }


    /**
     * @return void
     */
    public function rewind()
    {
        $this->index = 0;
    }


    /**
     * @return int
     */
    public function count()
    {
        return $this->length();
    }


    /**
     * @param int $offset
     * @return boolean
     */
    public function offsetExists($offset)
    {
        return array_key_exists($offset, $this->getCollection());
    }


    /**
     * @param int $offset
     * @return SelenideElement
     */
    public function offsetGet($offset)
    {
        return $this->get($offset);
    }


    /**
     * @param mixed $offset
     * @param mixed $value
     * @throws Exception_CollectionMethodNotImplemented
     */
    public function offsetSet($offset, $value)
    {
        throw new Exception_CollectionMethodNotImplemented();
    }


    /**
     * @param mixed $offset
     * @throws Exception_CollectionMethodNotImplemented
     */
    public function offsetUnset($offset)
    {
        throw new Exception_CollectionMethodNotImplemented();
    }
}