Git Product home page Git Product logo

webtest's Introduction

WebTest

This wraps any WSGI application and makes it easy to send test requests to that application, without starting up an HTTP server.

This provides convenient full-stack testing of applications written with any WSGI-compatible framework.

Full docs can be found at https://docs.pylonsproject.org/projects/webtest/en/latest/

webtest's People

Contributors

almet avatar arthru avatar azmeuk avatar bdauvergne avatar bjmc avatar cdevienne avatar domenkozar avatar gawel avatar hirokiky avatar homm avatar ianb avatar ianjosephwilson avatar julian avatar kedder avatar kmike avatar lrowe avatar luhn avatar madjar avatar magopian avatar mbertheau avatar mcdonc avatar mgedmin avatar rudaporto avatar sloria avatar stevepiercy avatar suvit avatar therefromhere avatar tshepang avatar wichert avatar wosc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webtest's Issues

Specifying content type of uploaded files

Currently WebTest relies on mimetype.guess_type(filename) when it formats multipart/form-data content with uploaded files. Unfortunately the results of guess_type are platform-specific, which causes a zope.testbrowser test failure on Windows.

It would be nice if we could explicitly specify the desired content type while creating a webtest.forms.Upload() object and avoid the mimetype guessing altogether.

I intend to submit a pull request implementing this.

Seleniums getLocation() working with Chrome, not Firefox

kvdb:

I use this code to get the current browser URL:
browser_url = self.app.browser.getLocation()

With *googlechrome, I get: http://127.0.0.1:53381/selenium-server/core/Blank.html?start=true

That's consistent with what I see in the logging: Allocated session 70056e911d6747dcbb71925ae0aa48db for http://127.0.0.1:53381/, launching...

With *firefox however, I get:

http://localhost:4444/selenium-server/core/Blank.html?start=true

Which is the port for server communication, not the browser, which
should be port 33844 according to the log:

Allocated session aa13e897f2ac40babc0563726f0fd4fa for http://127.0.0.1:33844/, launching...

Not sure if this the right way to get the URL, if it's a bug in webtest,
the selenium drivers or any other component.

URL: https://bitbucket.org/ianb/webtest/issue/43/seleniums-getlocation-working-with-chrome

Cookies with contain quotation marks are not parsed correctly.

This issue is occurring ever since version 1.4.2. Here is a testcase that will demonstrate the problem:

import webtest

def cookie_app(environ, start_response):
    start_response(webtest.compat.to_bytes("200 OK"), [])
    return [webtest.compat.to_bytes('Cookie')]

app = webtest.TestApp(cookie_app)
res = app.get('/', headers=[('Cookie', 'spam="eggs"')])
assert res.request.environ['HTTP_COOKIE'] == 'spam="eggs"'
assert dict(res.request.cookies) == {'spam': '"eggs"'}

The last assertion fails.

Multiple fields with same same produce assertion

I'm using webtest to test my django apps.

If I use django MultipleChoiceField using CheckboxSelectMultiple I get this error:

Multiple fields match 'workdays': , , , , , ,

The html that django generates is perfectly valid and works:

Workdays

  • Sunday
  • Monday
  • Tuesday
  • Wednesday
  • Thursday
  • Friday
  • \ Saturday

TestApp.get should pass REQUEST_URI

Anonymous:

A common workaround for unicode and slashes encoded in the URL
is to have the wsgi app server pass REQUEST_URI and then deal
with it in middleware. It would be nice to
be able to test said middleware.
For now, a workaround is to wrap TestApp.get and always specify
extra_environ={'REQUEST_URI':url}.

Ian Bicking:

This may be hard to implement correctly, as the request construction
deconstructs the URL, and that's happening in WebOb. I don't think
the change would be appropriate for WebOb itself. Also quite a lot
of WSGI servers at this point don't set REQUEST_URI, so always
having it on doesn't seem like a good idea (having it off is more
representative of lowest-common-denominator WSGI servers).
An option to turn it on seems okay though (something you can pass
in when instantiating TestApp).

URL: https://bitbucket.org/ianb/webtest/issue/8/testappget-should-pass-request_uri

Form.submit_fields() bug with index checking

There's a bug with the Form.submit_fields() method, which causes all fields with an index >= the specified index to be included in the submission.

For example, if I have a form with 4 submit buttons (all named 'submit'), and want to submit the 2nd button, I would call

form.submit('submit', 1)

I would expect only the 2nd button to be submitted, but WebTest will currently append values for the 2nd, 3rd and 4th buttons.

(Originally found in WebTest v1.4.3, but I see that this bug still exists HEAD)
-- In v1.4.3, see webtest/app.py, line 1740.
-- In HEAD, see webtest/form.py, line 554

The current implementation only increments 'current_index' if it is less than 'index'. Once 'current_index == index', it is no longer incremented and matching field values are always appended.

if submit_name is not None and name == submit_name and \
     current_index == index:                                                                                                                                                                                                                                                                                                                                 
     submit.append((name, field.value_if_submitted())) 
elif submit_name is not None and name == submit_name:                                                                                                                                                                                                                                                                                                       
    current_index += 1                                    

The correct way to do this is to ALWAYS increment 'current_index' (when the name matches):

if submit_name is not None and name == submit_name:                                                                                                                                                                                                                                        
    if current_index == index:
        submit.append((name, field.value_if_submitted()))
    current_index += 1           

PS: I love WebTest, thanks for maintaining!

Doctest failure with Python 3.3

1 doctest sometimes fails with Python 3.3 (probably due to hash randomization). You might need to run test suite multiple times to reproduce this bug.

$ nosetests-3.3
...
======================================================================
FAIL: Doctest: index.txt
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.3/doctest.py", line 2154, in runTest
    raise self.failureException(self.format_failure(new.getvalue()))
AssertionError: Failed doctest test for index.txt
  File "/tmp/WebTest-1.4.3/docs/index.txt", line 0

----------------------------------------------------------------------
File "/tmp/WebTest-1.4.3/docs/index.txt", line 327, in index.txt
Failed example:
    list(res.json.values())
