Skip to content

Commit

Permalink
Radio & list controls: select item by index
Browse files Browse the repository at this point in the history
This allows us to disambiguate multiple items that have the same value.

Fixes #31.
  • Loading branch information
mgedmin committed Sep 29, 2017
1 parent 0696cbf commit 46a4ef7
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 11 deletions.
37 changes: 26 additions & 11 deletions src/zope/testbrowser/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,15 @@ def value(self, value):
value = value[0]
self._control.value = value

@property
def _selectedIndex(self):
return self._control.selectedIndex

@_selectedIndex.setter
def _selectedIndex(self, index):
self._control.force_value(webtest.forms.NoValue)
self._control.selectedIndex = index

def _set_falsy_value(self, value):
self._control.force_value(value)

Expand Down Expand Up @@ -877,8 +886,9 @@ def controls(self):
if self._browser_counter != self.browser._counter:
raise interfaces.ExpiredError
ctrls = []
for elem in self._elem.select('option'):
ctrls.append(ItemControl(self, elem, self._form, self.browser))
for idx, elem in enumerate(self._elem.select('option')):
ctrls.append(ItemControl(self, elem, self._form, self.browser,
idx))

return ctrls

Expand Down Expand Up @@ -912,8 +922,8 @@ def __repr__(self):
def controls(self):
if self._browser_counter != self.browser._counter:
raise interfaces.ExpiredError
for opt in self._elems:
yield RadioItemControl(self, opt, self._form, self.browser)
for idx, opt in enumerate(self._elems):
yield RadioItemControl(self, opt, self._form, self.browser, idx)

@Lazy
def labels(self):
Expand Down Expand Up @@ -992,8 +1002,8 @@ def getControl(self, label=None, value=None, index=None):

@property
def controls(self):
return [CheckboxItemControl(self, c, e, c.form, self.browser)
for c, e in self._ctrlelems]
return [CheckboxItemControl(self, c, e, c.form, self.browser, i)
for i, (c, e) in enumerate(self._ctrlelems)]

def clear(self):
if self._browser_counter != self.browser._counter:
Expand Down Expand Up @@ -1030,9 +1040,10 @@ def mechRepr(self):
@implementer(interfaces.IItemControl)
class ItemControl(SetattrErrorsMixin):

def __init__(self, parent, elem, form, browser):
def __init__(self, parent, elem, form, browser, index):
self._parent = parent
self._elem = elem
self._index = index
self._form = form
self.browser = browser
self._browser_counter = self.browser._counter
Expand All @@ -1055,7 +1066,10 @@ def disabled(self):
@property
def selected(self):
"""See zope.testbrowser.interfaces.IControl"""
return self._value in self._parent.value
if self._parent.multiple:
return self._value in self._parent.value
else:
return self._parent._selectedIndex == self._index

@selected.setter
def selected(self, value):
Expand All @@ -1070,7 +1084,7 @@ def selected(self, value):
self._parent.value = values
else:
if value:
self._parent.value = self._value
self._parent._selectedIndex = self._index
else:
self._parent.value = None

Expand Down Expand Up @@ -1149,8 +1163,9 @@ def mechRepr(self):
class CheckboxItemControl(ItemControl):
_control = None

def __init__(self, parent, wtcontrol, elem, form, browser):
super(CheckboxItemControl, self).__init__(parent, elem, form, browser)
def __init__(self, parent, wtcontrol, elem, form, browser, index):
super(CheckboxItemControl, self).__init__(parent, elem, form, browser,
index)
self._control = wtcontrol

@property
Expand Down
43 changes: 43 additions & 0 deletions src/zope/testbrowser/tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,49 @@ def test_subcontrols_can_be_selected_by_value():
"""


def test_subcontrols_with_same_value_can_be_distinguished():
"""Regression test for GH #31.
https://github.com/zopefoundation/zope.testbrowser/issues/31
>>> app = TestApp()
>>> browser = Browser(wsgi_app=app)
>>> app.set_next_response(b'''\
... <html><body>
... <form method='get' action='action'>
... <input id="bar1" type='radio' name='bar' value="a">
... <label for="bar1">First</label>
... <input id="bar2" type='radio' name='bar' value="a">
... <label for="bar2">Second</label>
... <br>
... <select name="baz">
... <option value="b">uno</option>
... <option value="b">duos</option>
... </select>
... </form>
... </body></html>
... ''')
>>> browser.open('http://localhost/foo') # doctest: +ELLIPSIS
GET /foo HTTP/1.1
...
>>> radiobuttons = browser.getControl(name='bar')
>>> radiobuttons.getControl(value='a', index=1).selected = True
>>> radiobuttons.getControl(value='a', index=0)
<ItemControl name='bar' type='radio' optionValue='a' selected=False>
>>> radiobuttons.getControl(value='a', index=1)
<ItemControl name='bar' type='radio' optionValue='a' selected=True>
>>> listcontrol = browser.getControl(name='baz')
>>> listcontrol.getControl(value='b', index=1).selected = True
>>> listcontrol.getControl(value='b', index=0)
<ItemControl name='baz' type='select' optionValue='b' selected=False>
>>> listcontrol.getControl(value='b', index=1)
<ItemControl name='baz' type='select' optionValue='b' selected=True>
"""


def test_option_with_explicit_value_and_first_value_an_empty_string():
"""
>>> app = YetAnotherTestApp()
Expand Down

0 comments on commit 46a4ef7

Please sign in to comment.