# `webtest` API

Routines for testing WSGI applications.

## `webtest.app.TestApp`

class webtest.app.TestApp(app, extra_environ=None, relative_to=None, use_unicode=True, cookiejar=None, parser_features=None, json_encoder=None, lint=True)

  Wraps a WSGI application in a more convenient interface for testing. It uses extended version of `webob.BaseRequest` and `webob.Response`.

  Parameters:

    - app (WSGI application) --

      May be an WSGI application or Paste Deploy app, like `'config:filename.ini#test'`.

      Added in version 2.0.

      It can also be an actual full URL to an http server and webtest will proxy requests with WSGIProxy2.

    - extra_environ (dict) -- A dictionary of values that should go into the environment for each request. These can provide a communication channel with the application.

    - relative_to (string) -- A directory used for file uploads are calculated relative to this. Also `config:` URIs that aren't absolute.

    - cookiejar (CookieJar instance) -- `cookielib.CookieJar` alike API that keeps cookies across requests.

  cookies

    A convenient shortcut for a dict of all cookies in `cookiejar`.

  Parameters:

    - parser_features (string or list) -- Passed to BeautifulSoup when parsing responses.

    - json_encoder (A subclass of json.JSONEncoder) -- Passed to json.dumps when encoding json

    - lint (A boolean) -- If True (default) then check that the application is WSGI compliant

  RequestClass

    alias of `TestRequest`

  property authorization

    Allow to set the HTTP_AUTHORIZATION environ key. Value should look like one of the following:

    - `('Basic', ('user', 'password'))`

    - `('Bearer', 'mytoken')`

    - `('JWT', 'myjwt')`

    If value is None the the HTTP_AUTHORIZATION is removed

  delete(url, params='', headers=None, extra_environ=None, status=None, expect_errors=False, content_type=None, xhr=False)

    Do a DELETE request. Similar to `get()`.

    Returns:

      `webtest.TestResponse` instance.

  delete_json(url, params=<NoDefault>, **kw)

    Do a DELETE request. Very like the `delete` method.

    `params` are dumped to json and put in the body of the request. Content-Type is set to `application/json`.

    Returns a `webtest.TestResponse` object.

  do_request(req, status=None, expect_errors=None)

    Executes the given webob Request (`req`), with the expected `status`. Generally `get()` and `post()` are used instead.

    To use this:

        req = webtest.TestRequest.blank('url', ...args...)
        resp = app.do_request(req)

    Note

    You can pass any keyword arguments to `TestRequest.blank()`, which will be set on the request. These can be arguments like `content_type`, `accept`, etc.

  encode_multipart(params, files)

    Encodes a set of parameters (typically a name/value list) and a set of files (a list of (name, filename, file_body, mimetype)) into a typical POST body, returning the (content_type, body).

  get(url, params=None, headers=None, extra_environ=None, status=None, expect_errors=False, xhr=False)

    Do a GET request given the url path.

    Parameters:

      - params -- A query string, or a dictionary that will be encoded into a query string. You may also include a URL query string on the `url`.

      - headers (dictionary) -- Extra headers to send.

      - extra_environ (dictionary) -- Environmental variables that should be added to the request.

      - status (integer or string) -- The HTTP status code you expect in response (if not 200 or 3xx). You can also use a wildcard, like `'3*'` or `'*'`.

      - expect_errors (boolean) -- If this is False, then if anything is written to environ `wsgi.errors` it will be an error. If it is True, then non-200/3xx responses are also okay.

      - xhr (boolean) -- If this is true, then marks response as ajax. The same as headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }

    Returns:

      `webtest.TestResponse` instance.

  get_authorization()

    Allow to set the HTTP_AUTHORIZATION environ key. Value should look like one of the following:

    - `('Basic', ('user', 'password'))`

    - `('Bearer', 'mytoken')`

    - `('JWT', 'myjwt')`

    If value is None the the HTTP_AUTHORIZATION is removed

  head(url, params=None, headers=None, extra_environ=None, status=None, expect_errors=False, xhr=False)

    Do a HEAD request. Similar to `get()`.

    Returns:

      `webtest.TestResponse` instance.

  options(url, headers=None, extra_environ=None, status=None, expect_errors=False, xhr=False)

    Do a OPTIONS request. Similar to `get()`.

    Returns:

      `webtest.TestResponse` instance.

  patch(url, params='', headers=None, extra_environ=None, status=None, upload_files=None, expect_errors=False, content_type=None, xhr=False)

    Do a PATCH request. Similar to `post()`.

    Returns:

      `webtest.TestResponse` instance.

  patch_json(url, params=<NoDefault>, **kw)

    Do a PATCH request. Very like the `patch` method.

    `params` are dumped to json and put in the body of the request. Content-Type is set to `application/json`.

    Returns a `webtest.TestResponse` object.

  post(url, params='', headers=None, extra_environ=None, status=None, upload_files=None, expect_errors=False, content_type=None, xhr=False)

    Do a POST request. Similar to `get()`.

    Parameters:

      - params --

        Are put in the body of the request. If params is an iterator, it will be urlencoded. If it is a string, it will not be encoded, but placed in the body directly.

        Can be a `python:collections.OrderedDict` with `webtest.forms.Upload` fields included:

            app.post('/myurl', collections.OrderedDict([
                ('textfield1', 'value1'),
                ('uploadfield', webapp.Upload('filename.txt', 'contents'),
                ('textfield2', 'value2')])))

      - upload_files (list) -- It should be a list of `(fieldname, filename, file_content)`. You can also use just `(fieldname, filename)` and the file contents will be read from disk.

      - content_type (string) -- HTTP content type, for example application/json.

      - xhr (boolean) -- If this is true, then marks response as ajax. The same as headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }

    Returns:

      `webtest.TestResponse` instance.

  post_json(url, params=<NoDefault>, **kw)

    Do a POST request. Very like the `post` method.

    `params` are dumped to json and put in the body of the request. Content-Type is set to `application/json`.

    Returns a `webtest.TestResponse` object.

  put(url, params='', headers=None, extra_environ=None, status=None, upload_files=None, expect_errors=False, content_type=None, xhr=False)

    Do a PUT request. Similar to `post()`.

    Returns:

      `webtest.TestResponse` instance.

  put_json(url, params=<NoDefault>, **kw)

    Do a PUT request. Very like the `put` method.

    `params` are dumped to json and put in the body of the request. Content-Type is set to `application/json`.

    Returns a `webtest.TestResponse` object.

  request(url_or_req, status=None, expect_errors=False, **req_params)

    Creates and executes a request. You may either pass in an instantiated `TestRequest` object, or you may pass in a URL and keyword arguments to be passed to `TestRequest.blank()`.

    You can use this to run a request without the intermediary functioning of `TestApp.get()` etc. For instance, to test a WebDAV method:

        resp = app.request('/new-col', method='MKCOL')

    Note that the request won't have a body unless you specify it, like:

        resp = app.request('/test.txt', method='PUT', body='test')

    You can use `webtest.TestRequest`:

        req = webtest.TestRequest.blank('/url/', method='GET')
        resp = app.do_request(req)

  reset()

    Resets the state of the application; currently just clears saved cookies.

  set_cookie(name, value)

    Sets a cookie to be passed through with requests.

  set_parser_features(parser_features)

    Changes the parser used by BeautifulSoup. See its documentation to know the supported parsers.

