### Install WebTest using easy_install Source: https://docs.pylonsproject.org/projects/webtest/en/latest/index.html Use easy_install to install the latest stable release of WebTest. ```bash $ easy_install WebTest ``` -------------------------------- ### Install WebTest using pip Source: https://docs.pylonsproject.org/projects/webtest/en/latest/index.html Use pip to install the latest stable release of WebTest. ```bash $ pip install WebTest ``` -------------------------------- ### Install WebTest using pip or easy_install Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/index.rst.txt Use pip or easy_install to install the latest stable release of WebTest. ```sh $ pip install WebTest $ easy_install WebTest ``` -------------------------------- ### Install and Run tox for Multi-Version Testing Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/contributing.rst.txt Install tox and use it to run tests across multiple Python versions. Ensure you have the required Python interpreters installed and available in your PATH. ```bash $ pip install tox $ tox ``` ```bash $ bin/tox ``` -------------------------------- ### Install WebTest development version Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/index.rst.txt Install the development version of WebTest directly from its GitHub repository. ```sh $ pip install https://nodeload.github.com/Pylons/webtest/tar.gz/main ``` -------------------------------- ### Initialize WebTest Debug App Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/forms.rst.txt Setup a test application instance for form testing. ```python >>> from webtest.debugapp import make_debug_app >>> from webtest.app import TestApp >>> app = make_debug_app({}, ... form='docs/form.html', ... show_form=True) >>> app = TestApp(app) ``` -------------------------------- ### Initialize TestApp with WSGI application Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/testapp.rst.txt Setup a TestApp instance using a sample WSGI application that handles various content types. ```python import json import sys from webtest.app import TestApp from webob import Request from webob import Response def application(environ, start_response): req = Request(environ) if req.path_info.endswith('.html'): content_type = 'text/html' body = '
hey!
'.encode('latin-1') elif req.path_info.endswith('.xml'): content_type = 'text/xml' body = 'hey!'.encode('latin-1') elif req.path_info.endswith('.json'): content_type = 'application/json' body = json.dumps({"a": 1, "b": 2}).encode('latin-1') elif '/resource/' in req.path_info: content_type = 'application/json' body = json.dumps(dict(id=1, value='value')).encode('latin-1') resp = Response(body, content_type=content_type) return resp(environ, start_response) app = TestApp(application) ``` -------------------------------- ### Perform GET Request Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html Executes a GET request with optional parameters, headers, and environment overrides. ```python def get(self, url, params=None, headers=None, extra_environ=None, status=None, expect_errors=False, xhr=False): """ Do a GET request given the url path. :param 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``. :param headers: Extra headers to send. :type headers: dictionary :param extra_environ: Environmental variables that should be added to the request. :type extra_environ: dictionary :param status: The HTTP status code you expect in response (if not 200 or 3xx). You can also use a wildcard, like ``'3*'`` or ``'*'``. :type status: integer or string :param expect_errors: 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. :type expect_errors: boolean :param xhr: ``` -------------------------------- ### Generate Documentation with Sphinx Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/contributing.rst.txt Install Sphinx and generate HTML documentation for the project. Navigate to the docs directory and use make html or sphinx-build. ```bash $ pip install Sphinx $ cd docs $ make html ``` ```bash ../bin/sphinx-build -b html -d _build/doctrees . _build/html ``` -------------------------------- ### Find a Free Port Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/http.html Use this function to get an available IP address and port for binding a socket. It's useful for dynamically starting servers without port conflicts. ```python import socket import os def get_free_port(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('', 0)) ip, port = s.getsockname() s.close() ip = os.environ.get('WEBTEST_SERVER_BIND', '127.0.0.1') return ip, port ``` -------------------------------- ### GET /path Source: https://docs.pylonsproject.org/projects/webtest/en/latest/testapp.html Performs a GET request to the specified path with optional parameters, headers, and environment variables. ```APIDOC ## GET /path ### Description Performs a GET request to the specified path. Returns a TestResponse object. ### Method GET ### Endpoint /path ### Parameters #### Query Parameters - **params** (dict) - Optional - Query parameters for the request - **headers** (dict) - Optional - HTTP headers - **extra_environ** (dict) - Optional - WSGI environment keys ### Response #### Success Response (200) - **TestResponse** (object) - A response object based on webob.response.Response ``` -------------------------------- ### Make HTTP requests Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/testapp.rst.txt Perform GET and POST requests using the TestApp instance. ```python app.get('/path', [params], [headers], [extra_environ], ...) ``` ```python app.post('/path', {'vars': 'values'}, [headers], [extra_environ], [upload_files], ...) ``` -------------------------------- ### Perform OPTIONS and HEAD Requests Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html Methods for executing OPTIONS and HEAD requests, mirroring the behavior of the standard GET method. ```python def options(self, url, headers=None, extra_environ=None, status=None, expect_errors=False, xhr=False): """ Do a OPTIONS request. Similar to :meth:`~webtest.TestApp.get`. :returns: :class:`webtest.TestResponse` instance. """ if xhr: headers = self._add_xhr_header(headers) return self._gen_request('OPTIONS', url, headers=headers, extra_environ=extra_environ, status=status, upload_files=None, expect_errors=expect_errors) ``` ```python def head(self, url, params=None, headers=None, extra_environ=None, status=None, expect_errors=False, xhr=False): """ Do a HEAD request. Similar to :meth:`~webtest.TestApp.get`. :returns: :class:`webtest.TestResponse` instance. """ if params: url = utils.build_params(url, params) if xhr: headers = self._add_xhr_header(headers) return self._gen_request('HEAD', url, headers=headers, extra_environ=extra_environ, status=status, upload_files=None, expect_errors=expect_errors) ``` -------------------------------- ### Perform GET request and check response status Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/index.rst.txt Make an HTTP GET request to the root path ('/') of the wrapped application and assert the response status code and string. ```python resp = app.get('/') assert resp.status == '200 OK' assert resp.status_int == 200 ``` -------------------------------- ### GET Request Method Source: https://docs.pylonsproject.org/projects/webtest/en/latest/api.html Performs a GET request. ```APIDOC ## GET Request ### `get(url, params=None, headers=None, extra_environ=None, status=None, expect_errors=False, xhr=False)` #### Description Do a GET request given the url path. #### Parameters - **url** (string) - Required - The URL path for the request. - **params** (string or dict) - Optional - 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** (dict) - Optional - Extra headers to send. - **extra_environ** (dict) - Optional - Environmental variables to add to the request. - **status** (integer or string) - Optional - The expected HTTP status code (if not 200 or 3xx). You can also use a wildcard, like `'3*'` or `'*'`. - **expect_errors** (boolean) - Optional - 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) - Optional - If this is true, then marks response as ajax. The same as headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }. #### Returns `webtest.TestResponse` instance. ``` -------------------------------- ### Perform a GET Request Source: https://docs.pylonsproject.org/projects/webtest/en/latest/api.html Performs a GET request to the specified URL. Supports query parameters, custom headers, and environment variables. ```python resp = app.get('/users', params={'limit': 10}, headers={'X-Custom': 'value'}) ``` -------------------------------- ### Perform an OPTIONS Request Source: https://docs.pylonsproject.org/projects/webtest/en/latest/api.html Performs an OPTIONS request to the specified URL. Similar to the get() method. ```python resp = app.options('/users') ``` -------------------------------- ### Test Across Python Versions with Tox Source: https://docs.pylonsproject.org/projects/webtest/en/latest/contributing.html Install and execute tests across multiple Python versions using tox. ```bash $ pip install tox $ tox ``` ```bash $ bin/tox py26: commands succeeded py27: commands succeeded py32: commands succeeded py33: commands succeeded ``` -------------------------------- ### GET / (Generic Response Inspection) Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/testresponse.rst.txt Retrieves a response object from the application and demonstrates how to inspect its status, headers, and body content. ```APIDOC ## GET / ### Description Retrieves a response from the application. The returned object provides attributes for inspecting status, headers, and body content. ### Method GET ### Endpoint / ### Response #### Success Response (200) - **status** (string) - The text status of the response (e.g., "200 OK"). - **status_int** (integer) - The integer status code (e.g., 200). - **headers** (dict) - A dictionary-like object of response headers. - **body** (string) - The raw text body of the response. - **text** (string) - The unicode text body of the response. #### Response Example { "status": "200 OK", "status_int": 200, "body": "
hey!
" } ``` -------------------------------- ### Perform HTTP GET request Source: https://docs.pylonsproject.org/projects/webtest/en/latest/index.html Make an HTTP GET request to the root path of the wrapped WSGI application using TestApp. ```python resp = app.get('/') ``` -------------------------------- ### Execute a Request with TestApp Source: https://docs.pylonsproject.org/projects/webtest/en/latest/api.html Executes a pre-constructed webob Request object. Useful for more complex request setups. ```python req = webtest.TestRequest.blank('url', ...args...) resp = app.do_request(req) ``` -------------------------------- ### Define a basic WSGI application Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/index.rst.txt A simple WSGI application that returns a predefined HTML body. This is used as an example to be wrapped by WebTest's TestApp. ```python def application(environ, start_response): headers = [('Content-Type', 'text/html; charset=utf8'), ('Content-Length', str(len(body)))] start_response('200 OK', headers) return [body] ``` -------------------------------- ### Perform a HEAD Request Source: https://docs.pylonsproject.org/projects/webtest/en/latest/api.html Performs a HEAD request to the specified URL. Similar to the get() method. ```python resp = app.head('/users') ``` -------------------------------- ### Internal Request Handling Logic Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html Internal implementation details for request processing, including environment setup and header management. ```python environ = self._make_environ(extra_environ) url = str(url) url = self._remove_fragment(url) if params: url = utils.build_params(url, params) if '?' in url: url, environ['QUERY_STRING'] = url.split('?', 1) else: environ['QUERY_STRING'] = '' req = self.RequestClass.blank(url, environ) if xhr: headers = self._add_xhr_header(headers) if headers: req.headers.update(headers) return self.do_request(req, status=status, expect_errors=expect_errors) ``` -------------------------------- ### GET Authorization Source: https://docs.pylonsproject.org/projects/webtest/en/latest/api.html Retrieves the HTTP_AUTHORIZATION environment key value. ```APIDOC ## GET Authorization ### `get_authorization()` #### Description 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. ``` -------------------------------- ### Navigate to URL Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/response.html Navigates to a given URL, ignoring scheme, host, and fragment. It joins the provided href with the current request URL to resolve relative paths. Supports 'get' or 'post' methods and passes additional arguments to the underlying request method. ```python scheme, host, path, query, fragment = urlparse.urlsplit(href) ``` ```python scheme = host = fragment = '' href = urlparse.urlunsplit((scheme, host, path, query, fragment)) ``` ```python href = urlparse.urljoin(self.request.url, href) ``` ```python method = method.lower() assert method in ('get', 'post'), ( ``` -------------------------------- ### Getting Parsed XML with lxml Source: https://docs.pylonsproject.org/projects/webtest/en/latest/testresponse.html Use `response.lxml` to get the response body parsed by the `lxml` library, enabling XPath queries. This requires `lxml` to be installed. An `AttributeError` is raised if the content-type is incorrect. ```python >>> res = app.get('/index.html') >>> res.lxml >>> res.lxml.xpath('//body/div')[0].text 'hey!' >>> res = app.get('/document.xml') >>> res.lxml >>> res.lxml[0].tag 'message' >>> res.lxml[0].text 'hey!' ``` -------------------------------- ### Clone and Set Up webtest Project Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/contributing.rst.txt Clone the webtest repository and set up a virtual environment for development. This is the initial step for contributing to the project. ```bash $ git clone https://github.com/Pylons/webtest.git $ cd webtest $ virtualenv . $ . bin/activate $ python setup.py dev ``` -------------------------------- ### Initialize TestApp with different backends Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/testapp.rst.txt Demonstrates how to instantiate TestApp using specific request backends. ```python app = TestApp('http://my.cool.websi.te#requests') ``` ```python app = TestApp('http://my.cool.websi.te#restkit') ``` -------------------------------- ### Initialize and use debug_app Source: https://docs.pylonsproject.org/projects/webtest/en/latest/debugapp.html Demonstrates how to wrap the debug_app with TestApp and inspect the request environment. ```python >>> import webtest >>> from webtest.debugapp import debug_app >>> app = webtest.TestApp(debug_app) >>> res = app.post('/', params='foobar') >>> print(res.body) CONTENT_LENGTH: 6 CONTENT_TYPE: application/x-www-form-urlencoded HTTP_HOST: localhost:80 ... wsgi.url_scheme: 'http' wsgi.version: (1, 0) -- Body ---------- foobar ``` -------------------------------- ### Initialize Upload object Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/forms.html Demonstrates creating an Upload instance for file submission. ```python >>> Upload('filename.txt', 'data', 'application/octet-stream') >>> Upload('filename.txt', 'data') >>> Upload("README.txt") ``` -------------------------------- ### Generate Documentation with Sphinx Source: https://docs.pylonsproject.org/projects/webtest/en/latest/contributing.html Build the project documentation using Sphinx. ```bash $ pip install Sphinx $ cd docs $ make html ../bin/sphinx-build -b html -d _build/doctrees . _build/html Running Sphinx v1.1.3 loading pickled environment... done ... build succeeded, 3 warnings. Build finished. The HTML pages are in _build/html. ``` -------------------------------- ### goto Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/response.html Navigates to a specified URL using a defined HTTP method. ```APIDOC ## goto ### Description Navigates to the provided relative or absolute URL using GET or POST methods. ### Parameters #### Query Parameters - **href** (string) - Required - The target URL to navigate to. - **method** (string) - Optional - The HTTP method to use ('get' or 'post'). Defaults to 'get'. ``` -------------------------------- ### Instantiate TestApp Source: https://docs.pylonsproject.org/projects/webtest/en/latest/api.html Wraps a WSGI application for testing. Supports extra environment variables, relative paths, and cookie handling. ```python app = webtest.TestApp(my_wsgi_app, extra_environ={'REMOTE_ADDR': '127.0.0.1'}) ``` -------------------------------- ### Request Methods API Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html Provides methods for performing HTTP requests such as GET. ```APIDOC ## GET / ### Description Performs a GET request to the specified URL. ### Method GET ### Endpoint / ### Parameters #### Query Parameters - **url** (string) - Required - The URL path to request. - **params** (object or string) - Optional - Query string parameters or a dictionary to be encoded into a query string. - **headers** (object) - Optional - Extra headers to send with the request. - **extra_environ** (object) - Optional - Environmental variables to add to the request. - **status** (integer or string) - Optional - The expected HTTP status code (e.g., 200, '3*', '*'). - **expect_errors** (boolean) - Optional - If False, errors written to wsgi.errors will cause an exception. If True, non-200/3xx responses are also considered okay. - **xhr** (boolean) - Optional - Indicates if the request is an XMLHttpRequest. ### Response #### Success Response (200) - **body** (string) - The response body. - **status_code** (integer) - The HTTP status code of the response. - **headers** (object) - The response headers. #### Response Example ```json { "body": "Hello World", "status_code": 200, "headers": { "Content-Type": "text/html" } } ``` ``` -------------------------------- ### Environment Configuration Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html Creates a WSGI environment dictionary with default settings and optional overrides. ```python def _make_environ(self, extra_environ=None): environ = self.extra_environ.copy() environ['paste.throw_errors'] = True if extra_environ: environ.update(extra_environ) return environ ``` -------------------------------- ### Initialize TestApp Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html Initialize TestApp to wrap a WSGI application for testing. It can accept a WSGI application, a Paste Deploy URI, or a full URL for proxying. Configuration options include extra environment variables, relative path for file uploads, and cookie handling. ```python def __init__(self, app, extra_environ=None, relative_to=None, use_unicode=True, cookiejar=None, parser_features=None, json_encoder=None, lint=True): if 'WEBTEST_TARGET_URL' in os.environ: app = os.environ['WEBTEST_TARGET_URL'] if isinstance(app, str): if app.startswith('http'): try: from wsgiproxy import HostProxy except ImportError: raise ImportError( 'Using webtest with a real url requires WSGIProxy2. ' 'Please install it with: ' 'pip install WSGIProxy2') if '#' not in app: app += '#httplib' url, client = app.split('#', 1) app = HostProxy(url, client=client) else: from paste.deploy import loadapp app = loadapp(app, relative_to=relative_to) self.app = app ``` -------------------------------- ### Perform a DELETE Request Source: https://docs.pylonsproject.org/projects/webtest/en/latest/api.html Performs a DELETE request to the specified URL. Similar to the get() method. ```python resp = app.delete('/users/1') ``` -------------------------------- ### TestApp Initialization Source: https://docs.pylonsproject.org/projects/webtest/en/latest/api.html Initializes the TestApp class, wrapping a WSGI application for testing purposes. ```APIDOC ## `webtest.app.TestApp` ### Description Wraps a WSGI application in a more convenient interface for testing. It uses extended versions of `webob.BaseRequest` and `webob.Response`. ### Parameters #### Path Parameters - **app** (WSGI application) - Required - May be a WSGI application or Paste Deploy app, like `'config:filename.ini#test'`. It can also be an actual full URL to an http server and webtest will proxy requests with WSGIProxy2. - **extra_environ** (dict) - Optional - 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) - Optional - A directory used for file uploads are calculated relative to this. Also `config:` URIs that aren't absolute. - **cookiejar** (CookieJar instance) - Optional - `cookielib.CookieJar` alike API that keeps cookies across requests. - **parser_features** (string or list) - Optional - Passed to BeautifulSoup when parsing responses. - **json_encoder** (A subclass of json.JSONEncoder) - Optional - Passed to json.dumps when encoding json. - **lint** (boolean) - Optional - If True (default) then check that the application is WSGI compliant. ``` -------------------------------- ### Handle File Upload Fields Source: https://docs.pylonsproject.org/projects/webtest/en/latest/forms.html Use the `Upload` class to prepare files for upload. You can specify the filename, data, and content type. ```python >>> from webtest import Upload >>> form['file'] = Upload('README.rst') ``` ```python >>> form['file'] = Upload('README.rst', b'data') ``` ```python >>> form['file'] = Upload('README.rst', b'data', 'text/x-rst') ``` -------------------------------- ### Access XML response body Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/response.html Parses the response body as an ElementTree object. Requires ElementTree to be installed. ```python from xml.etree import ElementTree except ImportError: # pragma: no cover try: import ElementTree except ImportError: try: from elementtree import ElementTree # NOQA except ImportError: raise ImportError( "You must have ElementTree installed " "(or use Python 2.5) to use response.xml") # ElementTree can't parse unicode => use `body` instead of `testbody` return ElementTree.XML(self.body) ``` -------------------------------- ### Simulate authentication Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/testapp.rst.txt Configure authentication headers or environment variables for requests. ```python app.get('/secret', extra_environ=dict(REMOTE_USER='bob')) ``` ```python app = TestApp(my_app, extra_environ=dict(REMOTE_USER='bob')) ``` ```python app = TestApp(my_app) app.authorization = ('Basic', ('user', 'password')) ``` ```python app = TestApp(my_app) app.authorization = ('Bearer', 'mytoken') # or app.authorization = ('JWT', 'myjwt') ``` -------------------------------- ### Accessing Response as XML Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/response.html Provides the response body parsed as an ElementTree XML object. Requires ElementTree to be installed. ```APIDOC ## GET /response/xml ### Description Returns the response body parsed as an ElementTree XML object. ### Method GET ### Endpoint /response/xml ### Parameters None ### Request Example None ### Response #### Success Response (200) - **xml_object** (ElementTree.Element) - The parsed XML object. #### Response Example ```xml value ``` ``` -------------------------------- ### Handle Multiple File Uploads Source: https://docs.pylonsproject.org/projects/webtest/en/latest/forms.html For file input fields that accept multiple files, provide a list of `Upload` objects. ```python >>> from webtest import Upload >>> form['files'] = [ ... Upload('README.rst'), ... Upload('LICENSE.rst'), ... ] ``` -------------------------------- ### Create and Execute a Request Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html Use this method to create and execute a request. You can pass an instantiated TestRequest object or a URL with keyword arguments for TestRequest.blank. This is useful for testing custom methods like MKCOL or PUT with a body. ```python def request(self, url_or_req, status=None, expect_errors=False, **req_params): """ Creates and executes a request. You may either pass in an instantiated :class:`TestRequest` object, or you may pass in a URL and keyword arguments to be passed to :meth:`TestRequest.blank`. You can use this to run a request without the intermediary functioning of :meth:`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 :class:`webtest.TestRequest`:: req = webtest.TestRequest.blank('/url/', method='GET') resp = app.do_request(req) """ if isinstance(url_or_req, str): url_or_req = str(url_or_req) for (k, v) in req_params.items(): if isinstance(v, str): req_params[k] = str(v) if isinstance(url_or_req, str): req = self.RequestClass.blank(url_or_req, **req_params) else: req = url_or_req.copy() for name, value in req_params.items(): setattr(req, name, value) req.environ['paste.throw_errors'] = True for name, value in self.extra_environ.items(): req.environ.setdefault(name, value) return self.do_request(req, status=status, expect_errors=expect_errors, ) ``` -------------------------------- ### Manage HTTP Authorization Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html Methods to get and set the HTTP_AUTHORIZATION environment variable using Basic, Bearer, or JWT schemes. ```python def get_authorization(self): """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 """ return self.authorization_value def set_authorization(self, value): self.authorization_value = value if value is not None: invalid_value = ( "You should use a value like ('Basic', ('user', 'password'))" " OR ('Bearer', 'token') OR ('JWT', 'token')" ) if isinstance(value, (list, tuple)) and len(value) == 2: authtype, val = value if authtype == 'Basic' and val and \ isinstance(val, (list, tuple)): val = ':'.join(list(val)) val = b64encode(to_bytes(val)).strip() val = val.decode('latin1') elif authtype in ('Bearer', 'JWT') and val and \ isinstance(val, (str, str)): val = val.strip() else: raise ValueError(invalid_value) value = str(f'{authtype} {val}') else: raise ValueError(invalid_value) self.extra_environ.update({ 'HTTP_AUTHORIZATION': value, }) else: if 'HTTP_AUTHORIZATION' in self.extra_environ: del self.extra_environ['HTTP_AUTHORIZATION'] authorization = property(get_authorization, set_authorization) ``` -------------------------------- ### Handle Simple Select Fields Source: https://docs.pylonsproject.org/projects/webtest/en/latest/forms.html Manage single-selection dropdowns. You can get the current value and set a new option by its value. ```python >>> print(form['select'].value) option2 ``` ```python >>> form['select'] = 'option1' ``` -------------------------------- ### Initialize Form Parser Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/forms.html Instantiate the Form class with a webob.response.TestResponse and the HTML text of the form. The parser_features argument defaults to 'html.parser'. ```python form = Form(response, text) ``` -------------------------------- ### POST / Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html Performs a POST request to the specified URL with optional parameters, file uploads, and headers. ```APIDOC ## POST / ### Description Performs a POST request to the specified URL. Supports sending parameters in the body, file uploads, and custom content types. ### Method POST ### Parameters #### Query Parameters - **url** (string) - Required - The target URL path. - **params** (string/dict) - Optional - Data to be sent in the request body. - **headers** (dict) - Optional - Custom HTTP headers. - **upload_files** (list) - Optional - List of (fieldname, filename, file_content) tuples. - **content_type** (string) - Optional - The HTTP content type (e.g., application/json). - **xhr** (boolean) - Optional - If true, adds X-REQUESTED-WITH: XMLHttpRequest header. ### Response #### Success Response (200) - **TestResponse** (object) - Returns a webtest.TestResponse instance. ``` -------------------------------- ### Get a Single Form Source: https://docs.pylonsproject.org/projects/webtest/en/latest/forms.html Access the single HTML form on a page using the `.form` attribute. This is suitable when only one form is present. ```python >>> res = app.get('/form.html') >>> form = res.form ``` -------------------------------- ### Select Options by Text Source: https://docs.pylonsproject.org/projects/webtest/en/latest/forms.html Use `.select()` for single selects and `.select_multiple()` for multiple selects to choose options based on their visible text rather than their value attribute. ```python >>> form['select'].select(text="Option 2") >>> print(form['select'].value) option2 ``` ```python >>> form['multiple'].select_multiple(texts=["Option 1", "Option 2"]) >>> print(form['multiple'].value) ['option1', 'option2'] ``` -------------------------------- ### Get a Form by Index or ID Source: https://docs.pylonsproject.org/projects/webtest/en/latest/forms.html When multiple forms exist, access them using the `.forms` property by their index or the form's ID attribute. ```python >>> form = res.forms[0] ``` ```python >>> form = res.forms['myform'] ``` -------------------------------- ### Accessing Response as PyQuery Object Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/response.html Returns the response as a PyQuery object, which is useful for querying HTML and XML content. Requires PyQuery to be installed. ```APIDOC ## GET /response/pyquery ### Description Returns the response body as a PyQuery object. This is only applicable for HTML and XML content types. ### Method GET ### Endpoint /response/pyquery ### Parameters None ### Request Example None ### Response #### Success Response (200) - **pyquery_object** (PyQuery) - The parsed PyQuery object. #### Response Example ```html

