pax_global_header00006660000000000000000000000064147734650030014523gustar00rootroot0000000000000052 comment=c38cb389c10df934bd5d10bd2401462f337e3bbc django-webtest-1.9.13/000077500000000000000000000000001477346500300145335ustar00rootroot00000000000000django-webtest-1.9.13/.github/000077500000000000000000000000001477346500300160735ustar00rootroot00000000000000django-webtest-1.9.13/.github/workflows/000077500000000000000000000000001477346500300201305ustar00rootroot00000000000000django-webtest-1.9.13/.github/workflows/tox.yml000066400000000000000000000027671477346500300215010ustar00rootroot00000000000000name: tox on: [push, pull_request] jobs: tox: runs-on: ubuntu-latest strategy: matrix: python: ["3.9", "3.10", "3.11", "3.12"] django: ["42", "50", "51", "52"] suffix: [std, clocale, postgres] exclude: - python: "3.9" django: "50" - python: "3.9" django: "51" - python: "3.9" django: "52" services: postgres: image: postgres:latest env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: django_webtest_tests_${{ matrix.python }} ports: # will assign a random free host port - 5432/tcp # needed because the postgres container does not provide a healthcheck options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} - name: Install Tox and any other packages run: pip install tox - name: Run Tox env: POSTGRES_HOST: localhost POSTGRES_PORT: ${{ job.services.postgres.ports[5432] }} POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: django_webtest_tests_${{ matrix.python }} run: tox -e py$(echo ${{ matrix.python }} | sed 's/\.//')-django${{ matrix.django }}-${{ matrix.suffix }} django-webtest-1.9.13/.gitignore000066400000000000000000000001061477346500300165200ustar00rootroot00000000000000*.pyc __pycache__ .tox/ MANIFEST build/ dist/ django_webtest.egg-info django-webtest-1.9.13/.hgignore000066400000000000000000000004341477346500300163370ustar00rootroot00000000000000syntax: glob #IDE files .settings/* .project .pydevproject .cache/* #temp files *.swp *.pyc *.pyo *.orig *.egg-info *~ .tox/ db.sqlite #misc files pip-log.txt #os files .Python .DS_Store Thumbs.db #setup files build/ dist/ .build/ MANIFEST #virtualenv files bin/ lib/ include/ django-webtest-1.9.13/.hgtags000066400000000000000000000016461477346500300160200ustar00rootroot00000000000000bbf75c88dd403f4196c32cece70637f1a72c8e41 1.4.2 fb3366c135058fde31e30e3f448e6b5d7b0886c9 1.4.3 9c49e95b7e061acdb3e61be386d330b4304f1272 1.4.4 faf067bf60a968edfc09757e3b391472dcbe8207 1.5 fa90ae3ef2af6d3f7c43b5432d7846db13d1385a 1.5.1 bdc705e05a9885120a096ca51a5f33a4eb887e49 1.5.2 cd4acba387974335393f562a288c73b70757ce60 1.5.3 e32c67a3d323e2c0d5477f547398a648d9dfa679 1.5.4 75d307d2bf3759328b69922be47366d3be1fa6f3 1.5.5 21c051c35b6a4b3db48000dfb231369b7403d659 1.5.6 849980458d4fe6d7e99a8535d2183693636f8123 1.5.7 8ac69bc2eff1fc6fc7e605c1f77829d394246206 1.6 67412317381b597e9ce11ae9e91c0c5d3faa9d77 1.6.1 540a9321a3ce30e858069933bc8618ee213a505c 1.7 979ca8efd25b7990c2333a9eb212a1b72932a2ac 1.7.1 0769aa926ed80ff6007c4e5db2029e25da704991 1.7.2 5a6e648c6412e157d75cdfabc4ed2ddd51d8e45f 1.7.4 4795a68092e6d1d8ee29693a7ef60ed747b5d974 1.7.5 2b2c7e5fa220a59ea352dbb3ed664d087cb152a3 1.7.6 437060d0f02fbc04b1fae75b3e906570080e5bb6 1.7.7 django-webtest-1.9.13/.vscode/000077500000000000000000000000001477346500300160745ustar00rootroot00000000000000django-webtest-1.9.13/.vscode/settings.json000066400000000000000000000000651477346500300206300ustar00rootroot00000000000000{ "python.pythonPath": "/usr/local/bin/python3" }django-webtest-1.9.13/AUTHORS.txt000066400000000000000000000011171477346500300164210ustar00rootroot00000000000000Authors ======= * Mikhail Korobov * Gregor Müllegger * Gael Pasgrimaud * Anonymous contributor * Ilya Shalyapin * Joe Crobak * Ruslan Popov * bigkevmcd * Jeroen Vloothuis * Tai Lee * David Winterbottom * Marco Braak * Bruno Renié * Gautier Hayoun * Carl Meyer * Iurii Kriachko * Will Bradley * Julien Aubert * Darian Moody * Max Kharandziuk * Helen Sherwood-Taylor * Éric Araujo * Wayne Lambert django-webtest-1.9.13/CHANGES.rst000066400000000000000000000206761477346500300163500ustar00rootroot00000000000000 CHANGES ======= 1.9.13 (2025-04-03) ------------------- - Drop support for Django 3.x and 4.1 - Add support for Django 5.2 1.9.12 (2024-08-30) ------------------- - Add support for Django 5 - No longer compatible with assertFormError - pytest fixture now unpatch Django settings after fixture run 1.9.11 (2023-09-18) ------------------- - Add support for official Python & Django versions - Do not insert WebtestAuthentication to the head of DEFAULT_AUTHENTICATION_CLASSES. 1.9.10 (2022-03-02) ------------------- - Add an optional WebTest backend that does not interfere with handling of permissions by custom backends. Accessible via WEBTEST_AUTHENTICATION_BACKEND setting. Fixed #123 1.9.9 (2021-12-27) ------------------ - Add Django 4 support - Remove Django 2 support 1.9.8 (2021-10-06) ------------------ - Update testing configurations for Django and Python as per Django documentation - https://docs.djangoproject.com/en/3.0/faq/install/#what-python-version-can-i-use-with-django - Add some useful metadata for the project's PyPI listing - Minor changes to documentation - Update getting session in DjangoTestApp. Fixed #113 - Remove py27/py35 support 1.9.7 (2019-07-05) ------------------ - allow overriding HTTP_HOST with DjangoTestApp.__init__. Fixed #102 1.9.6 (2019-06-07) ------------------ - rest_framework auth class. Fixed #98 #100 1.9.5 (2019-05-31) ------------------ - Fix compatibility with django 3. See #96 - Add integration with django-rest-framework auth - Add missing args to DjangoTestApp. Fixed #86 1.9.4 (2018-10-27) ------------------ - py34 and Django 1.8 are no longer tested (but may works) - allow to use positionnal args; fixed #89 - remove deprecated pytest.yield_fixture functions. use pytest.fixture instead; fixed #88 - Don't add duplicate WebtestUserMiddleware to the list of middlewares in WebTestMixin. fixed #87 - restore MIDDLEWARE_CLASSES support; fixed #84 1.9.3 (2018-05-03) ------------------ - Passing `user=None` to get/post/etc. methods will clear a user previously set with `set_user` instead of doing nothing. - Avoid sharing settings between tests in pytest plugin - Fix middleware settings name used 1.9.2 (2017-05-17) ------------------ - silence warnings about is_authenticated on 1.11 - include correct hostname (testserver) when using set_cookie 1.9.1 (2017-03-09) ------------------ - Fix package description (multiline are no longer allowed by pypi) 1.9.0 (2017-03-09) ------------------ - Backward incompatibility: positionnal arguments are no longer supported. You'll need to replace them by keywords arguments. - Added support for Django 1.11 - Dropped support for Django <= 1.7 - Dropped support for Python 2.6 - Changed value of `HTTP_HOST` header from `localhost` to `testserver`, to match behaviour of Django test client. - Fixed `DjangoTestApp.options` - Added `DjangoTestApp.head` - Added pytest fixtures 1.8.0 (2016-09-14) ------------------ - Fixed issue #40 - combining ``app.get`` ``auto_follow=True`` with other keyword args. - Add compatibility to the MIDDLEWARE setting introduced in django 1.10 - Drop support for django 1.2 1.7.9 (2016-04-19) ------------------ - Add set_user() to allow to set a user globally for the app - Allow 'click' to be given a user param - Mention testapp.reset() in readme - Allow to use ``json_`` methods 1.7.8 (2015-04-21) ------------------ - setup.py is switched to setuptools; WebTest is now installed automatically (thanks Eric Araujo); - importlib from stdlib is used when available, for django 1.9 compatibility (thanks Helen Sherwood-Taylor); - django-webtest's own tests are fixed to work in django 1.6+; - https://bitbucket.org/kmike/django-webtest repository is no longer supported. 1.7.7 (2014-03-25) ------------------ - Fix installation for Python 3.x on systems with C locales. 1.7.6 (2014-01-20) ------------------ - DjangoTestApp methods pass all custom keyword arguments to webtest.TestApp; this allows to use ``xhr=True`` feature (thanks Max Kharandziuk). - Travis CI testing fixes (thanks Darian Moody). 1.7.5 (2013-07-17) ------------------ - OPTIONS method is fixed; - added workaround for DELETE method warnings (see https://github.com/Pylons/webtest/issues/50). 1.7.4 (2013-07-14) ------------------ - Really add ``TransactionWebTest`` base class (thanks Julien Aubert). 1.7.3 (2013-07-07) ------------------ - Added support for PATCH and OPTIONS HTTP methods (thanks Will Bradley). 1.7.2 (2013-06-27) ------------------ - ``TransactionWebTest`` base class is added (thanks Iurii Kriachko). 1.7.1 (2013-06-11) ------------------ - Added support for non-ascii usernames. 1.7 (2013-05-23) ---------------- - Added support for django 1.6 (thanks Carl Meyer). 1.6.1 (2013-03-31) ------------------ - Added support for django 1.5+ custom user models (thanks Gautier Hayoun). 1.6 (2013-03-07) ---------------- - Added ability to pass a custom response_class and app_class to WebTest (thanks Bruno Renié); - Added case-insensitive header access in DjangoWebtestResponse (thanks Bruno Renié). 1.5.7 (2013-02-27) ------------------ - WebTest 2.0 support. 1.5.6 (2013-01-21) ------------------ - django 1.5 support: transaction handling is fixed (thanks Marco Braak). 1.5.5 (2013-01-14) ------------------ - Fixed django 1.5 support: DjangoWebtestResponse.streaming attribute is added (thanks David Winterbottom). 1.5.4 (2012-09-13) ------------------ - fix django 1.5 issues with AdminMediaHandler (thanks Tai Lee); - tox.ini is updated to use latest django versions and the official trunk with python3 support; - django 1.5 SimpleCookie issues are fixed. 1.5.3 (2012-04-25) ------------------ - self.assertRedirects is fixed for authenticated requests. 1.5.2 (2012-04-01) ------------------ - if AuthenticationMiddleware is not in a middleware list, WebtestUserMiddleware is put to the end of middlewares in order to provide better backward compatibility with 1.4.x in case of custom auth middlewares. 1.5.1 (2012-03-22) ------------------ - Fixed handling of forms with method="get". Thanks Jeroen Vloothuis. 1.5 (2012-02-24) ---------------- - WebtestUserMiddleware is inserted after AuthenticationMiddleware, not to the end of middleware list (thanks bigkevmcd); - don't list python 2.5 as supported because WebOb dropped 2.5 support; - python 3 support; - test running using tox. 1.4.4 (2012-02-08) ------------------ - 'user' parameter for ``self.app.put`` and ``self.app.delete`` methods (thanks Ruslan Popov). 1.4.3 (2011-09-27) ------------------ - The django session dictionary is available via ``self.app.session``. 1.4.2 (2011-08-26) ------------------ - ``REMOTE_ADDR`` is now ``'127.0.0.1'`` by default. This is how standard django's test client behave. Please note that this can slow tests down and cause other side effects if django-debug-toolbar 0.9.x is installed+configured and ``INTERNAL_IPS`` contain ``'127.0.0.1'`` because debug toolbar will become turned on during tests. The workaround is to remove django-debug-toolbar middleware during tests in your test settings:: DEBUG_MIDDLEWARE = 'debug_toolbar.middleware.DebugToolbarMiddleware' if DEBUG_MIDDLEWARE in MIDDLEWARE_CLASSES: MIDDLEWARE_CLASSES.remove(DEBUG_MIDDLEWARE) 1.4.1 (2011-06-29) ------------------ - ``self.renew_app()`` method for resetting the 'browser' inside tests. 1.4 (2011-06-23) ---------------- - Better auth implementation; - support for assertRedirects, assertContains and assertNotContains. 1.3 (2010-12-31) ---------------- - Django 1.3 compatibility: test responses are now having 'templates' attribute; - Django 1.3 compatibility: the way exceptions are handled is changed; - auto_follow parameter for app.get method (redirect chains will be auto-followed with auto_follow=True). 1.2.1 (2010-08-24) ------------------ - REMOTE_USER authorization can be disabled. 1.2 (2010-08-21) ---------------- - ``response.template`` and ``response.context`` goodness (thanks Gregor Müllegger); - tests (thanks Gregor Müllegger); - csrf checks are now optional (thanks Gregor Müllegger). 1.1.1 (2010-07-16) ------------------ - User instance can be passed to `get` and `post` methods instead of user's username. 1.1 (2010-06-15) ---------------- - Original traceback instead of html 500 error page; - per-TestCase extra_environ (thanks Gael Pasgrimaud); - fixed a bug with app.post parameters (thanks anonymous). 1.0 (2010-04-20) ---------------- Initial release (thanks Ian Bicking for WebTest). django-webtest-1.9.13/LICENSE.txt000066400000000000000000000020501477346500300163530ustar00rootroot00000000000000Copyright (c) 2010-2020 Mikhail Korobov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. django-webtest-1.9.13/MANIFEST.in000066400000000000000000000002401477346500300162650ustar00rootroot00000000000000include *.txt include *.rst include *.ini prune .github prune .vscode recursive-include django_webtest_tests *.html recursive-include django_webtest_tests *.py django-webtest-1.9.13/README.rst000066400000000000000000000154601477346500300162300ustar00rootroot00000000000000============== django-webtest ============== .. image:: https://img.shields.io/pypi/v/django-webtest.svg :target: https://pypi.python.org/pypi/django-webtest :alt: PyPI Version .. image:: https://img.shields.io/github/license/kmike/django-webtest.svg :target: https://github.com/django-webtest/django-webtest/blob/master/LICENSE.txt :alt: License .. image:: https://img.shields.io/travis/django-webtest/django-webtest/master.svg :target: http://travis-ci.org/django-webtest/django-webtest :alt: Build Status django-webtest is an app for instant integration of Ian Bicking's WebTest (http://docs.pylonsproject.org/projects/webtest/) with Django's testing framework. Installation ============ .. code-block:: console $ pip install django-webtest Usage ===== .. code-block:: python from django_webtest import WebTest class MyTestCase(WebTest): # optional: we want some initial data to be able to login fixtures = ['users', 'blog_posts'] # optional: default extra_environ for this TestCase extra_environ = {'HTTP_ACCEPT_LANGUAGE': 'ru'} def testBlog(self): # pretend to be logged in as user `kmike` and go to the index page index = self.app.get('/', user='kmike') # All the webtest API is available. For example, we click # on a Blog link, check that it # works (result page doesn't raise exceptions and returns 200 http # code) and test if result page have 'My Article' text in # its body. assert 'My Article' in index.click('Blog') django-webtest provides a django.test.TestCase subclass (``django_webtest.WebTest``) that creates ``webtest.TestApp`` around django wsgi interface and makes it available in tests as ``self.app``. It also features an optional ``user`` argument for ``self.app.get``, ``self.app.post``, etc. to help making authorized requests. This argument should be a django.contrib.auth.models.User instance or a string with user's ``username`` for the user who is supposed to be logged in. To log out again, call ``self.app.reset``, clearing all cookies. To make a bunch of calls with the same user, call ``app.set_user(user)`` before your requests; if you want to disable that user, call ``app.get(..., user=None)`` for one request or ``app.set_user(None)`` to unset the user for all following calls. For 500 errors original traceback is shown instead of usual html result from handler500. You also get the ``response.templates`` and ``response.context`` goodness that is usually only available if you use Django's native test client. These attributes contain a list of templates that were used to render the response and the context used to render these templates. All of Django's native asserts ( ``assertFormError``, ``assertTemplateUsed``, ``assertTemplateNotUsed``, ``assertContains``, ``assertNotContains``, ``assertRedirects``) are also supported for WebTest responses. The session dictionary is available via ``self.app.session``, and has the same content than Django's native test client. Unlike Django's native test client CSRF checks are not suppressed by default so missing CSRF tokens will cause test fails (and that's good). If forms are submitted via WebTest forms API then all form fields (including CSRF token) are submitted automagically: .. code-block:: python class AuthTest(WebTest): fixtures = ['users.json'] def test_login(self): form = self.app.get(reverse('auth_login')).form form['username'] = 'foo' form['password'] = 'bar' response = form.submit().follow() self.assertEqual(response.context['user'].username, 'foo') However if forms are submitted via raw POST requests using ``app.post`` then csrf tokens become hard to construct. CSRF checks can be disabled by setting ``csrf_checks`` attribute to False in this case: .. code-block:: python class MyTestCase(WebTest): csrf_checks = False def test_post(self): self.app.post('/') When a subclass of Django's ``TransactionTestCase`` is desired, use ``django_webtest.TransactionWebTest``. For disabling CSRF checks in a ``pytest-django`` fixture, see `Usage with PyTest`_. All of these features can be easily set up manually (thanks to WebTest architecture) and they are even not neccessary for using WebTest with Django but it is nice to have some sort of integration instantly. See http://docs.pylonsproject.org/projects/webtest/ for API help. Webtest can follow links, submit forms, parse html, xml and json responses with different parsing libraries, upload files and more. Integration with django-rest-framework ====================================== If your project uses django-rest-framework__, the setting ``REST_FRAMEWORK['AUTHENTICATION_CLASSES']`` will be patched automatically to include a class that links the rest-framework authentication system with ``app.get(user=user)``. .. __: https://www.django-rest-framework.org/ Usage with PyTest ================= You need to install `pytest-django `_: .. code-block:: console $ pip install pytest-django Then you can use ``django-webtest``'s fixtures: .. code-block:: python def test_1(django_app): resp = django_app.get('/') assert resp.status_code == 200, 'Should return a 200 status code' We have a ``django_app_factory`` fixture we can use to create custom fixtures. For example, one that doesn't do CSRF checks: .. code-block:: python # conftest.py @pytest.fixture def csrf_exempt_django_app(django_app_factory): return django_app_factory(csrf_checks=False) ``csrf_checks`` and ``extra_environ`` are the only arguments to ``django_app_factory``. Why? ==== While django.test.client.Client is fine for its purposes, it is not well-suited for functional or integration testing. From Django's test client docstring: This is not intended as a replacement for Twill/Selenium or the like - it is here to allow testing against the contexts and templates produced by a view, rather than the HTML rendered to the end-user. WebTest plays on the same field as twill. WebTest has a nice API, is fast, small, talks to the django application via WSGI instead of HTTP and is an easy way to write functional/integration/acceptance tests. django-webtest is able to provide access to the names of rendered templates and template context just like native Django TestClient. Contributing ============ Development happens at github: https://github.com/django-webtest/django-webtest Issue tracker: https://github.com/django-webtest/django-webtest/issues Feel free to submit ideas, bugs or pull requests. Running tests ------------- Make sure `tox`_ is installed and run: .. code-block:: console $ tox from the source checkout. .. _tox: http://tox.testrun.org django-webtest-1.9.13/django_webtest/000077500000000000000000000000001477346500300175325ustar00rootroot00000000000000django-webtest-1.9.13/django_webtest/__init__.py000066400000000000000000000336541477346500300216560ustar00rootroot00000000000000# -*- coding: utf-8 -*- import copy from django.conf import settings from django.test.signals import template_rendered from django.core.handlers.wsgi import WSGIHandler from django.test import TestCase, TransactionTestCase from django.test.client import store_rendered_templates from functools import partial try: from importlib import import_module except ImportError: from django.utils.importlib import import_module from django.core import signals try: from django.db import close_old_connections except ImportError: from django.db import close_connection close_old_connections = None try: from django.core.servers.basehttp import ( AdminMediaHandler as StaticFilesHandler) except ImportError: from django.contrib.staticfiles.handlers import StaticFilesHandler from webtest import TestApp try: from webtest.utils import NoDefault except ImportError: NoDefault = '' from django_webtest.response import DjangoWebtestResponse from django_webtest.compat import to_string, to_wsgi_safe_string # sentinel to differentiate user=None / user param not given _notgiven = object() class DjangoTestApp(TestApp): response_class = DjangoWebtestResponse def __init__(self, *args, **kwargs): extra_environ = (kwargs.get('extra_environ') or {}).copy() extra_environ.setdefault('HTTP_HOST', 'testserver') kwargs['extra_environ'] = extra_environ super(DjangoTestApp, self).__init__(self.get_wsgi_handler(), *args, **kwargs) def get_wsgi_handler(self): return StaticFilesHandler(WSGIHandler()) def set_user(self, user): """Update the user used by the app globall; pass None to unset.""" if user is None and 'WEBTEST_USER' in self.extra_environ: del self.extra_environ['WEBTEST_USER'] if user is not None: self.extra_environ = self._update_environ(self.extra_environ, user) def _update_environ(self, environ, user=_notgiven): environ = environ or {} if user is not _notgiven: if user is None: # We can't just delete the key here, the test request is built # from self.extra_environ + this environ, so the header defined # by set_user will be found in self.extra_environ. environ['WEBTEST_USER'] = '' else: username = _get_username(user) environ['WEBTEST_USER'] = to_wsgi_safe_string(username) return environ def do_request(self, req, status, expect_errors): # Django closes the database connection after every request; # this breaks the use of transactions in your tests. if close_old_connections is not None: # Django 1.6+ signals.request_started.disconnect(close_old_connections) signals.request_finished.disconnect(close_old_connections) else: # Django < 1.6 signals.request_finished.disconnect(close_connection) try: req.environ.setdefault('REMOTE_ADDR', '127.0.0.1') # is this a workaround for # https://code.djangoproject.com/ticket/11111 ? req.environ['REMOTE_ADDR'] = to_string(req.environ['REMOTE_ADDR']) req.environ['PATH_INFO'] = to_string(req.environ['PATH_INFO']) # Curry a data dictionary into an instance of the template renderer # callback function. data = {} on_template_render = partial(store_rendered_templates, data) template_rendered.connect(on_template_render) response = super(DjangoTestApp, self).do_request(req, status, expect_errors) # Add any rendered template detail to the response. # If there was only one template rendered (the most likely case), # flatten the list to a single element. def flattend(detail): if len(data[detail]) == 1: return data[detail][0] return data[detail] response.context = None response.template = None response.templates = data.get('templates', None) if data.get('context'): response.context = flattend('context') if data.get('template'): response.template = flattend('template') elif data.get('templates'): response.template = flattend('templates') response.__class__ = self.response_class return response finally: if close_old_connections: # Django 1.6+ signals.request_started.connect(close_old_connections) signals.request_finished.connect(close_old_connections) else: # Django < 1.6 signals.request_finished.connect(close_connection) def get(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) auto_follow = kwargs.pop('auto_follow', False) kwargs['extra_environ'] = self._update_environ(extra_environ, user) response = super(DjangoTestApp, self).get(url, *args, **kwargs) def is_redirect(r): return r.status_int >= 300 and r.status_int < 400 while auto_follow and is_redirect(response): response = response.follow(**kwargs) return response def post(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) kwargs['extra_environ'] = self._update_environ(extra_environ, user) return super(DjangoTestApp, self).post(url, *args, **kwargs) def put(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) kwargs['extra_environ'] = self._update_environ(extra_environ, user) return super(DjangoTestApp, self).put(url, *args, **kwargs) def patch(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) kwargs['extra_environ'] = self._update_environ(extra_environ, user) return super(DjangoTestApp, self).patch(url, *args, **kwargs) def head(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) kwargs['extra_environ'] = self._update_environ(extra_environ, user) return super(DjangoTestApp, self).head(url, *args, **kwargs) def options(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) kwargs['extra_environ'] = self._update_environ(extra_environ, user) return super(DjangoTestApp, self).options(url, *args, **kwargs) def delete(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) kwargs['extra_environ'] = self._update_environ(extra_environ, user) return super(DjangoTestApp, self).delete(url, *args, **kwargs) def post_json(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) kwargs['extra_environ'] = self._update_environ(extra_environ, user) return super(DjangoTestApp, self).post_json(url, *args, **kwargs) def put_json(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) kwargs['extra_environ'] = self._update_environ(extra_environ, user) return super(DjangoTestApp, self).put_json(url, *args, **kwargs) def patch_json(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) kwargs['extra_environ'] = self._update_environ(extra_environ, user) return super(DjangoTestApp, self).patch_json(url, *args, **kwargs) def delete_json(self, url, *args, **kwargs): extra_environ = kwargs.get('extra_environ') user = kwargs.pop('user', _notgiven) kwargs['extra_environ'] = self._update_environ(extra_environ, user) return super(DjangoTestApp, self).delete_json(url, *args, **kwargs) @property def session(self): """ Obtains the current session variables. """ engine = import_module(settings.SESSION_ENGINE) cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None) if cookie: return engine.SessionStore(cookie) else: return {} def set_cookie(self, *args, **kwargs): self.extra_environ = self._update_environ(self.extra_environ) return super(DjangoTestApp, self).set_cookie(*args, **kwargs) class WebTestMixin(object): extra_environ = {} csrf_checks = True setup_auth = True app_class = DjangoTestApp def _patch_settings(self): ''' Patches settings to add support for django-webtest authorization and (optional) to disable CSRF checks. ''' self._DEBUG_PROPAGATE_EXCEPTIONS = settings.DEBUG_PROPAGATE_EXCEPTIONS self._MIDDLEWARE = self.settings_middleware[:] self._AUTHENTICATION_BACKENDS = settings.AUTHENTICATION_BACKENDS[:] self._REST_FRAMEWORK = getattr( settings, 'REST_FRAMEWORK', {'DEFAULT_AUTHENTICATION_CLASSES': []}) self.settings_middleware = list(self.settings_middleware) settings.AUTHENTICATION_BACKENDS = list( settings.AUTHENTICATION_BACKENDS) settings.REST_FRAMEWORK = copy.deepcopy(self._REST_FRAMEWORK) settings.DEBUG_PROPAGATE_EXCEPTIONS = True if not self.csrf_checks: self._disable_csrf_checks() if self.setup_auth: self._setup_auth() def _unpatch_settings(self): ''' Restores settings to before-patching state ''' self.settings_middleware = self._MIDDLEWARE settings.AUTHENTICATION_BACKENDS = self._AUTHENTICATION_BACKENDS settings.DEBUG_PROPAGATE_EXCEPTIONS = self._DEBUG_PROPAGATE_EXCEPTIONS settings.REST_FRAMEWORK = self._REST_FRAMEWORK def _setup_auth(self): ''' Setups django-webtest authorization ''' self._setup_auth_middleware() self._setup_auth_backend() self._setup_auth_class() def _disable_csrf_checks(self): disable_csrf_middleware = ( 'django_webtest.middleware.DisableCSRFCheckMiddleware') if disable_csrf_middleware not in self.settings_middleware: self.settings_middleware.insert(0, disable_csrf_middleware) def _setup_auth_middleware(self): webtest_auth_middleware = ( 'django_webtest.middleware.WebtestUserMiddleware') django_auth_middleware = ( 'django.contrib.auth.middleware.AuthenticationMiddleware') if django_auth_middleware not in self.settings_middleware: # There can be a custom AuthenticationMiddleware subclass or # replacement, we can't compute its index so just put our auth # middleware to the end. If appending causes problems # _setup_auth_middleware method can be overriden by a subclass. self.settings_middleware.append(webtest_auth_middleware) elif webtest_auth_middleware not in self.settings_middleware: index = self.settings_middleware.index(django_auth_middleware) self.settings_middleware.insert(index + 1, webtest_auth_middleware) def _setup_auth_backend(self): backend_name = getattr( settings, 'WEBTEST_AUTHENTICATION_BACKEND', 'django_webtest.backends.WebtestUserBackend') settings.AUTHENTICATION_BACKENDS.insert(0, backend_name) def _setup_auth_class(self): class_name = 'django_webtest.rest_framework_auth.WebtestAuthentication' drf_settings = settings.REST_FRAMEWORK try: classes = drf_settings['DEFAULT_AUTHENTICATION_CLASSES'] except KeyError: classes = [] if class_name not in classes: if isinstance(classes, tuple): classes = list(classes) classes.append(class_name) drf_settings['DEFAULT_AUTHENTICATION_CLASSES'] = classes @property def middleware_setting_name(self): try: return self._middleware_setting_name except AttributeError: if getattr(settings, 'MIDDLEWARE', None) is not None: name = 'MIDDLEWARE' else: name = 'MIDDLEWARE_CLASSES' self._middleware_setting_name = name return name @property def settings_middleware(self): return getattr(settings, self.middleware_setting_name) @settings_middleware.setter def settings_middleware(self, value): setattr(settings, self.middleware_setting_name, value) def renew_app(self): """ Resets self.app (drops the stored state): cookies, etc. Note: this renews only self.app, not the responses fetched by self.app. """ self.app = self.app_class(extra_environ=self.extra_environ) def __call__(self, result=None): self._patch_settings() self.renew_app() res = super(WebTestMixin, self).__call__(result) self._unpatch_settings() return res class WebTest(WebTestMixin, TestCase): pass class TransactionWebTest(WebTestMixin, TransactionTestCase): pass def _get_username(user): """ Return user's username. ``user`` can be standard Django User instance, a custom user model or just an username (as string). """ value = None # custom user, django 1.5+ get_username = getattr(user, 'get_username', None) if get_username is not None: value = get_username() if value is None: # standard User username = getattr(user, 'username', None) if username is not None: value = username else: # assume user is just an username value = user return value django-webtest-1.9.13/django_webtest/backends.py000066400000000000000000000031711477346500300216600ustar00rootroot00000000000000from __future__ import absolute_import from django.utils.version import get_complete_version from django.contrib.auth.backends import RemoteUserBackend from django_webtest.compat import from_wsgi_safe_string class WebtestUserBackend(RemoteUserBackend): """ Auth backend for django-webtest auth system """ # Although it appears that we're just creating work for ourselves here # because we're calling super(WebtestUserBackend, self).authenticate with # unchanged arguments, what matters is the name of the arguments. # Specifically, django.contrib.auth.authenticate looks at the names of the # arguments of a backend's authenticate method to decide whether the # backend can be used to authenticate a particular request. if get_complete_version() >= (1, 11): def authenticate(self, request, django_webtest_user): return super(WebtestUserBackend, self).authenticate( request, django_webtest_user) else: def authenticate(self, django_webtest_user): return super(WebtestUserBackend, self).authenticate( django_webtest_user) def clean_username(self, username): return from_wsgi_safe_string(username) class WebtestUserWithoutPermissionsBackend(WebtestUserBackend): """ Auth backend that passes-through any permission check to further backends """ def get_perm(self, user_obj, perm, obj=None): # Indicate that this backend does not handle permissions and # allow Django's django.contrib.auth.models._user_has_perm # utility to move on to other enabled authentication backends. return False django-webtest-1.9.13/django_webtest/compat.py000066400000000000000000000015571477346500300213770ustar00rootroot00000000000000import sys import urllib import django PY3 = sys.version_info[0] == 3 if PY3: from urllib import parse as urlparse def to_string(s): if isinstance(s, str): return s return str(s, 'latin1') def to_wsgi_safe_string(s): return urlparse.quote(to_string(s)) def from_wsgi_safe_string(s): return urlparse.unquote(s) else: import urlparse def to_string(s): return str(s) def to_wsgi_safe_string(s): return to_string(urllib.quote(s.encode('utf8'))) def from_wsgi_safe_string(s): return urllib.unquote(s).decode('utf8') def is_authenticated(user): if django.VERSION < (1, 10): return user.is_authenticated() return user.is_authenticated def is_anonymous(user): if django.VERSION < (1, 10): return user.is_anonymous() return user.is_anonymous django-webtest-1.9.13/django_webtest/middleware.py000066400000000000000000000054621477346500300222300ustar00rootroot00000000000000# -*- coding: utf-8 -*- import django from django.contrib.auth.middleware import RemoteUserMiddleware from django.core.exceptions import ImproperlyConfigured from django.contrib import auth if django.VERSION >= (1, 10): from django.utils.deprecation import MiddlewareMixin else: MiddlewareMixin = object from django_webtest.compat import is_authenticated class WebtestUserMiddleware(RemoteUserMiddleware): """ Middleware for utilizing django-webtest simplified auth ('user' arg for self.app.post and self.app.get). Mostly copied from RemoteUserMiddleware, but the auth backend is changed (by changing ``auth.authenticate`` arguments) in order to keep RemoteUser backend untouched during django-webtest auth. """ header = "WEBTEST_USER" def __call__(self, request): # AuthenticationMiddleware is required so that request.user exists. if not hasattr(request, 'user'): raise ImproperlyConfigured( "The django-webtest auth middleware requires the " "'django.contrib.auth.middleware.AuthenticationMiddleware' " "to be installed. Add it to your MIDDLEWARE setting " "or disable django-webtest auth support by setting " "'setup_auth' property of your WebTest subclass to False." ) try: username = request.META[self.header] except KeyError: # If specified header doesn't exist then return (leaving # request.user set to AnonymousUser by the # AuthenticationMiddleware). return self.get_response(request) # If the user is already authenticated and that user is the user we are # getting passed in the headers, then the correct user is already # persisted in the session and we don't need to continue. if is_authenticated(request.user): if hasattr(request.user, "get_username"): authenticated_username = request.user.get_username() else: authenticated_username = request.user.username clean_username = self.clean_username(username, request) if authenticated_username == clean_username: return self.get_response(request) # We are seeing this user for the first time in this session, attempt # to authenticate the user. user = auth.authenticate(request=request, django_webtest_user=username) if user: # User is valid. Set request.user and persist user in the session # by logging the user in. request.user = user auth.login(request, user) return self.get_response(request) class DisableCSRFCheckMiddleware(MiddlewareMixin): def process_request(self, request): request._dont_enforce_csrf_checks = True django-webtest-1.9.13/django_webtest/pytest_plugin.py000066400000000000000000000022471477346500300230170ustar00rootroot00000000000000# -*- coding: utf-8 -*- from django_webtest import WebTestMixin import pytest class MixinWithInstanceVariables(WebTestMixin): """ Override WebTestMixin to make all of its variables instance variables not class variables; otherwise multiple django_app_factory fixtures contend for the same class variables """ def __init__(self): self.extra_environ = {} self.csrf_checks = True self.setup_auth = True @pytest.fixture(scope='session') def django_app_mixin(): app_mixin = MixinWithInstanceVariables() return app_mixin @pytest.fixture def django_app(django_app_mixin): django_app_mixin._patch_settings() django_app_mixin.renew_app() yield django_app_mixin.app django_app_mixin._unpatch_settings() @pytest.fixture def django_app_factory(): app_mixin = MixinWithInstanceVariables() def factory(csrf_checks=True, extra_environ=None): app_mixin.csrf_checks = csrf_checks if extra_environ: app_mixin.extra_environ = extra_environ app_mixin._patch_settings() app_mixin.renew_app() return app_mixin.app yield factory app_mixin._unpatch_settings() django-webtest-1.9.13/django_webtest/response.py000066400000000000000000000030151477346500300217410ustar00rootroot00000000000000# -*- coding: utf-8 -*- from django.test import Client from django.http import SimpleCookie from webtest import TestResponse from django_webtest.compat import urlparse class DjangoWebtestResponse(TestResponse): """ WebOb's Response quacking more like django's HttpResponse. This is here to make more django's TestCase asserts work, not to provide a generally useful proxy. """ streaming = False @property def status_code(self): return self.status_int @property def _charset(self): return self.charset @property def content(self): return self.body @property def url(self): return self['location'] @property def client(self): client = Client() client.cookies = SimpleCookie() for k, v in self.test_app.cookies.items(): client.cookies[k] = v return client def __getitem__(self, item): item = item.lower() if item == 'location': # django's test response returns location as http://testserver/, # WebTest returns it as http://localhost:80/ scheme, netloc, path, query, fragment = urlparse.urlsplit( self.location) if netloc == 'localhost:80': netloc = 'testserver' return urlparse.urlunsplit( [scheme, netloc, path, query, fragment]) for header, value in self.headerlist: if header.lower() == item: return value raise KeyError(item) django-webtest-1.9.13/django_webtest/rest_framework_auth.py000066400000000000000000000007541477346500300241650ustar00rootroot00000000000000from django.contrib.auth import authenticate from rest_framework import authentication class WebtestAuthentication(authentication.BaseAuthentication): """Bridge between webtest and django-rest-framework.""" header = 'WEBTEST_USER' def authenticate(self, request): value = request.META.get(self.header) if value: account = authenticate(django_webtest_user=value) if account and account.is_active: return (account, None) django-webtest-1.9.13/django_webtest_tests/000077500000000000000000000000001477346500300207545ustar00rootroot00000000000000django-webtest-1.9.13/django_webtest_tests/__init__.py000066400000000000000000000000001477346500300230530ustar00rootroot00000000000000django-webtest-1.9.13/django_webtest_tests/manage.py000077500000000000000000000010421477346500300225560ustar00rootroot00000000000000#!/usr/bin/env python from django.core.management import execute_manager try: import settings # Assumed to be in the same directory. except ImportError: import sys sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) sys.exit(1) if __name__ == "__main__": execute_manager(settings) django-webtest-1.9.13/django_webtest_tests/runtests.py000077500000000000000000000005271477346500300232240ustar00rootroot00000000000000#!/usr/bin/env python import os import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") from django.core.management import execute_from_command_line sys.argv.insert(1, 'test') if len(sys.argv) == 2: sys.argv.append('testapp_tests') execute_from_command_line(sys.argv) django-webtest-1.9.13/django_webtest_tests/settings.py000066400000000000000000000056621477346500300231770ustar00rootroot00000000000000import os import sys import django PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) join = lambda p: os.path.abspath(os.path.join(PROJECT_ROOT, p)) # TODO configure pytest testpaths instead of doing this sys.path.insert(0, join('..')) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': join('db.sqlite'), 'USER': '', 'PASSWORD': '', 'HOST': '', 'PORT': '', } } if os.environ.get('USE_POSTGRES'): DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2' DATABASES['default']['HOST'] = os.environ.get('POSTGRES_HOST', '') DATABASES['default']['PORT'] = int(os.environ.get('POSTGRES_PORT', '5432')) DATABASES['default']['USER'] = os.environ.get('POSTGRES_USER', '') DATABASES['default']['PASSWORD'] = os.environ.get('POSTGRES_PASSWORD', '') DATABASES['default']['NAME'] = os.environ.get( 'POSTGRES_DB', 'django_webtest_tests' ) SITE_ID = 1 ROOT_URLCONF = 'urls' SECRET_KEY = '5mcs97ar-(nnxhfkx0%^+0^sr!e(ax=x$2-!8dqy25ff-l1*a=' DEBUG = False USE_I18N = True USE_L10N = True TIME_ZONE = 'America/Chicago' LANGUAGE_CODE = 'en-us' MEDIA_ROOT = join('media') MEDIA_URL = '/media/' STATIC_URL = '/static/' LOGIN_REDIRECT_URL = '/template/index.html' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'debug': DEBUG, 'context_processors': [ 'django.contrib.auth.context_processors.auth', 'django.template.context_processors.debug', 'django.template.context_processors.i18n', 'django.template.context_processors.media', 'django.template.context_processors.static', 'django.template.context_processors.tz', 'django.contrib.messages.context_processors.messages', ], }, }, ] if django.VERSION < (1, 10): TEMPLATE_DEBUG = DEBUG TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ) TEMPLATE_DIRS = ( join('templates'), ) MIDDLEWARE = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'testapp_tests.middleware.UserMiddleware', ) if django.VERSION < (1, 10): MIDDLEWARE_CLASSES = MIDDLEWARE del MIDDLEWARE INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django_webtest', 'django_webtest_tests', 'django_webtest_tests.testapp_tests', ) DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' django-webtest-1.9.13/django_webtest_tests/templates/000077500000000000000000000000001477346500300227525ustar00rootroot00000000000000django-webtest-1.9.13/django_webtest_tests/templates/404.html000066400000000000000000000000351477346500300241450ustar00rootroot00000000000000

