Skip to content

Commit

Permalink
Merge 3d8f80a into c622829
Browse files Browse the repository at this point in the history
  • Loading branch information
Milan Falešník committed Jan 6, 2017
2 parents c622829 + 3d8f80a commit f740741
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 2 deletions.
39 changes: 39 additions & 0 deletions src/widgetastic/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -583,3 +583,42 @@ def handle_alert(self, cancel=False, wait=30.0, squash=False, prompt=None, check
return False
else:
raise


class BrowserParentWrapper(object):
"""A wrapper/proxy class that ensures passing of correct parent locator on elements lookup.
Required for the proper operation of nesting.
Assumes the object passed has a ``browser`` attribute.
Args:
o: Object which should be considered as a parent element for lookups. Must have ``.browser``
defined.
"""
def __init__(self, o, browser):
self._o = o
self._browser = browser

def __eq__(self, other):
if not isinstance(other, BrowserParentWrapper):
return False
return self._o == other._o and self._browser == other._browser

def elements(self, locator, parent=None, check_visibility=False, check_safe=True,
force_check_safe=False):
if parent is None:
parent = self._o
return self._browser.elements(
locator,
parent=parent,
check_visibility=check_visibility,
check_safe=check_safe,
force_check_safe=force_check_safe)

def __getattr__(self, attr):
"""Route all other attribute requests into the parent object's browser."""
return getattr(self._browser, attr)

def __repr__(self):
return '<{} for {!r}>'.format(type(self).__name__, self._o)
9 changes: 7 additions & 2 deletions src/widgetastic/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from smartloc import Locator
from wait_for import wait_for

from .browser import Browser
from .browser import Browser, BrowserParentWrapper
from .exceptions import (
NoSuchElementException, LocatorNotImplemented, WidgetOperationFailed, DoNotReadThisWidget)
from .log import PrependParentsAdapter, create_widget_logger, logged
Expand Down Expand Up @@ -222,7 +222,12 @@ def browser(self):
:py:class:`ValueError` when the browser is not defined, which is an error.
"""
try:
return self.parent.browser
if hasattr(self, '__locator__'):
# Wrap it so we have automatic parent injection
return BrowserParentWrapper(self, self.parent.browser)
else:
# This view has no locator, therefore just use the parent browser
return self.parent.browser
except AttributeError:
raise ValueError('Unknown value {!r} specified as parent.'.format(self.parent))

Expand Down
41 changes: 41 additions & 0 deletions testing/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
from __future__ import unicode_literals
import pytest

from widgetastic.browser import BrowserParentWrapper
from widgetastic.exceptions import NoSuchElementException, LocatorNotImplemented
from widgetastic.widget import View, Text


def test_is_displayed(browser):
Expand Down Expand Up @@ -119,3 +121,42 @@ def test_simple_input_send_keys_clear(browser):
assert browser.get_attribute('value', '#input') == 'test!'
browser.clear('#input')
assert browser.get_attribute('value', '#input') == ''


def test_nested_views_parent_injection(browser):
class MyView(View):
ROOT = '#proper'

class c1(View): # noqa
ROOT = '.c1'

w = Text('.lookmeup')

class c2(View): # noqa
ROOT = '.c2'

w = Text('.lookmeup')

class c3(View): # noqa
ROOT = '.c3'

w = Text('.lookmeup')

class without(View): # noqa
# This one receives the parent browser wrapper
class nested(View): # noqa
# and it should work in multiple levels
pass

view = MyView(browser)
assert isinstance(view.browser, BrowserParentWrapper)
assert view.browser == view.without.browser
assert view.browser == view.without.nested.browser
assert len(view.c1.browser.elements('.lookmeup')) == 1
assert view.c1.w.text == 'C1'
assert len(view.c2.browser.elements('.lookmeup')) == 1
assert view.c2.w.text == 'C2'
assert len(view.c3.browser.elements('.lookmeup')) == 1
assert view.c3.w.text == 'C3'

assert len(view.browser.elements('.lookmeup')) == 3
14 changes: 14 additions & 0 deletions testing/testing_page.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,19 @@ <h3>test test</h3>
<option value="bar"> Bar </option>
<option value="baz">Baz</option>
</select>
<div id="bogus">
<span class="lookmeup">BAD</span>
</div>
<div id="proper">
<div class="c1">
<span class="lookmeup">C1</span>
</div>
<div class="c2">
<span class="lookmeup">C2</span>
</div>
<div class="c3">
<span class="lookmeup">C3</span>
</div>
</div>
</body>
</html>

0 comments on commit f740741

Please sign in to comment.