Passed
Push — master ( 05a640...f19445 )
by Alexander
03:06
created

tcms.testcases.tests.test_views   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 448
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 33
eloc 304
dl 0
loc 448
rs 9.76
c 0
b 0
f 0

28 Methods

Rating   Name   Duplication   Size   Complexity  
A TestGetCaseRunDetailsAsDefaultUser.test_user_sees_bugs() 0 19 1
A TestMultipleEmailField.test_clean() 0 24 1
A TestSearchCases.setUpTestData() 0 5 1
A TestPrintablePage.setUpTestData() 0 13 1
A TestEditCase.test_404_if_from_plan_not_exist() 0 3 1
A TestPrintablePage.test_printable_page() 0 20 1
A TestEditCase.test_continue_edit_next_confirmed_case_after_save() 0 11 1
A TestEditCase.test_show_edit_page() 0 4 1
A TestEditCase.test_return_to_plan_review_cases_tab() 0 11 1
A TestEditCase.test_continue_edit_next_non_confirmed_case_after_save() 0 12 1
A TestMultipleEmailField.setUpClass() 0 4 1
A TestMultipleEmailField.test_to_python() 0 12 2
A TestCloneCase.test_show_clone_page_without_from_plan() 0 16 1
A TestGetCasesFromPlan.setUpTestData() 0 4 1
A TestEditCase.test_return_to_plan_confirmed_cases_tab() 0 10 1
A TestSearchCases.test_page_renders() 0 3 1
A TestGetCaseRunDetailsAsDefaultUser.test_user_in_default_group_sees_comments() 0 27 2
A TestGetCasesFromPlan.test_disabled_priority_now_shown() 0 17 1
A TestCloneCase.test_refuse_if_missing_argument() 0 5 1
A TestEditCase.test_edit_a_case() 0 15 1
A TestGetSelectedTestcases.test_get_selected_testcases_works_with_both_string_and_int_pks() 0 31 3
A TestEditCase.setUpTestData() 0 40 1
A TestEditCase.test_404_if_case_id_not_exist() 0 4 1
A TestGetCasesFromPlan.test_casetags_are_shown_in_template() 0 17 1
A TestEditCase.test_continue_edit_this_case_after_save() 0 11 1
A TestGetCaseRunDetailsAsDefaultUser.setUpTestData() 0 3 1
A TestCloneCase.setUpTestData() 0 6 1
A TestCloneCase.test_show_clone_page_with_from_plan() 0 21 2
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.urls import reverse
9
from django.forms import ValidationError
10
from django.test import RequestFactory
11
12
from tcms.testcases.fields import MultipleEmailField
13
from tcms.management.models import Priority, Tag
14
from tcms.testcases.models import TestCase
15
from tcms.testcases.views import get_selected_testcases
16
from tcms.testruns.models import TestCaseRunStatus
17
from tcms.tests.factories import BugFactory
18
from tcms.tests.factories import TestCaseFactory
19
from tcms.tests import BasePlanCase, BaseCaseRun
20
from tcms.tests import user_should_have_perm
21
from tcms.utils.permissions import initiate_user_with_default_setups
22
23
24
class TestGetCaseRunDetailsAsDefaultUser(BaseCaseRun):
25
    """Assert what a default user (non-admin) will see"""
26
27
    @classmethod
28
    def setUpTestData(cls):
29
        super(TestGetCaseRunDetailsAsDefaultUser, cls).setUpTestData()
30
31
    def test_user_in_default_group_sees_comments(self):
32
        # test for https://github.com/kiwitcms/Kiwi/issues/74
33
        initiate_user_with_default_setups(self.tester)
34
35
        url = reverse('caserun-detail-pane', args=[self.case_run_1.case_id])
36
        response = self.client.get(
37
            url,
38
            {
39
                'case_run_id': self.case_run_1.pk,
40
                'case_text_version': self.case_run_1.case.latest_text_version()
41
            }
42
        )