Hello

``` ``` -------------------------------- ### Get File Upload Fields Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/forms.html Returns a list of file field tuples, each containing the field name and file name, optionally with file contents. ```python uploads = [] for name, fields in self.fields.items(): for field in fields: if isinstance(field, File) and field.value: ``` -------------------------------- ### Configuration API Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html APIs for configuring the testing environment, such as parser features and resetting state. ```APIDOC ## PUT /parser-features ### Description Changes the parser used by BeautifulSoup for response processing. ### Method PUT ### Endpoint /parser-features ### Parameters #### Request Body - **parser_features** (string) - Required - The name of the parser to use (e.g., 'html.parser'). ### Request Example ```json { "parser_features": "lxml" } ``` ### Response #### Success Response (200) - **message** (string) - Confirmation message. #### Response Example ```json { "message": "Parser features set successfully." } ``` ## POST /reset ### Description Resets the state of the application, primarily clearing saved cookies. ### Method POST ### Endpoint /reset ### Response #### Success Response (200) - **message** (string) - Confirmation message. #### Response Example ```json { "message": "State reset successfully." } ``` ``` -------------------------------- ### Handle Multiple Select Fields Source: https://docs.pylonsproject.org/projects/webtest/en/latest/forms.html Manage multi-selection dropdowns. You can get the current selection as a list and set new options by providing a list of values. ```python >>> print(form['multiple'].value) ['option2', 'option3'] ``` ```python >>> form['multiple'] = ['option1'] ``` -------------------------------- ### Initialize TestResponse Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/response.html The TestResponse class is instantiated by TestApp methods and extends webob.Response. It includes properties for request, forms, and parser features. ```python import re from json import loads from webtest import forms from webtest import utils from webtest.compat import print_stderr from webtest.compat import urlparse from webtest.compat import to_bytes from bs4 import BeautifulSoup import webob class TestResponse(webob.Response): """ Instances of this class are returned by :class:`~webtest.app.TestApp` methods. """ request = None _forms_indexed = None parser_features = 'html.parser' @property def forms( self ): """ Returns a dictionary containing all the forms in the pages as :class:`~webtest.forms.Form` objects. Indexes are both in order (from zero) and by form id (if the form is given an id). See :doc:`forms` for more info on form objects. """ if self._forms_indexed is None: self._parse_forms() return self._forms_indexed @property def form( self ): """ If there is only one form on the page, return it as a :class:`~webtest.forms.Form` object; raise a TypeError is there are no form or multiple forms. """ forms_ = self.forms if not forms_: raise TypeError( "You used response.form, but no forms exist" ) if 1 in forms_: # There is more than one form raise TypeError( "You used response.form, but more than one form exists" ) return forms_[0] @property def testbody( self ): self.decode_content() if self.charset: try: return self.text except UnicodeDecodeError: return self.body.decode(self.charset, 'replace') return self.body.decode('ascii', 'replace') _tag_re = re.compile(r'<(/?)([:a-z0-9_\-]*)(.*?)>', re.S | re.I) def _parse_forms( self ): forms_ = self._forms_indexed = {} form_texts = [str(f) for f in self.html('form')] for i, text in enumerate(form_texts): form = forms.Form(self, text, self.parser_features) forms_[i] = form if form.id: forms_[form.id] = form def _follow( self, **kw ): location = self.headers['location'] abslocation = urlparse.urljoin(self.request.url, location) # @@: We should test that it's not a remote redirect return self.test_app.get(abslocation, **kw) def follow( self, **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 :class:`~webtest.app.TestApp.get`. Returns another :class:`TestResponse` object. """ if not (300 <= self.status_int < 400): raise AssertionError( "You can only follow redirect responses (not %s)" % self.status ) return self._follow(**kw) def maybe_follow( self, **kw ): """ Follow all redirects. If this response is not a redirect, do nothing. Any keyword arguments are passed to :class:`webtest.app.TestApp.get`. Returns another :class:`TestResponse` object. """ remaining_redirects = 100 # infinite loops protection response = self while 300 <= response.status_int < 400 and remaining_redirects: response = response._follow(**kw) remaining_redirects -= 1 if remaining_redirects <= 0: raise AssertionError("redirects chain looks infinite") return response def click( self, 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 ```` and ````) * ``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 ``` -------------------------------- ### Define a Test Application Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_sources/testresponse.rst.txt Defines a simple WSGI application that serves different content types based on the request path, used for testing with TestApp. ```python >>> import json >>> import sys >>> from webob import Request >>> from webob import Response >>> from webtest.app import TestApp >>> def application(environ, start_response): ... req = Request(environ) ... if req.path_info.endswith('.html'): ... content_type = 'text/html' ... body = '
hey!
'.encode('latin-1') ... elif req.path_info.endswith('.xml'): ... content_type = 'text/xml' ... body = 'hey!'.encode('latin-1') ... elif req.path_info.endswith('.json'): ... content_type = 'application/json' ... body = json.dumps({"a": 1, "b": 2}).encode('latin-1') ... resp = Response(body, content_type=content_type) ... return resp(environ, start_response) >>> app = TestApp(application) ``` -------------------------------- ### Get Form Field Object Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/forms.html Retrieves a specific form field object by name. Raises an AssertionError if the field is not found or if multiple fields match the name. ```python fields = self.fields.get(name) assert fields is not None, ( "No field by the name %r found" % name) assert len(fields) == 1, ( "Multiple fields match %r: %s" % (name, ', '.join(map(repr, fields)))) return fields[0] ``` -------------------------------- ### Accessing Response as lxml Object Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/response.html Returns the response as an lxml object. This method is suitable for HTML and XML content types and requires the lxml library to be installed. ```APIDOC ## GET /response/lxml ### Description Returns the response body parsed as an lxml object. This is applicable for HTML and XML content types. ### Method GET ### Endpoint /response/lxml ### Parameters None ### Request Example None ### Response #### Success Response (200) - **lxml_object** (lxml.etree._Element or lxml.html.HtmlElement) - The parsed lxml object. #### Response Example ```html

