1# -- 2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/ 3# -- 4# This software comes with ABSOLUTELY NO WARRANTY. For details, see 5# the enclosed file COPYING for license information (GPL). If you 6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. 7# -- 8 9use strict; 10use warnings; 11use utf8; 12 13use vars (qw($Self)); 14 15$Kernel::OM->ObjectParamAdd( 16 'Kernel::System::UnitTest::Helper' => { 17 DisableAsyncCalls => 1, 18 }, 19); 20 21my $Selenium = $Kernel::OM->Get('Kernel::System::UnitTest::Selenium'); 22 23my $ElementReadOnly = sub { 24 my (%Param) = @_; 25 26 # Value is optional parameter. 27 for my $Needed (qw(UnitTestObject Element)) { 28 if ( !$Param{$Needed} ) { 29 $Kernel::OM->Get('Kernel::System::Log')->Log( 30 Priority => 'error', 31 Message => "Need $Needed!", 32 ); 33 return; 34 } 35 } 36 37 $Selenium->WaitFor( JavaScript => "return typeof(\$) === 'function' && \$('#$Param{Element}').length" ); 38 39 $Param{UnitTestObject}->Is( 40 $Selenium->execute_script( 41 "return \$('#$Param{Element}.ReadOnlyValue').length;" 42 ), 43 $Param{Value}, 44 "$Param{Element} read only ($Param{Value})", 45 ); 46}; 47 48my $ElementExists = sub { 49 my (%Param) = @_; 50 51 # Value is optional parameter. 52 for my $Needed (qw(UnitTestObject Element)) { 53 if ( !$Param{$Needed} ) { 54 $Kernel::OM->Get('Kernel::System::Log')->Log( 55 Priority => 'error', 56 Message => "Need $Needed!", 57 ); 58 return; 59 } 60 } 61 62 my $Length = $Selenium->execute_script( 63 "return \$('#$Param{Element}').length;" 64 ); 65 66 if ( $Param{Value} ) { 67 $Param{UnitTestObject}->True( 68 $Length, 69 "$Param{Element} exists", 70 ); 71 } 72 else { 73 $Param{UnitTestObject}->False( 74 $Length, 75 "$Param{Element} not exists", 76 ); 77 } 78}; 79 80$Selenium->RunTest( 81 sub { 82 my $Helper = $Kernel::OM->Get('Kernel::System::UnitTest::Helper'); 83 84 my $GroupObject = $Kernel::OM->Get('Kernel::System::Group'); 85 my $CalendarObject = $Kernel::OM->Get('Kernel::System::Calendar'); 86 my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket'); 87 88 my $RandomID = $Helper->GetRandomID(); 89 90 # Create test group. 91 my $GroupName = "test-calendar-group-$RandomID"; 92 my $GroupID = $GroupObject->GroupAdd( 93 Name => $GroupName, 94 ValidID => 1, 95 UserID => 1, 96 ); 97 98 # Create test group. 99 my $GroupName2 = "test-calendar-group2-$RandomID"; 100 my $GroupID2 = $GroupObject->GroupAdd( 101 Name => $GroupName2, 102 ValidID => 1, 103 UserID => 1, 104 ); 105 106 # Change resolution (desktop mode). 107 $Selenium->set_window_size( 768, 1050 ); 108 109 # Create test user. 110 my $Language = 'en'; 111 my $TestUserLogin = $Helper->TestUserCreate( 112 Groups => [ 'users', $GroupName ], 113 Language => $Language, 114 ) || die 'Did not get test user'; 115 116 # Get UserID. 117 my $UserID = $Kernel::OM->Get('Kernel::System::User')->UserLookup( 118 UserLogin => $TestUserLogin, 119 ); 120 121 my $TestUserLogin2 = $Helper->TestUserCreate( 122 Groups => [ 'users', $GroupName2 ], 123 Language => $Language, 124 ) || die 'Did not get test user'; 125 126 # Get UserID. 127 my $UserID2 = $Kernel::OM->Get('Kernel::System::User')->UserLookup( 128 UserLogin => $TestUserLogin2, 129 ); 130 131 # Create test customer user. 132 my $TestCustomerUserLogin = $Helper->TestCustomerUserCreate() 133 || die 'Did not get test customer user'; 134 135 # Create a few test calendars. 136 my %Calendar1 = $CalendarObject->CalendarCreate( 137 CalendarName => "Calendar1 $RandomID", 138 Color => '#3A87AD', 139 GroupID => $GroupID, 140 UserID => $UserID, 141 ValidID => 1, 142 ); 143 $Self->True( 144 $Calendar1{CalendarID}, 145 "Calendar1 $RandomID created successful.", 146 ); 147 148 my %Calendar2 = $CalendarObject->CalendarCreate( 149 CalendarName => "Calendar2 $RandomID", 150 Color => '#EC9073', 151 GroupID => $GroupID, 152 UserID => $UserID, 153 ValidID => 1, 154 ); 155 $Self->True( 156 $Calendar2{CalendarID}, 157 "Calendar2 $RandomID created successful.", 158 ); 159 160 my %Calendar3 = $CalendarObject->CalendarCreate( 161 CalendarName => "Calendar3 $RandomID", 162 Color => '#6BAD54', 163 GroupID => $GroupID, 164 UserID => $UserID, 165 ValidID => 1, 166 ); 167 $Self->True( 168 $Calendar3{CalendarID}, 169 "Calendar3 $RandomID created successful.", 170 ); 171 172 my %Calendar4 = $CalendarObject->CalendarCreate( 173 CalendarName => "Calendar4 $RandomID", 174 Color => '#78A7FC', 175 GroupID => $GroupID2, 176 UserID => $UserID2, 177 ValidID => 1, 178 ); 179 $Self->True( 180 $Calendar4{CalendarID}, 181 "Calendar4 $RandomID created successful.", 182 ); 183 184 # Create a test ticket. 185 my $TicketID = $TicketObject->TicketCreate( 186 Title => "Link Ticket $RandomID", 187 Queue => 'Raw', 188 Lock => 'unlock', 189 Priority => '3 normal', 190 State => 'open', 191 CustomerNo => '123465', 192 CustomerUser => 'customer@example.com', 193 OwnerID => $UserID, 194 UserID => $UserID, 195 ); 196 $Self->True( 197 $TicketID, 198 "TicketCreate() - $TicketID", 199 ); 200 my $TicketNumber = $TicketObject->TicketNumberLookup( 201 TicketID => $TicketID, 202 UserID => $UserID, 203 ); 204 $Self->True( 205 $TicketNumber, 206 "TicketNumberLookup() - $TicketNumber", 207 ); 208 209 $Selenium->Login( 210 Type => 'Agent', 211 User => $TestUserLogin, 212 Password => $TestUserLogin, 213 ); 214 215 my $ScriptAlias = $Kernel::OM->Get('Kernel::Config')->Get('ScriptAlias'); 216 217 # Go to calendar overview page. 218 $Selenium->VerifiedGet("${ScriptAlias}index.pl?Action=AgentAppointmentCalendarOverview"); 219 $Selenium->WaitFor( 220 JavaScript => 221 'return typeof($) === "function" && !$(".CalendarWidget.Loading").length && $(".fc-toolbar .fc-prev-button").length;' 222 ); 223 224 # Go to previous week. 225 $Selenium->find_element( '.fc-toolbar .fc-prev-button', 'css' )->click(); 226 $Selenium->WaitFor( 227 JavaScript => 228 'return typeof($) === "function" && !$(".CalendarWidget.Loading").length && $(".CalendarSwitch:visible").length == 3;' 229 ); 230 231 # Verify all three calendars are visible. 232 $Self->Is( 233 $Selenium->execute_script( 234 "return \$('.CalendarSwitch:visible').length;" 235 ), 236 3, 237 'All three calendars visible', 238 ); 239 240 # Verify copy-to-clipboard link. 241 my $URL = $Selenium->execute_script("return \$('.CopyToClipboard').attr('data-clipboard-text');"); 242 243 $Self->True( 244 $URL, 245 'CopyToClipboard URL present' 246 ); 247 248 # URL should not contain OTRS specific URL delimiter of semicolon (;). 249 # For better compatibility, use standard ampersand (&) instead. 250 # Please see bug#12667 for more information. 251 $Self->False( 252 ( $URL =~ /[;]/ ) ? 1 : 0, 253 'CopyToClipboard URL does not contain forbidden characters' 254 ); 255 256 # Click on the timeline view for an appointment dialog. 257 $Selenium->find_element( '.fc-timelineWeek-view .fc-slats td.fc-widget-content:nth-child(5)', 'css' )->click(); 258 $Selenium->WaitFor( JavaScript => "return typeof(\$) === 'function' && \$('#Title').length;" ); 259 260 # Elements that are not allowed in dialog. 261 for my $Element (qw(EditFormDelete EditFormCopy)) { 262 $ElementExists->( 263 UnitTestObject => $Self, 264 Element => $Element, 265 Value => 0, 266 ); 267 } 268 269 # Enter some data. 270 $Selenium->find_element( "#Title", 'css' )->send_keys('Appointment 1'); 271 $Selenium->find_element( "#Location", 'css' )->send_keys('Straubing'); 272 $Selenium->InputFieldValueSet( 273 Element => '#CalendarID', 274 Value => $Calendar1{CalendarID}, 275 ); 276 $Selenium->find_element( '#EndHour', 'css' )->send_keys('18'); 277 $Selenium->find_element( '.PluginField', 'css' )->send_keys($TicketNumber); 278 $Selenium->WaitFor( JavaScript => 'return typeof($) === "function" && $("li.ui-menu-item:visible").length;' ); 279 $Selenium->execute_script("\$('li.ui-menu-item:contains($TicketNumber)').click();"); 280 281 $Selenium->WaitFor( 282 JavaScript => 283 "return typeof(\$) === 'function' && \$('.PluginContainer div a[target=\"_blank\"]').length;" 284 ); 285 286 # Verify correct ticket is listed. 287 $Self->Is( 288 $Selenium->execute_script( 289 "return \$('.PluginContainer div a[target=\"_blank\"]').text();" 290 ), 291 "$TicketNumber Link Ticket $RandomID", 292 'Link ticket visible', 293 ); 294 295 # Check location link contains correct value. 296 my $LocationLinkURL = $Selenium->execute_script("return \$('.LocationLink').attr('href');"); 297 $Self->True( 298 $LocationLinkURL =~ /Straubing$/, 299 'Location link contains correct value', 300 ); 301 302 # Click on Save. 303 $Selenium->find_element( '#EditFormSubmit', 'css' )->click(); 304 $Selenium->WaitFor( 305 JavaScript => 306 'return typeof($) === "function" && !$(".Dialog:visible").length && !$(".CalendarWidget.Loading").length;' 307 ); 308 309 # Wait until all AJAX calls finished. 310 $Selenium->WaitFor( 311 JavaScript => "return \$.active == 0 && \$('.fc-timeline-event .fc-title').text() == 'Appointment 1';" 312 ); 313 314 # Verify first appointment is visible. 315 $Self->Is( 316 $Selenium->execute_script( 317 "return \$('.fc-timeline-event .fc-title').text();" 318 ), 319 'Appointment 1', 320 'First appointment visible', 321 ); 322 323 # Go to the ticket zoom screen. 324 $Selenium->VerifiedGet("${ScriptAlias}index.pl?Action=AgentTicketZoom;TicketID=${TicketID}"); 325 326 # Find link to the appointment on page. 327 $Selenium->WaitFor( JavaScript => "return \$('a.LinkObjectLink').length;" ); 328 $Selenium->execute_script( 329 "\$('.LinkObjectLink')[0].scrollIntoView(true);", 330 ); 331 $Selenium->execute_script('$("a.LinkObjectLink")[0].click();'); 332 $Selenium->WaitFor( 333 JavaScript => "return typeof(\$) === 'function' && \$('#Title').length && \$('#CalendarID').length;" 334 ); 335 336 $Self->Is( 337 $Selenium->execute_script( 338 "return \$('#Title').val();" 339 ), 340 'Appointment 1', 341 'Title matches', 342 ); 343 $Self->Is( 344 $Selenium->execute_script( 345 "return \$('#CalendarID').val();" 346 ), 347 $Calendar1{CalendarID}, 348 'Calendar matches', 349 ); 350 $Self->Is( 351 $Selenium->execute_script( 352 "return \$('.PluginContainer div a[href*=\"Action=AgentTicketZoom;TicketID=$TicketID\"]').text();" 353 ), 354 "$TicketNumber Link Ticket $RandomID", 355 'Link ticket matches', 356 ); 357 358 # Check location link contains correct value. 359 $LocationLinkURL = $Selenium->execute_script("return \$('.LocationLink').attr('href');"); 360 $Self->True( 361 $LocationLinkURL =~ /Straubing$/, 362 'Location link contains correct value', 363 ); 364 365 # Cancel the dialog. 366 $Selenium->find_element( '#EditFormCancel', 'css' )->click(); 367 $Selenium->WaitFor( 368 JavaScript => 369 'return typeof($) === "function" && !$(".Dialog:visible").length && !$(".CalendarWidget.Loading").length && $(".fc-toolbar .fc-prev-button").length;' 370 ); 371 372 # Go to previous week. 373 $Selenium->find_element( '.fc-toolbar .fc-prev-button', 'css' )->click(); 374 $Selenium->WaitFor( 375 JavaScript => 376 'return !$(".CalendarWidget.Loading").length && $(".fc-timelineWeek-view .fc-slats td.fc-widget-content:nth-child(5)").length;' 377 ); 378 379 # Click on the timeline view for another appointment dialog. 380 $Selenium->find_element( '.fc-timelineWeek-view .fc-slats td.fc-widget-content:nth-child(5)', 'css' )->click(); 381 $Selenium->WaitFor( 382 JavaScript => "return typeof(\$) === 'function' && \$('#Title').length && \$('#CalendarID').length;" 383 ); 384 385 # Enter some data. 386 $Selenium->find_element( 'Title', 'name' )->send_keys('Appointment 2'); 387 $Selenium->InputFieldValueSet( 388 Element => '#CalendarID', 389 Value => $Calendar2{CalendarID}, 390 ); 391 392 $Selenium->find_element( '#AllDay', 'css' )->click(); 393 $Selenium->WaitFor( JavaScript => 'return typeof($) === "function" && $("#AllDay").prop("checked") === true;' ); 394 395 # Click on Save. 396 $Selenium->find_element( '#EditFormSubmit', 'css' )->click(); 397 $Selenium->WaitFor( 398 JavaScript => 399 'return typeof($) === "function" && !$(".Dialog:visible").length && !$(".CalendarWidget.Loading").length;' 400 ); 401 $Selenium->WaitFor( 402 JavaScript => 403 'return $("#Calendar' . $Calendar1{CalendarID} . ':checked").length;' 404 ); 405 406 # Hide the first calendar from view. 407 $Selenium->execute_script("\$('#Calendar$Calendar1{CalendarID}').click();"); 408 $Selenium->WaitFor( 409 JavaScript => 'return typeof($) === "function" && $("#Calendar' 410 . $Calendar1{CalendarID} 411 . '").prop("checked") === false;' 412 ); 413 $Selenium->WaitFor( 414 JavaScript => 415 "return typeof(\$) === 'function' && \$('.fc-timeline-event .fc-title').text() === 'Appointment 2';" 416 ); 417 $Selenium->WaitFor( 418 JavaScript => 419 "return \$('.fc-timeline-event .fa-sun-o').length == 1;" 420 ); 421 422 # Verify second appointment is visible. 423 $Self->Is( 424 $Selenium->execute_script( 425 "return \$('.fc-timeline-event .fc-title').text();" 426 ), 427 'Appointment 2', 428 'Second appointment visible', 429 ); 430 431 # Verify second appointment is an all day appointment. 432 $Self->Is( 433 $Selenium->execute_script( 434 "return \$('.fc-timeline-event .fa-sun-o').length;" 435 ), 436 '1', 437 'Second appointment in an all day appointment', 438 ); 439 440 $Selenium->WaitFor( 441 JavaScript => 442 "return \$('.fc-timelineWeek-view .fc-slats td.fc-widget-content:nth-child(5)').length;" 443 ); 444 445 # Click again on the timeline view for an appointment dialog. 446 $Selenium->find_element( '.fc-timelineWeek-view .fc-slats td.fc-widget-content:nth-child(5)', 'css' )->click(); 447 $Selenium->WaitFor( 448 JavaScript => "return typeof(\$) === 'function' && \$('#Title').length && \$('#CalendarID').length;" 449 ); 450 451 # Enter some data. 452 $Selenium->find_element( 'Title', 'name' )->send_keys('Appointment 3'); 453 $Selenium->InputFieldValueSet( 454 Element => '#CalendarID', 455 Value => $Calendar3{CalendarID}, 456 ); 457 $Selenium->find_element( 'EndHour', 'name' )->send_keys('18'); 458 $Selenium->InputFieldValueSet( 459 Element => '#RecurrenceType', 460 Value => 'Daily', 461 ); 462 463 # Click on Save. 464 $Selenium->find_element( '#EditFormSubmit', 'css' )->click(); 465 $Selenium->WaitFor( 466 JavaScript => 467 'return typeof($) === "function" && !$(".Dialog:visible").length && !$(".CalendarWidget.Loading").length;' 468 ); 469 470 # Wait until all AJAX calls finished. 471 $Selenium->WaitFor( JavaScript => "return \$.active == 0;" ); 472 473 $Selenium->WaitFor( 474 JavaScript => 475 'return $("#Calendar' . $Calendar2{CalendarID} . ':checked").length;' 476 ); 477 478 # Hide the second calendar from view. 479 $Selenium->execute_script("\$('#Calendar$Calendar2{CalendarID}').click();"); 480 $Selenium->WaitFor( 481 JavaScript => 'return typeof($) === "function" && $("#Calendar' 482 . $Calendar2{CalendarID} 483 . '").prop("checked") === false;' 484 ); 485 486 # Verify all third appointment occurences are visible. 487 $Self->Is( 488 $Selenium->execute_script( 489 "return \$('.fc-timeline-event .fc-title').length;" 490 ), 491 '4', 492 'All third appointment occurrences visible', 493 ); 494 495 # Click on an appointment. 496 $Selenium->execute_script( 497 "\$('.fc-timeline-event:eq(0) .fc-title').trigger('click');" 498 ); 499 $Selenium->WaitFor( JavaScript => "return typeof(\$) === 'function' && \$('#EditFormDelete').length;" ); 500 501 # Click on Delete. 502 $Selenium->find_element( '#EditFormDelete', 'css' )->click(); 503 504 $Selenium->WaitFor( AlertPresent => 1 ); 505 $Selenium->accept_alert(); 506 507 # Wait for dialog to close and AJAX to finish. 508 $Selenium->WaitFor( 509 JavaScript => 510 'return typeof($) === "function" && !$(".Dialog:visible").length && !$(".fc-timeline-event .fc-title").length;' 511 ); 512 513 # Wait until all AJAX calls finished. 514 $Selenium->WaitFor( JavaScript => "return \$.active == 0;" ); 515 516 # Verify all third appointment occurences have been removed. 517 $Self->Is( 518 $Selenium->execute_script( 519 "return \$('.fc-timeline-event .fc-title').length;" 520 ), 521 '0', 522 'All third appointment occurrences removed', 523 ); 524 525 # Show all three calendars. 526 $Selenium->find_element( 'Calendar' . $Calendar1{CalendarID}, 'id' )->click(); 527 $Selenium->WaitFor( JavaScript => 'return typeof($) === "function" && !$(".CalendarWidget.Loading").length;' ); 528 $Selenium->find_element( 'Calendar' . $Calendar2{CalendarID}, 'id' )->click(); 529 $Selenium->WaitFor( JavaScript => 'return typeof($) === "function" && !$(".CalendarWidget.Loading").length;' ); 530 531 # Verify only two appointments are visible. 532 $Self->Is( 533 $Selenium->execute_script( 534 "return \$('.fc-timeline-event .fc-title').length;" 535 ), 536 '2', 537 'First and second appointment visible', 538 ); 539 540 # Open datepicker. 541 $Selenium->find_element( '.fc-toolbar .fc-jump-button', 'css' )->click(); 542 $Selenium->WaitFor( 543 JavaScript => 544 'return typeof($) === "function" && $("#Datepicker .ui-datepicker-calendar .Highlight").length === 1;' 545 ); 546 547 # Verify exactly one day with appointments is highlighted. 548 $Self->Is( 549 $Selenium->execute_script( 550 "return \$('.ui-datepicker .ui-datepicker-calendar .Highlight').length;" 551 ), 552 1, 553 'Datepicker properly highlighted', 554 ); 555 556 # Close datepicker. 557 $Selenium->find_element( 'div#DatepickerOverlay', 'css' )->click(); 558 $Selenium->WaitFor( JavaScript => 'return typeof($) === "function" && !$("#DatepickerOverlay").length;' ); 559 560 # Filter just third calendar. 561 $Selenium->find_element( 'input#FilterCalendars', 'css' )->send_keys('Calendar3'); 562 $Selenium->WaitFor( 563 JavaScript => 'return typeof($) === "function" && $(".CalendarSwitch:visible").length === 1;' 564 ); 565 566 # Verify only one calendar is shown in the list. 567 $Self->Is( 568 $Selenium->execute_script( 569 "return \$('.CalendarSwitch:visible').length;" 570 ), 571 1, 572 'Calendars are filtered correctly', 573 ); 574 575 # Create new Appointment (as root user). 576 my $StartTimeObject = $Kernel::OM->Create('Kernel::System::DateTime'); 577 $StartTimeObject->Subtract( 578 Weeks => 1, 579 ); 580 my $EndTimeObject = $StartTimeObject->Clone(); 581 $EndTimeObject->Add( 582 Hours => 2, 583 ); 584 585 my $AppointmentObject = $Kernel::OM->Get('Kernel::System::Calendar::Appointment'); 586 my $AppointmentID = $AppointmentObject->AppointmentCreate( 587 CalendarID => $Calendar4{CalendarID}, 588 Title => 'Permissions check appointment', 589 Description => 'How to use Process tickets...', 590 Location => 'Straubing', 591 StartTime => $StartTimeObject->ToString(), 592 EndTime => $EndTimeObject->ToString(), 593 UserID => $UserID, 594 TimezoneID => 0, 595 ); 596 597 $Self->True( 598 $AppointmentID, 599 'Permission Appointment created.', 600 ); 601 602 # Add ro permissions to the user. 603 $GroupObject->PermissionGroupUserAdd( 604 GID => $GroupID2, 605 UID => $UserID, 606 Permission => { 607 ro => 1, 608 }, 609 UserID => $UserID, 610 ); 611 612 # Reload page. 613 $Selenium->VerifiedGet("${ScriptAlias}index.pl?Action=AgentAppointmentCalendarOverview"); 614 $Selenium->WaitFor( JavaScript => 'return typeof($) === "function" && !$(".CalendarWidget.Loading").length;' ); 615 616 # Show the fourth calendar and hide all others. 617 $Selenium->execute_script("\$('#Calendar$Calendar4{CalendarID}').click();"); 618 $Selenium->WaitFor( 619 JavaScript => 'return typeof($) === "function" && $("#Calendar' 620 . $Calendar4{CalendarID} 621 . '").prop("checked") === true;' 622 ); 623 $Self->True( 624 $Selenium->execute_script( 625 'return $("#Calendar' . $Calendar4{CalendarID} . '").prop("checked") === true;' 626 ), 627 "CalendarID $Calendar4{CalendarID} - checked", 628 ); 629 630 $Selenium->execute_script("\$('#Calendar$Calendar1{CalendarID}').click();"); 631 $Selenium->WaitFor( 632 JavaScript => 'return typeof($) === "function" && $("#Calendar' 633 . $Calendar1{CalendarID} 634 . '").prop("checked") === false;' 635 ); 636 $Self->True( 637 $Selenium->execute_script( 638 'return $("#Calendar' . $Calendar1{CalendarID} . '").prop("checked") === false;' 639 ), 640 "CalendarID $Calendar1{CalendarID} - unchecked", 641 ); 642 643 $Selenium->execute_script("\$('#Calendar$Calendar2{CalendarID}').click();"); 644 $Selenium->WaitFor( 645 JavaScript => 'return typeof($) === "function" && $("#Calendar' 646 . $Calendar2{CalendarID} 647 . '").prop("checked") === false;' 648 ); 649 $Self->True( 650 $Selenium->execute_script( 651 'return $("#Calendar' . $Calendar2{CalendarID} . '").prop("checked") === false;' 652 ), 653 "CalendarID $Calendar2{CalendarID} - unchecked", 654 ); 655 656 $Selenium->execute_script("\$('#Calendar$Calendar3{CalendarID}').click();"); 657 $Selenium->WaitFor( 658 JavaScript => 'return typeof($) === "function" && $("#Calendar' 659 . $Calendar3{CalendarID} 660 . '").prop("checked") === false;' 661 ); 662 $Self->True( 663 $Selenium->execute_script( 664 'return $("#Calendar' . $Calendar3{CalendarID} . '").prop("checked") === false;' 665 ), 666 "CalendarID $Calendar3{CalendarID} - unchecked", 667 ); 668 669 $Selenium->WaitFor( JavaScript => 'return $(".fc-toolbar .fc-prev-button").length;' ); 670 671 # Go to previous week. 672 $Selenium->find_element( '.fc-toolbar .fc-prev-button', 'css' )->click(); 673 $Selenium->WaitFor( 674 JavaScript => 675 'return typeof($) === "function" && !$(".CalendarWidget.Loading").length && $(".fc-event-container a").length;' 676 ); 677 678 # Find the appointment link. 679 my $AppointmentLink = $Selenium->find_element( '.fc-event-container a', 'css' ); 680 681 # Click on appointment. 682 $AppointmentLink->click(); 683 $Selenium->WaitFor( JavaScript => "return typeof(\$) === 'function' && \$('#Title').length;" ); 684 685 my $TeamObjectRegistered 686 = $Kernel::OM->Get('Kernel::System::Main')->Require( 'Kernel::System::Calendar::Team', Silent => 1 ); 687 688 # Check if fields are disabled. 689 ELEMENT: 690 for my $Element ( 691 qw(Title Description Location CalendarID TeamID ResourceID StartDay EndDay AllDay 692 RecurrenceType 693 ) 694 ) 695 { 696 # Check if team object is registered. 697 if ( !$TeamObjectRegistered ) { 698 next ELEMENT if $Element eq 'TeamID' || $Element eq 'ResourceID'; 699 } 700 701 $ElementReadOnly->( 702 UnitTestObject => $Self, 703 Element => $Element, 704 Value => 1, 705 ); 706 } 707 708 # Elements that are not allowed on page. 709 for my $Element (qw(EditFormSubmit EditFormDelete EditFormCopy)) { 710 $ElementExists->( 711 UnitTestObject => $Self, 712 Element => $Element, 713 Value => 0, 714 ); 715 } 716 717 # Elements that should be on page. 718 for my $Element (qw(EditFormCancel)) { 719 $Selenium->WaitFor( 720 JavaScript => 721 "return typeof(\$) === 'function' && \$('#$Element').length;" 722 ); 723 $ElementExists->( 724 UnitTestObject => $Self, 725 Element => $Element, 726 Value => 1, 727 ); 728 } 729 730 # Click on cancel. 731 $Selenium->find_element( '#EditFormCancel', 'css' )->click(); 732 $Selenium->WaitFor( 733 JavaScript => 734 'return typeof($) === "function" && !$(".Dialog:visible").length && !$(".CalendarWidget.Loading").length;' 735 ); 736 737 # Add move_into permissions to the user. 738 $GroupObject->PermissionGroupUserAdd( 739 GID => $GroupID2, 740 UID => $UserID, 741 Permission => { 742 ro => 1, 743 move_into => 1, 744 }, 745 UserID => $UserID, 746 ); 747 748 # Click on appointment. 749 $AppointmentLink->click(); 750 $Selenium->WaitFor( JavaScript => "return typeof(\$) === 'function' && \$('#Title').length;" ); 751 752 # Check if fields are disabled. 753 for my $Element (qw( CalendarID )) { 754 $ElementReadOnly->( 755 UnitTestObject => $Self, 756 Element => $Element, 757 Value => 1, 758 ); 759 } 760 761 # Check if fields are enabled. 762 ELEMENT: 763 for my $Element ( 764 qw(Title Description Location TeamID ResourceID StartDay EndDay AllDay RecurrenceType) 765 ) 766 { 767 # Check if team object is registered. 768 if ( !$TeamObjectRegistered ) { 769 next ELEMENT if $Element eq 'TeamID' || $Element eq 'ResourceID'; 770 } 771 772 $ElementReadOnly->( 773 UnitTestObject => $Self, 774 Element => $Element, 775 Value => 0, 776 ); 777 } 778 779 # Elements that are not allowed on page. 780 for my $Element (qw(EditFormDelete EditFormCopy)) { 781 $ElementExists->( 782 UnitTestObject => $Self, 783 Element => $Element, 784 Value => 0, 785 ); 786 } 787 788 # Elements that should be on page. 789 for my $Element (qw(EditFormSubmit EditFormCancel)) { 790 $Selenium->WaitFor( 791 JavaScript => 792 "return typeof(\$) === 'function' && \$('#$Element').length;" 793 ); 794 $ElementExists->( 795 UnitTestObject => $Self, 796 Element => $Element, 797 Value => 1, 798 ); 799 } 800 801 # Click on cancel. 802 $Selenium->find_element( '#EditFormCancel', 'css' )->click(); 803 $Selenium->WaitFor( 804 JavaScript => 805 'return typeof($) === "function" && !$(".Dialog:visible").length && !$(".CalendarWidget.Loading").length;' 806 ); 807 808 # Add create permissions to the user. 809 $GroupObject->PermissionGroupUserAdd( 810 GID => $GroupID2, 811 UID => $UserID, 812 Permission => { 813 ro => 1, 814 move_into => 1, 815 create => 1, 816 }, 817 UserID => $UserID, 818 ); 819 820 # Click on appointment. 821 $AppointmentLink->click(); 822 $Selenium->WaitFor( JavaScript => "return typeof(\$) === 'function' && \$('#Title').length;" ); 823 824 # Check if fields are enabled. 825 ELEMENT: 826 for my $Element ( 827 qw(Title Description Location CalendarID TeamID ResourceID StartDay EndDay AllDay 828 RecurrenceType 829 ) 830 ) 831 { 832 # Check if team object is registered. 833 if ( !$TeamObjectRegistered ) { 834 next ELEMENT if $Element eq 'TeamID' || $Element eq 'ResourceID'; 835 } 836 837 $ElementReadOnly->( 838 UnitTestObject => $Self, 839 Element => $Element, 840 Value => 0, 841 ); 842 } 843 844 # Elements that should be on page. 845 for my $Element (qw(EditFormCopy EditFormSubmit EditFormDelete EditFormCancel)) { 846 $Selenium->WaitFor( 847 JavaScript => 848 "return typeof(\$) === 'function' && \$('#$Element').length;" 849 ); 850 $ElementExists->( 851 UnitTestObject => $Self, 852 Element => $Element, 853 Value => 1, 854 ); 855 } 856 857 # Click on cancel. 858 $Selenium->find_element( '.Close', 'css' )->click(); 859 $Selenium->WaitFor( 860 JavaScript => 861 'return typeof($) === "function" && !$(".Dialog:visible").length;' 862 ); 863 864 $Selenium->find_element( '.fc-agendaWeek-button', 'css' )->click(); 865 866 # Go to other screen to check if selected Timeline will be saved on return to Calendar overview. 867 # See bug#14629 - https://bugs.otrs.org/show_bug.cgi?id=14629. 868 $Selenium->VerifiedGet("${ScriptAlias}index.pl?Action=AgentTicketZoom;TicketID=${TicketID}"); 869 $Selenium->VerifiedGet("${ScriptAlias}index.pl?Action=AgentAppointmentCalendarOverview"); 870 871 $Self->Is( 872 $Selenium->execute_script( 873 "return \$('.fc-agendaWeek-button').hasClass('fc-state-active');" 874 ), 875 "1", 876 "Timeline is correctly selected after page reload" 877 ); 878 879 # 880 # Cleanup 881 # 882 883 my $SchedulerDBObject = $Kernel::OM->Get('Kernel::System::Daemon::SchedulerDB'); 884 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 885 886 # Delete appointments and calendars. 887 for my $CalendarID ( 888 $Calendar1{CalendarID}, 889 $Calendar2{CalendarID}, 890 $Calendar3{CalendarID}, 891 $Calendar4{CalendarID}, 892 ) 893 { 894 my @Appointments = $AppointmentObject->AppointmentList( 895 CalendarID => $CalendarID, 896 Result => 'ARRAY', 897 ); 898 for my $AppointmentID (@Appointments) { 899 $AppointmentObject->AppointmentDelete( 900 AppointmentID => $AppointmentID, 901 UserID => $UserID, 902 ); 903 } 904 905 # Delete test calendars. 906 my $Success = $DBObject->Do( 907 SQL => "DELETE FROM calendar WHERE id = $CalendarID", 908 ); 909 $Self->True( 910 $Success, 911 "Deleted test calendar - $CalendarID", 912 ); 913 } 914 915 # Delete test ticket. 916 my $Success = $TicketObject->TicketDelete( 917 TicketID => $TicketID, 918 UserID => $UserID, 919 ); 920 921 # Ticket deletion could fail if apache still writes to ticket history. Try again in this case. 922 if ( !$Success ) { 923 sleep 3; 924 $Success = $TicketObject->TicketDelete( 925 TicketID => $TicketID, 926 UserID => $UserID, 927 ); 928 } 929 $Self->True( 930 $Success, 931 "Deleted test ticket - $TicketID", 932 ); 933 934 # Remove scheduled asynchronous tasks from DB, as they may interfere with tests run later. 935 my @TaskIDs; 936 my @AllTasks = $SchedulerDBObject->TaskList( 937 Type => 'AsynchronousExecutor', 938 ); 939 for my $Task (@AllTasks) { 940 if ( $Task->{Name} eq 'Kernel::System::Calendar-TicketAppointmentProcessTicket()' ) { 941 push @TaskIDs, $Task->{TaskID}; 942 } 943 } 944 for my $TaskID (@TaskIDs) { 945 my $Success = $SchedulerDBObject->TaskDelete( 946 TaskID => $TaskID, 947 ); 948 $Self->True( 949 $Success, 950 "TaskDelete - Removed scheduled asynchronous task $TaskID", 951 ); 952 } 953 954 # Delete group-user relations. 955 $Success = $DBObject->Do( 956 SQL => "DELETE FROM group_user WHERE group_id = $GroupID OR group_id = $GroupID2", 957 ); 958 if ($Success) { 959 $Self->True( 960 $Success, 961 "GroupUserDelete - $RandomID", 962 ); 963 } 964 965 # Delete groups. 966 $Success = $DBObject->Do( 967 SQL => "DELETE FROM groups WHERE id = $GroupID OR id = $GroupID2", 968 ); 969 $Self->True( 970 $Success, 971 "GroupDelete - $RandomID", 972 ); 973 974 my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache'); 975 976 # Make sure cache is correct. 977 for my $Cache (qw(Appointment Calendar Group Ticket)) { 978 $CacheObject->CleanUp( Type => $Cache ); 979 } 980 }, 981); 982 9831; 984