Wagtail Streamforms met reCaptcha testen

Wagtail Streamforms biedt een zeer flexibele manier om bewerkbare formulieren toe te voegen aan je Wagtail-site. In deze tutorial testen we enkele op maat gemaakte functionaliteit die we hebben gemaakt.

15 juli 2020 14:51
Thema's: Wagtail Streamfield opties Testen

Ons uitgangspunt is een Wagtail-site waarin we Wagtail Streamforms hebben geïmplementeerd. We hebben een paar dingen toegevoegd aan de standaardfunctionaliteit, namelijk een reCaptcha-veld en een e-mail die wordt verzonden nadat een formulier is ingediend. Dat testen we in deze tutorial.

In tegenstelling tot eerdere tutorials zullen we Factory Boy niet gebruiken, enerzijds omdat we geen boom van Wagtail-pagina's nodig hebben, anderzijds omdat het creëren van een streamform-fabriek niet eenvoudig is. In plaats daarvan kopiëren we de aanpak die Wagtail Streamforms zelf gebruikt in haar tests.

Het testen van het reCaptcha-veld is vrij eenvoudig. Maak een bestand /tests/test_streamforms.py en voeg in:

from ..wagtailstreamforms_fields import ReCaptchaField
from django.test import TestCase

class TestWagtailStreamforms(TestCase):

    def test_recaptcha_field(self):
        field = ReCaptchaField().get_formfield({})
        self.assertTrue(field.required)

We creëren een instantie van een ReCaptchaField met de methode get_formfield(). In de definitie van ons model hebben we de methode get_options overschreven om de waarde van required in te stellen op True; in deze test gaan we na of dat inderdaad gebeurd is.

Het testen van de e-mailinzending in het bestand wagtailstreamforms_hooks.py dat we hebben gemaakt, is een andere kwestie. We moeten een formulier maken en simuleren dat het via mail wordt verzonden. Voor het maken van het formulier kopiëren we de aanpak in de tests van Wagtail Streamforms:

from wagtailstreamforms.models import Form
import json

def test_form(self):
    form = Form.objects.create(
        title="Form",
        template_name="streamforms/form_block.html",
        slug="form",
        fields=json.dumps(
            [
                {
                    "type": "singleline",
                    "value": {"label": "singleline", "required": True},
                    "id": "9c46e208-e53a-4562-81f6-3fb3f34520f2",
                },
                {
                    "type": "multifile",
                    "value": {"label": "multifile", "required": True},
                    "id": "91bac05f-754b-41a3-b038-ac7850e6f951",
                },
            ]
        ),
    )
    return form

Het veld fields wordt gevuld met de methode json.dumps uit een array van dictionaries met de inhoud van het formulier. Vervolgens definiëren we een methode test_send_email, die vergelijkbaar is met de methode test_saves_record_with_files in de Wagtail Streamforms-test, maar die steunt op de functionaliteit die Django biedt voor het testen van e-mailverzending. De volledige code is als volgt:

from ..wagtailstreamforms_hooks import email_submission
from django.core import mail
from django.core.files.uploadedfile import SimpleUploadedFile
from django.http import QueryDict

def test_send_email(self):
    instance = self.test_form()

    advancedformsetting = AdvancedFormSetting.objects.create(form=instance, to_address="mail@example.com")
    data_dict = {
        "singleline": 'text',
        "form_id": instance.pk,
        "form_reference": "some-ref",
    }
    uploadedfile = SimpleUploadedFile("file.mp4", b"file_content", content_type="video/mp4")
    files_dict = QueryDict(mutable=True)
    files_dict.update({"multifile": uploadedfile})
    files_dict.update({"multifile": uploadedfile})

    form_class = instance.get_form(data=data_dict, files=files_dict)

    assert form_class.is_valid()

    # Send message.
    email_submission(instance, form_class)

    # Test that one message has been sent.
    self.assertEqual(len(mail.outbox), 1)

    # Verify that the subject of the first message is correct.
    expected_subject = 'New Form Submission : %s' % instance.title
    self.assertEqual(mail.outbox[0].subject, expected_subject)

Tot aan de regel assert form_class.is_valid() is de code bijna gelijk aan die van test_saves_record_with_files, met twee uitzonderingen. De eerste is:

advancedformsetting = AdvancedFormSetting.objects.create(form=instance, to_address="mail@example.com")

We hebben de klasse AdvancedFormSetting in onze modellen gecreëerd om in onze admin het to-address van de mail met het ingezonden formulier te kunnen bewerken. We moeten hier een instantie maken, zodat Wagtail Streamforms dat oppikt bij het maken van de formulierklasse. De tweede wijziging is de regel:

uploadedfile = SimpleUploadedFile("file.mp4", b"file_content", content_type="video/mp4")

wat de code achter self.get_file() is in de code van test_saves_record_with_files (ingevoegd zodat we geen aparte TestCase-klasse hoeven te introduceren zoals in de tests van Wagtail Streamforms zelf).

Nu de e-mailverzending zelf. Om de mail te verzenden, roepen we gewoon de methode email_submission aan die we zelf hebben gedefinieerd en die we willen testen. De rest steunt op de e-mailtestfunctionaliteit van Django. Elke uitgaande e-mail wordt opgeslagen in django.core.mail.outbox. We kunnen dus in die mailbox controleren of er één bericht is en of het onderwerp van het bericht is zoals we hebben gedefinieerd in onze methode.

Laten we de test uitvoeren:

python3 manage.py test cms.tests.test_streamforms

We kunnen de dekking van alle tests van onze cms-app controleren met:

coverage run --source=cms manage.py test cms
coverage html

Het bestand index.html laat zien dat we een dekking van 97% hebben en de meest relevante regels code hebben gedekt. Dus we sluiten onze tests af. Tijd om onze applicatie online te zetten!

Reageer op dit artikel (log eerst in of bevestig hieronder met naam en email)