Skip to content

Commit

Permalink
Convert NewPlanForm into ModelForm. Refs #1384, #171
Browse files Browse the repository at this point in the history
  • Loading branch information
atodorov committed Apr 11, 2020
1 parent 7f49d08 commit 43f30d7
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 139 deletions.
28 changes: 12 additions & 16 deletions tcms/management/tests/tests.py
@@ -1,16 +1,13 @@
# -*- coding: utf-8 -*-
# pylint: disable=invalid-name

from http import HTTPStatus

from django.conf import settings
from django.test import TestCase
from django.test.client import Client
from django.urls import reverse
from django.utils.translation import gettext_lazy as _

from tcms.management.models import Product, Version
from tcms.testplans.models import TestPlan
from tcms.testplans.models import TestPlan, TestPlanEmailSettings
from tcms.tests.factories import (PlanTypeFactory, ProductFactory, UserFactory,
VersionFactory)

Expand Down Expand Up @@ -48,21 +45,20 @@ def test_product_delete_with_test_plan_wo_email_settings(self):
product_version = VersionFactory(value='0.1', product=product)
plan_type = PlanTypeFactory()

# create Test Plan via the UI by sending a POST request to the view
previous_plans_count = TestPlan.objects.count()
test_plan_name = 'Test plan for the new product'
response = self.c.post(reverse('plans-new'), {
'name': test_plan_name,
'product': product.pk,
'product_version': product_version.pk,
'type': plan_type.pk,
}, follow=True)
self.assertEqual(HTTPStatus.OK, response.status_code)
# verify test plan was created
self.assertTrue(test_plan_name in str(response.content,
encoding=settings.DEFAULT_CHARSET))
TestPlan.objects.create(
name='Test plan for the new product',
author=self.user,
product=product,
product_version=product_version,
type=plan_type,
)
# verify TP was created
self.assertEqual(previous_plans_count + 1, TestPlan.objects.count())

# make sure there are no email settings
TestPlanEmailSettings.objects.all().delete()

# now delete the product
admin_delete_url = "admin:%s_%s_delete" % (
product._meta.app_label, # pylint: disable=no-member
Expand Down
75 changes: 19 additions & 56 deletions tcms/testplans/forms.py
@@ -1,50 +1,22 @@
# -*- coding: utf-8 -*-
from django import forms
from django.forms import inlineformset_factory

from tcms.core.forms.fields import StripURLField
from tcms.core.utils import string_to_list
from tcms.core.widgets import SimpleMDE
from tcms.management.models import Product, Version
from tcms.testplans.models import TestPlan, TestPlanEmailSettings

from .models import PlanType, TestPlan

class NewPlanForm(forms.ModelForm):
class Meta:
model = TestPlan
exclude = ('tag', ) # pylint: disable=modelform-uses-exclude

# todo: merge with NewPlanForm below b/c not used
# anywhere else
class BasePlanForm(forms.Form):
name = forms.CharField(
required=True
)
type = forms.ModelChoiceField(
queryset=PlanType.objects.all(),
empty_label=None,
)
text = forms.CharField(
widget=SimpleMDE(),
required=False
)
product = forms.ModelChoiceField(
queryset=Product.objects.all(),
empty_label=None,
)
product_version = forms.ModelChoiceField(
queryset=Version.objects.none(),
empty_label=None,
)
extra_link = StripURLField(
max_length=1024,
required=False
)
parent = forms.IntegerField(required=False)

def clean_parent(self):
try:
parent_pk = self.cleaned_data['parent']
if parent_pk:
return TestPlan.objects.get(pk=parent_pk)
except TestPlan.DoesNotExist:
raise forms.ValidationError('The plan does not exist in database.')
return None

def populate(self, product_id):
if product_id:
Expand All @@ -54,29 +26,20 @@ def populate(self, product_id):
self.fields['product_version'].queryset = Version.objects.all()


class NewPlanForm(BasePlanForm):
# note: these fields can't change during runtime !
_email_settings_fields = [] # pylint: disable=invalid-name
for field in TestPlanEmailSettings._meta.fields:
_email_settings_fields.append(field.name)

auto_to_plan_author = forms.BooleanField(
initial=True,
required=False
)
auto_to_case_owner = forms.BooleanField(
initial=True,
required=False
)
auto_to_case_default_tester = forms.BooleanField(
initial=True,
required=False
)
notify_on_plan_update = forms.BooleanField(
initial=True,
required=False
)
notify_on_case_update = forms.BooleanField(
initial=True,
required=False
)
is_active = forms.BooleanField(required=False, initial=True)

# for usage in CreateView, UpdateView
PlanNotifyFormSet = inlineformset_factory( # pylint: disable=invalid-name
TestPlan,
TestPlanEmailSettings,
fields=_email_settings_fields,
can_delete=False,
can_order=False,
)


class SearchPlanForm(forms.Form):
Expand Down
3 changes: 3 additions & 0 deletions tcms/testplans/models.py
Expand Up @@ -93,6 +93,9 @@ def delete_case(self, case):
def _get_absolute_url(self):
return reverse('test_plan_url', args=[self.pk, slugify(self.name)])

def get_absolute_url(self):
return self._get_absolute_url()

def get_case_sortkey(self):
"""
Get case sortkey.
Expand Down
19 changes: 13 additions & 6 deletions tcms/testplans/templates/testplans/mutable.html
Expand Up @@ -18,7 +18,7 @@
<div class="container-fluid container-cards-pf">
<form class="form-horizontal" action="{% if test_plan %}{% url 'plan-edit' test_plan.pk %}{% else %}{% url 'plans-new' %}{% endif %}" method="post">
{% csrf_token %}

<input type="hidden" name="author" value="{{ form.author.value }}">
<div class="form-group">
<label class="col-md-1 col-lg-1" for="id_name">{% trans "Name" %}</label>
<div class="col-md-11 col-lg-11 {% if form.name.errors %}has-error{% endif %}">
Expand Down Expand Up @@ -97,25 +97,26 @@
</div>
</div>

{% for notify_form in notify_formset %}
<div class="form-group">
<label class="col-md-12 col-lg-12"> {% trans "Notify:" %} </label>
<div class="col-md-1 col-lg-1">
<label> {% trans "Author" %} </label>
</div>
<div class="col-md-3 col-lg-3">
<input class="bootstrap-switch" name="auto_to_plan_author" type="checkbox" {% if form.auto_to_plan_author.value %} checked {% endif %}>
<input class="bootstrap-switch" name="{{ notify_formset.prefix }}-{{ forloop.counter0 }}-auto_to_plan_author" type="checkbox" {% if notify_form.auto_to_plan_author.value %} checked {% endif %}>
</div>
<div class="col-md-1 col-lg-1">
<label> {% trans "TestCase author" %} </label>
</div>
<div class="col-md-3 col-lg-3">
<input class="bootstrap-switch" name="auto_to_case_owner" type="checkbox" {% if form.auto_to_case_owner.value %} checked {% endif %}>
<input class="bootstrap-switch" name="{{ notify_formset.prefix }}-{{ forloop.counter0 }}-auto_to_case_owner" type="checkbox" {% if notify_form.auto_to_case_owner.value %} checked {% endif %}>
</div>
<div class="col-md-1 col-lg-1">
<label> {% trans "Default tester" %} </label>
</div>
<div class="col-md-3 col-lg-3">
<input class="bootstrap-switch" name="auto_to_case_default_tester" type="checkbox" {% if form.auto_to_case_default_tester.value %} checked {% endif %}>
<input class="bootstrap-switch" name="{{ notify_formset.prefix }}-{{ forloop.counter0 }}-auto_to_case_default_tester" type="checkbox" {% if notify_form.auto_to_case_default_tester.value %} checked {% endif %}>
</div>
</div>

Expand All @@ -125,16 +126,22 @@
<label> {% trans "TestPlan is updated" %} </label>
</div>
<div class="col-md-3 col-lg-3">
<input class="bootstrap-switch" name="notify_on_plan_update" type="checkbox" {% if form.notify_on_plan_update.value %} checked {% endif %}>
<input class="bootstrap-switch" name="{{ notify_formset.prefix }}-{{ forloop.counter0 }}-notify_on_plan_update" type="checkbox" {% if notify_form.notify_on_plan_update.value %} checked {% endif %}>
</div>
<div class="col-md-1 col-lg-1">
<label> {% trans "Test cases are updated" %} </label>
</div>
<div class="col-md-3 col-lg-3">
<input class="bootstrap-switch" name="notify_on_case_update" type="checkbox" {% if form.notify_on_case_update.value %} checked {% endif %}>
<input class="bootstrap-switch" name="{{ notify_formset.prefix }}-{{ forloop.counter0 }}-notify_on_case_update" type="checkbox" {% if notify_form.notify_on_case_update.value %} checked {% endif %}>
</div>
</div>

{% for hidden_field in notify_form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% endfor %}
{{ notify_formset.management_form }}

<div class="form-group">
<label class="col-md-1 col-lg-1"> {% trans "Active" %} </label>
<div class="col-md-3 col-lg-3">
Expand Down
59 changes: 36 additions & 23 deletions tcms/testplans/tests/test_new_plan.py
Expand Up @@ -21,44 +21,53 @@ def setUp(self):
self.user.save()

self.request = {
'product': self.product.id,
'product_version': self.product_version.id,
'author': self.user.pk,
'product': self.product.pk,
'product_version': self.product_version.pk,
'type': self.plan_type.pk,
'name': self.plan_name,
'auto_to_plan_author': True,
'auto_to_case_owner': True,
'auto_to_case_default_tester': True,
'notify_on_case_update': False,

'email_settings-0-auto_to_plan_author': 'on',
'email_settings-0-auto_to_case_owner': 'on',
'email_settings-0-auto_to_case_default_tester': 'on',
'email_settings-0-notify_on_case_update': 'on',
'email_settings-0-notify_on_plan_update': 'on',

'email_settings-0-plan': '',
'email_settings-0-id': self.test_plan.emailing.pk,
'email_settings-TOTAL_FORMS': '1',
'email_settings-INITIAL_FORMS': '1',
'email_settings-MIN_NUM_FORMS': '0',
'email_settings-MAX_NUM_FORMS': '1',
}

def test_plan_new_get(self):
response = self.client.get(self.location, follow=True)
response = self.client.get(self.location)

self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertContains(
response,
'<input class="bootstrap-switch" name="is_active" type="checkbox" checked>',
html=True)
self.assertContains(
response,
'<input class="bootstrap-switch" name="auto_to_plan_author" type="checkbox" '
'checked>', html=True)
'<input class="bootstrap-switch" name="email_settings-0-auto_to_plan_author" '
'type="checkbox" checked>', html=True)
self.assertContains(
response,
'<input class="bootstrap-switch" name="auto_to_case_owner" type="checkbox" '
'checked>', html=True)
'<input class="bootstrap-switch" name="email_settings-0-auto_to_case_owner" '
'type="checkbox" checked>', html=True)
self.assertContains(
response,
'<input class="bootstrap-switch" name="auto_to_case_default_tester" type="checkbox" '
'checked>', html=True)
'<input class="bootstrap-switch" name="email_settings-0-auto_to_case_default_tester" '
'type="checkbox" checked>', html=True)
self.assertContains(
response,
'<input class="bootstrap-switch" name="notify_on_plan_update" type="checkbox" '
'checked>', html=True)
'<input class="bootstrap-switch" name="email_settings-0-notify_on_plan_update" '
'type="checkbox" checked>', html=True)
self.assertContains(
response,
'<input class="bootstrap-switch" name="notify_on_case_update" type="checkbox" '
'checked>', html=True)
'<input class="bootstrap-switch" name="email_settings-0-notify_on_case_update" '
'type="checkbox" checked>', html=True)

def test_plan_create_new_active(self):
self._test_plan_create_new(is_active=True)
Expand All @@ -69,19 +78,23 @@ def test_plan_create_new_inactive(self):
def _test_plan_create_new(self, is_active):
self.request['is_active'] = is_active

response = self.client.post(self.location, self.request, follow=True)
self.assertEqual(response.status_code, HTTPStatus.OK)
response = self.client.post(self.location, self.request)
self.assertEqual(response.status_code, HTTPStatus.FOUND)

plan = TestPlan.objects.get(name=self.plan_name)
plan = TestPlan.objects.get(
name=self.plan_name,
is_active=is_active,
)
self.assertEqual(plan.author, self.user)
self.assertEqual(plan.product, self.product)
self.assertEqual(plan.product_version, self.product_version)
self.assertEqual(plan.type, self.plan_type)
self.assertEqual(plan.is_active, is_active)
self.assertTrue(plan.emailing.auto_to_plan_author)
self.assertTrue(plan.emailing.auto_to_case_owner)
self.assertTrue(plan.emailing.auto_to_case_default_tester)
self.assertFalse(plan.emailing.notify_on_plan_update)
self.assertFalse(plan.emailing.notify_on_case_update)
self.assertTrue(plan.emailing.notify_on_plan_update)
self.assertTrue(plan.emailing.notify_on_case_update)

def test_get_with_no_perm_redirects_to_login(self):
remove_perm_from_user(self.user, self.add_testplan_permission)
Expand Down

0 comments on commit 43f30d7

Please sign in to comment.