43
44
        self.assertEqual(HTTPStatus.OK, response.status_code)
45
46
        self.assertContains(
47
            response,
48
            '<textarea name="comment" cols="40" id="id_comment" maxlength="10000" '
49
            'rows="10">\n</textarea>',
50
            html=True)
51
52
        for status in TestCaseRunStatus.objects.all():
53
            self.assertContains(
54
                response,
55
                "<input type=\"submit\" class=\"btn btn_%s btn_status js-status-button\" "
56
                "title=\"%s\"" % (status.name.lower(), status.name),
57
                html=False
58
            )
59
60
    def test_user_sees_bugs(self):
61
        bug_1 = BugFactory()
62
        bug_2 = BugFactory()
63
64
        self.case_run_1.add_bug(bug_1.bug_id, bug_1.bug_system.pk)
65
        self.case_run_1.add_bug(bug_2.bug_id, bug_2.bug_system.pk)
66
67
        url = reverse('caserun-detail-pane', args=[self.case_run_1.case.pk])
68
        response = self.client.get(
69
            url,
70
            {
71
                'case_run_id': self.case_run_1.pk,
72
                'case_text_version': self.case_run_1.case.latest_text_version()
73
            }
74
        )
75
76
        self.assertEqual(HTTPStatus.OK, response.status_code)
77
        self.assertContains(response, bug_1.get_full_url())
78
        self.assertContains(response, bug_2.get_full_url())
79
80
81
class TestMultipleEmailField(unittest.TestCase):
82
83
    @classmethod
84
    def setUpClass(cls):
85
        super().setUpClass()
86
        cls.field = MultipleEmailField()
87
88
    def test_to_python(self):
89
        value = u'zhangsan@localhost'
90
        pyobj = self.field.to_python(value)
91
        self.assertEqual(pyobj, [value])
92
93
        value = u'zhangsan@localhost,,[email protected],'
94
        pyobj = self.field.to_python(value)
95
        self.assertEqual(pyobj, [u'zhangsan@localhost', u'[email protected]'])
96
97
        for value in ('', None, []):
98
            pyobj = self.field.to_python(value)
99
            self.assertEqual(pyobj, [])
100
101
    def test_clean(self):
102
        value = u'zhangsan@localhost'
103
        data = self.field.clean(value)
104
        self.assertEqual(data, [value])
105
106
        value = u'zhangsan@localhost,[email protected]'
107
        data = self.field.clean(value)
108
        self.assertEqual(data, [u'zhangsan@localhost', u'[email protected]'])
109
110
        value = u',zhangsan@localhost, ,[email protected], \n'
111
        data = self.field.clean(value)
112
        self.assertEqual(data, [u'zhangsan@localhost', '[email protected]'])
113
114
        value = ',zhangsan,zhangsan@localhost, \n,[email protected], '
115
        self.assertRaises(ValidationError, self.field.clean, value)
116
117
        value = ''
118
        self.field.required = True
119
        self.assertRaises(ValidationError, self.field.clean, value)
120
121
        value = ''
122
        self.field.required = False
123
        data = self.field.clean(value)
124
        self.assertEqual(data, [])
125
126
127
class TestEditCase(BasePlanCase):
128
    """Test edit view method"""
129
130
    @classmethod
131
    def setUpTestData(cls):
132
        super(TestEditCase, cls).setUpTestData()
133
134
        cls.proposed_case = TestCaseFactory(
135
            author=cls.tester,
136
            default_tester=None,
137
            reviewer=cls.tester,
138
            case_status=cls.case_status_proposed,
139
            plan=[cls.plan])
140
141
        # test data for https://github.com/kiwitcms/Kiwi/issues/334
142
        # pylint: disable=objects-update-used
143
        Priority.objects.filter(value='P4').update(is_active=False)
144
145
        user_should_have_perm(cls.tester, 'testcases.change_testcase')