Title

``` ``` -------------------------------- ### OPTIONS /url Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/app.html Performs an OPTIONS request to the specified URL. ```APIDOC ## OPTIONS /url ### Description Performs an OPTIONS request to the specified URL. ### Method OPTIONS ### Endpoint /url ### Parameters #### Query Parameters - **url** (string) - Required - The target URL. - **headers** (dict) - Optional - Request headers. - **extra_environ** (dict) - Optional - Extra environment variables. - **status** (int/str) - Optional - Expected status code. - **expect_errors** (bool) - Optional - Whether to expect errors. - **xhr** (bool) - Optional - Whether to add XHR headers. ### Response #### Success Response (200) - **response** (TestResponse) - Returns a TestResponse instance. ``` -------------------------------- ### Get and Set Form Field Values Source: https://docs.pylonsproject.org/projects/webtest/en/latest/forms.html Retrieve the current value of a form field or set a new value. For fields with non-unique names, use `.set()` with an index. ```python >>> print(form['text'].value) Foo ``` ```python >>> form['text'] = 'Bar' ``` ```python >>> # When names don't point to a single field: >>> form.set('text', 'Bar', index=0) ``` -------------------------------- ### Execute Tests with Pytest Source: https://docs.pylonsproject.org/projects/webtest/en/latest/contributing.html Run the test suite using the local pytest binary. ```bash $ bin/pytest Doctest: forms.rst ... ok Doctest: index.rst ... ok ... test_url_class (tests.test_testing.TestTesting) ... ok tests.test_testing.test_print_unicode ... °C ok Name Stmts Miss Cover Missing ------------------------------------------------ webtest 18 0 100% webtest.app 603 92 85% 48, 61-62, 94, 98, 212-221, 264-265, 268-272, 347, 379-386, 422, 426-428, 432-434, 455, 463, 471, 473, 488, 496-497, 515, 520-527, 548, 553-554, 558-559, 577, 592, 597-598, 618, 624, 661-664, 742, 808, 872, 940-941, 945-948, 961-964, 975, 982, 995, 1000, 1006, 1010, 1049, 1051, 1095-1096, 1118-1119, 1122-1127, 1135-1136, 1148, 1155-1160, 1175 webtest.compat 50 11 78% 28-34, 55-56, 61-62 webtest.debugapp 58 0 100% webtest.ext 80 0 100% webtest.forms 324 23 93% 23, 49, 58, 61, 92, 116, 177, 205, 411, 478, 482-486, 491-493, 522, 538, 558-561 webtest.http 78 0 100% webtest.lint 215 45 79% 135, 176, 214-216, 219-224, 227-231, 234, 243-244, 247, 250-251, 254, 263-264, 270, 274, 307, 311, 335, 359, 407, 424-427, 441-444, 476-479, 493, 508 webtest.sel 479 318 34% 38-39, 45-46, 64-78, 88-108, 120, 126, 151-153, 156-158, 164-165, 168-191, 194-201, 219-231, 236, 240, 243-259, 263-297, 301-306, 316-326, 331-336, 340, 344, 347-352, 357-359, 364, 392-394, 397-404, 408, 412-417, 421, 425-426, 430, 434, 438, 442, 445, 448-457, 470-480, 483-485, 488, 492, 495, 503, 506, 515-516, 520, 524, 528, 533, 538, 542-544, 547, 560-565, 576, 579, 582, 593-596, 599-602, 605-606, 617-620, 623-642, 668-677, 680-688, 715, 720, 732, 735, 744-754, 757-762, 770-779, 791, 794, 805-809, 813-826, 838-842 webtest.utils 99 11 89% 19-20, 23, 26, 32, 38, 100, 109, 152-154 ------------------------------------------------ TOTAL 2004 500 75% ---------------------------------------------------------------------- Ran 70 tests in 14.940s ``` -------------------------------- ### Get Form Field Object with Default Source: https://docs.pylonsproject.org/projects/webtest/en/latest/_modules/webtest/forms.html Retrieves a form field object by name and optional index. Returns a default value if the field is not found, otherwise raises an AssertionError. ```python fields = self.fields.get(name) if fields is None: if default is utils.NoDefault: raise AssertionError( "No fields found matching %r (and no default given)" % name) return default if index is None: return self[name] return fields[index] ```