1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
# pylint: disable=invalid-name, too-many-ancestors |
3
|
|
|
|
4
|
|
|
import unittest |
5
|
|
|
from http import HTTPStatus |
6
|
|
|
from urllib.parse import urlencode |
7
|
|
|
|
8
|
|
|
from django.contrib.auth.models import User |
9
|
|
|
from django.urls import reverse |
10
|
|
|
from django.forms import ValidationError |
11
|
|
|
from django.test import RequestFactory |
12
|
|
|
|
13
|
|
|
from tcms.testcases.fields import MultipleEmailField |
14
|
|
|
from tcms.management.models import Priority, Tag |
15
|
|
|
from tcms.testcases.models import TestCase |
16
|
|
|
from tcms.testcases.models import BugSystem |
17
|
|
|
from tcms.testcases.models import TestCasePlan |
18
|
|
|
from tcms.testcases.views import get_selected_testcases |
19
|
|
|
from tcms.testruns.models import TestCaseRunStatus |
20
|
|
|
from tcms.tests.factories import BugFactory |
21
|
|
|
from tcms.tests.factories import TestCaseFactory |
22
|
|
|
from tcms.tests.factories import TestPlanFactory |
23
|
|
|
from tcms.tests import BasePlanCase, BaseCaseRun |
24
|
|
|
from tcms.tests import remove_perm_from_user |
25
|
|
|
from tcms.tests import user_should_have_perm |
26
|
|
|
from tcms.utils.permissions import initiate_user_with_default_setups |
27
|
|
|
|
28
|
|
|
|
29
|
|
|
class TestGetCaseRunDetailsAsDefaultUser(BaseCaseRun): |
30
|
|
|
"""Assert what a default user (non-admin) will see""" |
31
|
|
|
|
32
|
|
|
@classmethod |
33
|
|
|
def setUpTestData(cls): |
34
|
|
|
super(TestGetCaseRunDetailsAsDefaultUser, cls).setUpTestData() |
35
|
|
|
|
36
|
|
|
def test_user_in_default_group_sees_comments(self): |
37
|
|
|
# test for https://github.com/kiwitcms/Kiwi/issues/74 |
38
|
|
|
initiate_user_with_default_setups(self.tester) |
39
|
|
|
|
40
|
|
|
url = reverse('caserun-detail-pane', args=[self.case_run_1.case_id]) |
41
|
|
|
response = self.client.get( |
42
|
|
|
url, |
43
|
|
|
{ |
44
|
|
|
'case_run_id': self.case_run_1.pk, |
45
|
|
|
'case_text_version': self.case_run_1.case.latest_text_version() |
46
|
|
|
} |
47
|
|
|
) |
48
|
|
|
|
49
|
|
|
self.assertEqual(HTTPStatus.OK, response.status_code) |
50
|
|
|
|
51
|
|
|
self.assertContains( |
52
|
|
|
response, |
53
|
|
|
'<textarea name="comment" cols="40" id="id_comment" maxlength="10000" ' |
54
|
|
|
'rows="10">\n</textarea>', |
55
|
|
|
html=True) |
56
|
|
|
|
57
|
|
|
for status in TestCaseRunStatus.objects.all(): |
58
|
|
|
self.assertContains( |
59
|
|
|
response, |
60
|
|
|
"<input type=\"submit\" class=\"btn btn_%s btn_status js-status-button\" " |
61
|
|
|
"title=\"%s\"" % (status.name.lower(), status.name), |
62
|
|
|
html=False |
63
|
|
|
) |
64
|
|
|
|
65
|
|
|
def test_user_sees_bugs(self): |
66
|
|
|
bug_1 = BugFactory() |
67
|
|
|
bug_2 = BugFactory() |
68
|
|
|
|
69
|
|
|
self.case_run_1.add_bug(bug_1.bug_id, bug_1.bug_system.pk) |
70
|
|
|
self.case_run_1.add_bug(bug_2.bug_id, bug_2.bug_system.pk) |
71
|
|
|
|
72
|
|
|
url = reverse('caserun-detail-pane', args=[self.case_run_1.case.pk]) |
73
|
|
|
response = self.client.get( |
74
|
|
|
url, |
75
|
|
|
{ |
76
|
|
|
'case_run_id': self.case_run_1.pk, |
77
|
|
|
'case_text_version': self.case_run_1.case.latest_text_version() |
78
|
|
|
} |
79
|
|
|
) |
80
|
|
|
|
81
|
|
|
self.assertEqual(HTTPStatus.OK, response.status_code) |
82
|
|
|
self.assertContains(response, bug_1.get_full_url()) |
83
|
|
|
self.assertContains(response, bug_2.get_full_url()) |
84
|
|
|
|
85
|
|
|
|
86
|
|
|
class TestMultipleEmailField(unittest.TestCase): |
87
|
|
|
|
88
|
|
|
@classmethod |
89
|
|
|
def setUpClass(cls): |
90
|
|
|
super().setUpClass() |
91
|
|
|
cls.field = MultipleEmailField() |
92
|
|
|
|
93
|
|
|
def test_to_python(self): |
94
|
|
|
value = u'zhangsan@localhost' |
95
|
|
|
pyobj = self.field.to_python(value) |
96
|
|
|
self.assertEqual(pyobj, [value]) |
97
|
|
|
|
98
|
|
|
value = u'zhangsan@localhost,,[email protected],' |
99
|
|
|
pyobj = self.field.to_python(value) |
100
|
|
|
self.assertEqual(pyobj, [u'zhangsan@localhost', u'[email protected]']) |
101
|
|
|
|
102
|
|
|
for value in ('', None, []): |
103
|
|
|
pyobj = self.field.to_python(value) |
104
|
|
|
self.assertEqual(pyobj, []) |
105
|
|
|
|
106
|
|
|
def test_clean(self): |
107
|
|
|
value = u'zhangsan@localhost' |
108
|
|
|
data = self.field.clean(value) |
109
|
|
|
self.assertEqual(data, [value]) |
110
|
|
|
|
111
|
|
|
value = u'zhangsan@localhost,[email protected]' |
112
|
|
|
data = self.field.clean(value) |
113
|
|
|
self.assertEqual(data, [u'zhangsan@localhost', u'[email protected]']) |
114
|
|
|
|
115
|
|
|
value = u',zhangsan@localhost, ,[email protected], \n' |
116
|
|
|
data = self.field.clean(value) |
117
|
|
|
self.assertEqual(data, [u'zhangsan@localhost', '[email protected]']) |
118
|
|
|
|
119
|
|
|
value = ',zhangsan,zhangsan@localhost, \n,[email protected], ' |
120
|
|
|
self.assertRaises(ValidationError, self.field.clean, value) |
121
|
|
|
|
122
|
|
|
value = '' |
123
|
|
|
self.field.required = True |
124
|
|
|
self.assertRaises(ValidationError, self.field.clean, value) |
125
|
|
|
|
126
|
|
|
value = '' |
127
|
|
|
self.field.required = False |
128
|
|
|
data = self.field.clean(value) |
129
|
|
|
self.assertEqual(data, []) |
130
|
|
|
|
131
|
|
|
|
132
|
|
|
class TestAddIssueToCase(BasePlanCase): |
133
|
|
|
"""Tests for adding issue to case""" |
134
|
|
|
|
135
|
|
|
@classmethod |
136
|
|
|
def setUpTestData(cls): |
137
|
|
|
super(TestAddIssueToCase, cls).setUpTestData() |
138
|
|
|
|
139
|
|
|
cls.plan_tester = User.objects.create_user( # nosec:B106:hardcoded_password_funcarg |
140
|
|
|
username='plantester', |
141
|
|
|
email='[email protected]', |
142
|
|
|
password='password') |
143
|
|
|
user_should_have_perm(cls.plan_tester, 'testcases.change_bug') |
144
|
|
|
|
145
|
|
|
cls.case_bug_url = reverse('testcases-bug', args=[cls.case_1.pk]) |
146
|
|
|
cls.issue_tracker = BugSystem.objects.get(name='Bugzilla') |
147
|
|
|
|
148
|
|
|
def test_add_and_remove_a_bug(self): |
149
|
|
|
user_should_have_perm(self.plan_tester, 'testcases.add_bug') |
150
|
|
|
user_should_have_perm(self.plan_tester, 'testcases.delete_bug') |
151
|
|
|
|
152
|
|
|
self.client.login( # nosec:B106:hardcoded_password_funcarg |
153
|
|
|
username=self.plan_tester.username, |
154
|
|
|
password='password') |
155
|
|
|
request_data = { |
156
|
|
|
'handle': 'add', |
157
|
|
|
'case': self.case_1.pk, |
158
|
|
|
'bug_id': '123456', |
159
|
|
|
'bug_system': self.issue_tracker.pk, |
160
|
|
|
} |
161
|
|
|
self.client.get(self.case_bug_url, request_data) |
162
|
|
|
self.assertTrue(self.case_1.case_bug.filter(bug_id='123456').exists()) |
163
|
|
|
|
164
|
|
|
request_data = { |
165
|
|
|
'handle': 'remove', |
166
|
|
|
'case': self.case_1.pk, |
167
|
|
|
'bug_id': '123456', |
168
|
|
|
} |
169
|
|
|
self.client.get(self.case_bug_url, request_data) |
170
|
|
|
|
171
|
|
|
not_have_bug = self.case_1.case_bug.filter(bug_id='123456').exists() |
172
|
|
|
self.assertTrue(not_have_bug) |
173
|
|
|
|
174
|
|
|
|
175
|
|
|
class TestOperateCasePlans(BasePlanCase): |
176
|
|
|
"""Test operation in case' plans tab""" |
177
|
|
|
|
178
|
|
|
@classmethod |
179
|
|
|
def setUpTestData(cls): |
180
|
|
|
super(TestOperateCasePlans, cls).setUpTestData() |
181
|
|
|
|
182
|
|
|
# Besides the plan and its cases created in parent class, this test case |
183
|
|
|
# also needs other cases in order to list multiple plans of a case and |
184
|
|
|
# remove a plan from a case. |
185
|
|
|
|
186
|
|
|
cls.plan_test_case_plans = TestPlanFactory(author=cls.tester, |
187
|
|
|
product=cls.product, |
188
|
|
|
product_version=cls.version) |
189
|
|
|
cls.plan_test_add = TestPlanFactory(author=cls.tester, |
190
|
|
|
product=cls.product, |
191
|
|
|
product_version=cls.version) |
192
|
|
|
cls.plan_test_remove = TestPlanFactory(author=cls.tester, |
193
|
|
|
product=cls.product, |
194
|
|
|
product_version=cls.version) |
195
|
|
|
|
196
|
|
|
cls.case_1.add_to_plan(cls.plan_test_case_plans) |
197
|
|
|
cls.case_1.add_to_plan(cls.plan_test_remove) |
198
|
|
|
|
199
|
|
|
cls.plan_tester = User.objects.create_user( # nosec:B106:hardcoded_password_funcarg |
200
|
|
|
username='plantester', |
201
|
|
|
email='[email protected]', |
202
|
|
|
password='password') |
203
|
|
|
|
204
|
|
|
cls.case_plans_url = reverse('testcases-plan', args=[cls.case_1.pk]) |
205
|
|
|
|
206
|
|
|
def tearDown(self): |
207
|
|
|
remove_perm_from_user(self.plan_tester, 'testcases.add_testcaseplan') |
208
|
|
|
remove_perm_from_user(self.plan_tester, 'testcases.change_testcaseplan') |
209
|
|
|
|
210
|
|
|
def assert_list_case_plans(self, response, case): |
211
|
|
|
for case_plan_rel in TestCasePlan.objects.filter(case=case): |
212
|
|
|
plan = case_plan_rel.plan |
213
|
|
|
self.assertContains( |
214
|
|
|
response, |
215
|
|
|
'<a href="{0}">TP-{1}: {2}</a>'.format( |
216
|
|
|
reverse('test_plan_url_short', args=[plan.pk]), |
217
|
|
|
plan.pk, |
218
|
|
|
plan.name), |
219
|
|
|
html=True) |
220
|
|
|
|
221
|
|
|
def test_list_plans(self): |
222
|
|
|
response = self.client.get(self.case_plans_url) |
223
|
|
|
self.assert_list_case_plans(response, self.case_1) |
224
|
|
|
|
225
|
|
|
def test_missing_permission_to_add(self): |
226
|
|
|
response = self.client.get(self.case_plans_url, |
227
|
|
|
{'a': 'add', 'plan_id': self.plan_test_add.pk}) |
228
|
|
|
self.assertContains(response, 'Permission denied') |
229
|
|
|
|
230
|
|
|
def test_missing_permission_to_remove(self): |
231
|
|
|
response = self.client.get(self.case_plans_url, |
232
|
|
|
{'a': 'remove', 'plan_id': self.plan_test_remove.pk}) |
233
|
|
|
self.assertContains(response, 'Permission denied') |
234
|
|
|
|
235
|
|
|
def test_add_a_plan(self): |
236
|
|
|
user_should_have_perm(self.plan_tester, 'testcases.add_testcaseplan') |
237
|
|
|
self.client.login( # nosec:B106:hardcoded_password_funcarg |
238
|
|
|
username=self.plan_tester.username, |
239
|
|
|
password='password') |
240
|
|
|
response = self.client.get(self.case_plans_url, |
241
|
|
|
{'a': 'add', 'plan_id': self.plan_test_add.pk}) |
242
|
|
|
|
243
|
|
|
self.assert_list_case_plans(response, self.case_1) |
244
|
|
|
|
245
|
|
|
self.assertTrue(TestCasePlan.objects.filter( |
246
|
|
|
plan=self.plan_test_add, case=self.case_1).exists()) |
247
|
|
|
|
248
|
|
|
def test_remove_a_plan(self): |
249
|
|
|
user_should_have_perm(self.plan_tester, 'testcases.change_testcaseplan') |
250
|
|
|
self.client.login( # nosec:B106:hardcoded_password_funcarg |
251
|
|
|
username=self.plan_tester.username, |
252
|
|
|
password='password') |
253
|
|
|
response = self.client.get(self.case_plans_url, |
254
|
|
|
{'a': 'remove', 'plan_id': self.plan_test_remove.pk}) |
255
|
|
|
|
256
|
|
|
self.assert_list_case_plans(response, self.case_1) |
257
|
|
|
|
258
|
|
|
not_linked_to_plan = not TestCasePlan.objects.filter( |
259
|
|
|
case=self.case_1, plan=self.plan_test_remove).exists() |
260
|
|
|
self.assertTrue(not_linked_to_plan) |
261
|
|
|
|
262
|
|
|
def test_add_a_few_plans(self): |
263
|
|
|
user_should_have_perm(self.plan_tester, 'testcases.add_testcaseplan') |
264
|
|
|
self.client.login( # nosec:B106:hardcoded_password_funcarg |
265
|
|
|
username=self.plan_tester.username, |
266
|
|
|
password='password') |
267
|
|
|
# This time, add a few plans to another case |
268
|
|
|
url = reverse('testcases-plan', args=[self.case_2.pk]) |
269
|
|
|
|
270
|
|
|
response = self.client.get(url, |
271
|
|
|
{'a': 'add', 'plan_id': [self.plan_test_add.pk, |
272
|
|
|
self.plan_test_remove.pk]}) |
273
|
|
|
|
274
|
|
|
self.assert_list_case_plans(response, self.case_2) |
275
|
|
|
|
276
|
|
|
self.assertTrue(TestCasePlan.objects.filter( |
277
|
|
|
case=self.case_2, plan=self.plan_test_add).exists()) |
278
|
|
|
self.assertTrue(TestCasePlan.objects.filter( |
279
|
|
|
case=self.case_2, plan=self.plan_test_remove).exists()) |
280
|
|
|
|
281
|
|
|
|
282
|
|
|
class TestEditCase(BasePlanCase): |
283
|
|
|
"""Test edit view method""" |
284
|
|
|
|
285
|
|
|
@classmethod |
286
|
|
|
def setUpTestData(cls): |
287
|
|
|
super(TestEditCase, cls).setUpTestData() |
288
|
|
|
|
289
|
|
|
cls.proposed_case = TestCaseFactory( |
290
|
|
|
author=cls.tester, |
291
|
|
|
default_tester=None, |
292
|
|
|
reviewer=cls.tester, |
293
|
|
|
case_status=cls.case_status_proposed, |
294
|
|
|
plan=[cls.plan]) |
295
|
|
|
|
296
|
|
|
# test data for https://github.com/kiwitcms/Kiwi/issues/334 |
297
|
|
|
# pylint: disable=objects-update-used |
298
|
|
|
Priority.objects.filter(value='P4').update(is_active=False) |
299
|
|
|
|
300
|
|
|
user_should_have_perm(cls.tester, 'testcases.change_testcase') |
301
|
|
|
cls.case_edit_url = reverse('testcases-edit', args=[cls.case_1.pk]) |
302
|
|
|
|
303
|
|
|
# Copy, then modify or add new data for specific tests below |
304
|
|
|
cls.edit_data = { |
305
|
|
|
'from_plan': cls.plan.pk, |
306
|
|
|
'summary': cls.case_1.summary, |
307
|
|
|
'product': cls.case_1.category.product.pk, |
308
|
|
|
'category': cls.case_1.category.pk, |
309
|
|
|
'default_tester': '', |
310
|
|
|
'case_status': cls.case_status_confirmed.pk, |
311
|
|
|
'arguments': '', |
312
|
|
|
'extra_link': '', |
313
|
|
|
'notes': '', |
314
|
|
|
'is_automated': '0', |
315
|
|
|
'requirement': '', |
316
|
|
|
'script': '', |
317
|
|
|
'alias': '', |
318
|
|
|
'priority': cls.case_1.priority.pk, |
319
|
|
|
'tag': 'RHEL', |
320
|
|
|
'setup': '', |
321
|
|
|
'action': '', |
322
|
|
|
'breakdown': '', |
323
|
|
|
'effect': '', |
324
|
|
|
'cc_list': '', |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
def test_404_if_case_id_not_exist(self): |
328
|
|
|
url = reverse('testcases-edit', args=[99999]) |
329
|
|
|
response = self.client.get(url) |
330
|
|
|
self.assert404(response) |
331
|
|
|
|
332
|
|
|
def test_404_if_from_plan_not_exist(self): |
333
|
|
|
response = self.client.get(self.case_edit_url, {'from_plan': 9999}) |
334
|
|
|
self.assert404(response) |
335
|
|
|
|
336
|
|
|
def test_show_edit_page(self): |
337
|
|
|
response = self.client.get(self.case_edit_url) |
338
|
|
|
self.assertEqual(200, response.status_code) |
339
|
|
|
self.assertNotContains(response, ">P4</option") |
340
|
|
|
|
341
|
|
|
def test_edit_a_case(self): |
342
|
|
|
edit_data = self.edit_data.copy() |
343
|
|
|
new_summary = 'Edited: {0}'.format(self.case_1.summary) |
344
|
|
|
edit_data['summary'] = new_summary |
345
|
|
|
|
346
|
|
|
response = self.client.post(self.case_edit_url, edit_data) |
347
|
|
|
|
348
|
|
|
redirect_url = '{0}?from_plan={1}'.format( |
349
|
|
|
reverse('testcases-get', args=[self.case_1.pk]), |
350
|
|
|
self.plan.pk, |
351
|
|
|
) |
352
|
|
|
self.assertRedirects(response, redirect_url) |
353
|
|
|
|
354
|
|
|
edited_case = TestCase.objects.get(pk=self.case_1.pk) |
355
|
|
|
self.assertEqual(new_summary, edited_case.summary) |
356
|
|
|
|
357
|
|
|
def test_continue_edit_this_case_after_save(self): |
358
|
|
|
edit_data = self.edit_data.copy() |
359
|
|
|
edit_data['_continue'] = 'continue edit' |
360
|
|
|
|
361
|
|
|
response = self.client.post(self.case_edit_url, edit_data) |
362
|
|
|
|
363
|
|
|
redirect_url = '{0}?from_plan={1}'.format( |
364
|
|
|
reverse('testcases-edit', args=[self.case_1.pk]), |
365
|
|
|
self.plan.pk, |
366
|
|
|
) |
367
|
|
|
self.assertRedirects(response, redirect_url) |
368
|
|
|
|
369
|
|
|
def test_continue_edit_next_confirmed_case_after_save(self): |
370
|
|
|
edit_data = self.edit_data.copy() |
371
|
|
|
edit_data['_continuenext'] = 'continue edit next case' |
372
|
|
|
|
373
|
|
|
response = self.client.post(self.case_edit_url, edit_data) |
374
|
|
|
|
375
|
|
|
redirect_url = '{0}?from_plan={1}'.format( |
376
|
|
|
reverse('testcases-edit', args=[self.case_2.pk]), |
377
|
|
|
self.plan.pk, |
378
|
|
|
) |
379
|
|
|
self.assertRedirects(response, redirect_url) |
380
|
|
|
|
381
|
|
|
def test_continue_edit_next_non_confirmed_case_after_save(self): |
382
|
|
|
edit_data = self.edit_data.copy() |
383
|
|
|
edit_data['case_status'] = self.case_status_proposed.pk |
384
|
|
|
edit_data['_continuenext'] = 'continue edit next case' |
385
|
|
|
|
386
|
|
|
response = self.client.post(self.case_edit_url, edit_data) |
387
|
|
|
|
388
|
|
|
redirect_url = '{0}?from_plan={1}'.format( |
389
|
|
|
reverse('testcases-edit', args=[self.proposed_case.pk]), |
390
|
|
|
self.plan.pk, |
391
|
|
|
) |
392
|
|
|
self.assertRedirects(response, redirect_url) |
393
|
|
|
|
394
|
|
|
def test_return_to_plan_confirmed_cases_tab(self): |
395
|
|
|
edit_data = self.edit_data.copy() |
396
|
|
|
edit_data['_returntoplan'] = 'return to plan' |
397
|
|
|
|
398
|
|
|
response = self.client.post(self.case_edit_url, edit_data) |
399
|
|
|
|
400
|
|
|
redirect_url = '{0}#testcases'.format( |
401
|
|
|
reverse('test_plan_url_short', args=[self.plan.pk]) |
402
|
|
|
) |
403
|
|
|
self.assertRedirects(response, redirect_url, target_status_code=301) |
404
|
|
|
|
405
|
|
|
def test_return_to_plan_review_cases_tab(self): |
406
|
|
|
edit_data = self.edit_data.copy() |
407
|
|
|
edit_data['case_status'] = self.case_status_proposed.pk |
408
|
|
|
edit_data['_returntoplan'] = 'return to plan' |
409
|
|
|
|
410
|
|
|
response = self.client.post(self.case_edit_url, edit_data) |
411
|
|
|
|
412
|
|
|
redirect_url = '{0}#reviewcases'.format( |
413
|
|
|
reverse('test_plan_url_short', args=[self.plan.pk]) |
414
|
|
|
) |
415
|
|
|
self.assertRedirects(response, redirect_url, target_status_code=301) |
416
|
|
|
|
417
|
|
|
|
418
|
|
|
class TestPrintablePage(BasePlanCase): |
419
|
|
|
"""Test printable page view method""" |
420
|
|
|
|
421
|
|
|
@classmethod |
422
|
|
|
def setUpTestData(cls): |
423
|
|
|
super(TestPrintablePage, cls).setUpTestData() |
424
|
|
|
cls.printable_url = reverse('testcases-printable') |
425
|
|
|
|
426
|
|
|
cls.case_1.add_text(action='action', |
427
|
|
|
effect='effect', |
428
|
|
|
setup='setup', |
429
|
|
|
breakdown='breakdown') |
430
|
|
|
cls.case_2.add_text(action='action', |
431
|
|
|
effect='effect', |
432
|
|
|
setup='setup', |
433
|
|
|
breakdown='breakdown') |
434
|
|
|
|
435
|
|
|
def test_printable_page(self): |
436
|
|
|
# printing only 1 of the cases |
437
|
|
|
response = self.client.post(self.printable_url, |
438
|
|
|
{'case': [self.case_1.pk]}) |
439
|
|
|
|
440
|
|
|
# not printing the Test Plan header section |
441
|
|
|
self.assertNotContains(response, 'Test Plan Document') |
442
|
|
|
|
443
|
|
|
# response contains the first TestCase |
444
|
|
|
self.assertContains( |
445
|
|
|
response, |
446
|
|
|
'<h3>TC-{0}: {1}</h3>'.format(self.case_1.pk, self.case_1.summary), |
447
|
|
|
html=True |
448
|
|
|
) |
449
|
|
|
|
450
|
|
|
# but not the second TestCase b/c it was not selected |
451
|
|
|
self.assertNotContains( |
452
|
|
|
response, |
453
|
|
|
'<h3>TC-{0}: {1}'.format(self.case_2.pk, self.case_2.summary), |
454
|
|
|
html=True |
455
|
|
|
) |
456
|
|
|
|
457
|
|
|
|
458
|
|
|
class TestCloneCase(BasePlanCase): |
459
|
|
|
"""Test clone view method""" |
460
|
|
|
|
461
|
|
|
@classmethod |
462
|
|
|
def setUpTestData(cls): |
463
|
|
|
super(TestCloneCase, cls).setUpTestData() |
464
|
|
|
|
465
|
|
|
user_should_have_perm(cls.tester, 'testcases.add_testcase') |
466
|
|
|
cls.clone_url = reverse('testcases-clone') |
467
|
|
|
|
468
|
|
|
def test_refuse_if_missing_argument(self): |
469
|
|
|
# Refuse to clone cases if missing selectAll and case arguments |
470
|
|
|
response = self.client.get(self.clone_url, {}, follow=True) |
471
|
|
|
|
472
|
|
|
self.assertContains(response, 'At least one TestCase is required') |
473
|
|
|
|
474
|
|
|
def test_show_clone_page_with_from_plan(self): |
475
|
|
|
response = self.client.get(self.clone_url, |
476
|
|
|
{'from_plan': self.plan.pk, |
477
|
|
|
'case': [self.case_1.pk, self.case_2.pk]}) |
478
|
|
|
|
479
|
|
|
self.assertContains( |
480
|
|
|
response, |
481
|
|
|
"""<div> |
482
|
|
|
<input type="radio" id="id_use_sameplan" name="selectplan" value="{0}"> |
483
|
|
|
<label for="id_use_sameplan" class="strong">Use the same Plan -- {0} : {1}</label> |
484
|
|
|
</div>""".format(self.plan.pk, self.plan.name), |
485
|
|
|
html=True) |
486
|
|
|
|
487
|
|
|
for loop_counter, case in enumerate([self.case_1, self.case_2]): |
488
|
|
|
self.assertContains( |
489
|
|
|
response, |
490
|
|
|
'<label for="id_case_{0}">' |
491
|
|
|
'<input checked="checked" id="id_case_{0}" name="case" ' |
492
|
|
|
'type="checkbox" value="{1}"> {2}</label>'.format( |
493
|
|
|
loop_counter, case.pk, case.summary), |
494
|
|
|
html=True) |
495
|
|
|
|
496
|
|
|
def test_show_clone_page_without_from_plan(self): |
497
|
|
|
response = self.client.get(self.clone_url, {'case': self.case_1.pk}) |
498
|
|
|
|
499
|
|
|
self.assertNotContains( |
500
|
|
|
response, |
501
|
|
|
'Use the same Plan -- {0} : {1}'.format(self.plan.pk, |
502
|
|
|
self.plan.name), |
503
|
|
|
) |
504
|
|
|
|
505
|
|
|
self.assertContains( |
506
|
|
|
response, |
507
|
|
|
'<label for="id_case_0">' |
508
|
|
|
'<input checked="checked" id="id_case_0" name="case" ' |
509
|
|
|
'type="checkbox" value="{0}"> {1}</label>'.format( |
510
|
|
|
self.case_1.pk, self.case_1.summary), |
511
|
|
|
html=True) |
512
|
|
|
|
513
|
|
|
|
514
|
|
|
class TestSearchCases(BasePlanCase): |
515
|
|
|
"""Test search view method""" |
516
|
|
|
|
517
|
|
|
@classmethod |
518
|
|
|
def setUpTestData(cls): |
519
|
|
|
super().setUpTestData() |
520
|
|
|
|
521
|
|
|
cls.search_url = reverse('testcases-search') |
522
|
|
|
|
523
|
|
|
def test_page_renders(self): |
524
|
|
|
response = self.client.get(self.search_url, {}) |
525
|
|
|
self.assertContains(response, '<option value="">----------</option>', html=True) |
526
|
|
|
|
527
|
|
|
|
528
|
|
|
class TestGetCasesFromPlan(BasePlanCase): |
529
|
|
|
@classmethod |
530
|
|
|
def setUpTestData(cls): |
531
|
|
|
super().setUpTestData() |
532
|
|
|
initiate_user_with_default_setups(cls.tester) |
533
|
|
|
|
534
|
|
|
def test_casetags_are_shown_in_template(self): |
535
|
|
|
# pylint: disable=tag-objects-get_or_create |
536
|
|
|
tag, _ = Tag.objects.get_or_create(name='Linux') |
537
|
|
|
self.case.add_tag(tag) |
538
|
|
|
|
539
|
|
|
url = reverse('testcases-all') |
540
|
|
|
response_data = urlencode({ |
541
|
|
|
'from_plan': self.plan.pk, |
542
|
|
|
'template_type': 'case', |
543
|
|
|
'a': 'initial'}) |
544
|
|
|
# note: this is how the UI sends the request |
545
|
|
|
response = self.client.post(url, data=response_data, |
546
|
|
|
content_type='application/x-www-form-urlencoded; charset=UTF-8', |
547
|
|
|
HTTP_X_REQUESTED_WITH='XMLHttpRequest') |
548
|
|
|
self.assertEqual(HTTPStatus.OK, response.status_code) |
549
|
|
|
self.assertContains(response, 'Tags:') |
550
|
|
|
self.assertContains(response, '<a href="#testcases">Linux</a>') |
551
|
|
|
|
552
|
|
|
def test_disabled_priority_now_shown(self): |
553
|
|
|
# test data for https://github.com/kiwitcms/Kiwi/issues/334 |
554
|
|
|
# pylint: disable=objects-update-used |
555
|
|
|
Priority.objects.filter(value='P4').update(is_active=False) |
556
|
|
|
|
557
|
|
|
url = reverse('testcases-all') |
558
|
|
|
response_data = urlencode({ |
559
|
|
|
'from_plan': self.plan.pk, |
560
|
|
|
'template_type': 'case', |
561
|
|
|
'a': 'initial'}) |
562
|
|
|
# note: this is how the UI sends the request |
563
|
|
|
response = self.client.post(url, data=response_data, |
564
|
|
|
content_type='application/x-www-form-urlencoded; charset=UTF-8', |
565
|
|
|
HTTP_X_REQUESTED_WITH='XMLHttpRequest') |
566
|
|
|
self.assertEqual(HTTPStatus.OK, response.status_code) |
567
|
|
|
self.assertContains(response, 'Set P3') |
568
|
|
|
self.assertNotContains(response, 'Set P4') |
569
|
|
|
|
570
|
|
|
|
571
|
|
|
class TestGetSelectedTestcases(BasePlanCase): |
572
|
|
|
def test_get_selected_testcases_works_with_both_string_and_int_pks(self): |
573
|
|
|
""" |
574
|
|
|
Assures that tcms.testcases.views.get_selected_testcases |
575
|
|
|
returns the same results, regardless of whether the |
576
|
|
|
passed request contains the case pks as strings or |
577
|
|
|
integers, as long as they are the same in both occasions. |
578
|
|
|
""" |
579
|
|
|
|
580
|
|
|
case_int_pks = [self.case.pk, self.case_1.pk, self.case_2.pk, self.case_3.pk] |
581
|
|
|
case_str_pks = [] |
582
|
|
|
|
583
|
|
|
for _pk in case_int_pks: |
584
|
|
|
case_str_pks.append(str(_pk)) |
585
|
|
|
|
586
|
|
|
int_pk_query = get_selected_testcases( |
587
|
|
|
RequestFactory().post( |
588
|
|
|
reverse('testcases-clone'), |
589
|
|
|
{'case': case_int_pks} |
590
|
|
|
) |
591
|
|
|
) |
592
|
|
|
|
593
|
|
|
str_pk_query = get_selected_testcases( |
594
|
|
|
RequestFactory().post( |
595
|
|
|
reverse('testcases-clone'), |
596
|
|
|
{'case': case_str_pks} |
597
|
|
|
) |
598
|
|
|
) |
599
|
|
|
|
600
|
|
|
for case in TestCase.objects.filter(pk__in=case_int_pks): |
601
|
|
|
self.assertTrue(case in int_pk_query) |
602
|
|
|
self.assertTrue(case in str_pk_query) |
603
|
|
|
|