## `webtest.app.TestRequest`

class webtest.app.TestRequest(environ, charset=None, unicode_errors=None, decode_param_names=None, **kw)

  Bases: `BaseRequest`

  A subclass of webob.Request

  ResponseClass

    alias of `TestResponse`

## `webtest.response.TestResponse`

class webtest.response.TestResponse(body=None, status=None, headerlist=None, app_iter=None, content_type=None, conditional_response=None, charset=<object object>, **kw)

  Bases: `Response`

  Instances of this class are returned by `TestApp` methods.

  PyQuery(**kwargs)

    Same as pyquery but allow to pass arguments to initialize the PyQuery instance:

        pq = resp.PyQuery(parser='xml', remove_namespaces=True)

  click(description=None, linkid=None, href=None, index=None, verbose=False, extra_environ=None)

    Click the link as described. Each of `description`, `linkid`, and `url` are patterns, meaning that they are either strings (regular expressions), compiled regular expressions (objects with a `search` method), or callables returning true or false.

    All the given patterns are ANDed together:

    - `description` is a pattern that matches the contents of the anchor (HTML and all -- everything between `<a...>` and `</a>`)

    - `linkid` is a pattern that matches the `id` attribute of the anchor. It will receive the empty string if no id is given.

    - `href` is a pattern that matches the `href` of the anchor; the literal content of that attribute, not the fully qualified attribute.

    If more than one link matches, then the `index` link is followed. If `index` is not given and more than one link matches, or if no link matches, then `IndexError` will be raised.

    If you give `verbose` then messages will be printed about each link, and why it does or doesn't match. If you use `app.click(verbose=True)` you'll see a list of all the links.

    You can use multiple criteria to essentially assert multiple aspects about the link, e.g., where the link's destination is.

  clickbutton(description=None, buttonid=None, href=None, onclick=None, index=None, verbose=False)

    Like `click()`, except looks for link-like buttons. This kind of button should look like `<button onclick="...location.href='url'...">`.

  follow(**kw)

    If this response is a redirect, follow that redirect. It is an error if it is not a redirect response. Any keyword arguments are passed to `webtest.app.TestApp.get`. Returns another `TestResponse` object.

  property form

    If there is only one form on the page, return it as a `Form` object; raise a TypeError is there are no form or multiple forms.

  property forms

    Returns a dictionary containing all the forms in the pages as `Form` objects. Indexes are both in order (from zero) and by form id (if the form is given an id).

    See Form handling for more info on form objects.

  goto(href, method='get', **args)

    Go to the (potentially relative) link `href`, using the given method (`'get'` or `'post'`) and any extra arguments you want to pass to the `webtest.app.TestApp.get()` or `webtest.app.TestApp.post()` methods.

    All hostnames and schemes will be ignored.

  property html

    Returns the response as a BeautifulSoup object.

    Only works with HTML responses; other content-types raise AttributeError.

  property json

    Return the response as a JSON response. The content type must be one of json type to use this.

  property lxml

    Returns the response as an lxml object. You must have lxml installed to use this.

    If this is an HTML response and you have lxml 2.x installed, then an `lxml.html.HTML` object will be returned; if you have an earlier version of lxml then a `lxml.HTML` object will be returned.

  maybe_follow(**kw)

    Follow all redirects. If this response is not a redirect, do nothing. Any keyword arguments are passed to `webtest.app.TestApp.get`. Returns another `TestResponse` object.

  mustcontain(*strings, no=[])

    Assert that the response contains all of the strings passed in as arguments.

    Equivalent to:

        assert string in res

    Can take a no keyword argument that can be a string or a list of strings which must not be present in the response.

  property normal_body

    Return the whitespace-normalized body

  property pyquery

    Returns the response as a PyQuery object.

    Only works with HTML and XML responses; other content-types raise AttributeError.

  showbrowser()

    Show this response in a browser window (for debugging purposes, when it's hard to read the HTML).

  property unicode_normal_body

    Return the whitespace-normalized body, as unicode

  property xml

    Returns the response as an `ElementTree` object.

    Only works with XML responses; other content-types raise AttributeError

## `webtest.forms`

Helpers to fill and submit forms.

class webtest.forms.Checkbox(*args, **attrs)

  Bases: `Field`

  Field representing `<input type="checkbox">`

  checked

    Returns True if checkbox is checked.

  force_value(value)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.Email(form, tag, name, pos, value=None, id=None, **attrs)

  Bases: `Field`

  Field representing `<input type="email">`

  force_value(value)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.Field(form, tag, name, pos, value=None, id=None, **attrs)

  Bases: `object`

  Base class for all Field objects.

  classes

    Dictionary of field types (select, radio, etc)

  value

    Set/get value of the field.

  force_value(value)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.File(form, tag, name, pos, value=None, id=None, **attrs)

  Bases: `Field`

  Field representing `<input type="file">`

  force_value(value)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.Form(response, text, parser_features='html.parser')

  Bases: `object`

  This object represents a form that has been found in a page.

  Parameters:

    - response -- webob.response.TestResponse instance

    - text -- Unparsed html of the form

  text

    the full HTML of the form.

  action

    the relative URI of the action.

  method

    the HTTP method (e.g., `'GET'`).

  id

    the id, or None if not given.

  enctype

    encoding of the form submission

  fields

    a dictionary of fields, each value is a list of fields by that name. `<input type="radio">` and `<select>` are both represented as single fields with multiple options.

  field_order

    Ordered list of field names as found in the html.

  FieldClass

    alias of `Field`

  get(name, index=None, default=<NoDefault>)

    Get the named/indexed field object, or `default` if no field is found. Throws an AssertionError if no field is found and no `default` was given.

  lint()

    Check that the html is valid:

    - each field must have an id

    - each field must have a label

  select(name, value=None, text=None, index=None)

    Like `.set()`, except also confirms the target is a `<select>` and allows selecting options by text.

  select_multiple(name, value=None, texts=None, index=None)

    Like `.set()`, except also confirms the target is a `<select multiple>` and allows selecting options by text.

  set(name, value, index=None)

    Set the given name, using `index` to disambiguate.

  submit(name=None, index=None, value=None, **args)

    Submits the form. If `name` is given, then also select that button (using `index` or `value` to disambiguate)``.

    Any extra keyword arguments are passed to the `webtest.TestResponse.get()` or `webtest.TestResponse.post()` method.

    Returns a `webtest.TestResponse` object.

  submit_fields(name=None, index=None, submit_value=None)

    Return a list of `[(name, value), ...]` for the current state of the form.

    Parameters:

      - name -- Same as for `submit()`

      - index -- Same as for `submit()`

  upload_fields()

    Return a list of file field tuples of the form:

        (field name, file name)

    or:

        (field name, file name, file contents).

class webtest.forms.Hidden(form, tag, name, pos, value=None, id=None, **attrs)

  Bases: `Text`

  Field representing `<input type="hidden">`

  force_value(value)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.MultipleSelect(*args, **attrs)

  Bases: `Field`

  Field representing `<select multiple="multiple">`

  force_value(values)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.Radio(*args, **attrs)

  Bases: `Select`

  Field representing `<input type="radio">`

  force_value(value)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.Select(*args, **attrs)

  Bases: `Field`

  Field representing `<select />` form element.

  force_value(value)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.Submit(form, tag, name, pos, value=None, id=None, **attrs)

  Bases: `Field`

  Field representing `<input type="submit">` and `<button>`

  force_value(value)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.Text(form, tag, name, pos, value=None, id=None, **attrs)

  Bases: `Field`

  Field representing `<input type="text">`

  force_value(value)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.Textarea(form, tag, name, pos, value=None, id=None, **attrs)

  Bases: `Text`

  Field representing `<textarea>`

  force_value(value)

    Like setting a value, except forces it (even for, say, hidden fields).

class webtest.forms.Upload(filename, content=None, content_type=None)

  Bases: `object`

  A file to upload:

      >>> Upload('filename.txt', 'data', 'application/octet-stream')
      <Upload "filename.txt">
      >>> Upload('filename.txt', 'data')
      <Upload "filename.txt">
      >>> Upload("README.txt")
      <Upload "README.txt">

  Parameters:

    - filename -- Name of the file to upload.

    - content -- Contents of the file.

    - content_type -- MIME type of the file.

## `webtest.http`

This module contains some helpers to deal with the real http world.

class webtest.http.StopableWSGIServer(application, *args, **kwargs)

  Bases: `TcpWSGIServer`

  StopableWSGIServer is a TcpWSGIServer which run in a separated thread. This allow to use tools like casperjs or selenium.

  Server instance have an `application_url` attribute formatted with the server host and port.

  classmethod create(application, **kwargs)

    Start a server to serve `application`. Return a server instance.

  run()

    Run the server

  shutdown(debug: bool = False) → Literal[True]

    Shutdown the server

  wait(retries=30)

    Wait until the server is started

  wrapper(environ, start_response)

    Wrap the wsgi application to override some path:

    `/__application__`: allow to ping the server.

    `/__file__?__file__={path}`: serve the file found at `path`

webtest.http.check_server(host, port, path_info='/', timeout=3, retries=30)

  Perform a request until the server reply

## `webtest.lint`

Middleware to check for obedience to the WSGI specification.

Some of the things this checks:

- Signature of the application and start_response (including that keyword arguments are not used).

- Environment checks:

  - Environment is a dictionary (and not a subclass).

  - That all the required keys are in the environment: REQUEST_METHOD, SERVER_NAME, SERVER_PORT, wsgi.version, wsgi.input, wsgi.errors, wsgi.multithread, wsgi.multiprocess, wsgi.run_once

  - That HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH are not in the environment (these headers should appear as CONTENT_LENGTH and CONTENT_TYPE).

  - Warns if QUERY_STRING is missing, as the cgi module acts unpredictably in that case.

  - That CGI-style variables (that don't contain a .) have (non-unicode) string values

  - That wsgi.version is a tuple

  - That wsgi.url_scheme is 'http' or 'https' (@@: is this too restrictive?)

  - Warns if the REQUEST_METHOD is not known (@@: probably too restrictive).

  - That SCRIPT_NAME and PATH_INFO are empty or start with /

  - That at least one of SCRIPT_NAME or PATH_INFO are set.

  - That CONTENT_LENGTH is a positive integer.

  - That SCRIPT_NAME is not '/' (it should be '', and PATH_INFO should be '/').

  - That wsgi.input has the methods read, readline, readlines, and __iter__

  - That wsgi.errors has the methods flush, write, writelines

- The status is a string, contains a space, starts with an integer, and that integer is in range (> 100).

- That the headers is a list (not a subclass, not another kind of sequence).

- That the items of the headers are tuples of 'native' strings (i.e. bytestrings in Python2, and unicode strings in Python3).

- That there is no 'status' header (that is used in CGI, but not in WSGI).

- That the headers don't contain newlines or colons, end in _ or -, or contain characters codes below 037.

- That Content-Type is given if there is content (CGI often has a default content type, but WSGI does not).

- That no Content-Type is given when there is no content (@@: is this too restrictive?)

- That the exc_info argument to start_response is a tuple or None.

- That all calls to the writer are with strings, and no other methods on the writer are accessed.

- That wsgi.input is used properly:

  - .read() is called with zero or one argument

  - That it returns a string

  - That readline, readlines, and __iter__ return strings

  - That .close() is not called

  - No other methods are provided

- That wsgi.errors is used properly:

  - .write() and .writelines() is called with a string, except with python3

  - That .close() is not called, and no other methods are provided.

- The response iterator:

  - That it is not a string (it should be a list of a single string; a string will work, but perform horribly).

  - That .next() returns a string

  - That the iterator is not iterated over until start_response has been called (that can signal either a server or application error).

  - That .close() is called (doesn't raise exception, only prints to sys.stderr, because we only know it isn't called when the object is garbage collected).

webtest.lint.middleware(application, global_conf=None)

  When applied between a WSGI server and a WSGI application, this middleware will check for WSGI compliance on a number of levels. This middleware does not modify the request or response in any way, but will throw an AssertionError if anything seems off (except for a failure to close the application iterator, which will be printed to stderr -- there's no way to throw an exception at that point).

## `webtest.debugapp`

class webtest.debugapp.DebugApp(form=None, show_form=False)

  Bases: `object`

  The WSGI application used for testing

webtest.debugapp.make_debug_app(global_conf, **local_conf)

  An application that displays the request environment, and does nothing else (useful for debugging and test purposes).