1
2
3
4
5
6
7
8
9
10
11
12
13
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
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
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
53
54
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
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
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
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
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
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
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
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
166
167
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
178 """Admin create milestone with a space"""
179 self._tester.create_milestone('Milestone 1')
180
181
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
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&' \
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&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
231
232
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
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
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
274 self._tester.go_to_roadmap()
275 tc.find(name)
276
277
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
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
317
318
321 """Admin modify milestone duedate on detail page"""
322 name = "DetailDueMilestone"
323
324 self._tester.create_milestone(name)
325
326
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
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
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
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
402 self._tester.go_to_roadmap()
403 tc.find(name)
404
405
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
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
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
461 """Admin set default ticket milestone, default retarget milestone
462 and clear defaults."""
463 def clear_defaults():
464
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
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
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
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
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
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
525 tc.go(self._tester.url + '/newticket')
526 tc.find('<option selected="selected" value="%s">%s</option>'
527 % (mid1, mid1))
528
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
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
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
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
558
559
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
575
576
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
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
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
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
642
643
646 """Admin modify priority details"""
647 name = "DetailPriority"
648
649 self._tester.create_priority(name + '1')
650
651
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
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
669 tc.notfind(name + '1')
670 tc.find(name + '2')
671 tc.notfind(name + '3')
672
673
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
696 tc.find(name + '2.*' + name + '1', 's')
697
698
701 """Admin badly renumber priorities"""
702
703
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
717
718
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
734
735
741
742
747
748
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
764
765
771
772
775 """Admin create type"""
776 self._tester.create_type()
777
778
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
794
795
801
802
807
808
811 """Check permissions required to access the Versions panel."""
812 self.test_authorization('/admin/ticket/versions', 'TICKET_ADMIN',
813 "Manage Versions")
814
815
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
831
832
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
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
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
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
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
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
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
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
947 tc.go(self._tester.url + '/newticket')
948 tc.find('<option selected="selected" value="%s">%s</option>'
949 % (name, name))
950
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
962 """Admin create version without release time (r5665)"""
963 self._tester.create_version(releasetime='')
964
965
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&'
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&'
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
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
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
1126
1127
1128 test_suite = functionalSuite
1129
1130
1131 if __name__ == '__main__':
1132 unittest.main(defaultTest='test_suite')
1133