146
        cls.case_edit_url = reverse('testcases-edit', args=[cls.case_1.pk])
147
148
        # Copy, then modify or add new data for specific tests below
149
        cls.edit_data = {
150
            'from_plan': cls.plan.pk,
151
            'summary': cls.case_1.summary,
152
            'product': cls.case_1.category.product.pk,
153
            'category': cls.case_1.category.pk,
154
            'default_tester': '',
155
            'case_status': cls.case_status_confirmed.pk,
156
            'arguments': '',
157
            'extra_link': '',
158
            'notes': '',
159
            'is_automated': '0',
160
            'requirement': '',
161
            'script': '',
162
            'alias': '',
163
            'priority': cls.case_1.priority.pk,
164
            'tag': 'RHEL',
165
            'setup': '',
166
            'action': '',
167
            'breakdown': '',
168
            'effect': '',
169
            'cc_list': '',
170
        }
171
172
    def test_404_if_case_id_not_exist(self):
173
        url = reverse('testcases-edit', args=[99999])
174
        response = self.client.get(url)
175
        self.assert404(response)
176
177
    def test_404_if_from_plan_not_exist(self):
178
        response = self.client.get(self.case_edit_url, {'from_plan': 9999})
179
        self.assert404(response)
180
181
    def test_show_edit_page(self):
182
        response = self.client.get(self.case_edit_url)
183
        self.assertEqual(200, response.status_code)
184
        self.assertNotContains(response, ">P4</option")
185
186
    def test_edit_a_case(self):
187
        edit_data = self.edit_data.copy()
188
        new_summary = 'Edited: {0}'.format(self.case_1.summary)
189
        edit_data['summary'] = new_summary
190
191
        response = self.client.post(self.case_edit_url, edit_data)
192
193
        redirect_url = '{0}?from_plan={1}'.format(
194
            reverse('testcases-get', args=[self.case_1.pk]),
195
            self.plan.pk,
196
        )
197
        self.assertRedirects(response, redirect_url)
198
199
        edited_case = TestCase.objects.get(pk=self.case_1.pk)
200
        self.assertEqual(new_summary, edited_case.summary)
201
202
    def test_continue_edit_this_case_after_save(self):
203
        edit_data = self.edit_data.copy()
204
        edit_data['_continue'] = 'continue edit'
205
206
        response = self.client.post(self.case_edit_url, edit_data)
207
208
        redirect_url = '{0}?from_plan={1}'.format(
209
            reverse('testcases-edit', args=[self.case_1.pk]),
210
            self.plan.pk,
211
        )
212
        self.assertRedirects(response, redirect_url)
213
214
    def test_continue_edit_next_confirmed_case_after_save(self):
215
        edit_data = self.edit_data.copy()
216
        edit_data['_continuenext'] = 'continue edit next case'
217
218
        response = self.client.post(self.case_edit_url, edit_data)
219
220
        redirect_url = '{0}?from_plan={1}'.format(
221
            reverse('testcases-edit', args=[self.case_2.pk]),
222
            self.plan.pk,
223
        )
224
        self.assertRedirects(response, redirect_url)
225
226
    def test_continue_edit_next_non_confirmed_case_after_save(self):
227
        edit_data = self.edit_data.copy()
228
        edit_data['case_status'] = self.case_status_proposed.pk
229
        edit_data['_continuenext'] = 'continue edit next case'
230
231
        response = self.client.post(self.case_edit_url, edit_data)
232
233
        redirect_url = '{0}?from_plan={1}'.format(
234
            reverse('testcases-edit', args=[self.proposed_case.pk]),
235
            self.plan.pk,
236
        )
237
        self.assertRedirects(response, redirect_url)
238
239
    def test_return_to_plan_confirmed_cases_tab(self):
240
        edit_data = self.edit_data.copy()
241
        edit_data['_returntoplan'] = 'return to plan'
242
243
        response = self.client.post(self.case_edit_url, edit_data)
