[Zope3-checkins]
SVN: Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/
more major refactoring, zope.testbrowser tests pass (at least)
Benji York
benji at zope.com
Wed Aug 16 22:37:15 EDT 2006
Log message for revision 69578:
more major refactoring, zope.testbrowser tests pass (at least)
Changed:
U Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/browser.py
U Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/forms.py
U Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/real/real.py
-=-
Modified: Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/browser.py
===================================================================
--- Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/browser.py 2006-08-17 01:50:54 UTC (rev 69577)
+++ Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/browser.py 2006-08-17 02:37:14 UTC (rev 69578)
@@ -16,18 +16,13 @@
$Id$
"""
__docformat__ = "reStructuredText"
-from cStringIO import StringIO
-from test import pystone
from zope.testbrowser import interfaces
-from zope.testbrowser.forms import getControl, getForm, getAllControls
+from zope.testbrowser.forms import getControl, getForm, getAllControls, \
+ controlFactory, Form
from zope.testbrowser.utilities import disambiguate, any, onlyOne, zeroOrOne, \
SetattrErrorsMixin, PystoneTimer, compressText, RegexType
-import ClientForm
import mechanize
-import operator
import re
-import sys
-import time
import urllib2
try:
@@ -35,22 +30,6 @@
except ImportError:
from dummymodules import interface
-def controlFactory(control, form, browser):
- if isinstance(control, ClientForm.Item):
- # it is a subcontrol
- return ItemControl(control, form, browser)
- else:
- t = control.type
- if t in ('checkbox', 'select', 'radio'):
- return ListControl(control, form, browser)
- elif t in ('submit', 'submitbutton'):
- return SubmitControl(control, form, browser)
- elif t=='image':
- return ImageControl(control, form, browser)
- else:
- return Control(control, form, browser)
-
-
class Browser(SetattrErrorsMixin):
"""A web user agent."""
interface.implements(interfaces.IBrowser)
@@ -258,302 +237,3 @@
def __repr__(self):
return "<%s text=%r url=%r>" % (
self.__class__.__name__, self.text, self.url)
-
-
-class Control(SetattrErrorsMixin):
- """A control of a form."""
- interface.implements(interfaces.IControl)
-
- _enable_setattr_errors = False
-
- def __init__(self, control, form, browser):
- self.mech_control = control
- self.mech_form = form
- self.browser = browser
- self._browser_counter = self.browser._counter
-
- if self.mech_control.type == 'file':
- self.filename = None
- self.content_type = None
-
- # for some reason ClientForm thinks we shouldn't be able to modify
- # hidden fields, but while testing it is sometimes very important
- if self.mech_control.type == 'hidden':
- self.mech_control.readonly = False
-
- # disable addition of further attributes
- self._enable_setattr_errors = True
-
- @property
- def disabled(self):
- return bool(getattr(self.mech_control, 'disabled', False))
-
- @property
- def type(self):
- return getattr(self.mech_control, 'type', None)
-
- @property
- def name(self):
- return getattr(self.mech_control, 'name', None)
-
- @property
- def multiple(self):
- return bool(getattr(self.mech_control, 'multiple', False))
-
- @apply
- def value():
- """See zope.testbrowser.interfaces.IControl"""
-
- def fget(self):
- if (self.type == 'checkbox' and
- len(self.mech_control.items) == 1 and
- self.mech_control.items[0].name == 'on'):
- return self.mech_control.items[0].selected
- return self.mech_control.value
-
- def fset(self, value):
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- if self.mech_control.type == 'file':
- self.mech_control.add_file(value,
- content_type=self.content_type,
- filename=self.filename)
- elif self.type == 'checkbox' and len(self.mech_control.items) == 1:
- self.mech_control.items[0].selected = bool(value)
- else:
- self.mech_control.value = value
- return property(fget, fset)
-
- def add_file(self, file, content_type, filename):
- if not self.mech_control.type == 'file':
- raise TypeError("Can't call add_file on %s controls"
- % self.mech_control.type)
- if isinstance(file, str):
- file = StringIO(file)
- self.mech_control.add_file(file, content_type, filename)
-
- def clear(self):
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- self.mech_control.clear()
-
- def __repr__(self):
- return "<%s name=%r type=%r>" % (
- self.__class__.__name__, self.name, self.type)
-
-
-class ListControl(Control):
- interface.implements(interfaces.IListControl)
-
- @apply
- def displayValue():
- """See zope.testbrowser.interfaces.IListControl"""
- # not implemented for anything other than select;
- # would be nice if ClientForm implemented for checkbox and radio.
- # attribute error for all others.
-
- def fget(self):
- return self.mech_control.get_value_by_label()
-
- def fset(self, value):
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- self.mech_control.set_value_by_label(value)
-
- return property(fget, fset)
-
- @property
- def displayOptions(self):
- """See zope.testbrowser.interfaces.IListControl"""
- res = []
- for item in self.mech_control.items:
- if not item.disabled:
- for label in item.get_labels():
- if label.text:
- res.append(label.text)
- break
- else:
- res.append(None)
- return res
-
- @property
- def options(self):
- """See zope.testbrowser.interfaces.IListControl"""
- if (self.type == 'checkbox' and len(self.mech_control.items) == 1 and
- self.mech_control.items[0].name == 'on'):
- return [True]
- return [i.name for i in self.mech_control.items if not i.disabled]
-
- @property
- def disabled(self):
- if self.type == 'checkbox' and len(self.mech_control.items) == 1:
- return bool(getattr(self.mech_control.items[0], 'disabled', False))
- return bool(getattr(self.mech_control, 'disabled', False))
-
- @property
- def controls(self):
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- res = [controlFactory(i, self.mech_form, self.browser) for i in
- self.mech_control.items]
- for s in res:
- s.__dict__['control'] = self
- return res
-
- def getControl(self, label=None, value=None, index=None):
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
-
- onlyOne([label, value], '"label" and "value"')
-
- if label is not None:
- options = self.mech_control.get_items(label=label)
- msg = 'label %r' % label
- elif value is not None:
- options = self.mech_control.get_items(name=value)
- msg = 'value %r' % value
- res = controlFactory(
- disambiguate(options, msg, index), self.mech_form, self.browser)
- res.__dict__['control'] = self
- return res
-
-
-class SubmitControl(Control):
- interface.implements(interfaces.ISubmitControl)
-
- def click(self):
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- self.browser._clickSubmit(self.mech_form, self.mech_control, (1,1))
- self.browser._changed()
-
-
-class ImageControl(Control):
- interface.implements(interfaces.IImageSubmitControl)
-
- def click(self, coord=(1,1)):
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- self.browser._clickSubmit(self.mech_form, self.mech_control, coord)
- self.browser._changed()
-
-
-class ItemControl(SetattrErrorsMixin):
- interface.implements(interfaces.IItemControl)
-
- def __init__(self, item, form, browser):
- self.mech_item = item
- self.mech_form = form
- self.browser = browser
- self._browser_counter = self.browser._counter
- self._enable_setattr_errors = True
-
- @property
- def control(self):
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- res = controlFactory(
- self.mech_item._control, self.mech_form, self.browser)
- self.__dict__['control'] = res
- return res
-
- @property
- def disabled(self):
- return self.mech_item.disabled
-
- @apply
- def selected():
- """See zope.testbrowser.interfaces.IControl"""
-
- def fget(self):
- return self.mech_item.selected
-
- def fset(self, value):
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- self.mech_item.selected = value
-
- return property(fget, fset)
-
- @property
- def optionValue(self):
- return self.mech_item.attrs.get('value')
-
- def click(self):
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- self.mech_item.selected = not self.mech_item.selected
-
- def __repr__(self):
- return "<%s name=%r type=%r optionValue=%r>" % (
- self.__class__.__name__, self.mech_item._control.name,
- self.mech_item._control.type, self.optionValue)
-
-
-class Form(SetattrErrorsMixin):
- """HTML Form"""
- interface.implements(interfaces.IForm)
-
- def __init__(self, browser, form):
- """Initialize the Form
-
- browser - a Browser instance
- form - a ClientForm instance
- """
- self.browser = browser
- self.mech_form = form
- self._browser_counter = self.browser._counter
- self._enable_setattr_errors = True
-
- @property
- def action(self):
- return self.mech_form.action
-
- @property
- def method(self):
- return self.mech_form.method
-
- @property
- def enctype(self):
- return self.mech_form.enctype
-
- @property
- def name(self):
- return self.mech_form.name
-
- @property
- def id(self):
- """See zope.testbrowser.interfaces.IForm"""
- return self.mech_form.attrs.get('id')
-
- def submit(self, label=None, name=None, index=None, coord=(1,1)):
- """See zope.testbrowser.interfaces.IForm"""
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- form = self.mech_form
- if label is not None or name is not None:
- intermediate, msg = getAllControls([form], label, name)
- intermediate = [
- (control, form) for (control, form) in intermediate if
- control.type in ('submit', 'submitbutton', 'image')]
- control, form = disambiguate(intermediate, msg, index)
- self.browser._clickSubmit(form, control, coord)
- else: # JavaScript sort of submit
- if index is not None or coord != (1,1):
- raise ValueError(
- 'May not use index or coord without a control')
- request = self.mech_form._switch_click("request", urllib2.Request)
- self.browser._start_timer()
- self.browser.mech_browser.open(request)
- self.browser._stop_timer()
- self.browser._changed()
-
- def getControl(self, label=None, name=None, index=None):
- """See zope.testbrowser.interfaces.IBrowser"""
- if self._browser_counter != self.browser._counter:
- raise interfaces.ExpiredError
- forms = [self.mech_form]
- intermediate, msg = getAllControls(forms, label, name,
- include_subcontrols=True)
- control, form = disambiguate(intermediate, msg, index)
- return controlFactory(control, form, self.browser)
Modified: Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/forms.py
===================================================================
--- Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/forms.py 2006-08-17 01:50:54 UTC (rev 69577)
+++ Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/forms.py 2006-08-17 02:37:14 UTC (rev 69578)
@@ -1,6 +1,11 @@
+from cStringIO import StringIO
+from zope import interface
+from zope.testbrowser import interfaces
from zope.testbrowser.utilities import disambiguate, any, onlyOne, zeroOrOne, \
- compressText
+ compressText, SetattrErrorsMixin, compressText
+import ClientForm
import re
+import urllib2
def findByLabel(label, forms, include_subcontrols=False):
# forms are iterable of mech_forms
@@ -66,3 +71,318 @@
matching_forms.append(form)
return disambiguate(matching_forms, '', index)
+
+
+class Control(SetattrErrorsMixin):
+ """A control of a form."""
+ interface.implements(interfaces.IControl)
+
+ _enable_setattr_errors = False
+
+ def __init__(self, control, form, browser):
+ self.mech_control = control
+ self.mech_form = form
+ self.browser = browser
+ self._browser_counter = self.browser._counter
+
+ if self.mech_control.type == 'file':
+ self.filename = None
+ self.content_type = None
+
+ # for some reason ClientForm thinks we shouldn't be able to modify
+ # hidden fields, but while testing it is sometimes very important
+ if self.mech_control.type == 'hidden':
+ self.mech_control.readonly = False
+
+ # disable addition of further attributes
+ self._enable_setattr_errors = True
+
+ @property
+ def disabled(self):
+ return bool(getattr(self.mech_control, 'disabled', False))
+
+ @property
+ def type(self):
+ return getattr(self.mech_control, 'type', None)
+
+ @property
+ def name(self):
+ return getattr(self.mech_control, 'name', None)
+
+ @property
+ def multiple(self):
+ return bool(getattr(self.mech_control, 'multiple', False))
+
+ @apply
+ def value():
+ """See zope.testbrowser.interfaces.IControl"""
+
+ def fget(self):
+ if (self.type == 'checkbox' and
+ len(self.mech_control.items) == 1 and
+ self.mech_control.items[0].name == 'on'):
+ return self.mech_control.items[0].selected
+ return self.mech_control.value
+
+ def fset(self, value):
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ if self.mech_control.type == 'file':
+ self.mech_control.add_file(value,
+ content_type=self.content_type,
+ filename=self.filename)
+ elif self.type == 'checkbox' and len(self.mech_control.items) == 1:
+ self.mech_control.items[0].selected = bool(value)
+ else:
+ self.mech_control.value = value
+ return property(fget, fset)
+
+ def add_file(self, file, content_type, filename):
+ if not self.mech_control.type == 'file':
+ raise TypeError("Can't call add_file on %s controls"
+ % self.mech_control.type)
+ if isinstance(file, str):
+ file = StringIO(file)
+ self.mech_control.add_file(file, content_type, filename)
+
+ def clear(self):
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ self.mech_control.clear()
+
+ def __repr__(self):
+ return "<%s name=%r type=%r>" % (
+ self.__class__.__name__, self.name, self.type)
+
+
+class ListControl(Control):
+ interface.implements(interfaces.IListControl)
+
+ @apply
+ def displayValue():
+ """See zope.testbrowser.interfaces.IListControl"""
+ # not implemented for anything other than select;
+ # would be nice if ClientForm implemented for checkbox and radio.
+ # attribute error for all others.
+
+ def fget(self):
+ return self.mech_control.get_value_by_label()
+
+ def fset(self, value):
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ self.mech_control.set_value_by_label(value)
+
+ return property(fget, fset)
+
+ @property
+ def displayOptions(self):
+ """See zope.testbrowser.interfaces.IListControl"""
+ res = []
+ for item in self.mech_control.items:
+ if not item.disabled:
+ for label in item.get_labels():
+ if label.text:
+ res.append(label.text)
+ break
+ else:
+ res.append(None)
+ return res
+
+ @property
+ def options(self):
+ """See zope.testbrowser.interfaces.IListControl"""
+ if (self.type == 'checkbox' and len(self.mech_control.items) == 1 and
+ self.mech_control.items[0].name == 'on'):
+ return [True]
+ return [i.name for i in self.mech_control.items if not i.disabled]
+
+ @property
+ def disabled(self):
+ if self.type == 'checkbox' and len(self.mech_control.items) == 1:
+ return bool(getattr(self.mech_control.items[0], 'disabled', False))
+ return bool(getattr(self.mech_control, 'disabled', False))
+
+ @property
+ def controls(self):
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ res = [controlFactory(i, self.mech_form, self.browser) for i in
+ self.mech_control.items]
+ for s in res:
+ s.__dict__['control'] = self
+ return res
+
+ def getControl(self, label=None, value=None, index=None):
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+
+ onlyOne([label, value], '"label" and "value"')
+
+ if label is not None:
+ options = self.mech_control.get_items(label=label)
+ msg = 'label %r' % label
+ elif value is not None:
+ options = self.mech_control.get_items(name=value)
+ msg = 'value %r' % value
+ res = controlFactory(
+ disambiguate(options, msg, index), self.mech_form, self.browser)
+ res.__dict__['control'] = self
+ return res
+
+
+class SubmitControl(Control):
+ interface.implements(interfaces.ISubmitControl)
+
+ def click(self):
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ self.browser._clickSubmit(self.mech_form, self.mech_control, (1,1))
+ self.browser._changed()
+
+
+class ImageControl(Control):
+ interface.implements(interfaces.IImageSubmitControl)
+
+ def click(self, coord=(1,1)):
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ self.browser._clickSubmit(self.mech_form, self.mech_control, coord)
+ self.browser._changed()
+
+
+class ItemControl(SetattrErrorsMixin):
+ interface.implements(interfaces.IItemControl)
+
+ def __init__(self, item, form, browser):
+ self.mech_item = item
+ self.mech_form = form
+ self.browser = browser
+ self._browser_counter = self.browser._counter
+ self._enable_setattr_errors = True
+
+ @property
+ def control(self):
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ res = controlFactory(
+ self.mech_item._control, self.mech_form, self.browser)
+ self.__dict__['control'] = res
+ return res
+
+ @property
+ def disabled(self):
+ return self.mech_item.disabled
+
+ @apply
+ def selected():
+ """See zope.testbrowser.interfaces.IControl"""
+
+ def fget(self):
+ return self.mech_item.selected
+
+ def fset(self, value):
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ self.mech_item.selected = value
+
+ return property(fget, fset)
+
+ @property
+ def optionValue(self):
+ return self.mech_item.attrs.get('value')
+
+ def click(self):
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ self.mech_item.selected = not self.mech_item.selected
+
+ def __repr__(self):
+ return "<%s name=%r type=%r optionValue=%r>" % (
+ self.__class__.__name__, self.mech_item._control.name,
+ self.mech_item._control.type, self.optionValue)
+
+
+class Form(SetattrErrorsMixin):
+ """HTML Form"""
+ interface.implements(interfaces.IForm)
+
+ def __init__(self, browser, form):
+ """Initialize the Form
+
+ browser - a Browser instance
+ form - a ClientForm instance
+ """
+ self.browser = browser
+ self.mech_form = form
+ self._browser_counter = self.browser._counter
+ self._enable_setattr_errors = True
+
+ @property
+ def action(self):
+ return self.mech_form.action
+
+ @property
+ def method(self):
+ return self.mech_form.method
+
+ @property
+ def enctype(self):
+ return self.mech_form.enctype
+
+ @property
+ def name(self):
+ return self.mech_form.name
+
+ @property
+ def id(self):
+ """See zope.testbrowser.interfaces.IForm"""
+ return self.mech_form.attrs.get('id')
+
+ def submit(self, label=None, name=None, index=None, coord=(1,1)):
+ """See zope.testbrowser.interfaces.IForm"""
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ form = self.mech_form
+ if label is not None or name is not None:
+ intermediate, msg = getAllControls([form], label, name)
+ intermediate = [
+ (control, form) for (control, form) in intermediate if
+ control.type in ('submit', 'submitbutton', 'image')]
+ control, form = disambiguate(intermediate, msg, index)
+ self.browser._clickSubmit(form, control, coord)
+ else: # JavaScript sort of submit
+ if index is not None or coord != (1,1):
+ raise ValueError(
+ 'May not use index or coord without a control')
+ request = self.mech_form._switch_click("request", urllib2.Request)
+ self.browser._start_timer()
+ self.browser.mech_browser.open(request)
+ self.browser._stop_timer()
+ self.browser._changed()
+
+ def getControl(self, label=None, name=None, index=None):
+ """See zope.testbrowser.interfaces.IBrowser"""
+ if self._browser_counter != self.browser._counter:
+ raise interfaces.ExpiredError
+ forms = [self.mech_form]
+ intermediate, msg = getAllControls(forms, label, name,
+ include_subcontrols=True)
+ control, form = disambiguate(intermediate, msg, index)
+ return controlFactory(control, form, self.browser)
+
+
+def controlFactory(control, form, browser):
+ if isinstance(control, ClientForm.Item):
+ # it is a subcontrol
+ return ItemControl(control, form, browser)
+ else:
+ t = control.type
+ if t in ('checkbox', 'select', 'radio'):
+ return ListControl(control, form, browser)
+ elif t in ('submit', 'submitbutton'):
+ return SubmitControl(control, form, browser)
+ elif t=='image':
+ return ImageControl(control, form, browser)
+ else:
+ return Control(control, form, browser)
Modified: Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/real/real.py
===================================================================
--- Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/real/real.py 2006-08-17 01:50:54 UTC (rev 69577)
+++ Zope3/branches/benji-testbrowser-with-real-browsers-take-2/src/zope/testbrowser/real/real.py 2006-08-17 02:37:14 UTC (rev 69578)
@@ -18,6 +18,8 @@
__docformat__ = "reStructuredText"
from BeautifulSoup import BeautifulSoup
from zope.testbrowser import interfaces
+from zope.testbrowser.forms import getControl, getForm, getAllControls, \
+ controlFactory
from zope.testbrowser.real.proxy import ServerManager, PROXY_PORT
from zope.testbrowser.utilities import disambiguate, zeroOrOne, \
SetattrErrorsMixin, PystoneTimer
@@ -182,8 +184,23 @@
def getControl(self, label=None, name=None, index=None):
"""See zope.testbrowser.interfaces.IBrowser"""
- raise NotImplementedError
+ import ClientForm
+ from StringIO import StringIO
+ class DummyResponse(object):
+ def __init__(self, contents, url):
+ self.stringIo = StringIO(contents)
+ self.url = url
+ def read(self, size):
+ return self.stringIo.read(size)
+ def geturl(self):
+ return self.url
+
+ dummy_response = DummyResponse(self.contents, self.url)
+ forms = ClientForm.ParseResponse(dummy_response)
+ control, form = getControl(forms, label, name, index)
+ return controlFactory(control, form, self)
+
def getForm(self, id=None, name=None, action=None, index=None):
"""See zope.testbrowser.interfaces.IBrowser"""
raise NotImplementedError
More information about the Zope3-Checkins
mailing list