Package trac :: Package ticket :: Package tests :: Package functional :: Module admin

Source Code for Module trac.ticket.tests.functional.admin

   1  #!/usr/bin/env python 
   2  # -*- coding: utf-8 -*- 
   3  # 
   4  # Copyright (C) 2008-2020 Edgewall Software 
   5  # All rights reserved. 
   6  # 
   7  # This software is licensed as described in the file COPYING, which 
   8  # you should have received as part of this distribution. The terms 
   9  # are also available at https://trac.edgewall.org/wiki/TracLicense. 
  10  # 
  11  # This software consists of voluntary contributions made by many 
  12  # individuals. For the exact contribution history, see the revision 
  13  # history and logs, available at https://trac.edgewall.org/log/. 
  14   
  15  import re 
  16  import unittest 
  17   
  18  from datetime import timedelta 
  19   
  20  from trac.admin.tests.functional import AuthorizationTestCaseSetup 
  21  from trac.test import locale_en 
  22  from trac.tests.contentgen import random_unique_camel 
  23  from trac.tests.functional import FunctionalTwillTestCaseSetup, b, \ 
  24                                    internal_error, tc 
  25  from trac.util.datefmt import datetime_now, format_date, format_datetime, \ 
  26                                localtz, utc 
  27  from trac.util.html import escape 
  28   
  29   