244
245
        redirect_url = '{0}#testcases'.format(
246
            reverse('test_plan_url_short', args=[self.plan.pk])
247
        )
248
        self.assertRedirects(response, redirect_url, target_status_code=301)
249
250
    def test_return_to_plan_review_cases_tab(self):
251
        edit_data = self.edit_data.copy()
252
        edit_data['case_status'] = self.case_status_proposed.pk
253
        edit_data['_returntoplan'] = 'return to plan'
254
255
        response = self.client.post(self.case_edit_url, edit_data)
256
257
        redirect_url = '{0}#reviewcases'.format(
258
            reverse('test_plan_url_short', args=[self.plan.pk])
259
        )
260
        self.assertRedirects(response, redirect_url, target_status_code=301)
261
262
263
class TestPrintablePage(BasePlanCase):
264
    """Test printable page view method"""
265
266
    @classmethod
267
    def setUpTestData(cls):
268
        super(TestPrintablePage, cls).setUpTestData()
269
        cls.printable_url = reverse('testcases-printable')
270
271
        cls.case_1.add_text(action='action',
272
                            effect='effect',
273
                            setup='setup',
274
                            breakdown='breakdown')
275
        cls.case_2.add_text(action='action',
276
                            effect='effect',
277
                            setup='setup',
278
                            breakdown='breakdown')
279
280
    def test_printable_page(self):
281
        # printing only 1 of the cases
282
        response = self.client.post(self.printable_url,
283
                                    {'case': [self.case_1.pk]})
284
285
        # not printing the Test Plan header section
286
        self.assertNotContains(response, 'Test Plan Document')
287
288
        # response contains the first TestCase
289
        self.assertContains(
290
            response,
291
            '<h3>TC-{0}: {1}</h3>'.format(self.case_1.pk, self.case_1.summary),
292
            html=True
293
        )
294
295
        # but not the second TestCase b/c it was not selected
296
        self.assertNotContains(
297
            response,
298
            '<h3>TC-{0}: {1}'.format(self.case_2.pk, self.case_2.summary),
299
            html=True
300
        )
301
302
303
class TestCloneCase(BasePlanCase):
304
    """Test clone view method"""
305
306
    @classmethod
307
    def setUpTestData(cls):
308
        super(TestCloneCase, cls).setUpTestData()
309
310
        user_should_have_perm(cls.tester, 'testcases.add_testcase')
311
        cls.clone_url = reverse('testcases-clone')
312
313
    def test_refuse_if_missing_argument(self):
314
        # Refuse to clone cases if missing selectAll and case arguments
315
        response = self.client.get(self.clone_url, {}, follow=True)
316
317
        self.assertContains(response, 'At least one TestCase is required')
318
319
    def test_show_clone_page_with_from_plan(self):
320
        response = self.client.get(self.clone_url,
321
                                   {'from_plan': self.plan.pk,
322
                                    'case': [self.case_1.pk, self.case_2.pk]})
323
324
        self.assertContains(
325
            response,
326
            """<div>
327
    <input type="radio" id="id_use_sameplan" name="selectplan" value="{0}">
328
    <label for="id_use_sameplan" class="strong">Use the same Plan -- {0} : {1}</label>
329
</div>""".format(self.plan.pk, self.plan.name),
330
            html=True)
331
332
        for loop_counter, case in enumerate([self.case_1, self.case_2]):
333
            self.assertContains(
334
                response,
335
                '<label for="id_case_{0}">'
336
                '<input checked="checked" id="id_case_{0}" name="case" '
337
                'type="checkbox" value="{1}"> {2}</label>'.format(
338
                    loop_counter, case.pk, case.summary),
339
                html=True)
340
341
    def test_show_clone_page_without_from_plan(self):
342
        response = self.client.get(self.clone_url, {'case': self.case_1.pk})