Expected:
    [1, 2]
Got:
    [2, 1]

>>  raise self.failureException(self.format_failure(<_io.StringIO object at 0x7f5bbb72d180>.getvalue()))


----------------------------------------------------------------------
Ran 58 tests in 1.584s

FAILED (failures=1)

With 1.3.6 I got new error in test, but in 1.3.5 was nothing

Victor Safronovich:


...........................E..............................
======================================================================
ERROR: test_manage_manager (pwmanager.tests.PricemasterManageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/var/lib/jenkins/jobs/techno4me/workspace/apps/pwmanager/tests.py", line 62, in test_manage_manager
    r = form.submit()
  File "/var/lib/jenkins/jobs/techno4me/workspace/env/lib/python2.6/site-packages/webtest/app.py", line 1704, in submit
    params=fields, **args)
  File "/var/lib/jenkins/jobs/techno4me/workspace/env/lib/python2.6/site-packages/webtest/app.py", line 368, in goto
    return method(href, **args)
  File "/var/lib/jenkins/jobs/techno4me/workspace/env/lib/python2.6/site-packages/django_webtest/__init__.py", line 92, in post
    upload_files, expect_errors, content_type)
  File "/var/lib/jenkins/jobs/techno4me/workspace/env/lib/python2.6/site-packages/webtest/app.py", line 835, in post
    content_type=content_type)
  File "/var/lib/jenkins/jobs/techno4me/workspace/env/lib/python2.6/site-packages/webtest/app.py", line 778, in _gen_request
    params, upload_files or ())
  File "/var/lib/jenkins/jobs/techno4me/workspace/env/lib/python2.6/site-packages/webtest/app.py", line 997, in encode_multipart
    body = join_bytes('\r\n', lines)
  File "/var/lib/jenkins/jobs/techno4me/workspace/env/lib/python2.6/site-packages/webtest/compat.py", line 77, in join_bytes
    return sep.join(l)
TypeError: sequence item 51: expected string, datetime.date found

Gael Pasgrimaud:

is mean that you use something like form['date'] = datetime.date ?

Victor Safronovich:

Yes.

form['work_start_date'] = today - datetime.timedelta(days=10)

In 1.3.5 this works

URL: https://bitbucket.org/ianb/webtest/issue/44/with-136-i-got-new-error-in-test-but-in

Don't use value of <input type="file"> when parsing form

I have a form with an <input name="image" type="file" value="some/path">. When submitting the form in the browser it submits an empty string for image. However, submitting the form with webtests submits some/path which trips up Django upon processing the form. I believe the right thing is to use the empty string for all File fields until a value was explicitly set. That's the way browsers do it, see http://stackoverflow.com/questions/20537696/remember-and-repopulate-file-input/20537822#20537822 .

If you agree I should be able to create a pull request to that effect.

quoted urls UnicodeDecodeError

I use quoted URLs such as /fr/livres/cr%C3%A9ation/ (for /fr/livres/création/).
get() is working fine with these urls but once I have the response if I try to use click() or submit() on it I get the following error:

/usr/lib/python3.3/http/cookiejar.py:1588: UserWarning: http.cookiejar bug!
Traceback (most recent call last):
  File "/usr/lib/python3.3/http/cookiejar.py", line 1586, in make_cookies
    parse_ns_headers(ns_hdrs), request)
  File "/usr/lib/python3.3/http/cookiejar.py", line 1543, in _cookies_from_attrs_set
    cookie = self._cookie_from_cookie_tuple(tup, request)
  File "/usr/lib/python3.3/http/cookiejar.py", line 1492, in _cookie_from_cookie_tuple
    req_host, erhn = eff_request_host(request)
  File "/usr/lib/python3.3/http/cookiejar.py", line 612, in eff_request_host
    erhn = req_host = request_host(request)
  File "/usr/lib/python3.3/http/cookiejar.py", line 597, in request_host
    url = request.get_full_url()
  File "/usr/local/lib/python3.3/dist-packages/WebTest-2.0.8.dev0-py3.3.egg/webtest/utils.py", line 116, in get_full_url
    return self._request.url
  File "/usr/local/lib/python3.3/dist-packages/WebOb-1.2.3-py3.3.egg/webob/request.py", line 505, in url
    url = self.path_url
  File "/usr/local/lib/python3.3/dist-packages/WebOb-1.2.3-py3.3.egg/webob/request.py", line 477, in path_url
    bpath_info = bytes_(self.path_info, self.url_encoding)
  File "/usr/local/lib/python3.3/dist-packages/WebOb-1.2.3-py3.3.egg/webob/descriptors.py", line 68, in fget
    return req.encget(key, encattr=encattr)
  File "/usr/local/lib/python3.3/dist-packages/WebOb-1.2.3-py3.3.egg/webob/request.py", line 167, in encget
    return bytes_(val, 'latin-1').decode(encoding)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 5: invalid continuation byte

  _warn_unhandled_exception()

I'm using Ubuntu 13.04 64 bit and Python 3.3.1 with the last commit of Webtest.

Test failures with Python 3.3

Test suite with Python 3.3 triggers 4 errors.
(All tests pass with Python 2.6, 2.7 and 3.2.)