30 -class AdminEnumDefaultTestCaseSetup(FunctionalTwillTestCaseSetup):
31 - def test_default(self, enum, name):
32 url = self._tester.url + '/admin/ticket/%s' % enum 33 tc.go(url) 34 tc.url(url + '$') 35 tc.find(name) 36 tc.formvalue('enumtable', 'default', name) 37 tc.submit('apply') 38 tc.url(url + '$') 39 tc.find('radio.*checked="checked" value="%s"' % name) 40 # Test the "Clear default" button 41 tc.go(url) 42 tc.submit('clear', formname='enumtable') 43 tc.url(url + '$') 44 tc.notfind(internal_error) 45 tc.find('<input type="radio" name="default" value="[^>]+"/>') 46 tc.notfind('type="radio" name="default" checked="checked" value=".+"')
47 48
49 -class TestAdminComponent(FunctionalTwillTestCaseSetup):
50 - def runTest(self):
51 """Admin create component""" 52 self._tester.create_component()
53 54
55 -class TestAdminComponentAuthorization(AuthorizationTestCaseSetup):
56 - def runTest(self):
57 """Check permissions required to access the Ticket Components 58 panel.""" 59 self.test_authorization('/admin/ticket/components', 'TICKET_ADMIN', 60 "Manage Components")
61 62
63 -class TestAdminComponentDuplicates(FunctionalTwillTestCaseSetup):
64 - def runTest(self):
65 """Admin create duplicate component""" 66 name = "DuplicateComponent" 67 self._tester.create_component(name) 68 component_url = self._tester.url + "/admin/ticket/components" 69 tc.go(component_url) 70 tc.formvalue('addcomponent', 'name', name) 71 tc.submit() 72 tc.notfind(internal_error) 73 tc.find('Component .* already exists')
74 75
76 -class TestAdminComponentRemoval(FunctionalTwillTestCaseSetup):
77 - def runTest(self):
78 """Admin remove component""" 79 name = "RemovalComponent" 80 self._tester.create_component(name) 81 component_url = self._tester.url + "/admin/ticket/components" 82 tc.go(component_url) 83 tc.formvalue('component_table', 'sel', name) 84 tc.submit('remove') 85 tc.notfind(name)
86 87
88 -class TestAdminComponentNonRemoval(FunctionalTwillTestCaseSetup):
89 - def runTest(self):
90 """Admin remove no selected component""" 91 component_url = self._tester.url + "/admin/ticket/components" 92 tc.go(component_url) 93 tc.submit('remove', formname='component_table') 94 tc.find('No component selected')
95 96
97 -class TestAdminComponentDefault(FunctionalTwillTestCaseSetup):
98 - def runTest(self):
99 """Admin set default component""" 100 name = "DefaultComponent" 101 self._tester.create_component(name) 102 component_url = self._tester.url + "/admin/ticket/components" 103 tc.go(component_url) 104 tc.formvalue('component_table', 'default', name) 105 tc.submit('apply') 106 tc.find('type="radio" name="default" checked="checked" value="%s"' % \ 107 name) 108 tc.go(self._tester.url + '/newticket') 109 tc.find('<option selected="selected" value="%s">%s</option>' 110 % (name, name)) 111 # Test the "Clear default" button 112 self._testenv.set_config('ticket', 'allowed_empty_fields', 'component') 113 tc.go(component_url) 114 tc.submit('clear', formname='component_table') 115 tc.notfind('type="radio" name="default" checked="checked" value=".+"') 116 self._tester.create_ticket() 117 tc.find('<th class="missing" id="h_component">\s*Component:\s*</th>' 118 '\s*<td headers="h_component">\s*</td>') 119 self._testenv.remove_config('ticket', 'allowed_empty_fields')
120 121
122 -class TestAdminComponentDetail(FunctionalTwillTestCaseSetup):
123 - def runTest(self):
124 """Admin component detail""" 125 name = "DetailComponent" 126 self._tester.create_component(name) 127 component_url = self._tester.url + "/admin/ticket/components" 128 tc.go(component_url) 129 tc.follow(name) 130 desc = 'Some component description' 131 tc.formvalue('edit', 'description', desc) 132 tc.submit('cancel') 133 tc.url(component_url + '$') 134 tc.follow(name) 135 tc.notfind(desc)
136 137
138 -class TestAdminComponentNoneDefined(FunctionalTwillTestCaseSetup):
139 - def runTest(self):
140 """The table should be hidden and help text shown when there are no 141 components defined (#11103).""" 142 from trac.ticket import model 143 env = self._testenv.get_trac_environment() 144 components = list(model.Component.select(env)) 145 self._tester.go_to_admin() 146 tc.follow(r"\bComponents\b") 147 148 try: 149 for comp in components: 150 tc.formvalue('component_table', 'sel', comp.name) 151 tc.submit('remove') 152 tc.notfind('<table class="listing" id="complist">') 153 tc.find("As long as you don't add any items to the list, this " 154 "field[ \t\n]*will remain completely hidden from the " 155 "user interface.") 156 finally: 157 for comp in components: 158 self._tester.create_component(comp.name, comp.owner, 159 comp.description)
160 161
162 -class TestAdminMilestone(FunctionalTwillTestCaseSetup):
163 - def runTest(self):
164 """Admin create milestone""" 165 self._tester.create_milestone()
166 167
168 -class TestAdminMilestoneAuthorization(AuthorizationTestCaseSetup):
169 - def runTest(self):
170 """Check permissions required to access the Ticket Milestone 171 panel.""" 172 self.test_authorization('/admin/ticket/milestones', 'TICKET_ADMIN', 173 "Manage Milestones")
174 175
176 -class TestAdminMilestoneSpace(FunctionalTwillTestCaseSetup):
177 - def runTest(self):
178 """Admin create milestone with a space""" 179 self._tester.create_milestone('Milestone 1')
180 181
182 -class TestAdminMilestoneDuplicates(FunctionalTwillTestCaseSetup):
183 - def runTest(self):
184 """Admin create duplicate milestone""" 185 name = "DuplicateMilestone" 186 self._tester.create_milestone(name) 187 milestone_url = self._tester.url + "/admin/ticket/milestones" 188 tc.go(milestone_url) 189 tc.url(milestone_url) 190 tc.formvalue('addmilestone', 'name', name) 191 tc.submit() 192 tc.notfind(internal_error) 193 tc.find('Milestone "%s" already exists, please choose ' 194 'another name.' % name) 195 tc.notfind('%s')
196 197
198 -class TestAdminMilestoneListing(FunctionalTwillTestCaseSetup):
199 - def runTest(self):
200 """Admin milestone listing.""" 201 name1 = self._tester.create_milestone() 202 self._tester.create_ticket(info={'milestone': name1}) 203 name2 = self._tester.create_milestone() 204 205 milestone_url = self._tester.url + '/admin/ticket/milestones' 206 tc.go(milestone_url) 207 tc.url(milestone_url) 208 tc.find(r'<a href="/admin/ticket/milestones/%(name)s">%(name)s</a>' 209 % {'name': name1}) 210 m1_query_link = r'<a href="/query\?group=status&amp;' \ 211 r'milestone=%(name)s">1</a>' % {'name': name1} 212 tc.find(m1_query_link) 213 tc.find(r'<a href="/admin/ticket/milestones/%(name)s">%(name)s</a>' 214 % {'name': name2}) 215 tc.notfind(r'<a href="/query\?group=status&amp;milestone=%(name)s">' 216 r'0</a>' % {'name': name2}) 217 218 apply_submit = '<input type="submit" name="apply" ' \ 219 'value="Apply changes" />' 220 clear_submit = '<input type="submit"[ \t\n]+title="Clear default ' \ 221 'ticket milestone and default retargeting milestone"' \ 222 '[ \t\n]+name="clear" value="Clear defaults" />' 223 tc.find(apply_submit) 224 tc.find(clear_submit) 225 tc.find('<input type="radio" name="ticket_default" value="%(name)s"/>' 226 % {'name': name1}) 227 tc.find('<input type="radio" name="retarget_default" value="%(name)s"/>' 228 % {'name': name1}) 229 230 # TICKET_ADMIN is required to change the ticket default and retarget 231 # default configuration options. TICKET_VIEW is required for the 232 # milestone tickets query link to be present. 233 try: 234 self._testenv.grant_perm('user', 'MILESTONE_ADMIN') 235 self._testenv.revoke_perm('anonymous', 'TICKET_VIEW') 236 self._tester.go_to_front() 237 self._tester.logout() 238 self._tester.login('user') 239 tc.go(milestone_url) 240 tc.notfind(apply_submit) 241 tc.notfind(clear_submit) 242 tc.find('<input type="radio" name="ticket_default" ' 243 'disabled="disabled" value="%(name)s"/>' % {'name': name1}) 244 tc.find('<input type="radio" name="retarget_default" ' 245 'disabled="disabled" value="%(name)s"/>' % {'name': name1}) 246 tc.notfind(m1_query_link) 247 finally: 248 self._testenv.revoke_perm('user', 'MILESTONE_ADMIN') 249 self._testenv.grant_perm('anonymous', 'TICKET_VIEW') 250 self._tester.logout() 251 self._tester.login('admin')
252 253
254 -class TestAdminMilestoneDetail(FunctionalTwillTestCaseSetup):
255 - def runTest(self):
256 """Admin modify milestone details""" 257 name = self._tester.create_milestone() 258 259 milestone_url = self._tester.url + '/admin/ticket/milestones' 260 def go_to_milestone_detail(): 261 tc.go(milestone_url) 262 tc.url(milestone_url) 263 tc.follow(name) 264 tc.url(milestone_url + '/' + name)
265 266 # Modify the details of the milestone 267 go_to_milestone_detail() 268 tc.formvalue('edit', 'due', True) 269 tc.formvalue('edit', 'description', 'Some description.') 270 tc.submit('save') 271 tc.url(milestone_url) 272 273 # Milestone is not closed 274 self._tester.go_to_roadmap() 275 tc.find(name) 276 277 # Cancel more modifications and modification are not saved 278 go_to_milestone_detail() 279 tc.formvalue('edit', 'description', '~~Some other description.~~') 280 tc.submit('cancel') 281 tc.url(milestone_url) 282 self._tester.go_to_roadmap() 283 tc.find('Some description.') 284 tc.follow(name) 285 tc.find('Some description.') 286 287 # Milestone is readonly when user doesn't have MILESTONE_MODIFY 288 self._tester.logout() 289 self._testenv.grant_perm('user', 'TICKET_ADMIN') 290 self._tester.login('user') 291 go_to_milestone_detail() 292 try: 293 tc.find(r'<input[^>]+id="name"[^>]+readonly="readonly"') 294 tc.find(r'<input[^>]+id="due"[^>]+disabled="disabled"') 295 tc.find(r'<input[^>]+id="duedate"[^>]+readonly="readonly"') 296 tc.find(r'<input[^>]+id="completed"[^>]+disabled="disabled"') 297 tc.find(r'<input[^>]+id="completeddate"[^>]+readonly="readonly"') 298 tc.find(r'<textarea[^>]+id="description"[^>]+readonly="readonly"') 299 tc.find(r'<input[^>]+name="save"[^>]+disabled="disabled"') 300 tc.submit('cancel', 'edit') 301 tc.url(milestone_url) 302 finally: 303 self._tester.logout() 304 self._testenv.revoke_perm('user', 'TICKET_ADMIN') 305 self._tester.login('admin')
306 307
308 -class TestAdminMilestoneDue(FunctionalTwillTestCaseSetup):
309 - def runTest(self):
310 """Admin milestone duedate""" 311 name = "DueMilestone" 312 duedate = datetime_now(tz=utc) 313 duedate_string = format_datetime(duedate, tzinfo=utc, 314 locale=locale_en) 315 self._tester.create_milestone(name, due=duedate_string) 316 tc.find(duedate_string)
317 318
319 -class TestAdminMilestoneDetailDue(FunctionalTwillTestCaseSetup):
320 - def runTest(self):
321 """Admin modify milestone duedate on detail page""" 322 name = "DetailDueMilestone" 323 # Create a milestone 324 self._tester.create_milestone(name) 325 326 # Modify the details of the milestone 327 milestone_url = self._tester.url + "/admin/ticket/milestones" 328 tc.go(milestone_url) 329 tc.url(milestone_url) 330 tc.follow(name) 331 tc.url(milestone_url + '/' + name) 332 duedate = datetime_now(tz=utc) 333 duedate_string = format_datetime(duedate, tzinfo=utc, 334 locale=locale_en) 335 tc.formvalue('edit', 'due', True) 336 tc.formvalue('edit', 'duedate', duedate_string) 337 tc.submit('save') 338 tc.url(milestone_url + '$') 339 tc.find(name + '(<[^>]*>|\\s)*'+ duedate_string, 's')
340 341
342 -class TestAdminMilestoneDetailRename(FunctionalTwillTestCaseSetup):
343 - def runTest(self):
344 """Admin rename milestone""" 345 name1 = self._tester.create_milestone() 346 name2 = random_unique_camel() 347 tid = self._tester.create_ticket(info={'milestone': name1}) 348 milestone_url = self._tester.url + '/admin/ticket/milestones' 349 350 self._tester.go_to_url(milestone_url) 351 tc.follow(name1) 352 tc.url(milestone_url + '/' + name1) 353 tc.formvalue('edit', 'name', name2) 354 tc.submit('save') 355 356 tc.find(r"Your changes have been saved\.") 357 tc.find(r"\b%s\b" % name2) 358 tc.notfind(r"\b%s\b" % name1) 359 self._tester.go_to_ticket(tid) 360 tc.find('<a class="milestone" href="/milestone/%(name)s" ' 361 'title="No date set">%(name)s</a>' % {'name': name2}) 362 tc.find('<th class="trac-field-milestone">Milestone:</th>[ \t\n]+' 363 '<td>[ \t\n]+<span class="trac-field-old">%s</span>' 364 '[ \t\n]+→[ \t\n]+' 365 '<span class="trac-field-new">%s</span>[ \t\n]+</td>' 366 % (name1, name2)) 367 tc.find("Milestone renamed")
368 369
370 -class TestAdminMilestoneCompleted(FunctionalTwillTestCaseSetup):
371 - def runTest(self):
372 """Admin milestone completed""" 373 name = "CompletedMilestone" 374 self._tester.create_milestone(name) 375 milestone_url = self._tester.url + "/admin/ticket/milestones" 376 tc.go(milestone_url) 377 tc.url(milestone_url) 378 tc.follow(name) 379 tc.url(milestone_url + '/' + name) 380 tc.formvalue('edit', 'completed', True) 381 tc.submit('save') 382 tc.url(milestone_url + "$")
383 384
385 -class TestAdminMilestoneCompletedFuture(FunctionalTwillTestCaseSetup):
386 - def runTest(self):
387 """Admin milestone completed in the future""" 388 name = "CompletedFutureMilestone" 389 self._tester.create_milestone(name) 390 milestone_url = self._tester.url + "/admin/ticket/milestones" 391 tc.go(milestone_url) 392 tc.url(milestone_url) 393 tc.follow(name) 394 tc.url(milestone_url + '/' + name) 395 tc.formvalue('edit', 'completed', True) 396 cdate = datetime_now(tz=utc) + timedelta(days=2) 397 cdate_string = format_date(cdate, tzinfo=localtz, locale=locale_en) 398 tc.formvalue('edit', 'completeddate', cdate_string) 399 tc.submit('save') 400 tc.find('Completion date may not be in the future') 401 # And make sure it wasn't marked as completed. 402 self._tester.go_to_roadmap() 403 tc.find(name)
404 405
406 -class TestAdminMilestoneRemove(FunctionalTwillTestCaseSetup):
407 - def runTest(self):
408 """Admin remove milestone""" 409 name = "MilestoneRemove" 410 self._tester.create_milestone(name) 411 tid = self._tester.create_ticket(info={'milestone': name}) 412 milestone_url = self._tester.url + '/admin/ticket/milestones' 413 414 tc.go(milestone_url) 415 tc.formvalue('milestone_table', 'sel', name) 416 tc.submit('remove') 417 418 tc.url(milestone_url + '$') 419 tc.notfind(name) 420 self._tester.go_to_ticket(tid) 421 tc.find('<th class="missing" id="h_milestone">' 422 '[ \t\n]*Milestone:[ \t\n]*</th>') 423 tc.find('<th class="trac-field-milestone">Milestone:</th>[ \t\n]+' 424 '<td>[ \t\n]+' 425 '<span class="trac-field-deleted">%s</span>' 426 '[ \t\n]+</td>' % name) 427 tc.find("Milestone deleted")
428 429
430 -class TestAdminMilestoneRemoveMulti(FunctionalTwillTestCaseSetup):
431 - def runTest(self):
432 """Admin remove multiple milestones""" 433 name = "MultiRemoveMilestone" 434 count = 3 435 for i in xrange(count): 436 self._tester.create_milestone("%s%s" % (name, i)) 437 milestone_url = self._tester.url + '/admin/ticket/milestones' 438 tc.go(milestone_url) 439 tc.url(milestone_url + '$') 440 for i in xrange(count): 441 tc.find("%s%s" % (name, i)) 442 for i in xrange(count): 443 tc.formvalue('milestone_table', 'sel', "%s%s" % (name, i)) 444 tc.submit('remove') 445 tc.url(milestone_url + '$') 446 for i in xrange(count): 447 tc.notfind("%s%s" % (name, i))
448 449
450 -class TestAdminMilestoneNonRemoval(FunctionalTwillTestCaseSetup):
451 - def runTest(self):
452 """Admin remove no selected milestone""" 453 milestone_url = self._tester.url + "/admin/ticket/milestones" 454 tc.go(milestone_url) 455 tc.submit('remove', formname='milestone_table') 456 tc.find('No milestone selected')
457 458
459 -class TestAdminMilestoneDefaults(FunctionalTwillTestCaseSetup):
460 - def runTest(self):
461 """Admin set default ticket milestone, default retarget milestone 462 and clear defaults.""" 463 def clear_defaults(): 464 # Test the "Clear default" button 465 tc.go(milestone_url) 466 tc.submit('clear', formname='milestone_table') 467 tc.notfind('type="radio" name="ticket_default" ' 468 'checked="checked" value=".+"') 469 tc.notfind('type="radio" name="retarget_default" ' 470 'checked="checked value=".+""') 471 self._tester.go_to_ticket(tid) 472 tc.find('<th class="missing" id="h_milestone">[ \t\n]+' 473 'Milestone:[ \t\n]+</th>[ \t\n]+' 474 '(?!<td headers="h_milestone">)') 475 self._tester.go_to_milestone(mid2) 476 tc.submit(formname='deletemilestone') 477 tc.notfind('<option selected="selected" value="%s">%s</option>' 478 % (mid1, mid1))
479 480 milestone_url = self._tester.url + "/admin/ticket/milestones" 481 tid = self._tester.create_ticket() 482 mid1 = self._tester.create_milestone() 483 mid2 = self._tester.create_milestone() 484 self._tester.create_ticket(info={'milestone': mid2}) 485 486 # Set default ticket milestone 487 tc.go(milestone_url) 488 tc.formvalue('milestone_table', 'ticket_default', mid1) 489 tc.submit('apply') 490 tc.find('type="radio" name="ticket_default"' 491 ' checked="checked" value="%s"' % mid1) 492 tc.notfind('type="radio" name="retarget_default"' 493 ' checked="checked" value=".+"') 494 # verify it is the default on the newticket page. 495 tc.go(self._tester.url + '/newticket') 496 tc.find('<option selected="selected" value="%s">%s</option>' 497 % (mid1, mid1)) 498 clear_defaults() 499 500 # Set default retarget to milestone 501 tc.go(milestone_url) 502 tc.formvalue('milestone_table', 'retarget_default', mid1) 503 tc.submit('apply') 504 tc.find('type="radio" name="retarget_default"' 505 ' checked="checked" value="%s"' % mid1) 506 tc.notfind('type="radio" name="ticket_default"' 507 ' checked="checked" value=".+"') 508 # verify it is the default on the confirm delete page. 509 self._tester.go_to_milestone(mid2) 510 tc.submit(formname='deletemilestone') 511 tc.find('<option selected="selected" value="%s">%s</option>' 512 % (mid1, mid1)) 513 clear_defaults() 514 515 # Set both 516 tc.go(milestone_url) 517 tc.formvalue('milestone_table', 'ticket_default', mid1) 518 tc.formvalue('milestone_table', 'retarget_default', mid1) 519 tc.submit('apply') 520 tc.find('type="radio" name="ticket_default"' 521 ' checked="checked" value="%s"' % mid1) 522 tc.find('type="radio" name="retarget_default"' 523 ' checked="checked" value="%s"' % mid1) 524 # verify it is the default on the newticket page. 525 tc.go(self._tester.url + '/newticket') 526 tc.find('<option selected="selected" value="%s">%s</option>' 527 % (mid1, mid1)) 528 # verify it is the default on the confirm delete page. 529 self._tester.go_to_milestone(mid2) 530 tc.submit(formname='deletemilestone') 531 tc.find('<option selected="selected" value="%s">%s</option>' 532 % (mid1, mid1)) 533 clear_defaults() 534 535 #Set neither 536 tc.go(milestone_url) 537 tc.submit('apply', formname='milestone_table') 538 tc.notfind('type="radio" name="retarget_default"' 539 ' checked="checked" value=".+"') 540 tc.notfind('type="radio" name="ticket_default"' 541 ' checked="checked" value=".+"') 542 # verify no default on the newticket page. 543 tc.go(self._tester.url + '/newticket') 544 tc.find('<th class="missing" id="h_milestone">[ \t\n]+' 545 'Milestone:[ \t\n]+</th>[ \t\n]+' 546 '(?!<td headers="h_milestone">)') 547 # verify none selected on the confirm delete page. 548 self._tester.go_to_milestone(mid2) 549 tc.submit(formname='deletemilestone') 550 tc.notfind('<option selected="selected" value="%s">%s</option>' 551 % (mid1, mid1))
552 553
554 -class TestAdminPriority(FunctionalTwillTestCaseSetup):
555 - def runTest(self):
556 """Admin create priority""" 557 self._tester.create_priority()
558 559
560 -class TestAdminPriorityAuthorization(AuthorizationTestCaseSetup):
561 - def runTest(self):
562 """Check permissions required to access the Ticket Priority 563 panel.""" 564 self.test_authorization('/admin/ticket/priority', 'TICKET_ADMIN', 565 "Manage Priorities")
566 567
568 -class TestAdminPriorityDuplicates(FunctionalTwillTestCaseSetup):
569 - def runTest(self):
570 """Admin create duplicate priority""" 571 name = "DuplicatePriority" 572 self._tester.create_priority(name) 573 self._tester.create_priority(name) 574 tc.find('Priority %s already exists' % name)
575 576
577 -class TestAdminPriorityModify(FunctionalTwillTestCaseSetup):
578 - def runTest(self):
579 """Admin modify priority""" 580 name = "ModifyPriority" 581 self._tester.create_priority(name) 582 priority_url = self._tester.url + '/admin/ticket/priority' 583 tc.go(priority_url) 584 tc.url(priority_url + '$') 585 tc.find(name) 586 tc.follow(name) 587 tc.formvalue('edit', 'name', name * 2) 588 tc.submit('save') 589 tc.url(priority_url + '$') 590 tc.find(name * 2)
591 592
593 -class TestAdminPriorityRemove(FunctionalTwillTestCaseSetup):
594 - def runTest(self):
595 """Admin remove priority""" 596 name = "RemovePriority" 597 self._tester.create_priority(name) 598 priority_url = self._tester.url + '/admin/ticket/priority' 599 tc.go(priority_url) 600 tc.url(priority_url + '$') 601 tc.find(name) 602 tc.formvalue('enumtable', 'sel', name) 603 tc.submit('remove') 604 tc.url(priority_url + '$') 605 tc.notfind(name)
606 607
608 -class TestAdminPriorityRemoveMulti(FunctionalTwillTestCaseSetup):
609 - def runTest(self):
610 """Admin remove multiple priorities""" 611 name = "MultiRemovePriority" 612 count = 3 613 for i in xrange(count): 614 self._tester.create_priority("%s%s" % (name, i)) 615 priority_url = self._tester.url + '/admin/ticket/priority' 616 tc.go(priority_url) 617 tc.url(priority_url + '$') 618 for i in xrange(count): 619 tc.find("%s%s" % (name, i)) 620 for i in xrange(count): 621 tc.formvalue('enumtable', 'sel', "%s%s" % (name, i)) 622 tc.submit('remove') 623 tc.url(priority_url + '$') 624 for i in xrange(count): 625 tc.notfind("%s%s" % (name, i))
626 627
628 -class TestAdminPriorityNonRemoval(FunctionalTwillTestCaseSetup):
629 - def runTest(self):
630 """Admin remove no selected priority""" 631 priority_url = self._tester.url + "/admin/ticket/priority" 632 tc.go(priority_url) 633 tc.submit('remove', formname='enumtable') 634 tc.find('No priority selected')
635 636
637 -class TestAdminPriorityDefault(AdminEnumDefaultTestCaseSetup):
638 - def runTest(self):
639 """Admin default priority""" 640 name = self._tester.create_priority() 641 self.test_default('priority', name)
642 643
644 -class TestAdminPriorityDetail(FunctionalTwillTestCaseSetup):
645 - def runTest(self):
646 """Admin modify priority details""" 647 name = "DetailPriority" 648 # Create a priority 649 self._tester.create_priority(name + '1') 650 651 # Modify the details of the priority 652 priority_url = self._tester.url + "/admin/ticket/priority" 653 tc.go(priority_url) 654 tc.url(priority_url + '$') 655 tc.follow(name + '1') 656 tc.url(priority_url + '/' + name + '1') 657 tc.formvalue('edit', 'name', name + '2') 658 tc.submit('save') 659 tc.url(priority_url + '$') 660 661 # Cancel more modifications 662 tc.go(priority_url) 663 tc.follow(name) 664 tc.formvalue('edit', 'name', name + '3') 665 tc.submit('cancel') 666 tc.url(priority_url + '$') 667 668 # Verify that only the correct modifications show up 669 tc.notfind(name + '1') 670 tc.find(name + '2') 671 tc.notfind(name + '3')
672 673
674 -class TestAdminPriorityRenumber(FunctionalTwillTestCaseSetup):
675 - def runTest(self):
676 """Admin renumber priorities""" 677 valuesRE = re.compile('<select name="value_([0-9]+)">', re.M) 678 html = b.get_html() 679 max_priority = max([int(x) for x in valuesRE.findall(html)]) 680 681 name = "RenumberPriority" 682 self._tester.create_priority(name + '1') 683 self._tester.create_priority(name + '2') 684 priority_url = self._tester.url + '/admin/ticket/priority' 685 tc.go(priority_url) 686 tc.url(priority_url + '$') 687 tc.find(name + '1') 688 tc.find(name + '2') 689 tc.formvalue('enumtable', 690 'value_%s' % (max_priority + 1), str(max_priority + 2)) 691 tc.formvalue('enumtable', 692 'value_%s' % (max_priority + 2), str(max_priority + 1)) 693 tc.submit('apply') 694 tc.url(priority_url + '$') 695 # Verify that their order has changed. 696 tc.find(name + '2.*' + name + '1', 's')
697 698
699 -class TestAdminPriorityRenumberDup(FunctionalTwillTestCaseSetup):
700 - def runTest(self):
701 """Admin badly renumber priorities""" 702 # Make the first priority the 2nd priority, and leave the 2nd priority 703 # as the 2nd priority. 704 priority_url = self._tester.url + '/admin/ticket/priority' 705 tc.go(priority_url) 706 tc.url(priority_url + '$') 707 tc.formvalue('enumtable', 'value_1', '2') 708 tc.submit('apply') 709 tc.url(priority_url + '$') 710 tc.find('Order numbers must be unique')
711 712
713 -class TestAdminResolution(FunctionalTwillTestCaseSetup):
714 - def runTest(self):
715 """Admin create resolution""" 716 self._tester.create_resolution()
717 718
719 -class TestAdminResolutionAuthorization(AuthorizationTestCaseSetup):
720 - def runTest(self):
721 """Check permissions required to access the Ticket Resolutions 722 panel.""" 723 self.test_authorization('/admin/ticket/resolution', 'TICKET_ADMIN', 724 "Manage Resolutions")
725 726
727 -class TestAdminResolutionDuplicates(FunctionalTwillTestCaseSetup):
728 - def runTest(self):
729 """Admin create duplicate resolution""" 730 name = "DuplicateResolution" 731 self._tester.create_resolution(name) 732 self._tester.create_resolution(name) 733 tc.find(escape('Resolution value "%s" already exists' % name))
734 735
736 -class TestAdminResolutionDefault(AdminEnumDefaultTestCaseSetup):
737 - def runTest(self):
738 """Admin default resolution""" 739 name = self._tester.create_resolution() 740 self.test_default('resolution', name)
741 742
743 -class TestAdminSeverity(FunctionalTwillTestCaseSetup):
744 - def runTest(self):
745 """Admin create severity""" 746 self._tester.create_severity()
747 748
749 -class TestAdminSeverityAuthorization(AuthorizationTestCaseSetup):
750 - def runTest(self):
751 """Check permissions required to access the Ticket Severities 752 panel.""" 753 self.test_authorization('/admin/ticket/severity', 'TICKET_ADMIN', 754 "Manage Severities")
755 756
757 -class TestAdminSeverityDuplicates(FunctionalTwillTestCaseSetup):
758 - def runTest(self):
759 """Admin create duplicate severity""" 760 name = "DuplicateSeverity" 761 self._tester.create_severity(name) 762 self._tester.create_severity(name) 763 tc.find(escape('Severity value "%s" already exists' % name))
764 765
766 -class TestAdminSeverityDefault(AdminEnumDefaultTestCaseSetup):
767 - def runTest(self):
768 """Admin default severity""" 769 name = self._tester.create_severity() 770 self.test_default('severity', name)
771 772
773 -class TestAdminType(FunctionalTwillTestCaseSetup):
774 - def runTest(self):
775 """Admin create type""" 776 self._tester.create_type()
777 778
779 -class TestAdminTypeAuthorization(AuthorizationTestCaseSetup):
780 - def runTest(self):
781 """Check permissions required to access the Ticket Types 782 panel.""" 783 self.test_authorization('/admin/ticket/type', 'TICKET_ADMIN', 784 "Manage Ticket Types")
785 786
787 -class TestAdminTypeDuplicates(FunctionalTwillTestCaseSetup):
788 - def runTest(self):
789 """Admin create duplicate type""" 790 name = "DuplicateType" 791 self._tester.create_type(name) 792 self._tester.create_type(name) 793 tc.find(escape('Type value "%s" already exists' % name))
794 795
796 -class TestAdminTypeDefault(AdminEnumDefaultTestCaseSetup):
797 - def runTest(self):
798 """Admin default type""" 799 name = self._tester.create_type() 800 self.test_default('type', name)
801 802
803 -class TestAdminVersion(FunctionalTwillTestCaseSetup):
804 - def runTest(self):
805 """Admin create version""" 806 self._tester.create_version()
807 808
809 -class TestAdminVersionAuthorization(AuthorizationTestCaseSetup):
810 - def runTest(self):
811 """Check permissions required to access the Versions panel.""" 812 self.test_authorization('/admin/ticket/versions', 'TICKET_ADMIN', 813 "Manage Versions")
814 815
816 -class TestAdminVersionDuplicates(FunctionalTwillTestCaseSetup):
817 - def runTest(self):
818 """Admin create duplicate version""" 819 name = "DuplicateVersion" 820 self._tester.create_version(name) 821 version_admin = self._tester.url + "/admin/ticket/versions" 822 tc.go(version_admin) 823 tc.url(version_admin) 824 tc.formvalue('addversion', 'name', name) 825 tc.submit() 826 tc.notfind(internal_error) 827 tc.find(escape('Version "%s" already exists.' % name))
828 829
830 -class TestAdminVersionDetail(FunctionalTwillTestCaseSetup):
831 # This is somewhat pointless... the only place to find the version 832 # description is on the version details page.
833 - def runTest(self):
834 """Admin version details""" 835 name = "DetailVersion" 836 self._tester.create_version(name) 837 version_admin = self._tester.url + "/admin/ticket/versions" 838 tc.go(version_admin) 839 tc.url(version_admin) 840 tc.follow(name) 841 842 desc = 'Some version description.' 843 tc.formvalue('edit', 'description', desc) 844 tc.submit('save') 845 tc.url(version_admin) 846 tc.follow(name) 847 tc.find(desc)
848 849
850 -class TestAdminVersionDetailTime(FunctionalTwillTestCaseSetup):
851 - def runTest(self):
852 """Admin version detail set time""" 853 name = "DetailTimeVersion" 854 self._tester.create_version(name) 855 version_admin = self._tester.url + "/admin/ticket/versions" 856 tc.go(version_admin) 857 tc.url(version_admin) 858 tc.follow(name) 859 860 tc.formvalue('edit', 'time', '') 861 tc.submit('save') 862 tc.url(version_admin + '$') 863 tc.find(name + '(<[^>]*>|\\s)*<[^>]* name="default" value="%s"' 864 % name, 's') 865 866 # Empty time value is not automatically populated. 867 tc.follow(name) 868 tc.find('<input type="text" id="releaseddate"[^>]*value=""') 869 tc.submit('save', formname="edit") 870 tc.url(version_admin + '$') 871 tc.find(name + '(<[^>]*>|\\s)*<[^>]* name="default" value="%s"' 872 % name, 's')
873 874
875 -class TestAdminVersionDetailCancel(FunctionalTwillTestCaseSetup):
876 - def runTest(self):
877 """Admin version details""" 878 name = "DetailVersion" 879 self._tester.create_version(name) 880 version_admin = self._tester.url + "/admin/ticket/versions" 881 tc.go(version_admin) 882 tc.url(version_admin) 883 tc.follow(name) 884 885 desc = 'Some other version description.' 886 tc.formvalue('edit', 'description', desc) 887 tc.submit('cancel') 888 tc.url(version_admin) 889 tc.follow(name) 890 tc.notfind(desc)
891 892
893 -class TestAdminVersionRemove(FunctionalTwillTestCaseSetup):
894 - def runTest(self):
895 """Admin remove version""" 896 name = "VersionRemove" 897 self._tester.create_version(name) 898 version_url = self._tester.url + "/admin/ticket/versions" 899 tc.go(version_url) 900 tc.formvalue('version_table', 'sel', name) 901 tc.submit('remove') 902 tc.url(version_url + '$') 903 tc.notfind(name)
904 905
906 -class TestAdminVersionRemoveMulti(FunctionalTwillTestCaseSetup):
907 - def runTest(self):
908 """Admin remove multiple versions""" 909 name = "MultiRemoveVersion" 910 count = 3 911 for i in xrange(count): 912 self._tester.create_version("%s%s" % (name, i)) 913 version_url = self._tester.url + '/admin/ticket/versions' 914 tc.go(version_url) 915 tc.url(version_url + '$') 916 for i in xrange(count): 917 tc.find("%s%s" % (name, i)) 918 for i in xrange(count): 919 tc.formvalue('version_table', 'sel', "%s%s" % (name, i)) 920 tc.submit('remove') 921 tc.url(version_url + '$') 922 for i in xrange(count): 923 tc.notfind("%s%s" % (name, i))
924 925
926 -class TestAdminVersionNonRemoval(FunctionalTwillTestCaseSetup):
927 - def runTest(self):
928 """Admin remove no selected version""" 929 version_url = self._tester.url + "/admin/ticket/versions" 930 tc.go(version_url) 931 tc.submit('remove', formname='version_table') 932 tc.find('No version selected')
933 934
935 -class TestAdminVersionDefault(FunctionalTwillTestCaseSetup):
936 - def runTest(self):
937 """Admin set default version""" 938 name = "DefaultVersion" 939 self._tester.create_version(name) 940 version_url = self._tester.url + "/admin/ticket/versions" 941 tc.go(version_url) 942 tc.formvalue('version_table', 'default', name) 943 tc.submit('apply') 944 tc.find('type="radio" name="default" checked="checked" value="%s"' % \ 945 name) 946 # verify it is the default on the newticket page. 947 tc.go(self._tester.url + '/newticket') 948 tc.find('<option selected="selected" value="%s">%s</option>' 949 % (name, name)) 950 # Test the "Clear default" button 951 tc.go(version_url) 952 tc.submit('clear', formname='version_table') 953 tc.notfind('type="radio" name="default" checked="checked" value=".+"') 954 self._tester.create_ticket() 955 tc.find('<th class="missing" id="h_version">[ \t\n]+' 956 'Version:[ \t\n]+</th>[ \t\n]+' 957 '(?!<td headers="h_version">)')
958 959
960 -class RegressionTestRev5665(FunctionalTwillTestCaseSetup):
961 - def runTest(self):
962 """Admin create version without release time (r5665)""" 963 self._tester.create_version(releasetime='')
964 965
966 -class RegressionTestTicket10772(FunctionalTwillTestCaseSetup):
967 - def runTest(self):
968 """Test for regression of https://trac.edgewall.org/ticket/10772""" 969 def find_prop(field, value=None): 970 if value and field == 'type': 971 tc.find(r'<span class="trac-%(field)s">\s*' 972 r'<a href="/query\?status=!closed&amp;' 973 r'%(field)s=%(value)s">\s*%(value)s\s*</a>\s*</span>' 974 % {'field': field, 'value': value}) 975 elif value and field == 'milestone': 976 tc.find(r'<td headers="h_%(field)s">\s*' 977 r'<a class="%(field)s" href="/%(field)s/%(value)s" ' 978 r'title=".+">\s*%(value)s\s*</a>\s*</td>' 979 % {'field': field, 'value': value}) 980 elif value: 981 tc.find(r'<td headers="h_%(field)s">\s*' 982 r'<a href="/query\?status=!closed&amp;' 983 r'%(field)s=%(value)s">\s*%(value)s\s*</a>\s*</td>' 984 % {'field': field, 'value': value}) 985 else: 986 tc.find(r'<td headers="h_%(field)s">\s*</td>' 987 % {'field': field})
988 989 self._testenv.set_config('ticket', 'allowed_empty_fields', 990 'component, milestone, priority, version') 991 992 try: 993 # TODO: use the //Clear default// buttons to clear these values 994 self._tester.go_to_admin("Components") 995 tc.submit('clear', formname='component_table') 996 self._tester.go_to_admin("Milestones") 997 tc.submit('clear', formname='milestone_table') 998 self._tester.go_to_admin("Versions") 999 tc.submit('clear', formname='version_table') 1000 self._tester.go_to_admin("Priorities") 1001 tc.formvalue('enumtable', 'default', 'major') 1002 tc.submit('apply') 1003 1004 self._tester.create_ticket('ticket summary') 1005 1006 find_prop('component') 1007 find_prop('milestone') 1008 find_prop('priority', 'major') 1009 find_prop('version') 1010 1011 self._testenv.set_config('ticket', 'allowed_empty_fields', '') 1012 self._tester.go_to_admin("Components") 1013 tc.formvalue('component_table', 'default', 'component2') 1014 tc.submit('apply') 1015 self._tester.go_to_admin("Milestones") 1016 tc.formvalue('milestone_table', 'ticket_default', 'milestone2') 1017 tc.submit('apply') 1018 self._tester.go_to_admin("Priorities") 1019 tc.formvalue('enumtable', 'default', 'minor') 1020 tc.submit('apply') 1021 self._tester.go_to_admin("Versions") 1022 tc.formvalue('version_table', 'default', '2.0') 1023 tc.submit('apply') 1024 self._tester.go_to_admin("Ticket Types") 1025 tc.formvalue('enumtable', 'default', 'task') 1026 tc.submit('apply') 1027 1028 self._tester.create_ticket('ticket summary') 1029 1030 find_prop('component', 'component2') 1031 find_prop('milestone', 'milestone2') 1032 find_prop('priority', 'minor') 1033 find_prop('version', '2.0') 1034 find_prop('type', 'task') 1035 finally: 1036 self._testenv.remove_config('ticket', 'allowed_empty_fields')
1037 1038
1039 -class RegressionTestTicket11618(FunctionalTwillTestCaseSetup):
1040 - def runTest(self):
1041 """Test for regression of https://trac.edgewall.org/ticket/11618 1042 fix for malformed `readonly="True"` attribute in milestone admin page 1043 """ 1044 name = "11618Milestone" 1045 self._tester.create_milestone(name) 1046 try: 1047 self._testenv.grant_perm('user', 'TICKET_ADMIN') 1048 self._tester.go_to_front() 1049 self._tester.logout() 1050 self._tester.login('user') 1051 tc.go(self._tester.url + "/admin/ticket/milestones/" + name) 1052 tc.notfind('No administration panels available') 1053 tc.find(' readonly="readonly"') 1054 tc.notfind(' readonly="True"') 1055 finally: 1056 self._testenv.revoke_perm('user', 'TICKET_ADMIN') 1057 self._tester.go_to_front() 1058 self._tester.logout() 1059 self._tester.login('admin')
1060 1061
1062 -def functionalSuite(suite=None):
1063 if not suite: 1064 import trac.tests.functional 1065 suite = trac.tests.functional.functionalSuite() 1066 suite.addTest(TestAdminComponent()) 1067 suite.addTest(TestAdminComponentAuthorization()) 1068 suite.addTest(TestAdminComponentDuplicates()) 1069 suite.addTest(TestAdminComponentRemoval()) 1070 suite.addTest(TestAdminComponentNonRemoval()) 1071 suite.addTest(TestAdminComponentDefault()) 1072 suite.addTest(TestAdminComponentDetail()) 1073 suite.addTest(TestAdminComponentNoneDefined()) 1074 suite.addTest(TestAdminMilestone()) 1075 suite.addTest(TestAdminMilestoneAuthorization()) 1076 suite.addTest(TestAdminMilestoneSpace()) 1077 suite.addTest(TestAdminMilestoneDuplicates()) 1078 suite.addTest(TestAdminMilestoneListing()) 1079 suite.addTest(TestAdminMilestoneDetail()) 1080 suite.addTest(TestAdminMilestoneDue()) 1081 suite.addTest(TestAdminMilestoneDetailDue()) 1082 suite.addTest(TestAdminMilestoneDetailRename()) 1083 suite.addTest(TestAdminMilestoneCompleted()) 1084 suite.addTest(TestAdminMilestoneCompletedFuture()) 1085 suite.addTest(TestAdminMilestoneRemove()) 1086 suite.addTest(TestAdminMilestoneRemoveMulti()) 1087 suite.addTest(TestAdminMilestoneNonRemoval()) 1088 suite.addTest(TestAdminMilestoneDefaults()) 1089 suite.addTest(TestAdminPriority()) 1090 suite.addTest(TestAdminPriorityAuthorization()) 1091 suite.addTest(TestAdminPriorityModify()) 1092 suite.addTest(TestAdminPriorityRemove()) 1093 suite.addTest(TestAdminPriorityRemoveMulti()) 1094 suite.addTest(TestAdminPriorityNonRemoval()) 1095 suite.addTest(TestAdminPriorityDefault()) 1096 suite.addTest(TestAdminPriorityDetail()) 1097 suite.addTest(TestAdminPriorityRenumber()) 1098 suite.addTest(TestAdminPriorityRenumberDup()) 1099 suite.addTest(TestAdminResolution()) 1100 suite.addTest(TestAdminResolutionAuthorization()) 1101 suite.addTest(TestAdminResolutionDuplicates()) 1102 suite.addTest(TestAdminResolutionDefault()) 1103 suite.addTest(TestAdminSeverity()) 1104 suite.addTest(TestAdminSeverityAuthorization()) 1105 suite.addTest(TestAdminSeverityDuplicates()) 1106 suite.addTest(TestAdminSeverityDefault()) 1107 suite.addTest(TestAdminType()) 1108 suite.addTest(TestAdminTypeAuthorization()) 1109 suite.addTest(TestAdminTypeDuplicates()) 1110 suite.addTest(TestAdminTypeDefault()) 1111 suite.addTest(TestAdminVersion()) 1112 suite.addTest(TestAdminVersionAuthorization()) 1113 suite.addTest(TestAdminVersionDuplicates()) 1114 suite.addTest(TestAdminVersionDetail()) 1115 suite.addTest(TestAdminVersionDetailTime()) 1116 suite.addTest(TestAdminVersionDetailCancel()) 1117 suite.addTest(TestAdminVersionRemove()) 1118 suite.addTest(TestAdminVersionRemoveMulti()) 1119 suite.addTest(TestAdminVersionNonRemoval()) 1120 suite.addTest(TestAdminVersionDefault()) 1121 suite.addTest(RegressionTestRev5665()) 1122 suite.addTest(RegressionTestTicket10772()) 1123 suite.addTest(RegressionTestTicket11618()) 1124 1125 return suite
1126 1127 1128 test_suite = functionalSuite 1129 1130 1131 if __name__ == '__main__': 1132 unittest.main(defaultTest='test_suite') 1133