Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CAPTCHA_TEST_MODE doesn't work with override_settings decorator #84

Open
romlok opened this issue Jun 12, 2015 · 7 comments
Open

CAPTCHA_TEST_MODE doesn't work with override_settings decorator #84

romlok opened this issue Jun 12, 2015 · 7 comments

Comments

@romlok
Copy link

romlok commented Jun 12, 2015

Django provides some decorators to modify settings on a per-test or per-test-class basis: django.test.override_settings and django.test.modify_settings (https://docs.djangoproject.com/en/dev/topics/testing/tools/#overriding-settings).

However, it seems django-simple-captcha reads and stores the project's value of settings.CAPTCHA_TEST_MODE (and other settings) only the first time captcha.conf.settings is imported. Consequently, one must either specify CAPTCHA_TEST_MODE globally for all tests in a custom settings.py, or monkey-patch captcha.conf.settings...

It would make testing easier if settings were always read on-the-fly, rather than cached.
Or, failing that, it would be good to at least provide notice in the config documentation (particularly for CAPTCHA_TEST_MODE) that they cannot be overridden by override_settings and modify_settings.

@kumrzz
Copy link

kumrzz commented Dec 16, 2016

agree: neither @django.test.override_settings nor django.conf.settings worked for me. I can see them altered, but since captcha.conf.settings is only imported the first time, these are ignored. Interestingly, I see the tests(django-simple-captcha/captcha/tests/tests.py) overriding these on the fly, but pretty sure those aren't passing(test_test_mode_issue15).

@ziima
Copy link
Contributor

ziima commented Jan 29, 2018

I suggest to use django-appsettings or similar project to manage application settings.

@jna99
Copy link

jna99 commented Dec 28, 2020

There is a solution for this. To make the CAPTCHA_TEST_MODE work, it needs to be set to True and the form will only be valid if you set captcha_0 and captcha_1. captcha_0 needs a hash (I copied one from my browser) and captcha_1 needs to contain "PASSED" (can be lower or uppercase) in string format.

for example:
"captcha_0": "8e10ebf60c5f23fd6e6a9959853730cd69062a15",
"captcha_1": "PASSED",

@Deguise
Copy link

Deguise commented Jan 29, 2021

Hello,
My solution is to detect if test are running or not.
In settings.py file:

# Allow to detect if test are running or not
TESTING = bool(len(sys.argv) > 1 and sys.argv[1] == 'test')
# When set to True, the string “PASSED” (any case) will be accepted as a valid response to any CAPTCHA. Use this for testing purposes. 
CAPTCHA_TEST_MODE = TESTING

Now, if TESTING is True, CAPTCHA_TEST_MODE is also set to True and you can validate your form as usually.
In tests.py file:

def test_form(self):
    """Test Form with captcha"""
    form_data = {
        'captcha_0': "dummy_value",
        'captcha_1': "PASSED",
        }
    form = MyForm(data=form_data)
    is_valid = form.is_valid()
    if not is_valid:
        print(form.errors)
    self.assertTrue(is_valid)

@atodorov
Copy link

FTR neither does this work:

            try:
                settings.CAPTCHA_TEST_MODE = True

                response = self.client.post(
                    self.register_url,
                    {
                        "username": username,
                        "password1": "password",
                        "password2": "password",
                        "email": "[email protected]",
                        "captcha_0": "PASSED",
                        "captcha_1": "PASSED",
                    },
                    follow=follow,
                )
            finally:
                settings.CAPTCHA_TEST_MODE = False

This is the only way how I managed to get it working:

            try:
                # https://github.com/mbi/django-simple-captcha/issues/84
                from captcha.conf import settings as captcha_settings
                captcha_settings.CAPTCHA_TEST_MODE = True

                response = self.client.post(
                    self.register_url,
                    {
                        "username": username,
                        "password1": "password",
                        "password2": "password",
                        "email": "[email protected]",
                        "captcha_0": "PASSED",
                        "captcha_1": "PASSED",
                    },
                    follow=follow,
                )
            finally:
                captcha_settings.CAPTCHA_TEST_MODE = False

@0xalen
Copy link

0xalen commented Feb 18, 2022

This worked for me:


from django.test import TestCase
from captcha.conf import settings as captcha_settings

class TestRandomForms(TestCase):

    databases = "__all__"

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        captcha_settings.CAPTCHA_TEST_MODE = True

    @classmethod
    def tearDownClass(cls):
        super().tearDownClass()
        captcha_settings.CAPTCHA_TEST_MODE = False
        
    def test_random_form_valid(self):
        . . . 
        form_data = {
            . . .
            'captcha_0': 'PASSED',
            'captcha_1': 'PASSED',
            .
        }
        form = RandomForm(data=form_data)
        
       self.assertTrue(form.is_valid())

I hope it helps.

@leolivier
Copy link

Seeing the 2 previous answers which are actually the only ones working, maybe the package should provide it's own decorator/context manager eg something like '@ignore_captcha_errors'? Starting from there, I wrote this small piece of code and tested it and it works!

from captcha.conf import settings as captcha_settings
from django.test.utils import TestContextDecorator
class ignore_captcha_errors(TestContextDecorator):
	def __init__(self):
		super().__init__()
		self.captcha_test_mode = captcha_settings.CAPTCHA_TEST_MODE

	def enable(self):
		captcha_settings.CAPTCHA_TEST_MODE = True

	def disable(self):
		captcha_settings.CAPTCHA_TEST_MODE = self.captcha_test_mode

	def decorate_class(self, cls):
		from django.test import SimpleTestCase
		if not issubclass(cls, SimpleTestCase):
			raise ValueError(
				"Only subclasses of Django SimpleTestCase can be decorated "
				"with ignore_captcha_errors"
			)
		self.captcha_test_mode = captcha_settings.CAPTCHA_TEST_MODE
		return cls

To be used as

class TestSomething(SimpleTestCase):
  @ignore_captcha_errors()
  def test_something(self):
     response  = self.client.post(my_url, {... 'captcha_0': 'whatever', 'captcha_1': 'passed'}, follow=True)

or

class TestSomething(SimpleTestCase):
  
  def test_something(self):
     with ignore_captcha_errors():
        response  = self.client.post(my_url, {... 'captcha_0': 'whatever', 'captcha_1': 'passed'}, follow=True)

I'll do a PR for that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants