Skip to content

Commit 6eda667

Browse files
test: Add tests to the business app for creating promo codes.
- Add tests for creating promo codes, validating input data, and for permissions - Separate tests into folders for future scaling - Add several fields to PromoCreateSerializer for better input data validation
1 parent 1d49c7c commit 6eda667

File tree

8 files changed

+691
-5
lines changed

8 files changed

+691
-5
lines changed

promo_code/business/serializers.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ class TargetSerializer(rest_framework.serializers.Serializer):
147147
allow_null=True,
148148
)
149149
country = rest_framework.serializers.CharField(
150+
max_length=2,
151+
min_length=2,
150152
required=False,
151153
allow_null=True,
152154
allow_blank=True,
@@ -173,7 +175,6 @@ def validate(self, data):
173175
{'age_until': 'Must be greater than or equal to age_from.'},
174176
)
175177

176-
# change validation
177178
country = data.get('country')
178179
if country:
179180
country = country.strip().upper()
@@ -189,6 +190,18 @@ def validate(self, data):
189190

190191

191192
class PromoCreateSerializer(rest_framework.serializers.ModelSerializer):
193+
description = rest_framework.serializers.CharField(
194+
min_length=10,
195+
max_length=300,
196+
required=True,
197+
)
198+
image_url = rest_framework.serializers.CharField(
199+
required=False,
200+
max_length=350,
201+
validators=[
202+
django.core.validators.URLValidator(schemes=['http', 'https']),
203+
],
204+
)
192205
target = TargetSerializer(required=True)
193206
promo_common = rest_framework.serializers.CharField(
194207
min_length=5,
@@ -220,10 +233,6 @@ class Meta:
220233
'promo_common',
221234
'promo_unique',
222235
)
223-
extra_kwargs = {
224-
'description': {'min_length': 10, 'max_length': 300},
225-
'image_url': {'max_length': 350},
226-
}
227236

228237
def validate(self, data):
229238
mode = data.get('mode')

promo_code/business/tests/promocodes/__init__.py

Whitespace-only changes.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import business.models
2+
import django.urls
3+
import rest_framework
4+
import rest_framework.status
5+
import rest_framework.test
6+
7+
8+
class BasePromoCreateTestCase(rest_framework.test.APITestCase):
9+
@classmethod
10+
def setUpTestData(cls):
11+
super().setUpTestData()
12+
cls.client = rest_framework.test.APIClient()
13+
cls.promo_create_url = django.urls.reverse('api-business:promo-create')
14+
cls.signup_url = django.urls.reverse('api-business:company-sign-up')
15+
cls.signin_url = django.urls.reverse('api-business:company-sign-in')
16+
cls.valid_data = {
17+
'name': 'Digital Marketing Solutions Inc.',
18+
'email': '[email protected]',
19+
'password': 'SecurePass123!',
20+
}
21+
business.models.Company.objects.create_company(
22+
name=cls.valid_data['name'],
23+
email=cls.valid_data['email'],
24+
password=cls.valid_data['password'],
25+
)
26+
27+
response = cls.client.post(
28+
cls.signin_url,
29+
{
30+
'email': cls.valid_data['email'],
31+
'password': cls.valid_data['password'],
32+
},
33+
format='json',
34+
)
35+
cls.token = response.data['access']
36+
37+
def tearDown(self):
38+
business.models.Company.objects.all().delete()
39+
business.models.Promo.objects.all().delete()
40+
business.models.PromoCode.objects.all().delete()

promo_code/business/tests/promocodes/operations/__init__.py

Whitespace-only changes.
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import business.tests.promocodes.base
2+
import rest_framework.status
3+
4+
5+
class TestSuccessfulPromoCreation(
6+
business.tests.promocodes.base.BasePromoCreateTestCase,
7+
):
8+
def test_successful_promo_creation_1(self):
9+
payload = {
10+
'description': 'Increased cashback 10% for new bank clients!',
11+
'image_url': 'https://cdn2.thecatapi.com/images/3lo.jpg',
12+
'target': {},
13+
'max_count': 10,
14+
'active_from': '2025-01-10',
15+
'mode': 'COMMON',
16+
'promo_common': 'sale-10',
17+
}
18+
response = self.client.post(
19+
self.promo_create_url,
20+
payload,
21+
format='json',
22+
HTTP_AUTHORIZATION='Bearer ' + self.token,
23+
)
24+
self.assertEqual(
25+
response.status_code,
26+
rest_framework.status.HTTP_201_CREATED,
27+
)
28+
29+
def test_successful_promo_creation_2(self):
30+
payload = {
31+
'description': 'Increased cashback 40% for new bank clients!',
32+
'image_url': 'https://cdn2.thecatapi.com/images/3lo.jpg',
33+
'target': {'age_from': 15, 'country': 'fr'},
34+
'max_count': 100,
35+
'active_from': '2028-12-20',
36+
'mode': 'COMMON',
37+
'promo_common': 'sale-40',
38+
}
39+
response = self.client.post(
40+
self.promo_create_url,
41+
payload,
42+
format='json',
43+
HTTP_AUTHORIZATION='Bearer ' + self.token,
44+
)
45+
self.assertEqual(
46+
response.status_code,
47+
rest_framework.status.HTTP_201_CREATED,
48+
)
49+
50+
def test_successful_promo_creation_3(self):
51+
payload = {
52+
'description': 'Gift sleeping mask with car loan application',
53+
'target': {'age_from': 28, 'age_until': 50, 'country': 'us'},
54+
'max_count': 1,
55+
'active_from': '2025-01-01',
56+
'active_until': '2028-12-30',
57+
'mode': 'UNIQUE',
58+
'promo_unique': ['uniq1', 'uniq2', 'uniq3'],
59+
}
60+
response = self.client.post(
61+
self.promo_create_url,
62+
payload,
63+
format='json',
64+
HTTP_AUTHORIZATION='Bearer ' + self.token,
65+
)
66+
self.assertEqual(
67+
response.status_code,
68+
rest_framework.status.HTTP_201_CREATED,
69+
)
70+
71+
def test_successful_promo_creation_4(self):
72+
payload = {
73+
'description': 'We gift a globe when ordering for 30000!',
74+
'target': {'age_from': 28, 'age_until': 50, 'country': 'us'},
75+
'max_count': 1,
76+
'active_until': '2025-01-10',
77+
'mode': 'UNIQUE',
78+
'promo_unique': ['only_youuuu', 'not_only_you'],
79+
}
80+
response = self.client.post(
81+
self.promo_create_url,
82+
payload,
83+
format='json',
84+
HTTP_AUTHORIZATION='Bearer ' + self.token,
85+
)
86+
self.assertEqual(
87+
response.status_code,
88+
rest_framework.status.HTTP_201_CREATED,
89+
)
90+
91+
def test_successful_promo_creation_5(self):
92+
payload = {
93+
'description': 'Increased cashback 10% for new bank clients!',
94+
'image_url': 'http://cdn2.thecatapi.com/',
95+
'target': {},
96+
'max_count': 10,
97+
'active_from': '1950-01-01',
98+
'mode': 'COMMON',
99+
'promo_common': 'sale-10',
100+
}
101+
response = self.client.post(
102+
self.promo_create_url,
103+
payload,
104+
format='json',
105+
HTTP_AUTHORIZATION='Bearer ' + self.token,
106+
)
107+
self.assertEqual(
108+
response.status_code,
109+
rest_framework.status.HTTP_201_CREATED,
110+
)
111+
112+
def test_successful_promo_creation_6_country_lower(self):
113+
payload = {
114+
'description': 'Increased cashback 10% for new bank clients!',
115+
'image_url': 'http://cdn2.thecatapi.com/',
116+
'target': {'country': 'Us'},
117+
'max_count': 10,
118+
'mode': 'COMMON',
119+
'promo_common': 'sale-10',
120+
}
121+
response = self.client.post(
122+
self.promo_create_url,
123+
payload,
124+
format='json',
125+
HTTP_AUTHORIZATION='Bearer ' + self.token,
126+
)
127+
self.assertEqual(
128+
response.status_code,
129+
rest_framework.status.HTTP_201_CREATED,
130+
)
131+
132+
def test_successful_promo_creation_6_country_upper(self):
133+
payload = {
134+
'description': 'Increased cashback 10% for new bank clients!',
135+
'image_url': 'http://cdn2.thecatapi.com/',
136+
'target': {'country': 'US'},
137+
'max_count': 10,
138+
'mode': 'COMMON',
139+
'promo_common': 'sale-10',
140+
}
141+
response = self.client.post(
142+
self.promo_create_url,
143+
payload,
144+
format='json',
145+
HTTP_AUTHORIZATION='Bearer ' + self.token,
146+
)
147+
self.assertEqual(
148+
response.status_code,
149+
rest_framework.status.HTTP_201_CREATED,
150+
)
151+
152+
def test_successful_promo_creation_7(self):
153+
payload = {
154+
'description': 'Increased cashback 10% for new bank clients!',
155+
'image_url': 'http://cdn2.thecatapi.com/',
156+
'target': {'age_from': 100, 'age_until': 100},
157+
'max_count': 10,
158+
'mode': 'COMMON',
159+
'promo_common': 'sale-10',
160+
}
161+
response = self.client.post(
162+
self.promo_create_url,
163+
payload,
164+
format='json',
165+
HTTP_AUTHORIZATION='Bearer ' + self.token,
166+
)
167+
self.assertEqual(
168+
response.status_code,
169+
rest_framework.status.HTTP_201_CREATED,
170+
)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import business.models
2+
import business.permissions
3+
import business.tests.promocodes.base
4+
import django.contrib.auth
5+
import rest_framework.status
6+
import rest_framework.test
7+
8+
import user.models
9+
10+
11+
class TestIsCompanyUserPermission(
12+
business.tests.promocodes.base.BasePromoCreateTestCase,
13+
):
14+
def setUp(self):
15+
self.factory = rest_framework.test.APIRequestFactory()
16+
self.permission = business.permissions.IsCompanyUser()
17+
get_user_model = django.contrib.auth.get_user_model
18+
self.regular_user = get_user_model().objects.create_user(
19+
name='regular',
20+
password='testpass123',
21+
surname='adadioa',
22+
23+
)
24+
self.company_user = business.models.Company.objects.create_company(
25+
password='testpass123',
26+
name='Test Company',
27+
28+
)
29+
30+
def tearDown(self):
31+
business.models.Company.objects.all().delete()
32+
user.models.User.objects.all().delete()
33+
34+
def test_has_permission_for_company_user(self):
35+
request = self.factory.get(self.promo_create_url)
36+
request.user = self.company_user
37+
self.assertTrue(self.permission.has_permission(request, None))
38+
39+
def test_has_permission_for_regular_user(self):
40+
request = self.factory.get(self.promo_create_url)
41+
request.user = self.regular_user
42+
self.assertFalse(self.permission.has_permission(request, None))
43+
44+
def test_has_permission_for_anonymous_user(self):
45+
request = self.factory.get(self.promo_create_url)
46+
request.user = None
47+
self.assertFalse(self.permission.has_permission(request, None))

promo_code/business/tests/promocodes/validations/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)