diff --git a/doc/guide/working_with_elements.rst b/doc/guide/working_with_elements.rst index 9db7549..2cb598f 100644 --- a/doc/guide/working_with_elements.rst +++ b/doc/guide/working_with_elements.rst @@ -135,6 +135,48 @@ Accessing custom elements is much like accessing inline ones: Page factory takes care of creating custom elements and their class names follow the same rules as Page class names. +Elements can be nested, so similar to how elements can be retrieved from a `Page`, elements can also be +retrieved from an element: + + + .. code-block:: php + + '#logo', + ]; + + /** + * @return SearchForm + */ + public function searchForm() + { + return $this->getElement(SearchForm::class); + } + + /** + * @return InlineElement + */ + public function logo() + { + return $this->getElement('Logo')' + } + } + Element is an instance of a `NodeElement `_, so similarly to pages, we can take advantage of existing `Mink `_ @@ -145,4 +187,3 @@ a full list of available methods: * `NodeElement `_ * `TraversableElement `_ * `Element `_ - diff --git a/spec/PageObject/ElementSpec.php b/spec/PageObject/ElementSpec.php index 574bc88..2a96758 100644 --- a/spec/PageObject/ElementSpec.php +++ b/spec/PageObject/ElementSpec.php @@ -13,11 +13,20 @@ class MyElement extends BaseElement { public $selector = array('xpath' => '//div[@id="my-box"]'); + protected $elements = [ + 'Logo' => 'img#logo', + ]; + public function callGetPage($name) { return $this->getPage($name); } + public function callGetElement($name) + { + return $this->getElement($name); + } + public function callGetName() { return $this->getName(); @@ -78,6 +87,20 @@ function it_creates_a_page(Factory $factory, Page $page) $this->callGetPage('Home')->shouldReturn($page); } + function it_creates_an_element(Factory $factory, BaseElement $element) + { + $factory->createElement('Button')->willReturn($element); + + $this->callGetElement('Button')->shouldReturn($element); + } + + function it_creates_an_inline_element(Factory $factory, BaseElement $element) + { + $factory->createElement('img#logo')->willReturn($element); + + $this->callGetElement('Logo')->shouldReturn($element); + } + function it_returns_the_element_name() { $this->callGetName()->shouldReturn('MyElement'); diff --git a/src/PageObject/Element.php b/src/PageObject/Element.php index d9f4417..55aef98 100644 --- a/src/PageObject/Element.php +++ b/src/PageObject/Element.php @@ -3,6 +3,7 @@ namespace SensioLabs\Behat\PageObjectExtension\PageObject; use Behat\Mink\Element\NodeElement; +use Behat\Mink\Exception\ElementNotFoundException; use Behat\Mink\Selector\SelectorsHandler; use Behat\Mink\Session; @@ -13,6 +14,11 @@ abstract class Element extends NodeElement implements PageObject */ protected $selector = array('xpath' => '//'); + /** + * @var array + */ + protected $elements = array(); + /** * @var Factory */ @@ -40,6 +46,22 @@ public function __call($name, $arguments) throw new \BadMethodCallException($message); } + /** + * @param string $name + * + * @return Element + */ + public function getElement($name) + { + $element = $this->createElement($name); + + if (!$this->has('xpath', $element->getXpath())) { + throw new ElementNotFoundException(sprintf('"%s" element is not present on the page', $name)); + } + + return $element; + } + /** * @param string $name * @@ -50,6 +72,30 @@ protected function getPage($name) return $this->factory->createPage($name); } + /** + * @param string $name + * + * @return boolean + */ + protected function hasElement($name) + { + return $this->has('xpath', $this->createElement($name)->getXpath()); + } + + /** + * @param string $name + * + * @return Element + */ + protected function createElement($name) + { + if (isset($this->elements[$name])) { + return $this->factory->createInlineElement($this->elements[$name]); + } + + return $this->factory->createElement($name); + } + /** * @return string */