343
344
        self.assertNotContains(
345
            response,
346
            'Use the same Plan -- {0} : {1}'.format(self.plan.pk,
347
                                                    self.plan.name),
348
        )
349
350
        self.assertContains(
351
            response,
352
            '<label for="id_case_0">'
353
            '<input checked="checked" id="id_case_0" name="case" '
354
            'type="checkbox" value="{0}"> {1}</label>'.format(
355
                self.case_1.pk, self.case_1.summary),
356
            html=True)
357
358
359
class TestSearchCases(BasePlanCase):
360
    """Test search view method"""
361
362
    @classmethod
363
    def setUpTestData(cls):
364
        super().setUpTestData()
365
366
        cls.search_url = reverse('testcases-search')
367
368
    def test_page_renders(self):
369
        response = self.client.get(self.search_url, {})
370
        self.assertContains(response, '<option value="">----------</option>', html=True)
371
372
373
class TestGetCasesFromPlan(BasePlanCase):
374
    @classmethod
375
    def setUpTestData(cls):
376
        super().setUpTestData()
377
        initiate_user_with_default_setups(cls.tester)
378
379
    def test_casetags_are_shown_in_template(self):
380
        # pylint: disable=tag-objects-get_or_create
381
        tag, _ = Tag.objects.get_or_create(name='Linux')
382
        self.case.add_tag(tag)
383
384
        url = reverse('testcases-all')
385
        response_data = urlencode({
386
            'from_plan': self.plan.pk,
387
            'template_type': 'case',
388
            'a': 'initial'})
389
        # note: this is how the UI sends the request
390
        response = self.client.post(url, data=response_data,
391
                                    content_type='application/x-www-form-urlencoded; charset=UTF-8',
392
                                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')
393
        self.assertEqual(HTTPStatus.OK, response.status_code)
394
        self.assertContains(response, 'Tags:')
395
        self.assertContains(response, '<a href="#testcases">Linux</a>')
396
397
    def test_disabled_priority_now_shown(self):
398
        # test data for https://github.com/kiwitcms/Kiwi/issues/334
399
        # pylint: disable=objects-update-used
400
        Priority.objects.filter(value='P4').update(is_active=False)
401
402
        url = reverse('testcases-all')
403
        response_data = urlencode({
404
            'from_plan': self.plan.pk,
405
            'template_type': 'case',
406
            'a': 'initial'})
407
        # note: this is how the UI sends the request
408
        response = self.client.post(url, data=response_data,
409
                                    content_type='application/x-www-form-urlencoded; charset=UTF-8',
410
                                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')
411
        self.assertEqual(HTTPStatus.OK, response.status_code)
412
        self.assertContains(response, 'Set P3')
413
        self.assertNotContains(response, 'Set P4')
414
415
416
class TestGetSelectedTestcases(BasePlanCase):
417
    def test_get_selected_testcases_works_with_both_string_and_int_pks(self):
418
        """
419
        Assures that tcms.testcases.views.get_selected_testcases
420
        returns the same results, regardless of whether the
421
        passed request contains the case pks as strings or
422
        integers, as long as they are the same in both occasions.
423
        """
424
425
        case_int_pks = [self.case.pk, self.case_1.pk, self.case_2.pk, self.case_3.pk]
426
        case_str_pks = []
427
428
        for _pk in case_int_pks:
429
            case_str_pks.append(str(_pk))
430
431
        int_pk_query = get_selected_testcases(
432
            RequestFactory().post(
433
                reverse('testcases-clone'),
434
                {'case': case_int_pks}
435
            )
436
        )
437
438
        str_pk_query = get_selected_testcases(
439
            RequestFactory().post(
440
                reverse('testcases-clone'),
441
                {'case': case_str_pks}
442
            )
443
        )
444
445
        for case in TestCase.objects.filter(pk__in=case_int_pks):
446
            self.assertTrue(case in int_pk_query)
447
            self.assertTrue(case in str_pk_query)
448