404

django-webtest-1.9.13/django_webtest_tests/templates/500.html000066400000000000000000000000351477346500300241420ustar00rootroot00000000000000

500

django-webtest-1.9.13/django_webtest_tests/templates/complex.html000066400000000000000000000001231477346500300253030ustar00rootroot00000000000000 {% for bar in foo %} {% include "include.html" %} {% endfor %} django-webtest-1.9.13/django_webtest_tests/templates/form.html000066400000000000000000000002641477346500300246050ustar00rootroot00000000000000
{% csrf_token %} {{ form.as_p }}
Login django-webtest-1.9.13/django_webtest_tests/templates/get_form.html000066400000000000000000000002661477346500300254460ustar00rootroot00000000000000
{{ form.as_p }} You searched for: {{ q }}
django-webtest-1.9.13/django_webtest_tests/templates/include.html000066400000000000000000000000121477346500300252540ustar00rootroot00000000000000{{ bar }} django-webtest-1.9.13/django_webtest_tests/templates/index.html000066400000000000000000000003501477346500300247450ustar00rootroot00000000000000

Hello :)

User: {{ user }}

{% if bar %}
    {% for bar in foo %}
  • {{ object }}
  • {% endfor %}
{% endif %}

Do we want spam? {{ spam|yesno }}

