stages/prompt: add unittests

This commit is contained in:
Jens Langhammer 2020-05-10 17:52:26 +02:00
parent a3a3dde1c8
commit f6461b08d7
3 changed files with 171 additions and 4 deletions

View File

@ -14,6 +14,7 @@ class FieldTypes(models.TextChoices):
EMAIL = "e-mail"
PASSWORD = "password" # noqa # nosec
NUMBER = "number"
HIDDEN = "hidden"
class Prompt(UUIDModel):
@ -55,7 +56,26 @@ class Prompt(UUIDModel):
widget=forms.NumberInput(attrs=attrs),
required=self.required,
)
if self.type == FieldTypes.HIDDEN:
return forms.CharField(
widget=forms.HiddenInput(attrs=attrs),
required=False,
initial=self.placeholder,
)
raise ValueError("field_type is not valid, not one of FieldTypes.")
def save(self, *args, **kwargs):
if self.type not in FieldTypes:
raise ValueError
return super().save(*args, **kwargs)
def __str__(self):
return f"Prompt '{self.field_key}' type={self.type}'"
class Meta:
verbose_name = _("Prompt")
verbose_name_plural = _("Prompts")
class PromptStage(Stage):

View File

@ -1,4 +1,4 @@
"""Enrollment Stage Logic"""
"""Prompt Stage Logic"""
from django.http import HttpResponse
from django.utils.translation import gettext_lazy as _
from django.views.generic import FormView
@ -11,8 +11,8 @@ LOGGER = get_logger()
PLAN_CONTEXT_PROMPT = "prompt_data"
class EnrollmentStageView(FormView, AuthenticationStage):
"""Enrollment Stage, save form data in plan context."""
class PromptStageView(FormView, AuthenticationStage):
"""Prompt Stage, save form data in plan context."""
template_name = "login/form.html"
form_class = PromptForm

View File

@ -0,0 +1,147 @@
"""Prompt tests"""
from unittest.mock import MagicMock, patch
from django.shortcuts import reverse
from django.test import Client, TestCase
from passbook.core.models import User
from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding
from passbook.flows.planner import FlowPlan
from passbook.flows.views import SESSION_KEY_PLAN
from passbook.stages.prompt.forms import PromptForm
from passbook.stages.prompt.models import FieldTypes, Prompt, PromptStage
from passbook.stages.prompt.stage import PLAN_CONTEXT_PROMPT
class TestPromptStage(TestCase):
"""Prompt tests"""
def setUp(self):
super().setUp()
self.user = User.objects.create(username="unittest", email="test@beryju.org")
self.client = Client()
self.flow = Flow.objects.create(
name="test-prompt",
slug="test-prompt",
designation=FlowDesignation.AUTHENTICATION,
)
text_prompt = Prompt.objects.create(
field_key="text_prompt",
label="TEXT_LABEL",
type=FieldTypes.TEXT,
required=True,
placeholder="TEXT_PLACEHOLDER",
)
email_prompt = Prompt.objects.create(
field_key="email_prompt",
label="EMAIL_LABEL",
type=FieldTypes.EMAIL,
required=True,
placeholder="EMAIL_PLACEHOLDER",
)
password_prompt = Prompt.objects.create(
field_key="password_prompt",
label="PASSWORD_LABEL",
type=FieldTypes.PASSWORD,
required=True,
placeholder="PASSWORD_PLACEHOLDER",
)
number_prompt = Prompt.objects.create(
field_key="number_prompt",
label="NUMBER_LABEL",
type=FieldTypes.NUMBER,
required=True,
placeholder="NUMBER_PLACEHOLDER",
)
hidden_prompt = Prompt.objects.create(
field_key="hidden_prompt",
type=FieldTypes.HIDDEN,
required=True,
placeholder="HIDDEN_PLACEHOLDER",
)
self.stage = PromptStage.objects.create(name="prompt-stage")
self.stage.fields.set(
[text_prompt, email_prompt, password_prompt, number_prompt, hidden_prompt,]
)
self.stage.save()
self.prompt_data = {
text_prompt.field_key: "test-input",
email_prompt.field_key: "test@test.test",
password_prompt.field_key: "test",
number_prompt.field_key: 3,
hidden_prompt.field_key: hidden_prompt.placeholder,
}
FlowStageBinding.objects.create(flow=self.flow, stage=self.stage, order=2)
def test_invalid_type(self):
"""Test that invalid form type raises an error"""
with self.assertRaises(ValueError):
_ = Prompt.objects.create(
field_key="hidden_prompt",
type="invalid",
required=True,
placeholder="HIDDEN_PLACEHOLDER",
)
with self.assertRaises(ValueError):
prompt = Prompt.objects.create(
field_key="hidden_prompt",
type=FieldTypes.HIDDEN,
required=True,
placeholder="HIDDEN_PLACEHOLDER",
)
with patch.object(prompt, "type", MagicMock(return_value="invalid")):
_ = prompt.field
def test_render(self):
"""Test render of form, check if all prompts are rendered correctly"""
plan = FlowPlan(stages=[self.stage])
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
response = self.client.get(
reverse(
"passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug}
)
)
self.assertEqual(response.status_code, 200)
for prompt in self.stage.fields.all():
self.assertIn(prompt.field_key, response.rendered_content)
self.assertIn(prompt.label, response.rendered_content)
self.assertIn(prompt.placeholder, response.rendered_content)
def test_valid_form(self) -> PromptForm:
"""Test form validation"""
form = PromptForm(stage=self.stage, data=self.prompt_data)
self.assertEqual(form.is_valid(), True)
return form
def test_valid_form_request(self):
"""Test a request with valid form data"""
plan = FlowPlan(stages=[self.stage])
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
form = self.test_valid_form()
with patch("passbook.flows.views.FlowExecutorView.cancel", MagicMock()):
response = self.client.post(
reverse(
"passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug}
),
form.cleaned_data,
)
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, reverse("passbook_core:overview"))
# Check that valid data has been saved
session = self.client.session
plan: FlowPlan = session[SESSION_KEY_PLAN]
data = plan.context[PLAN_CONTEXT_PROMPT]
for prompt in self.stage.fields.all():
prompt: Prompt
self.assertEqual(data[prompt.field_key], self.prompt_data[prompt.field_key])