00001
00002 from __future__ import unicode_literals
00003
00004 import sys
00005
00006
00007 import webtest
00008 from webtest.debugapp import debug_app
00009 from webob import Request
00010 from webob.response import gzip_app_iter
00011 from webtest.compat import PY3
00012
00013 from tests.compat import unittest
00014
00015 import webbrowser
00016
00017
00018 def links_app(environ, start_response):
00019 req = Request(environ)
00020 status = "200 OK"
00021 responses = {
00022 '/': """
00023 <html>
00024 <head><title>page with links</title></head>
00025 <body>
00026 <a href="/foo/">Foo</a>
00027 <a href='bar'>Bar</a>
00028 <a href='baz/' id='id_baz'>Baz</a>
00029 <a href='#' id='fake_baz'>Baz</a>
00030 <a href='javascript:alert("123")' id='js_baz'>Baz</a>
00031 <script>
00032 var link = "<a href='/boo/'>Boo</a>";
00033 </script>
00034 <a href='/spam/'>Click me!</a>
00035 <a href='/egg/'>Click me!</a>
00036 <button
00037 id="button1"
00038 onclick="location.href='/foo/'"
00039 >Button</button>
00040 <button
00041 id="button2">Button</button>
00042 <button
00043 id="button3"
00044 onclick="lomistakecation.href='/foo/'"
00045 >Button</button>
00046 </body>
00047 </html>
00048 """,
00049
00050 '/foo/': (
00051 '<html><body>This is foo. <a href="bar">Bar</a> '
00052 '</body></html>'
00053 ),
00054 '/foo/bar': '<html><body>This is foobar.</body></html>',
00055 '/bar': '<html><body>This is bar.</body></html>',
00056 '/baz/': '<html><body>This is baz.</body></html>',
00057 '/spam/': '<html><body>This is spam.</body></html>',
00058 '/egg/': '<html><body>Just eggs.</body></html>',
00059
00060 '/utf8/': """
00061 <html>
00062 <head><title>Тестовая страница</title></head>
00063 <body>
00064 <a href='/foo/'>Менделеев</a>
00065 <a href='/baz/' title='Поэт'>Пушкин</a>
00066 <img src='/egg/' title='Поэт'>
00067 <script>
00068 var link = "<a href='/boo/'>Злодейская ссылка</a>";
00069 </script>
00070 </body>
00071 </html>
00072 """,
00073 '/no_form/': """
00074 <html>
00075 <head><title>Page without form</title></head>
00076 <body>
00077 <h1>This is not the form you are looking for</h1>
00078 </body>
00079 </html>
00080 """,
00081 '/one_forms/': """
00082 <html>
00083 <head><title>Page without form</title></head>
00084 <body>
00085 <form method="POST" id="first_form"></form>
00086 </body>
00087 </html>
00088 """,
00089 '/many_forms/': """
00090 <html>
00091 <head><title>Page without form</title></head>
00092 <body>
00093 <form method="POST" id="first_form"></form>
00094 <form method="POST" id="second_form"></form>
00095 </body>
00096 </html>
00097 """,
00098 '/html_in_anchor/': """
00099 <html>
00100 <head><title>Page with HTML in an anchor tag</title></head>
00101 <body>
00102 <a href='/foo/'>Foo Bar<span class='baz qux'>Quz</span></a>
00103 </body>
00104 </html>
00105 """,
00106 '/json/': '{"foo": "bar"}',
00107 }
00108
00109 utf8_paths = ['/utf8/']
00110 body = responses[req.path_info]
00111 body = body.encode('utf8')
00112 headers = [
00113 ('Content-Type', str('text/html')),
00114 ('Content-Length', str(len(body)))
00115 ]
00116 if req.path_info in utf8_paths:
00117 headers[0] = ('Content-Type', str('text/html; charset=utf-8'))
00118
00119 start_response(str(status), headers)
00120 return [body]
00121
00122
00123 def gzipped_app(environ, start_response):
00124 status = "200 OK"
00125 encoded_body = list(gzip_app_iter([b'test']))
00126 headers = [
00127 ('Content-Type', str('text/html')),
00128 ('Content-Encoding', str('gzip')),
00129 ]
00130
00131 start_response(str(status), headers)
00132 return encoded_body
00133
00134
00135 class TestResponse(unittest.TestCase):
00136 def test_repr(self):
00137 def _repr(v):
00138 br = repr(v)
00139 if len(br) > 18:
00140 br = br[:10] + '...' + br[-5:]
00141 br += '/%s' % len(v)
00142
00143 return br
00144
00145 app = webtest.TestApp(debug_app)
00146 res = app.post('/')
00147 self.assertEqual(
00148 repr(res),
00149 '<200 OK text/plain body=%s>' % _repr(res.body)
00150 )
00151 res.content_type = None
00152 self.assertEqual(
00153 repr(res),
00154 '<200 OK body=%s>' % _repr(res.body)
00155 )
00156 res.location = 'http://pylons.org'
00157 self.assertEqual(
00158 repr(res),
00159 '<200 OK location: http://pylons.org body=%s>' % _repr(res.body)
00160 )
00161
00162 res.body = b''
00163 self.assertEqual(
00164 repr(res),
00165 '<200 OK location: http://pylons.org no body>'
00166 )
00167
00168 def test_mustcontains(self):
00169 app = webtest.TestApp(debug_app)
00170 res = app.post('/', params='foobar')
00171 res.mustcontain('foobar')
00172 self.assertRaises(IndexError, res.mustcontain, 'not found')
00173 res.mustcontain('foobar', no='not found')
00174 res.mustcontain('foobar', no=['not found', 'not found either'])
00175 self.assertRaises(IndexError, res.mustcontain, no='foobar')
00176 self.assertRaises(
00177 TypeError,
00178 res.mustcontain, invalid_param='foobar'
00179 )
00180
00181 def test_click(self):
00182 app = webtest.TestApp(links_app)
00183 self.assertIn('This is foo.', app.get('/').click('Foo'))
00184 self.assertIn(
00185 'This is foobar.',
00186 app.get('/').click('Foo').click('Bar')
00187 )
00188 self.assertIn('This is bar.', app.get('/').click('Bar'))
00189
00190 self.assertIn(
00191 'This is baz.',
00192 app.get('/').click('Baz')
00193 )
00194 self.assertIn('This is baz.', app.get('/').click(linkid='id_baz'))
00195 self.assertIn('This is baz.', app.get('/').click(href='baz/'))
00196 self.assertIn(
00197 'This is spam.',
00198 app.get('/').click('Click me!', index=0)
00199 )
00200 self.assertIn(
00201 'Just eggs.',
00202 app.get('/').click('Click me!', index=1)
00203 )
00204 self.assertIn(
00205 'This is foo.',
00206 app.get('/html_in_anchor/').click('baz qux')
00207 )
00208
00209 def dont_match_anchor_tag():
00210 app.get('/html_in_anchor/').click('href')
00211 self.assertRaises(IndexError, dont_match_anchor_tag)
00212
00213 def multiple_links():
00214 app.get('/').click('Click me!')
00215 self.assertRaises(IndexError, multiple_links)
00216
00217 def invalid_index():
00218 app.get('/').click('Click me!', index=2)
00219 self.assertRaises(IndexError, invalid_index)
00220
00221 def no_links_found():
00222 app.get('/').click('Ham')
00223 self.assertRaises(IndexError, no_links_found)
00224
00225 def tag_inside_script():
00226 app.get('/').click('Boo')
00227 self.assertRaises(IndexError, tag_inside_script)
00228
00229 def test_click_utf8(self):
00230 app = webtest.TestApp(links_app, use_unicode=False)
00231 resp = app.get('/utf8/')
00232 self.assertEqual(resp.charset, 'utf-8')
00233 if not PY3:
00234
00235 self.assertIn("Тестовая страница".encode('utf8'), resp)
00236 self.assertIn("Тестовая страница", resp, resp)
00237 target = 'Менделеев'.encode('utf8')
00238 self.assertIn('This is foo.', resp.click(target, verbose=True))
00239
00240 def test_click_u(self):
00241 app = webtest.TestApp(links_app)
00242 resp = app.get('/utf8/')
00243
00244 self.assertIn("Тестовая страница", resp)
00245 self.assertIn('This is foo.', resp.click('Менделеев'))
00246
00247 def test_clickbutton(self):
00248 app = webtest.TestApp(links_app)
00249 self.assertIn(
00250 'This is foo.',
00251 app.get('/').clickbutton(buttonid='button1', verbose=True)
00252 )
00253 self.assertRaises(
00254 IndexError,
00255 app.get('/').clickbutton, buttonid='button2'
00256 )
00257 self.assertRaises(
00258 IndexError,
00259 app.get('/').clickbutton, buttonid='button3'
00260 )
00261
00262 def test_xml_attribute(self):
00263 app = webtest.TestApp(links_app)
00264
00265 resp = app.get('/no_form/')
00266 self.assertRaises(
00267 AttributeError,
00268 getattr,
00269 resp, 'xml'
00270 )
00271
00272 resp.content_type = 'text/xml'
00273 resp.xml
00274
00275 @unittest.skipIf('PyPy' in sys.version, 'skip lxml tests on pypy')
00276 def test_lxml_attribute(self):
00277 app = webtest.TestApp(links_app)
00278 resp = app.post('/')
00279 resp.content_type = 'text/xml'
00280 print(resp.body)
00281 print(resp.lxml)
00282
00283 def test_html_attribute(self):
00284 app = webtest.TestApp(links_app)
00285 res = app.post('/')
00286 res.content_type = 'text/plain'
00287 self.assertRaises(
00288 AttributeError,
00289 getattr, res, 'html'
00290 )
00291
00292 def test_no_form(self):
00293 app = webtest.TestApp(links_app)
00294
00295 resp = app.get('/no_form/')
00296 self.assertRaises(
00297 TypeError,
00298 getattr,
00299 resp, 'form'
00300 )
00301
00302 def test_one_forms(self):
00303 app = webtest.TestApp(links_app)
00304
00305 resp = app.get('/one_forms/')
00306 self.assertEqual(resp.form.id, 'first_form')
00307
00308 def test_too_many_forms(self):
00309 app = webtest.TestApp(links_app)
00310
00311 resp = app.get('/many_forms/')
00312 self.assertRaises(
00313 TypeError,
00314 getattr,
00315 resp, 'form'
00316 )
00317
00318 def test_showbrowser(self):
00319 def open_new(f):
00320 self.filename = f
00321
00322 webbrowser.open_new = open_new
00323 app = webtest.TestApp(debug_app)
00324 res = app.post('/')
00325 res.showbrowser()
00326
00327 def test_unicode_normal_body(self):
00328 app = webtest.TestApp(debug_app)
00329 res = app.post('/')
00330 self.assertRaises(
00331 AttributeError,
00332 getattr, res, 'unicode_normal_body'
00333 )
00334 res.charset = 'latin1'
00335 res.body = 'été'.encode('latin1')
00336 self.assertEqual(res.unicode_normal_body, 'été')
00337
00338 def test_testbody(self):
00339 app = webtest.TestApp(debug_app)
00340 res = app.post('/')
00341 res.charset = 'utf8'
00342 res.body = 'été'.encode('latin1')
00343 res.testbody
00344
00345 def test_xml(self):
00346 app = webtest.TestApp(links_app)
00347
00348 resp = app.get('/no_form/')
00349 self.assertRaises(
00350 AttributeError,
00351 getattr,
00352 resp, 'xml'
00353 )
00354
00355 resp.content_type = 'text/xml'
00356 resp.xml
00357
00358 def test_json(self):
00359 app = webtest.TestApp(links_app)
00360
00361 resp = app.get('/json/')
00362 with self.assertRaises(AttributeError):
00363 resp.json
00364
00365 resp.content_type = 'text/json'
00366 self.assertIn('foo', resp.json)
00367
00368 resp.content_type = 'application/json'
00369 self.assertIn('foo', resp.json)
00370
00371 resp.content_type = 'application/vnd.webtest+json'
00372 self.assertIn('foo', resp.json)
00373
00374 def test_unicode(self):
00375 app = webtest.TestApp(links_app)
00376
00377 resp = app.get('/')
00378 if not PY3:
00379 unicode(resp)
00380
00381 print(resp.__unicode__())
00382
00383 def test_content_dezips(self):
00384 app = webtest.TestApp(gzipped_app)
00385 resp = app.get('/')
00386 self.assertEqual(resp.body, b'test')
00387
00388
00389 class TestFollow(unittest.TestCase):
00390
00391 def get_redirects_app(self, count=1, locations=None):
00392 """Return an app that issues a redirect ``count`` times"""
00393
00394 remaining_redirects = [count]
00395 if locations is None:
00396 locations = ['/'] * count
00397
00398 def app(environ, start_response):
00399 headers = [('Content-Type', str('text/html'))]
00400
00401 if remaining_redirects[0] == 0:
00402 status = "200 OK"
00403 body = b"done"
00404 else:
00405 status = "302 Found"
00406 body = b''
00407 nextloc = str(locations.pop(0))
00408 headers.append(('location', nextloc))
00409 remaining_redirects[0] -= 1
00410
00411 headers.append(('Content-Length', str(len(body))))
00412 start_response(str(status), headers)
00413 return [body]
00414
00415 return webtest.TestApp(app)
00416
00417 def test_follow_with_cookie(self):
00418 app = webtest.TestApp(debug_app)
00419 app.get('/?header-set-cookie=foo=bar')
00420 self.assertEqual(app.cookies['foo'], 'bar')
00421 resp = app.get('/?status=302%20Found&header-location=/')
00422 resp = resp.follow()
00423 resp.mustcontain('HTTP_COOKIE: foo=bar')
00424
00425 def test_follow(self):
00426 app = self.get_redirects_app(1)
00427 resp = app.get('/')
00428 self.assertEqual(resp.status_int, 302)
00429
00430 resp = resp.follow()
00431 self.assertEqual(resp.body, b'done')
00432
00433
00434 self.assertRaises(AssertionError, resp.follow)
00435
00436 def test_follow_relative(self):
00437 app = self.get_redirects_app(2, ['hello/foo/', 'bar'])
00438 resp = app.get('/')
00439 self.assertEqual(resp.status_int, 302)
00440 resp = resp.follow()
00441 self.assertEqual(resp.status_int, 302)
00442 resp = resp.follow()
00443 self.assertEqual(resp.body, b'done')
00444 self.assertEqual(resp.request.url, 'http://localhost/hello/foo/bar')
00445
00446 def test_follow_twice(self):
00447 app = self.get_redirects_app(2)
00448 resp = app.get('/').follow()
00449 self.assertEqual(resp.status_int, 302)
00450 resp = resp.follow()
00451 self.assertEqual(resp.status_int, 200)
00452
00453 def test_maybe_follow_200(self):
00454 app = self.get_redirects_app(0)
00455 resp = app.get('/').maybe_follow()
00456 self.assertEqual(resp.body, b'done')
00457
00458 def test_maybe_follow_once(self):
00459 app = self.get_redirects_app(1)
00460 resp = app.get('/').maybe_follow()
00461 self.assertEqual(resp.body, b'done')
00462
00463 def test_maybe_follow_twice(self):
00464 app = self.get_redirects_app(2)
00465 resp = app.get('/').maybe_follow()
00466 self.assertEqual(resp.body, b'done')
00467
00468 def test_maybe_follow_infinite(self):
00469 app = self.get_redirects_app(100000)
00470 self.assertRaises(AssertionError, app.get('/').maybe_follow)