привет-привет.

django-webtest-1.9.13/django_webtest_tests/templates/registration/000077500000000000000000000000001477346500300254645ustar00rootroot00000000000000django-webtest-1.9.13/django_webtest_tests/templates/registration/login.html000066400000000000000000000000321477346500300274550ustar00rootroot00000000000000{% extends "form.html" %} django-webtest-1.9.13/django_webtest_tests/test_pytest.py000066400000000000000000000013531477346500300237170ustar00rootroot00000000000000# -*- coding: utf-8 -*- from django.conf import settings initial_settings = { "DEBUG_PROPAGATE_EXCEPTIONS": settings.DEBUG_PROPAGATE_EXCEPTIONS, "AUTHENTICATION_BACKENDS": settings.AUTHENTICATION_BACKENDS, } def test_django_app(django_app): resp = django_app.get('/') assert resp.status_int == 200 def test_django_app_post(django_app_factory): app = django_app_factory(csrf_checks=False) resp = app.post('/') assert resp.status_int == 200 def test_app_factory(): """Ensure django_app_factory properly resets settings.""" assert settings.DEBUG_PROPAGATE_EXCEPTIONS is initial_settings["DEBUG_PROPAGATE_EXCEPTIONS"] assert settings.AUTHENTICATION_BACKENDS == initial_settings["AUTHENTICATION_BACKENDS"] django-webtest-1.9.13/django_webtest_tests/testapp_tests/000077500000000000000000000000001477346500300236565ustar00rootroot00000000000000django-webtest-1.9.13/django_webtest_tests/testapp_tests/__init__.py000066400000000000000000000000001477346500300257550ustar00rootroot00000000000000django-webtest-1.9.13/django_webtest_tests/testapp_tests/middleware.py000066400000000000000000000004751477346500300263530ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import import django if django.VERSION >= (1, 10): from django.utils.deprecation import MiddlewareMixin else: MiddlewareMixin = object class UserMiddleware(MiddlewareMixin): def process_request(self, request): request.user.processed = True django-webtest-1.9.13/django_webtest_tests/testapp_tests/models.py000066400000000000000000000006201477346500300255110ustar00rootroot00000000000000import django if django.VERSION >= (1, 5): from django.contrib.auth.models import AbstractBaseUser from django.db import models class MyCustomUser(AbstractBaseUser): email = models.EmailField( max_length=255, unique=True, db_index=True, ) USERNAME_FIELD = 'email' class Meta: app_label = "testapp_tests" django-webtest-1.9.13/django_webtest_tests/testapp_tests/tests.py000066400000000000000000000423741477346500300254040ustar00rootroot00000000000000# -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals import django from django.contrib.auth.models import User try: from django.urls import reverse except ImportError: from django.core.urlresolvers import reverse from unittest import skipIf from unittest.mock import patch from django.test.testcases import override_settings from webtest import AppError, TestApp from django_webtest import WebTest from django_webtest.compat import is_anonymous, is_authenticated class MethodsTest(WebTest): csrf_checks = False def assertMethodWorks(self, meth, name): response = meth('/') self.assertEqual(response.status_int, 200) response.mustcontain(name) #self.assertTrue(name in response) def assertMethodWorksXHR(self, meth, name): try: response = meth('/', xhr=True) except TypeError as e: # for webtest < 2 self.assertIn('xhr', e.message) else: # for webtest == 2 self.assertEqual(response.status_int, 200) response.mustcontain(name) def test_get(self): self.assertMethodWorks(self.app.get, 'GET') def test_post(self): self.assertMethodWorks(self.app.post, 'POST') def test_put(self): self.assertMethodWorks(self.app.put, 'PUT') def test_delete(self): self.assertMethodWorks(self.app.delete, 'DELETE') def test_get_json(self): self.assertMethodWorks(self.app.get, 'GET') def test_post_json(self): self.assertMethodWorks(self.app.post_json, 'POST') def test_put_json(self): self.assertMethodWorks(self.app.put_json, 'PUT') def test_delete_json(self): self.assertMethodWorks(self.app.delete_json, 'DELETE') def test_get_xhr(self): self.assertMethodWorksXHR(self.app.get, 'GET') def test_post_xhr(self): self.assertMethodWorksXHR(self.app.post, 'POST') def test_put_xhr(self): self.assertMethodWorksXHR(self.app.put, 'PUT') def test_delete_xhr(self): self.assertMethodWorksXHR(self.app.delete, 'DELETE') if hasattr(TestApp, 'patch'): # old WebTest versions don't have 'patch' method def test_patch(self): self.assertMethodWorks(self.app.patch, 'PATCH') def test_head(self): response = self.app.head('/') self.assertEqual(response.status_int, 200) expected = b'' if django.VERSION < (1, 10) else b'HEAD' self.assertEqual(response.body, expected) def test_options(self): self.assertMethodWorks(self.app.options, 'OPTIONS') def test_get_auto_follow_default(self): response = self.app.get(reverse('remove-prefix-redirect', args=('template/index.html',))) self.assertEqual(response.status_code, 302) def test_get_auto_follow_true(self): response = self.app.get(reverse('remove-prefix-redirect', args=('template/index.html',)), auto_follow=True) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Hello') def test_get_auto_follow_and_expect_errors(self): response = self.app.get(reverse('remove-prefix-redirect', args=('some-404/',)), auto_follow=True, expect_errors=True) self.assertEqual(response.status_code, 404) def test_get_with_positional_args(self): response = self.app.get('/', {}) self.assertEqual(response.status_code, 200) class PostRequestTest(WebTest): csrf_checks = False def test_post_request(self): response = self.app.post('/') self.assertEqual(response.status_int, 200) self.assertTrue('POST' in response) def test_404_response(self): self.assertRaises(AppError, self.app.get, '/404/') class CsrfProtectionTest(WebTest): def test_csrf_failed(self): response = self.app.post('/', expect_errors=True) self.assertEqual(response.status_int, 403) class FormSubmitTest(WebTest): def test_form_submit(self): page = self.app.get(reverse('check_password')) page.form['password'] = 'bar' page_with_errors = page.form.submit() assert 'Incorrect password' in page_with_errors page_with_errors.form['password'] = 'foo' page_with_errors.form.submit().follow() # check for 302 response class GetFormSubmitTest(WebTest): def test_form_submit(self): page = self.app.get(reverse('search')) page.form['q'] = 'bar' response = page.form.submit() self.assertEqual(response.context['q'], 'bar') class TemplateContextTest(WebTest): def test_rendered_templates(self): response = self.app.get('/template/index.html') self.assertTrue(hasattr(response, 'context')) self.assertTrue(hasattr(response, 'template')) self.assertEqual(response.template.name, 'index.html') self.assertEqual(response.context['bar'], True) self.assertEqual(response.context['spam'], None) self.assertRaises(KeyError, response.context.__getitem__, 'invalid') def test_multiple_templates(self): response = self.app.get('/template/complex.html') self.assertEqual(len(response.template), 4) self.assertEqual(response.template[0].name, 'complex.html') self.assertEqual(response.template[1].name, 'include.html') self.assertEqual(response.template[2].name, 'include.html') self.assertEqual(response.template[3].name, 'include.html') self.assertEqual(response.context['foo'], ('a', 'b', 'c')) self.assertEqual(response.context['bar'], True) self.assertEqual(response.context['spam'], None) class BaseAuthTest(WebTest): def setUp(self): self.user = User.objects.create_user('foo', 'example@example.com', '123') def _login(self, username, password): form = self.app.get(reverse('auth_login')).form form['username'] = username form['password'] = password return form.submit() def assertCanLogin(self, user): response = self.app.get('/template/index.html', user=user) res_user = response.context['user'] assert is_authenticated(res_user) if isinstance(user, User): self.assertEqual(res_user, user) else: self.assertEqual(res_user.username, user) class AuthTest(BaseAuthTest): def test_not_logged_in(self): response = self.app.get('/template/index.html') user = response.context['user'] assert not is_authenticated(user) def test_logged_using_username(self): self.assertCanLogin('foo') def test_logged_using_native_username(self): self.assertCanLogin(str('foo')) def test_logged_using_unicode_username(self): self.assertCanLogin('ƒøø') def test_logged_using_instance(self): self.assertCanLogin(self.user) def test_logged_using_unicode_instance(self): user = User.objects.create_user('ƒøø', 'example@example.com', '123') self.assertCanLogin(user) def test_auth_is_enabled(self): from django.conf import settings auth_middleware = 'django_webtest.middleware.WebtestUserMiddleware' assert auth_middleware in self.settings_middleware assert 'django_webtest.backends.WebtestUserBackend' in settings.AUTHENTICATION_BACKENDS dependency_index = self.settings_middleware.index( 'django.contrib.auth.middleware.AuthenticationMiddleware') self.assertEqual( self.settings_middleware.index(auth_middleware), dependency_index + 1, ) def test_custom_middleware(self): response = self.app.get('/template/index.html', user=self.user) user = response.context['user'] self.assertTrue(user.processed) def test_standard_auth(self): resp = self._login(self.user.username, '123').follow() user = resp.context['user'] self.assertEqual(user, self.user) self.assertIn('sessionid', self.app.cookies) resp = self.app.get(reverse('protected')) self.assertEqual(resp.status_int, 200) resp.mustcontain('ok: {0}'.format(self.user.username)) def test_reusing_custom_user(self): if django.VERSION >= (1, 5): from django_webtest_tests.testapp_tests.models import MyCustomUser with self.settings(AUTH_USER_MODEL = 'testapp_tests.MyCustomUser'): custom_user = MyCustomUser.objects.create( email="custom@example.com") custom_user.set_password("123") custom_user.save() # Let the middleware logs the user in self.app.get('/template/index.html', user=custom_user) # Middleware authentication check shouldn't crash response = self.app.get('/template/index.html', user=custom_user) user = response.context['user'] assert is_authenticated(user) self.assertEqual(user, custom_user) def test_normal_user(self): """Make sure the fix for custom users in django 1.5 doesn't break normal django users""" self.app.get('/template/index.html', user=self.user) self.app.get('/template/index.html', user=self.user) @override_settings( WEBTEST_AUTHENTICATION_BACKEND=( 'django_webtest.backends.WebtestUserWithoutPermissionsBackend'), AUTHENTICATION_BACKENDS=['testapp_tests.SimpleBackend'], ) class CustomAuthTest(BaseAuthTest): def test_backend_is_enabled(self): from django.conf import settings assert len(settings.AUTHENTICATION_BACKENDS) == 2 assert ( settings.AUTHENTICATION_BACKENDS[0] == 'django_webtest.backends.WebtestUserWithoutPermissionsBackend' ) def test_permission_passthrough(self): from django.contrib.auth.backends import ModelBackend class SimpleBackend(ModelBackend): def has_perm(self, user_obj, perm, obj=None): return perm == 'tests.allow' with patch('testapp_tests.SimpleBackend', SimpleBackend, create=True): assert self.user.has_perm('tests.allow') is True assert self.user.has_perm('tests.deny') is False class GlobalAuthTest(BaseAuthTest): def test_set_user(self): self.app.set_user(self.user.username) environ = self.app.extra_environ self.assertEqual(environ['WEBTEST_USER'], self.user.username) resp = self.app.get('/template/index.html') environ = resp.request.environ self.assertEqual(environ['WEBTEST_USER'], self.user.username) resp.mustcontain('User: {}'.format(self.user.username)) def test_set_user_reset(self): self.app.set_user(self.user.username) self.app.set_user(None) environ = self.app.extra_environ self.assertNotIn('WEBTEST_USER', environ) resp = self.app.get('/template/index.html') environ = resp.request.environ self.assertNotIn('WEBTEST_USER', environ) resp.mustcontain('User: AnonymousUser') def test_user_param(self): resp = self.app.get('/template/index.html', user='bob_morane') self.assertEqual(resp.request.environ['WEBTEST_USER'], 'bob_morane') resp.mustcontain('User: bob_morane') def test_user_param_reset(self): self.app.set_user(self.user.username) resp = self.app.get('/template/index.html', user=None) # this request had no user self.assertEqual(resp.request.environ['WEBTEST_USER'], '') resp.mustcontain('User: AnonymousUser') # app object is unchanged self.assertEqual(self.app.extra_environ['WEBTEST_USER'], self.user.username) class EnvironTest(BaseAuthTest): extra_environ = {'REMOTE_ADDR': '127.0.0.2'} def test_extra_environ_reset(self): resp = self.app.get('/template/index.html', user=self.user) environ = resp.request.environ self.assertEqual(environ['WEBTEST_USER'], 'foo') self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.2') resp2 = self.app.get('/template/index.html') environ = resp2.request.environ self.assertNotIn('WEBTEST_USER', environ) self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.2') resp3 = self.app.get('/template/index.html', extra_environ={'REMOTE_ADDR': '127.0.0.1'}) environ = resp3.request.environ self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1') class RenewAppTest(BaseAuthTest): def test_renew_app(self): self._login(self.user.username, '123').follow() # auth cookie is preserved between self.app.get calls page1 = self.app.get('/template/form.html') self.assertEqual(page1.context['user'], self.user) self.renew_app() # cookies were dropped page2 = self.app.get('/template/form.html') self.assertTrue(is_anonymous(page2.context['user'])) # but cookies are still there while browsing from stored page page1_1 = page1.click('Login') self.assertEqual(page1_1.context['user'], self.user) class DjangoAssertsTest(BaseAuthTest): def test_assert_template_used(self): response = self.app.get('/template/index.html') self.assertTemplateUsed(response, 'index.html') self.assertTemplateNotUsed(response, 'complex.html') complex_response = self.app.get('/template/complex.html') self.assertTemplateUsed(complex_response, 'complex.html') self.assertTemplateUsed(complex_response, 'include.html') self.assertTemplateNotUsed(complex_response, 'foo.html') # def test_assert_form_error(self): # page = self.app.get(reverse('check_password')) # page.form['password'] = 'bar' # page_with_errors = page.form.submit() # self.assertFormError(page_with_errors, 'password', 'Incorrect password.') def test_assert_contains(self): response = self.app.get('/template/index.html') self.assertContains(response, 'Hello', 1) self.assertNotContains(response, 'Good bye!') def test_assert_contains_unicode(self): response = self.app.get('/template/index.html') self.assertContains(response, 'привет', 2) def test_assert_redirects(self): page = self.app.get(reverse('check_password')) page.form['password'] = 'foo' resp = page.form.submit() self.assertRedirects(resp, '/') def test_redirects_noauth(self): self.app.get(reverse('redirect-to-protected')).follow(status=302) def test_redirects(self): self.app.get(reverse('redirect-to-protected'), user=self.user).follow() def test_assert_redirects_auth(self): page = self.app.get(reverse('redirect-to-protected'), user=self.user) self.assertRedirects(page, reverse('protected')) class DisableAuthSetupTest(WebTest): setup_auth = False def test_no_auth(self): from django.conf import settings middleware = getattr(settings, 'MIDDLEWARE', None) or settings.MIDDLEWARE_CLASSES assert 'django_webtest.middleware.WebtestUserMiddleware' not in middleware assert 'django_webtest.backends.WebtestUserBackend' not in settings.AUTHENTICATION_BACKENDS class TestSession(WebTest): def test_session_not_set(self): response = self.app.get('/') self.assertEqual(response.status_int, 200) self.assertEqual({}, self.app.session) def test_sessions_disabled(self): from django.conf import settings apps = list(settings.INSTALLED_APPS) apps.remove("django.contrib.sessions") settings.INSTALLED_APPS = apps response = self.app.get('/') self.assertEqual(response.status_int, 200) self.assertEqual({}, self.app.session) def test_session_not_empty(self): self.app.get(reverse('set_session')) self.assertEqual('foo', self.app.session['test']) class TestHeaderAccess(WebTest): def test_headers(self): response = self.app.get('/') self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8') self.assertEqual(response['content-type'], 'text/html; charset=utf-8') def test_bad_header(self): def access_bad_header(): response = self.app.get('/') response['X-Unknown-Header'] self.assertRaises(KeyError, access_bad_header) class TestCookies(WebTest): def test_cookies(self): self.app.set_cookie(str('test_cookie'), str('cookie monster!')) rsp = self.app.get(reverse('cookie_test')) self.assertContains(rsp, 'cookie monster!') @skipIf(django.VERSION < (1, 10), 'MIDDLEWARE is added in Django 1.10') @override_settings(MIDDLEWARE=[]) class MiddlewareTest(WebTest): def test_middleware_setting_name(self): self.assertEqual( self.middleware_setting_name, 'MIDDLEWARE' ) @skipIf(django.VERSION < (1, 10) or django.VERSION >= (2, 0), 'MIDDLEWARE is added in Django 1.10') @override_settings(MIDDLEWARE=None, MIDDLEWARE_CLASSES=[]) class MiddlewareClassesTest(WebTest): def test_middleware_setting_name(self): self.assertEqual( self.middleware_setting_name, 'MIDDLEWARE_CLASSES' ) django-webtest-1.9.13/django_webtest_tests/testapp_tests/views.py000066400000000000000000000026401477346500300253670ustar00rootroot00000000000000from django import forms from django.contrib.auth.decorators import login_required from django.http import HttpResponseRedirect, HttpResponse from django.shortcuts import render, redirect class PasswordForm(forms.Form): password = forms.CharField(widget=forms.PasswordInput()) def clean_password(self): if self.cleaned_data['password'] != 'foo': raise forms.ValidationError('Incorrect password.') return self.cleaned_data['password'] def check_password(request): form = PasswordForm(request.POST or None) if form.is_valid(): return HttpResponseRedirect('/') return render(request, 'form.html', {'form': form}) class SearchForm(forms.Form): q = forms.CharField(required=False) def search(request): form = SearchForm(request.GET) q = None if form.is_valid(): q = form.cleaned_data['q'] return render(request, 'get_form.html', {'form': form, 'q': q}) def set_session(request): request.session['test'] = 'foo' return HttpResponseRedirect('/') def redirect_to_protected(request): return redirect('protected') @login_required def protected(request): return HttpResponse('ok: {0}'.format(request.user.username)) def remove_prefix_redirect(request, arg): return HttpResponseRedirect("/" + arg) def cookie_test(request): cookie = request.COOKIES.get(str('test_cookie'), None) return HttpResponse('cookie: {0}'.format(cookie)) django-webtest-1.9.13/django_webtest_tests/tox2travis.py000066400000000000000000000024061477346500300234550ustar00rootroot00000000000000# -*- coding: utf-8 -*- TRAVIS_CONF = ''' language: python cache: directories: - $HOME/.cache/pip services: - postgresql before_script: - psql -c 'create database django_webtest_tests;' -U postgres install: - pip install tox script: - tox matrix: include: ''' if __name__ == '__main__': import subprocess import sys p = subprocess.check_output('tox -l', shell=True) if sys.version_info.major == 3: p = p.decode('utf-8') with open('.travis.yml', 'w') as fd: fd.write(TRAVIS_CONF) for env in p.split('\n'): env = env.strip() if env and env not in ('travis',): dist = None if env.startswith('pypy'): py = 'pypy' else: py = '{0}.{1}'.format(env[2], env[3]) if int(env[2] + env[3]) > 38: # looks like psql dos not work on xenial... skip 3.7 # for now continue dist = 'xenial' fd.write(' - python: "{}"\n'.format(py)) fd.write(' env: TOXENV={}\n'.format(env)) if dist is not None: fd.write(' dist: {}\n'.format(dist)) django-webtest-1.9.13/django_webtest_tests/urls.py000066400000000000000000000050021477346500300223100ustar00rootroot00000000000000import django from django.http import HttpResponse from django.shortcuts import render from testapp_tests.views import check_password, search, set_session, \ protected, redirect_to_protected, remove_prefix_redirect, cookie_test major_version = int(django.__version__[0]) if major_version >= 4: from django.urls import re_path else: try: from django.conf.urls import url except ImportError: from django.conf.urls.defaults import url try: from django.contrib.auth.views import login except ImportError: # django 2+ from django.contrib.auth.views import LoginView login = LoginView.as_view() def simple_method_test(request): return HttpResponse(str(request.method)) def simple_template_render(request, template_name): return render(request, template_name, { 'user': request.user, 'foo': ('a', 'b', 'c'), 'bar': True, 'spam': None, }) if major_version >= 4: urlpatterns = ( re_path(r'$', simple_method_test, name='simple-method-test'), re_path(r'template/(.*)$', simple_template_render, name='simple-template-test'), re_path(r'check-password/$', check_password, name='check_password'), re_path(r'search/$', search, name='search'), re_path(r'login/$', login, name='auth_login'), re_path(r'set-session/$', set_session, name='set_session'), re_path(r'protected/$', protected, name='protected'), re_path(r'redirect-to-protected/$', redirect_to_protected, name='redirect-to-protected'), re_path(r'remove-prefix-redirect/(.*)/$', remove_prefix_redirect, name='remove-prefix-redirect'), re_path(r'cookie-test/$', cookie_test, name='cookie_test'), ) else: urlpatterns = ( url(r'^$', simple_method_test, name='simple-method-test'), url(r'^template/(.*)$', simple_template_render, name='simple-template-test'), url(r'^check-password/$', check_password, name='check_password'), url(r'^search/$', search, name='search'), url(r'^login/$', login, name='auth_login'), url(r'^set-session/$', set_session, name='set_session'), url(r'^protected/$', protected, name='protected'), url(r'^redirect-to-protected/$', redirect_to_protected, name='redirect-to-protected'), url(r'^remove-prefix-redirect/(.*)/$', remove_prefix_redirect, name='remove-prefix-redirect'), url(r'^cookie-test/$', cookie_test, name='cookie_test'), ) django-webtest-1.9.13/setup.py000077500000000000000000000043251477346500300162540ustar00rootroot00000000000000#!/usr/bin/env python import sys from setuptools import setup version = '1.9.13' def _read(name): if sys.version_info[0] < 3: with open(name) as f: return f.read() else: with open(name, encoding='utf8') as f: return f.read() def get_long_description(): return _read('README.rst') + "\n\n" + _read('CHANGES.rst') setup( name='django-webtest', version=version, author='Mikhail Korobov', author_email='kmike84@gmail.com', packages=['django_webtest'], url='https://github.com/django-webtest/django-webtest', license='MIT license', description=( "Instant integration of Ian Bicking's WebTest " "(http://docs.pylonsproject.org/projects/webtest/) " "with Django's testing framework." ), long_description=get_long_description(), install_requires=['webtest >= 1.3.3'], entry_points=""" [pytest11] django_webtest = django_webtest.pytest_plugin """, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Framework :: Django', 'Framework :: Django :: 4.2', 'Framework :: Django :: 5.0', 'Framework :: Django :: 5.1', 'Framework :: Django :: 5.2', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Testing', ], project_urls={ 'Code': 'https://github.com/django-webtest/django-webtest', 'Issue Tracker': 'https://github.com/django-webtest/django-webtest/issues', 'Changelog': 'https://github.com/django-webtest/django-webtest/blob/master/CHANGES.rst', }, keywords=['django', 'webtest', 'pytest'], ) django-webtest-1.9.13/tox.ini000066400000000000000000000014001477346500300160410ustar00rootroot00000000000000[tox] skip_missing_interpreters = true envlist = {py39,py311,py312}-django{42,50,51,52}-{std,clocale,postgres} [testenv] deps= pytest pytest-django postgres: psycopg2-binary django42: django >=4.2, <5.0 django50: django >=5.0, <5.1 django51: django >=5.1, <5.2 django52: django >=5.2, <6.0 setenv= clocale: LC_ALL=C postgres: USE_POSTGRES=true DJANGO_SETTINGS_MODULE=settings passenv = POSTGRES_HOST POSTGRES_PORT POSTGRES_USER POSTGRES_PASSWORD POSTGRES_NAME allowlist_externals = env changedir=django_webtest_tests commands= env python runtests.py pytest test_pytest.py [testenv:travis] # use `tox -e travis` to update .travis.yml basepython=python3.11 commands= python tox2travis.py