$ nosetests-3.3
...
======================================================================
ERROR: test_expires_cookies (tests.test_app.TestCookies)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.3/site-packages/mock.py", line 1201, in patched
    return func(*args, **keywargs)
  File "/tmp/WebTest-2.0.5/tests/test_app.py", line 241, in test_expires_cookies
    app.get('/')
  File "/tmp/WebTest-2.0.5/webtest/app.py", line 199, in get
    expect_errors=expect_errors)
  File "/tmp/WebTest-2.0.5/webtest/app.py", line 494, in do_request
    utils._RequestCookieAdapter(req))
  File "/usr/lib64/python3.3/http/cookiejar.py", line 1647, in extract_cookies
    if self._policy.set_ok(cookie, request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 931, in set_ok
    if not fn(cookie, request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 952, in set_ok_verifiability
    if request.unverifiable and is_third_party(request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 707, in is_third_party
    if not domain_match(req_host, reach(request.origin_req_host)):
AttributeError: '_RequestCookieAdapter' object has no attribute 'origin_req_host'

======================================================================
ERROR: test_preserves_cookies (tests.test_app.TestCookies)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/WebTest-2.0.5/tests/test_app.py", line 172, in test_preserves_cookies
    res = app.get('/')
  File "/tmp/WebTest-2.0.5/webtest/app.py", line 199, in get
    expect_errors=expect_errors)
  File "/tmp/WebTest-2.0.5/webtest/app.py", line 494, in do_request
    utils._RequestCookieAdapter(req))
  File "/usr/lib64/python3.3/http/cookiejar.py", line 1647, in extract_cookies
    if self._policy.set_ok(cookie, request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 931, in set_ok
    if not fn(cookie, request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 952, in set_ok_verifiability
    if request.unverifiable and is_third_party(request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 707, in is_third_party
    if not domain_match(req_host, reach(request.origin_req_host)):
AttributeError: '_RequestCookieAdapter' object has no attribute 'origin_req_host'

======================================================================
ERROR: test_secure_cookies (tests.test_app.TestCookies)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/WebTest-2.0.5/tests/test_app.py", line 207, in test_secure_cookies
    res = app.get('https://localhost/')
  File "/tmp/WebTest-2.0.5/webtest/app.py", line 199, in get
    expect_errors=expect_errors)
  File "/tmp/WebTest-2.0.5/webtest/app.py", line 494, in do_request
    utils._RequestCookieAdapter(req))
  File "/usr/lib64/python3.3/http/cookiejar.py", line 1647, in extract_cookies
    if self._policy.set_ok(cookie, request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 931, in set_ok
    if not fn(cookie, request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 952, in set_ok_verifiability
    if request.unverifiable and is_third_party(request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 707, in is_third_party
    if not domain_match(req_host, reach(request.origin_req_host)):
AttributeError: '_RequestCookieAdapter' object has no attribute 'origin_req_host'

======================================================================
ERROR: test_follow_with_cookie (tests.test_response.TestFollow)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/WebTest-2.0.5/tests/test_response.py", line 382, in test_follow_with_cookie
    app.get('/?header-set-cookie=foo=bar')
  File "/tmp/WebTest-2.0.5/webtest/app.py", line 199, in get
    expect_errors=expect_errors)
  File "/tmp/WebTest-2.0.5/webtest/app.py", line 494, in do_request
    utils._RequestCookieAdapter(req))
  File "/usr/lib64/python3.3/http/cookiejar.py", line 1647, in extract_cookies
    if self._policy.set_ok(cookie, request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 931, in set_ok
    if not fn(cookie, request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 952, in set_ok_verifiability
    if request.unverifiable and is_third_party(request):
  File "/usr/lib64/python3.3/http/cookiejar.py", line 707, in is_third_party
    if not domain_match(req_host, reach(request.origin_req_host)):
AttributeError: '_RequestCookieAdapter' object has no attribute 'origin_req_host'

Name               Stmts   Miss  Cover   Missing
------------------------------------------------
webtest               24      0   100%   
webtest.app          263      1    99%   146
webtest.compat        18      2    89%   34-35
webtest.debugapp      63      1    98%   35
webtest.ext            3      0   100%   
webtest.forms        288      0   100%   
webtest.http          87      3    97%   89-91
webtest.lint         203      1    99%   251
webtest.response     256     14    95%   270-286, 382, 389, 539
webtest.sel            6      0   100%   
webtest.utils         91     10    89%   88, 107, 118, 121, 124, 127, 130, 135, 138, 153
------------------------------------------------
TOTAL               1302     32    98%   
----------------------------------------------------------------------
Ran 166 tests in 11.006s

FAILED (errors=4)

TestApp.post() with upload_files not working

i'm using webtest, by way of django-webtest to test an API written using django-tastypie.

I am trying to make a post that includes a file to be uploaded, but as soon as i add the upload_files parameter to the post, the server responds with:

2013-02-06 17:58:43,072 [ERROR] django.request.tastypie: Internal Server Error: /api/v1/caseattachment/
Traceback (most recent call last):
File "/home/klrmn/moztrap-host/requirements/vendor/lib/python/tastypie/resources.py", line 192, in wrapper
response = callback(request, _args, *_kwargs)
File "/home/klrmn/moztrap-host/requirements/vendor/lib/python/tastypie/resources.py", line 397, in dispatch_list
return self.dispatch('list', request, *_kwargs)
File "/home/klrmn/moztrap-host/requirements/vendor/lib/python/tastypie/resources.py", line 427, in dispatch
response = method(request, *_kwargs)
File "/home/klrmn/moztrap-host/requirements/vendor/lib/python/tastypie/resources.py", line 1161, in post_list
deserialized = self.deserialize(request, request.raw_post_data, format=request.META.get('CONTENT_TYPE', 'application/json'))
File "/home/klrmn/moztrap-host/requirements/vendor/lib/python/tastypie/resources.py", line 346, in deserialize
deserialized = self.meta.serializer.deserialize(data, format=request.META.get('CONTENT_TYPE', 'application/json'))
File "/home/klrmn/moztrap-host/requirements/vendor/lib/python/tastypie/serializers.py", line 193, in deserialize
deserialized = getattr(self, "from
%s" % desired_format)(content)
File "/home/klrmn/moztrap-host/requirements/vendor/lib/python/tastypie/serializers.py", line 337, in from_json
return simplejson.loads(content)
File "/usr/lib/python2.7/json/init.py", line 328, in loads
return _default_decoder.decode(s)
File "/usr/lib/python2.7/json/decoder.py", line 365, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python2.7/json/decoder.py", line 383, in raw_decode
raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

I took a look in your unit tests, and https://github.com/Pylons/webtest/blob/master/tests/test_file_upload.py doesn't seem to use app.post(), and none of the other instances of app.post() in the tests use the upload_files parameter.

Application cookies for localhost are ignored

The following setup will fail:

  • create a WSGI application that sets cookies for the localhost domain
  • test the WSGI application using WebTest
  • do a GET request using WebTest to the application
  • check if the cookies are set in app.cookies

The underlying problem appears to be a bug in Python's cookielib: when the cookies are parsed localhost is transformed to .localhost, and the cookie is then rejected by the CookieJar because .localhost due to the non-local domain %s contains no embedded dot check. Since Python upstream is very unlikely to fix this WebTest will need to work around this.

WEBTEST_TARGET_URL feature not working

def __init__(self, app, extra_environ=None, relative_to=None,
             use_unicode=True, cookiejar=None, parser_features=None):
    if 'WEBTEST_TARGET_URL' in os.environ:
        app = os.environ['WEBTEST_TARGET_URL']
    if isinstance(app, string_types):
        if app.startswith('http'):
          from wsgiproxy import HostProxy

E ImportError: cannot import name HostProxy

Please note, that the initial error is that wsgiproxy is not installed, the above error happened after I've run a manual pip install wsgiproxy

Versions involved:
WSGIProxy==0.2.2
WebTest==2.0.14

[FEATURE] Allow submit to take button value instead of index

I use webtest to submit forms with buttons like this:

<button name="action" type="submit" value="deactivate">Deactivate</button>
<button name="action" type="submit" value="save_active">Save</button>

Currently I have to know the index of the button I want, or I can find it out from form.fields['action'].

I want to specify the button using its value attribute.

I could write a pull request that adds a keyword attribute value to Form.submit that selects the button by value instead of index.

Alternatively I could modify Form.submit to accept a string for index to select the button by value.

Currently I use this method

    def submit_form_with_button(self, form, button_value, button_name='action'):
        buttons = form.fields[button_name]
        button_values = [button.value_if_submitted() for button in buttons]
        button_index = button_values.index(button_value)
        return form.submit(button_name, button_index)

What are your thoughts?

Support basic authentication

WebTest currently does not support testing applications that require basic authentication. You can do this by writing your own code to generate an Authorization header and passing that to all get/post/put/etc. method, but that quickly becomes unwieldy.

This feature is available via the webtest-plus, which shows this is simple to add to WebTest.

Tox fails for py32

___________________________________________________________________________________ summary ____________________________________________________________________________________
ERROR:   py32: commands failed
  py26: commands succeeded
  py27: commands succeeded
  cover: commands succeeded

Some kind of problem with zc.buildout where it installs 2.0.0a2 (Python 3 compatible) but also the older (non Python 3 compatible) 1.6.3 version.

py32 runtests: commands[2]
Getting distribution for 'gp.vcsdevelop'.
warning: no previously-included files matching '*' found under directory 'docs/_build'
Got gp.vcsdevelop 2.2.3.
Getting distribution for 'zc.buildout'.
  File "build/bdist.macosx-10.6-intel/egg/zc/buildout/buildout.py", line 82
    print "Annotated sections"
                             ^
SyntaxError: invalid syntax

  File "build/bdist.macosx-10.6-intel/egg/zc/buildout/download.py", line 184
    except IOError, e:
                  ^
SyntaxError: invalid syntax

  File "build/bdist.macosx-10.6-intel/egg/zc/buildout/easy_install.py", line 927
    except pkg_resources.VersionConflict, err:
                                        ^
SyntaxError: invalid syntax

  File "build/bdist.macosx-10.6-intel/egg/zc/buildout/rmtree.py", line 57
    os.chmod (path, 0600)
                       ^
SyntaxError: invalid token

  File "build/bdist.macosx-10.6-intel/egg/zc/buildout/testing.py", line 65
    print open(path).read(),
             ^
SyntaxError: invalid syntax

  File "build/bdist.macosx-10.6-intel/egg/zc/buildout/testrecipes.py", line 13
    print "  %s=%r" % (option, value)
                  ^
SyntaxError: invalid syntax

  File "build/bdist.macosx-10.6-intel/egg/zc/buildout/tests.py", line 2975
    print 'downloaded', dist.version
                     ^
SyntaxError: invalid syntax

  File "/Users/marca/dev/git-repos/webtest/eggs/tmp2ubkn5/zc.buildout-1.6.3-py3.2.egg/zc/buildout/buildout.py", line 82
    print "Annotated sections"
                             ^
SyntaxError: invalid syntax

  File "/Users/marca/dev/git-repos/webtest/eggs/tmp2ubkn5/zc.buildout-1.6.3-py3.2.egg/zc/buildout/download.py", line 184
    except IOError, e:
                  ^
SyntaxError: invalid syntax

  File "/Users/marca/dev/git-repos/webtest/eggs/tmp2ubkn5/zc.buildout-1.6.3-py3.2.egg/zc/buildout/easy_install.py", line 927
    except pkg_resources.VersionConflict, err:
                                        ^
SyntaxError: invalid syntax

  File "/Users/marca/dev/git-repos/webtest/eggs/tmp2ubkn5/zc.buildout-1.6.3-py3.2.egg/zc/buildout/rmtree.py", line 57
    os.chmod (path, 0600)
                       ^
SyntaxError: invalid token

  File "/Users/marca/dev/git-repos/webtest/eggs/tmp2ubkn5/zc.buildout-1.6.3-py3.2.egg/zc/buildout/testing.py", line 65
    print open(path).read(),
             ^
SyntaxError: invalid syntax

  File "/Users/marca/dev/git-repos/webtest/eggs/tmp2ubkn5/zc.buildout-1.6.3-py3.2.egg/zc/buildout/testrecipes.py", line 13
    print "  %s=%r" % (option, value)
                  ^
SyntaxError: invalid syntax

  File "/Users/marca/dev/git-repos/webtest/eggs/tmp2ubkn5/zc.buildout-1.6.3-py3.2.egg/zc/buildout/tests.py", line 2975
    print 'downloaded', dist.version
                     ^
SyntaxError: invalid syntax

Got zc.buildout 2.0.0a2.
Upgraded:
  zc.buildout version 1.6.3;
restarting.
Generated script '/Users/marca/dev/git-repos/webtest/.tox/py32/bin/buildout'.
Traceback (most recent call last):
  File "/Users/marca/dev/git-repos/webtest/.tox/py32/bin/buildout", line 10, in <module>
    import zc.buildout.buildout
  File "/Users/marca/dev/git-repos/webtest/eggs/zc.buildout-1.6.3-py3.2.egg/zc/buildout/buildout.py", line 82
    print "Annotated sections"
                             ^
SyntaxError: invalid syntax
ERROR: InvocationError: '/Users/marca/dev/git-repos/webtest/.tox/py32/bin/buildout buildout:parts-directory=/Users/marca/dev/git-repos/webtest/.tox/py32/parts buildout:bin-directory=/Users/marca/dev/git-repos/webtest/.tox/py32/bin'
___________________________________________________________________________________ summary ____________________________________________________________________________________
ERROR:   py32: commands failed

WebTest 1.4.1: Test error

WebTest 1.4.0 passes all tests.
WebTest 1.4.1 has an error:

$ nosetests-2.7
Failure: ValueError (line 82 of the docstring for index.txt has inconsistent leading whitespace: '\r') ... ERROR
...
======================================================================
ERROR: Failure: ValueError (line 82 of the docstring for index.txt has inconsistent leading whitespace: '\r')
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/nose/plugins/manager.py", line 154, in generate
    for r in result:
  File "/usr/lib64/python2.7/site-packages/nose/plugins/doctests.py", line 287, in loadTestsFromFile
    filename=filename, lineno=0)
  File "/usr/lib64/python2.7/doctest.py", line 645, in get_doctest
    return DocTest(self.get_examples(string, name), globs,
  File "/usr/lib64/python2.7/doctest.py", line 659, in get_examples
    return [x for x in self.parse(string, name)
  File "/usr/lib64/python2.7/doctest.py", line 621, in parse
    self._parse_example(m, name, lineno)
  File "/usr/lib64/python2.7/doctest.py", line 691, in _parse_example
    lineno + len(source_lines))
  File "/usr/lib64/python2.7/doctest.py", line 777, in _check_prefix
    (lineno+i+1, name, line))
ValueError: line 82 of the docstring for index.txt has inconsistent leading whitespace: '\r'

Name               Stmts   Miss  Cover   Missing
------------------------------------------------
webtest               18      0   100%   
webtest.app          964    169    82%   40, 67-68, 98-106, 119, 223-232, 255, 273, 275-276, 279-283, 358, 387, 404-407, 411, 437, 441-443, 447-449, 470, 478, 486, 488, 502-516, 529-546, 561-579, 591-598, 609-619, 639, 676-679, 746, 807, 995, 1008, 1013, 1019, 1023, 1057, 1059, 1109-1110, 1113-1118, 1126-1127, 1137, 1144-1149, 1164, 1220, 1230, 1233, 1267, 1291, 1358, 1360, 1384, 1389, 1599, 1661-1665, 1672-1682, 1689-1691, 1720, 1737, 1758-1761, 1778-1780, 1788-1806, 1816-1818, 1835, 1837
webtest.compat       100     58    42%   5-36, 54-55, 61-67, 82, 88-89, 94-97, 101-102, 107-118
webtest.debugapp      37      4    89%   10-16, 60
webtest.ext           81     11    86%   57-58, 64, 68, 96-105
webtest.lint         191     35    82%   164, 202-204, 207-212, 215-219, 222, 231-232, 235, 238-239, 242, 251-252, 258, 262, 295, 299, 323, 347, 394, 446-449, 470
webtest.lint3        206    157    24%   149-190, 196, 199-202, 205-207, 210-215, 218-222, 225, 231, 234-235, 238, 241-242, 245, 251, 254-255, 261, 265, 271-274, 277, 280-291, 296-298, 301-304, 309-368, 374-375, 381-382, 388-397, 404-438, 444-468, 472, 481-484, 492
webtest.sel          572    369    35%   39-43, 48-49, 74-88, 98-118, 130, 136, 161-163, 166-168, 174-175, 178-201, 204-211, 229-240, 245, 249, 252-268, 272-306, 310-331, 335-349, 359-369, 374-379, 383, 387, 390-396, 401-403, 408, 436-438, 441-448, 452, 456-461, 465, 469-470, 474, 478, 482, 486, 489, 492-501, 514-524, 527-529, 532, 536, 539, 547, 550, 559-560, 564, 568, 572, 577, 582, 586-588, 591, 604-609, 620, 623, 626, 637-640, 643-646, 649-650, 661-664, 667-686, 712-721, 724-732, 759, 764, 776, 779, 788-798, 801-806, 814-823, 847-858, 862, 865, 890, 893, 904-907, 911-915, 919-932, 948, 961-974
------------------------------------------------
TOTAL               2169    803    63%   
----------------------------------------------------------------------
Ran 58 tests in 1.771s

FAILED (errors=1)

Setting charset for all requests & responses

Hi, I'm using webtest to automate some steps on an external server. Since the server only speaks Windows-1252 it would be great if I could set the charset or content_type on initialization of TestApp.

Currently I'm setting charset for each response individually, which is really tedious and too verbose. Did I overlook something and there is already a better way to do it?

Any help is highly appreciated!

Unicode cookie string is not supported

George Fox:

with unicode cookie set from Bottle.py web framework.
I started to get an error: "AttributeError: 'unicode' object has no attribute 'items'".

I figured out an issue & monkeypatched it.

[FIX AT WEBTEST'S APP.PY LINE 1122]
Instead of this code:

c = SimpleCookie(header)
I made additional check for unicode:

if type(header) == unicode:
    header = header.encode("utf8")

c = SimpleCookie(header)
Regards, George.

URL: https://bitbucket.org/ianb/webtest/issue/47/unicode-cookie-string-is-not-supported

HTML5 form support

Anonymous:

HTML5 adds a new attribute to input tags, named "form":
( see http://dev.w3.org/html5/spec/single-page.html#form-associated-element ).
If an input has a "form" attribute, webtest breaks when one
accesses response.forms:

TypeError: init() got multiple values for keyword argument 'form'

(this is on line 1563 of app.py in webtest 1.4.0)

The problem is actually on line 1206, which includes a positional arg called
'form'. An attribute named 'form' will now be passed in attrs, causing the
conflict.

def init(self, form, tag, name, pos, value=None, id=None, attrs):

Iwan Vosloo:

I guess supporting form-associated elements is actually a slightly bigger issue
than that conflicting kwarg... WebTest would have to make sure it collects all
the inputs of a particular form - including those that are associated with the
form but located elsewhere.

URL: https://bitbucket.org/ianb/webtest/issue/45/html5-form-associated-inputs-break-webtest

Namespace in XHTML

kvdb:

I'm using selenium with webtest. I was expecting this to work:
doc.get('input', name='email')
After a while, I found out, it didn't because of the webpage was
XHTML. So, including namespace 'x' works:

doc.xpath('x:input[@name="email"]')

It would be nice if there was a way for me to set the prefix just
once and forget about it.

This would also allow me to use the helper functions like:
doc.input(name="email")

URL: https://bitbucket.org/ianb/webtest/issue/34/namespace-in-xhtml

Cannot specify custom json serializer

There seems to be no way to specify a custom JSON serializer. I would like to suggest perhaps adding the ability to configure a custom serializer.

Multiple submit buttons do not work

I have a form with multiple submit buttons. Webtest finds them correctly:

(Pdb) pp self.get(name='action', index=0).__dict__
{'_value': u'previous',
 'attrs': {'class': u'previous button', 'type': u'submit'},
 'form': <Form />,
 'id': None,
 'name': u'action',
 'pos': 9210,
 'tag': u'button'}
(Pdb) pp self.get(name='action', index=1).__dict__
{'_value': u'next',
 'attrs': {'class': u'default next button', 'type': u'submit'},
 'form': <Form />,
 'id': None,
 'name': u'action',
 'pos': 9367,
 'tag': u'button'}

I try to submit using the first button:

form.submit(name='action', index=0)

Which should trigger the previous-button. This does not happen though: Webtest submit all button values:

-> fields = self.submit_fields(name, index=index)
(Pdb) pp fields
[(u'csrf_token', u'5c097ab965cb7559f319138d046213c04833d7be'),
 (u'action', u'previous'),
 (u'action', u'next')]

This appears to be caused by a bug in submit_fields: it does not update current_index correctly when it hits a match, which results in current_index getting out of sync.

Setting body in app.request() causes AttributeError

When doing a request with method='POST' and setting a body all tests fail with:

AttributeError: 'InputWrapper' object has no attribute 'seek'

This comes from body being set on the request and then made seekable:
https://github.com/Pylons/webob/blob/master/webob/request.py#L694

Then do_request sets the lint middleware:
https://github.com/Pylons/webtest/blob/master/webtest/app.py#L464

Lint wraps wsgi.input with it's own helper:
https://github.com/Pylons/webtest/blob/master/webtest/lint.py#L195

However lint's input wrapper does not support seeking and webob still has the body marked as seekable, hence the error.

Workarounds for now are:

  • use body_file=io.BytesIO(body) in the request
  • set environ['wsgi.input'] = io.BytesIO(body) in the environment.

Test case showing issue:
https://gist.github.com/ianjosephwilson/5617417

int & files in a form

The integer on a field don't seem to work when a file is uploaded. I was using django-webtest but the crash occurs in webtest and it seems to be the source of that small bug:

copied from here: django-webtest/django-webtest#18

I used to have a form like this with the test passing:
form = response.form
form['structure-total_number_of_employees'] = 50
...
response = form.submit()

Then when I've added a file to that and updated my code:
form = response.form
form['logo'] = ...
form['structure-total_number_of_employees'] = 50
...
response = form.submit()

It crashed with the following error:
virtual_env/dev_env/lib/python2.7/site-packages/webtest/app.py", line 382, in encode_multipart
body = b'\r\n'.join(lines)
TypeError: sequence item 12: expected string, int found

To get it to work, I've replaced 50 by "50":
form = response.form
form['logo'] = ...
form['structure-total_number_of_employees'] = "50"
...
response = form.submit()

I reckon that the encode multipart should be updated to handle integers.

Thanks !

webtest.http.StopableWSGIServer broken with waitress 0.8.4

waitress 0.8.4 turns WSGIServer into a factory function, so webtest.http.StopableWSGIServer can no longer subclass it. Presumably it should now subclass TcpWSGIServer instead and create the adjustments in its init. It all seems a little messy, I wonder if there is a better way.

CC'ing @kgaughan in case he has a better idea.

Webtest - testing forms, on form.submit() forgets the user

Consider following test:

def test_form_no_gifs(self):
        url = self.a.url_to('create_form')
        r = self.app.get(url, user=self.u1)
        form = r.forms[0]

        form['name'] = 'Test 2'
        form['img'] = Upload(settings.PROJECT_ROOT + '/static/img/test.gif')
        r2 = form.submit()
        assert 'has-error' in r2

The view is login protected. On get everything is ok, on post (r2) the user is anonymous and i get a redirect back to login view.

Running same test with following fix:

def test_form_no_gifs(self):
        url = self.a.url_to('create_form')
        r = self.app.get(url, user=self.u1)
        form = r.forms[0]

        form['name'] = 'Test 2'
        form['img'] = Upload(settings.PROJECT_ROOT + '/static/img/test.gif')
        r2 = form.submit(user=self.u1)
        assert 'has-error' in r2

And everything is ok.

Using django-webtest==1.7.5, WebOb==1.3.1, WebTest==2.0.10, django-nose==1.2, nose==1.3.0, django==1.6.1.

Update jenkins job

The tox.ini file has been changed and needs the Jenkins job to be updated :

  • The script should not pass the '--xunit' switch anymore (it seems to be already ok but just in case)
  • The nosetests xml output are now nosetests-pyXX.xml, so the test files pattern may need to be changed accordingly (nosetests.xml -> nosetests-*.xml)

We also enabled tests with pypy, and it seems we cannot have lxml to install properly. What is the installed version of pypy ? if < 1.9 could it be upgraded ?

Thanks,

Christophe

Params are being parsed properly!

I have written a very small test-case using Bottle and unittest:

sample_app.py

from bottle import Bottle, response, request

sample_app = Bottle()

@sample_app.route('/api/foo')
def foo():
    return dict(request.query)

if __name__ == '__main__':
    sample_app.run()

test_sample_app.py

from sample_app import sample_app
from webtest import TestApp
from unittest import TestCase, main as unittest_main


class TestSampleApp(TestCase):
    def setUp(self):
        self.app = TestApp(sample_app)

    def test_foo(self):
        self.assertEqual(self.app.get('/api/foo', params={'foo':'bar'}
                                      ).json,
                         {'foo': 'bar'})

if __name__ == '__main__':
    unittest_main()

Allow developers to define TestRequest URL params and body separately

Webtest seems to confuse URL parameters and body content when creating JSON requests.

For example:

# Test GET /api/photos?id=10
response = self.testapp.get('/api/photos/', {'id': 10})

# If I want to test PUT /api/photos?id=10 I have to do this:
response = self.testapp.put_json('/api/photos?id=10', {'title': 'Different title'})
# Because the following will PUT to /api/photos and will serialize id=10 in the JSON body.
response = self.testapp.put_json('/api/photos', {'id': 10, 'title': 'Different title'})

In my request handlers, request.get and request.json.get are not equivalent. Example:

def put(self):
  # Get the id from the URL params.
  id_param = self.request.get('id')
  # Get the id from the JSON body.
  id_val = self.request.json.get('id')

It'd be fantastic if webtest supported both as separate options.

response = self.testapp.put_json(url, params, body, headers, *args, **kwargs)

Python 3.3 and PyPy 2.0 beta1 tests are failing on Mac OS X

It seems they are failing because of BeautifulSoup. The exception is

======================================================================
ERROR: test_too_many_forms (tests.test_response.TestResponse)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/kmike/svn/webtest/tests/test_response.py", line 282, in test_too_many_forms
    resp, 'form'
  File "/Users/kmike/svn/webtest/.tox/py33/lib/python3.3/site-packages/unittest2/case.py", line 490, in assertRaises
    callableObj(*args, **kwargs)
  File "/Users/kmike/svn/webtest/webtest/response.py", line 52, in form
    forms_ = self.forms
  File "/Users/kmike/svn/webtest/webtest/response.py", line 42, in forms
    self._parse_forms()
  File "/Users/kmike/svn/webtest/webtest/response.py", line 75, in _parse_forms
    form_texts = [str(f) for f in self.html('form')]
  File "/Users/kmike/svn/webtest/webtest/response.py", line 406, in html
    soup = BeautifulSoup(self.testbody)
  File "/Users/kmike/svn/webtest/.tox/py33/lib/python3.3/site-packages/bs4/__init__.py", line 172, in __init__
    self._feed()
  File "/Users/kmike/svn/webtest/.tox/py33/lib/python3.3/site-packages/bs4/__init__.py", line 185, in _feed
    self.builder.feed(self.markup)
  File "/Users/kmike/svn/webtest/.tox/py33/lib/python3.3/site-packages/bs4/builder/_lxml.py", line 194, in feed
    self.parser.feed(markup)
  File "parser.pxi", line 1105, in lxml.etree._FeedParser.feed (src/lxml/lxml.etree.c:88059)
lxml.etree.ParserError: Unicode parsing is not supported on this platform

(and there are 43 such exceptions both for Python 3.3 and PyPy 2.0). I tried to replace

soup = BeautifulSoup(self.testbody) with soup = BeautifulSoup(self.body), but this doesn't help.

Functional test warning when app uses SQLAlchemy and binds engine

Anonymous:

I'm getting the following warning:
SAWarning: At least one scoped session is already present.
configure() can not affect sessions that have already been created.

The Warning is raised when TestApp.post() or .get() is called
for the SECOND time in the life of entire test, but only once. The
warning is raised at the second of these two lines of code:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) DBSession.configure(bind=engine)

This code is called ONCE per application startup (per default
Pyramid pyramid_routesalchemy template setup).

URL: https://bitbucket.org/ianb/webtest/issue/27/functional-test-warning-when-app-uses

Certain quote characters are not decoded

ianjosephwilson:

Using html5 or html4 strict the following character within a
textarea is not decoded when using resp.forms[0].submit(): "&#39;"
This code I think needs to be extended: https://bitbucket.org/ianb/webtest/src/86b89134ec1b/webtest/app.py#cl-1813

I will try to include more information. I'm not sure if the best
approach is using a more well rounded dependency or
extending that function in webtest itself.

This can be worked around by not using submit and rather
running through all the fields and decoding the value of
textareas specifically for these types of entities and then
submitting a POST request.

URL: https://bitbucket.org/ianb/webtest/issue/46/certain-quote-characters-are-not-decoded

form test failures

I get multiple test failures on Python 2.6.2 related to forms processing with a typical traceback:

....

======================================================================
ERROR: test_single_select_forced_value (tests.test_forms.TestSelect)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/users/is/skolesnik/webtest/WebTest-v2.0.6/WebTest-2.0.6/tests/test_forms.py", line 502, in test_single_select_forced_value
    single_form = res.forms["single_select_form"]
  File "/users/is/skolesnik/webtest/WebTest-v2.0.6/WebTest-2.0.6/webtest/response.py", line 42, in forms
    self._parse_forms()
  File "/users/is/skolesnik/webtest/WebTest-v2.0.6/WebTest-2.0.6/webtest/response.py", line 77, in _parse_forms
    form = forms.Form(self, text)
  File "/users/is/skolesnik/webtest/WebTest-v2.0.6/WebTest-2.0.6/webtest/forms.py", line 367, in __init__
    self._parse_fields()
  File "/users/is/skolesnik/webtest/WebTest-v2.0.6/WebTest-2.0.6/webtest/forms.py", line 414, in _parse_fields
    field = FieldClass(self, tag, name, pos, **attrs)
TypeError: __init__() keywords must be strings

...
----------------------------------------------------------------------
Ran 162 tests in 8.353s

FAILED (errors=37)

It is happening because BeautifulSoup returns form attributes as a dict where both keys and values are unicode strings. This dict is then attempted to be exploded as kwargs to a function, which fails on Python<3. Is it a known incompatibility or a bug?

Test environment is RHEL5 plus Python 2.6.2. pip freeze returns:

distribute==0.6.36
beautifulsoup4==4.2.1
coverage==3.5.3
cssselect==0.7.1
lxml==2.3.6
mock==1.0.1
nose=1.3.0
ordereddict==1.1
PasteDeploy==1.5.0
pyquery==1.2.4
six==1.3.0
unittest2==0.5.1
waitress==0.8.1
WebOb==1.2.3
WSGIProxy2==0.2

Any ideas?

tox produces errors under 3.2 and 2.6

Currently running tox produces failures even with "the right" software installed (enough to compile lxml).

For Python 3.2, It wants a nonexistent buildout-py3k.cfg.

The Python 2.6 tests fail while installing like so:

Generated script '/home/chrism/projects/webtest/bin/nosetests'.
Generated interpreter '/home/chrism/projects/webtest/bin/python'.
Installing casperjs.
While:
  Installing casperjs.

An internal error occurred due to a bug in either zc.buildout or in a
recipe being used:
Traceback (most recent call last):
  File "/home/chrism/projects/webtest/.tox/py2.6/lib/python2.6/site-packages/zc/buildout/buildout.py", line 1852, in main
    getattr(buildout, command)(args)
  File "/home/chrism/projects/webtest/.tox/py2.6/lib/python2.6/site-packages/zc/buildout/buildout.py", line 618, in install
    installed_files = self[part]._call(recipe.install)
  File "/home/chrism/projects/webtest/.tox/py2.6/lib/python2.6/site-packages/zc/buildout/buildout.py", line 1327, in _call
    return f()
  File "/home/chrism/projects/webtest/eggs/gp.recipe.phantomjs-1.7.0-py2.6.egg/gp/recipe/phantomjs/__init__.py", line 46, in install
    raise RuntimeError('Please specify a phantomjs-url')
RuntimeError: Please specify a phantomjs-url
ERROR: InvocationError: '/home/chrism/projects/webtest/.tox/py2.6/bin/buildout -c /home/chrism/projects/webtest/.tox/../buildout.cfg'

The tox-invoked Python 2.7 tests do pass.

TestApp._get_request does not use the Request's charset

app = TestApp(app)
app.post('/', params=u'Sébastien'')

TestApp._get_request will invoke to_bytes on the params which encodes it using latin1 while the resulting request instance has a default charset of utf-8.

Instead, _get_request should convert params based on request.charset to avoid this incongruity.

Expiring cookies is broken

6a2fb2a doesn't work at all, and there's no code coverage for someone doing self.cookies["whatever"] = foo so nothing is failing.

More broadly though, this isn't the right way to do this. We should strip out the cookie handling in TestApp and use cookielib.CookieJar but we need to check that:

  1. CookieJar.make_cookies expects Request objects with particular interfaces, so hopefully webob.Request satisfies that.
  2. it doesn't allow passing in a now function to mock out the date during expiry, which is pretty essential

I'll probably work on this in the next few days, so you can assign this to me if that's a thing you guys do on your issue tracker.

TestApp.delete causes spurious warning

webtest/app.py:550: WSGIWarning: You are not supposed to send a body in a DELETE request. Most web servers will ignore it

This is caused by a test that checks if params is not NoDefault, but the default value is u'' instead of NoDefault.

(Side note: using the stacklevel param of warnings.warn will cause the traceback to show the line that called the function, not the line of the function that calls warn).

Shortcut for ajax requests

As a user I want to have a self descriptive shortcut like self.app.get_ajax() instead of self.app.get(headers={'X-Requested-With': 'XMLHttpRequest', }). Can I add this shotcut for all type of request?

Get a list of Element using get()/xpath() in Selenium tests

It would be nice to get a list of Elements or an iterator instead of just one element. A simple usecase:

for error_span in doc.xpath('//x:span[contains(@Class, "error")]'):
hoover = error_span.mouseOver()
...

Also, there's no easy way to assert there are 4 elements in the list currently.

http.py tests sometimes fail

FAIL: test_shutdown_non_running (tests.test_http.TestBrokenServer)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ielectric/code/webtest/tests/test_http.py", line 57, in test_shutdown_non_running
    self.assertFalse(s.wait(retries=1))
AssertionError: True is not False
    'True is not False' = self._formatMessage('True is not False', "%s is not False" % safe_repr(True))
>>  raise self.failureException('True is not False')


======================================================================
FAIL: test_server (tests.test_http.TestServer)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ielectric/code/webtest/tests/test_http.py", line 18, in test_server
    '/__application__'))
AssertionError: 200 != 0
    '200 != 0' = '%s != %s' % (safe_repr(200), safe_repr(0))
    '200 != 0' = self._formatMessage('200 != 0', '200 != 0')
>>  raise self.failureException('200 != 0')

Cookie support still lacks tests, has different behavior than the last release

A few things still need addressing:

  • Request support for cookies was accidentally dropped. So no cookies are ever actually being sent
  • TestApp.cookies now returns keys : Cookie objects, when it should return keys : Cookie.values
  • TestApp should probably allow accepting a CookieJar to __init__ since otherwise there is no way in a test to get the CookieJar to sanely ignore things like domain that may differ in the tests.
  • It may need re-looking at to see if expiry is easily accessible/stubbable but due to ^ I can't yet test this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.