Routines for testing WSGI applications with selenium.
Most interesting is SeleniumApp and the selenium() decorator
See webtest.TestApp
SeleniumApp only support GET requests
Selenium RC control aka browser
A object use to manipulate DOM nodes. This object allow to use the underlying selenium api. See Selenium api
You can use the original method name:
browser.fireEvent('id=#myid", 'focus')
Or a more pythonic name:
browser.fire_event('id=#myid", 'focus')
Both are equal to:
browser.execute('fireEvent', 'id=#myid', 'focus')
A callable usable as:
Some of the return values return instances of these classes:
The browser document. resp.doc.myid is egual to resp.doc.css('#myid')
Get a button
A object use to manipulate DOM nodes. This object allow to use the underlying selenium api for the specified locator. See Selenium api
You can use the original method name:
element.fireEvent('focus')
Or a more pythonic name:
element.fire_event('focus')
Both are equal to:
browser.execute('fireEvent', element.locator, 'focus')
Those value are used if found in environment:
SELENIUM_HOST: Default to 127.0.0.1
SELENIUM_PORT: Default to 4444
SELENIUM_BIND: IP used to bind extra servers (WSGI Server/File server). Default to 127.0.0.1
SELENIUM_DRIVER: The driver used to start the browser. Usualy something in *chrome, *firefox, *googlechrome. Default to *googlechrome. You can get the full list by running:
$ java -jar selenium-server.jar -interactive
cmd=getNewBrowserSession
SELENIUM_KEEP_OPEN: If exist then browser session are not closed so you can introspect the problem on failure.
SELENIUM_JAR: If selenium is not running then this jar is used to run selenium.
class TestApp(unittest.TestCase):
def setUp(self):
self.app = webtest.TestApp(application)
def test_webtest(self):
resp = self.app.get('/', {'redirect': '/message.html?message=submited'})
resp.mustcontain('It Works!')
form = resp.forms['myform']
form.lint()
self.assertEqual(form['mytext'].value, '')
resp.mustcontain(no='Form submited')
with webtest.selenium(resp) as sresp:
if sresp:
sform = sresp.forms['myform']
sform['mytext'] = 'foo'
sresp = sform.submit(name='go', timeout=0)
sresp.mustcontain('Form submited')
if resp.updated:
resp.mustcontain('Form submited')
form = resp.forms['myform']
self.assertEqual(form['mytext'].value, 'foo')
resp = form.submit(name='go')
resp = resp.follow()
resp.mustcontain('<pre>submited</pre>')
@webtest.selenium
def test_selenium(self):
resp = self.app.get('/', {'redirect': '/message.html?message=submited'})
resp.mustcontain('It Works!')
form = resp.forms['myform']
form.lint()
form['mytext'] = 'foo'
self.assertEqual(form['mytext'].value, 'foo')
# file upload are only supported with *firefox *chrome drivers
filename = os.path.join(files, 'html', 'index.html')
file = form['myfile']
file.value = (filename,)
form['myradio'] = 'true'
self.assertEqual(form['myradio'].value, 'true')
check = form.get('mycheckbox', index=0)
check.value = 'true'
self.assertEqual(check.value, 'true')
form['myselect'] = 'value2'
form['myselect'] = 'value2'
self.assertEqual(form['myselect'].value, 'value2')
form['mymultiselect'] = ['value1', 'value3']
self.assertEqual(form['mymultiselect'].value, ['value1', 'value3'])
# there is an ajax hook on the page
resp = form.submit(name='go', timeout=0)
resp.mustcontain('Form submited')
# but we can submit the form to get the non-javascript behavior
resp = form.submit()
resp = resp.follow()
resp.mustcontain('<pre>submited</pre>')
class TestJQueryUI(unittest.TestCase):
@classmethod
def setupClass(cls):
cls.app = webtest.SeleniumApp(url='http://jqueryui.com/')
def setUp(self):
self.resp = self.app.get('http://jqueryui.com/demos/')
def test_autocomplete(self):
resp = self.resp.click('Autocomplete')
field = resp.doc.xpath('//input[@id="tags"]')
field.value = 'a'
item = resp.doc.xpath('//ul[@role="listbox"]//a[.="AppleScript"]')
item.wait().fireEvent('mouseover')
field.value = resp.doc.css('#ui-active-menuitem').html()
self.assertEqual(field.value, "AppleScript")
def test_datepicker(self):
resp = self.resp.click('Datepicker')
field = resp.doc.datepicker
field.fireEvent('focus')
resp.doc.link('16').wait_and_click()
self.assertIn('/16/', field.value)
def test_dialog(self):
resp = self.resp.click('Dialog')
close = resp.doc.xpath('//div[@role="dialog"]//span[.="close"]')
close.wait_and_click()
resp.doc.link('Modal form').click()
resp.doc.button('Create new user').wait().click()
form = resp.form
form['name'].value = 'Gael'
form['email'] = 'gael@gawel.org'
create = resp.doc.button('Create an account')
create.click()
pwd = form['password']
self.assertTrue(pwd.hasClass('ui-state-error'))
pwd.value = 'pwd'
create.click()
resp.mustcontain('Length of password must be between 5 and 16.')
pwd.value = 'passwd'
create.click()
resp.mustcontain('<td>Gael</td>')
def test_dropable(self):
resp = self.resp.click('Droppable')
draggable = resp.doc.draggable
droppable = resp.doc.droppable
self.assertFalse(droppable.hasClass('ui-state-highlight'))
draggable.drag_and_drop(droppable)
self.assertTrue(droppable.hasClass('ui-state-highlight'))
resp.doc.link('Shopping Cart').click()
cart = resp.doc.css('#cart ol.ui-droppable')
cart.wait()
item = resp.doc.xpath('//li[.="Lolcat Shirt"]')
self.assertNotIn(item, cart)
item.drag_and_drop(cart)
self.assertIn(item, cart)
@classmethod
def teardownClass(cls):
cls.app.close()