|
Lines 676-715
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 676 |
|
676 |
|
| 677 |
it("should handle lead and trail period behavior correctly", () => { |
677 |
it("should handle lead and trail period behavior correctly", () => { |
| 678 |
/** |
678 |
/** |
| 679 |
* Lead and Trail Period Behavior Tests |
679 |
* Lead and Trail Period Behavior Tests (with Bidirectional Enhancement) |
| 680 |
* ==================================== |
680 |
* ==================================================================== |
| 681 |
* |
681 |
* |
| 682 |
* Validates that bookings lead and trail periods work correctly with hover |
682 |
* Validates that bookings lead and trail periods work correctly with hover |
| 683 |
* effects and click prevention to avoid conflicts with existing bookings. |
683 |
* effects and click prevention to avoid conflicts with existing bookings. |
| 684 |
* |
684 |
* |
|
|
685 |
* CRITICAL ENHANCEMENT: Bidirectional Lead/Trail Period Checking |
| 686 |
* ============================================================= |
| 687 |
* This test validates that lead/trail periods work in BOTH directions: |
| 688 |
* - New booking's LEAD period must not conflict with existing booking's TRAIL period |
| 689 |
* - New booking's TRAIL period must not conflict with existing booking's LEAD period |
| 690 |
* - This ensures full "protected periods" around existing bookings are respected |
| 691 |
* |
| 685 |
* Test Coverage: |
692 |
* Test Coverage: |
| 686 |
* 1. Lead period visual hints (hover CSS classes) when selecting start dates |
693 |
* 1. Lead period visual hints (hover CSS classes) when selecting start dates |
| 687 |
* 2. Lead period click prevention when it would conflict with existing bookings |
694 |
* 2A. Lead period conflicts with existing booking ACTUAL dates (original) |
| 688 |
* 3. Lead period click prevention when it would extend into past dates |
695 |
* 2B. Lead period conflicts with existing booking TRAIL periods (NEW bidirectional) |
| 689 |
* 4. Trail period visual hints (hover CSS classes) when selecting end dates |
696 |
* 3. Lead period clear - no conflicts |
| 690 |
* 5. Trail period click prevention when it would conflict with existing bookings |
697 |
* 4. Trail period does NOT incorrectly limit max date when no conflicts exist (BUG FIX) |
| 691 |
* 6. Trail period does NOT incorrectly limit max date when no conflicts exist (BUG FIX) |
698 |
* 5. Trail period visual hints (hover CSS classes) when selecting end dates |
| 692 |
* 7. Bookings can reach full max date when trail period is clear |
699 |
* 6A. Trail period conflicts with existing booking ACTUAL dates (original) |
|
|
700 |
* 6B. Trail period conflicts with existing booking LEAD periods (NEW bidirectional) |
| 701 |
* 7. Valid booking range can be selected respecting all constraints |
| 693 |
* |
702 |
* |
| 694 |
* LEAD PERIOD EXPLANATION: |
703 |
* LEAD PERIOD EXPLANATION: |
| 695 |
* ======================= |
704 |
* ======================= |
| 696 |
* Lead period is a number of days prepended to a new booking to give librarians |
705 |
* Lead period is a number of days prepended to a new booking to give librarians |
| 697 |
* time to prepare the item for collection (e.g. find it on shelf, prepare it). |
706 |
* time to prepare the item for collection (e.g. find it on shelf, prepare it). |
| 698 |
* On hover, CSS classes show the lead period days. If lead period would conflict |
707 |
* On hover, CSS classes show the lead period days. If lead period would conflict |
| 699 |
* with an existing booking or past date, the date gets 'leadDisable' class and |
708 |
* with an existing booking (actual dates OR trail period), the date gets 'leadDisable' |
| 700 |
* clicking is prevented. |
709 |
* class and clicking is prevented. |
| 701 |
* |
710 |
* |
| 702 |
* TRAIL PERIOD EXPLANATION: |
711 |
* TRAIL PERIOD EXPLANATION: |
| 703 |
* ======================== |
712 |
* ======================== |
| 704 |
* Trail period is a number of days appended to the end of a booking to allow |
713 |
* Trail period is a number of days appended to the end of a booking to allow |
| 705 |
* librarians time to process the item after return (e.g. account for late return, |
714 |
* librarians time to process the item after return (e.g. account for late return, |
| 706 |
* assess damage, clean). On hover, CSS classes show the trail period days. If |
715 |
* assess damage, clean). On hover, CSS classes show the trail period days. If |
| 707 |
* trail period would conflict with an existing booking, the date gets 'trailDisable' |
716 |
* trail period would conflict with an existing booking (actual dates OR lead period), |
| 708 |
* class and clicking is prevented. |
717 |
* the date gets 'trailDisable' class and clicking is prevented. |
| 709 |
* |
718 |
* |
| 710 |
* The trail period should ONLY prevent selection when it conflicts with an existing |
719 |
* The trail period should ONLY prevent selection when it conflicts with an existing |
| 711 |
* booking. It should NOT subtract from the max date allowed by circulation rules. |
720 |
* booking. It should NOT subtract from the max date allowed by circulation rules. |
| 712 |
* |
721 |
* |
|
|
722 |
* PROTECTED PERIOD CONCEPT: |
| 723 |
* ======================== |
| 724 |
* Each existing booking has a "protected period" = Lead + Actual + Trail |
| 725 |
* New bookings must ensure their Lead + Actual + Trail does not overlap |
| 726 |
* with ANY part of existing bookings' protected periods. |
| 727 |
* |
| 713 |
* Implementation Details: |
728 |
* Implementation Details: |
| 714 |
* ====================== |
729 |
* ====================== |
| 715 |
* - Hover shows lead/trail with CSS classes: leadRange, leadRangeStart, leadRangeEnd, |
730 |
* - Hover shows lead/trail with CSS classes: leadRange, leadRangeStart, leadRangeEnd, |
|
Lines 728-761
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 728 |
* - Renewal period: 7 days each |
743 |
* - Renewal period: 7 days each |
| 729 |
* - Max period: 14 + (2 × 7) = 28 days |
744 |
* - Max period: 14 + (2 × 7) = 28 days |
| 730 |
* |
745 |
* |
| 731 |
* Timeline with Existing Bookings: |
746 |
* Timeline with Existing Bookings and Protected Periods: |
| 732 |
* ================================================================ |
747 |
* ====================================================================== |
| 733 |
* Day: 5 6 7 8 9 10 11 12 ... 37 38 39 40 41 42 43 44 45 46 |
748 |
* Day: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ... 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
| 734 |
* Booking A: [===] O O O O O ... O O O O O O O O [====== |
|
|
| 735 |
* ↑ ↑ |
| 736 |
* Conflict zone Conflict zone |
| 737 |
* for lead period for trail period |
| 738 |
* |
749 |
* |
| 739 |
* Booking A: Days 5-7 (tests lead period conflict) |
750 |
* Booking A (Days 20-25): |
| 740 |
* Booking B: Days 45-50 (tests trail period conflict) |
751 |
* Lead: L L |
|
|
752 |
* Actual: [===================] |
| 753 |
* Trail: T T T |
| 754 |
* Protected: L L [===================] T T T |
| 755 |
* 18 19 20 21 22 23 24 25 26 27 28 |
| 741 |
* |
756 |
* |
| 742 |
* Clear booking window: Days 10-38 |
757 |
* Booking B (Days 60-65): |
| 743 |
* - Start Day 10: Lead period Days 8-9 (clear) |
758 |
* Lead: L L |
| 744 |
* - End Day 38: Trail period Days 39-41 (clear, max date test) |
759 |
* Actual: [===================] |
| 745 |
* - End Day 42: Trail period Days 43-45 (conflicts with Booking B at Day 45) |
760 |
* Trail: T T T |
|
|
761 |
* Protected: L L [===================] T T T |
| 762 |
* 58 59 60 61 62 63 64 65 66 67 68 |
| 746 |
* |
763 |
* |
| 747 |
* Expected Behaviors: |
764 |
* Test Zones: |
| 748 |
* - Hovering Day 8 for start: leadRange classes show Days 6-7, leadDisable due to Booking A |
765 |
* =========== |
| 749 |
* - Hovering Day 9 for start: leadRange classes show Days 7-8, leadDisable due to Booking A |
766 |
* - Day 15: Clear start (lead Days 13-14, well before Booking A) |
| 750 |
* - Hovering Day 10 for start: leadRange classes show Days 8-9, no leadDisable (clear) |
767 |
* - Days 22-26: Lead conflicts with Booking A ACTUAL dates (original behavior) |
| 751 |
* - With start Day 10, max end should be Day 38 (10 + 28) |
768 |
* - Days 27-30: Lead conflicts with Booking A TRAIL period (NEW bidirectional) |
| 752 |
* - Hovering Day 38 for end: trailRange classes show Days 39-41, no trailDisable (clear) |
769 |
* - Day 31: Clear start (lead Days 29-30, after Booking A trail ends Day 28) |
| 753 |
* - Hovering Day 42 for end: trailRange classes show Days 43-45, trailDisable due to Booking B |
770 |
* - Day 45: Clear end from Day 31 (trail Days 46-48, before Booking B lead starts Day 58) |
| 754 |
* - Day 38 must be selectable (full max period, trail doesn't reduce it) |
771 |
* - Days 55-56: Trail conflicts with Booking B LEAD period (NEW bidirectional) |
|
|
772 |
* - Days 58-59: Trail conflicts with Booking B ACTUAL dates (original behavior) |
| 773 |
* - Day 54: Clear end from Day 31 (trail Days 55-57, just before Booking B lead Day 58) |
| 774 |
* |
| 775 |
* Expected Behaviors - Original: |
| 776 |
* ============================== |
| 777 |
* - Days 22, 24, 26: leadDisable (lead overlaps Booking A actual) |
| 778 |
* - Days 58, 59: trailDisable (trail overlaps Booking B actual) |
| 779 |
* |
| 780 |
* Expected Behaviors - NEW Bidirectional: |
| 781 |
* ======================================= |
| 782 |
* - Days 27, 28, 29, 30: leadDisable (lead overlaps Booking A TRAIL Days 26-28) |
| 783 |
* - Days 55, 56: trailDisable (trail overlaps Booking B LEAD Days 58-59) |
| 784 |
* |
| 785 |
* Valid Booking Window: |
| 786 |
* ==================== |
| 787 |
* - Start Day 31, End Day 54 |
| 788 |
* - New booking lead Days 29-30: Clear of Booking A trail (ends Day 28) ✓ |
| 789 |
* - New booking trail Days 55-57: Clear of Booking B lead (starts Day 58) ✓ |
| 755 |
*/ |
790 |
*/ |
| 756 |
|
791 |
|
| 757 |
const today = dayjs().startOf("day"); |
792 |
const today = dayjs().startOf("day"); |
| 758 |
|
793 |
|
|
|
794 |
/* |
| 795 |
* CROSS-MONTH BOUNDARY TESTING: |
| 796 |
* ============================= |
| 797 |
* This test IMPLICITLY tests the critical cross-month boundary scenario |
| 798 |
* that was fixed in the implementation. |
| 799 |
* |
| 800 |
* How it works: |
| 801 |
* - Booking A is at Days 20-25 (trail Days 26-28) |
| 802 |
* - Test dates for conflicts are Days 27-30 |
| 803 |
* - Booking B is at Days 60-65 (lead Days 58-59) |
| 804 |
* - Test dates span ~68 days from today |
| 805 |
* |
| 806 |
* With this spread, depending on when the test runs (which day of month |
| 807 |
* "today" is), the bookings and test dates will span across multiple |
| 808 |
* calendar months. When the user navigates flatpickr to February to |
| 809 |
* select a date, Booking A's trail period (in late January) may not be |
| 810 |
* visible in the DOM. |
| 811 |
* |
| 812 |
* The mathematical checks we implemented handle this by: |
| 813 |
* 1. Calculating date range overlaps mathematically (lines 1025-1078 in place_booking.js) |
| 814 |
* 2. Setting leadDisable/trailDisable flags based on math, not just DOM classes |
| 815 |
* 3. Visual classes (existingBookingTrail/Lead) are added as UX enhancement |
| 816 |
* |
| 817 |
* Therefore, these tests validate that conflicts are detected even when |
| 818 |
* the conflicting booking's protected period is not rendered in the |
| 819 |
* current calendar view - exactly the bug that was fixed. |
| 820 |
* |
| 821 |
* No additional test case needed - the mathematical approach guarantees |
| 822 |
* boundary detection regardless of calendar pagination state. |
| 823 |
*/ |
| 824 |
|
| 759 |
// Set up circulation rules with lead and trail periods |
825 |
// Set up circulation rules with lead and trail periods |
| 760 |
const leadTrailCirculationRules = { |
826 |
const leadTrailCirculationRules = { |
| 761 |
bookings_lead_period: 2, // 2 days before start |
827 |
bookings_lead_period: 2, // 2 days before start |
|
Lines 775-792
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 775 |
}).as("getLeadTrailRules"); |
841 |
}).as("getLeadTrailRules"); |
| 776 |
|
842 |
|
| 777 |
// Create existing bookings to test conflict detection |
843 |
// Create existing bookings to test conflict detection |
|
|
844 |
// IMPORTANT: Existing bookings also have lead/trail periods that must be respected |
| 778 |
const conflictBookings = [ |
845 |
const conflictBookings = [ |
| 779 |
{ |
846 |
{ |
| 780 |
name: "Booking A (lead conflict test)", |
847 |
name: "Booking A (bidirectional lead/trail conflict test)", |
| 781 |
start: today.add(5, "day"), |
848 |
start: today.add(20, "day"), // Changed from Day 5 to Day 20 for clearer testing |
| 782 |
end: today.add(7, "day"), |
849 |
end: today.add(25, "day"), // Changed from Day 7 to Day 25 |
| 783 |
item_id: testData.items[0].item_id, |
850 |
item_id: testData.items[0].item_id, |
|
|
851 |
// Booking A protected period calculation: |
| 852 |
// - Lead: Days 18-19 (2 days before start Day 20) |
| 853 |
// - Actual: Days 20-25 |
| 854 |
// - Trail: Days 26-28 (3 days after end Day 25) |
| 855 |
// - Total protected: Days 18-28 |
| 784 |
}, |
856 |
}, |
| 785 |
{ |
857 |
{ |
| 786 |
name: "Booking B (trail conflict test)", |
858 |
name: "Booking B (trail conflict test)", |
| 787 |
start: today.add(45, "day"), |
859 |
start: today.add(60, "day"), // Moved further out |
| 788 |
end: today.add(50, "day"), |
860 |
end: today.add(65, "day"), |
| 789 |
item_id: testData.items[0].item_id, |
861 |
item_id: testData.items[0].item_id, |
|
|
862 |
// Booking B protected period: |
| 863 |
// - Lead: Days 58-59 |
| 864 |
// - Actual: Days 60-65 |
| 865 |
// - Trail: Days 66-68 |
| 866 |
// - Total protected: Days 58-68 |
| 790 |
}, |
867 |
}, |
| 791 |
]; |
868 |
]; |
| 792 |
|
869 |
|
|
Lines 827-840
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 827 |
* - Hovering over a potential start date should show lead period with CSS classes |
904 |
* - Hovering over a potential start date should show lead period with CSS classes |
| 828 |
* - Classes: leadRangeStart, leadRange, leadRangeEnd |
905 |
* - Classes: leadRangeStart, leadRange, leadRangeEnd |
| 829 |
* - This provides visual feedback to users about preparation days |
906 |
* - This provides visual feedback to users about preparation days |
|
|
907 |
* - Using Day 15 which is well before Booking A (Days 18-28 protected) |
| 830 |
*/ |
908 |
*/ |
| 831 |
|
909 |
|
| 832 |
const clearStartDate = today.add(10, "day"); |
910 |
const clearStartDate = today.add(15, "day"); |
| 833 |
const leadStart = clearStartDate.subtract( |
911 |
const leadStart = clearStartDate.subtract( |
| 834 |
leadTrailCirculationRules.bookings_lead_period, |
912 |
leadTrailCirculationRules.bookings_lead_period, |
| 835 |
"day" |
913 |
"day" |
| 836 |
); // Day 8 |
914 |
); // Day 13 |
| 837 |
const leadEnd = clearStartDate.subtract(1, "day"); // Day 9 |
915 |
const leadEnd = clearStartDate.subtract(1, "day"); // Day 14 |
| 838 |
|
916 |
|
| 839 |
cy.log( |
917 |
cy.log( |
| 840 |
`Hovering ${clearStartDate.format("YYYY-MM-DD")} to check lead period visual hints` |
918 |
`Hovering ${clearStartDate.format("YYYY-MM-DD")} to check lead period visual hints` |
|
Lines 879-912
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 879 |
} |
957 |
} |
| 880 |
|
958 |
|
| 881 |
// ======================================================================== |
959 |
// ======================================================================== |
| 882 |
// TEST 2: Lead Period Conflict Prevention with Existing Booking |
960 |
// TEST 2A: Lead Period Conflict with Existing Booking ACTUAL Dates |
| 883 |
// ======================================================================== |
961 |
// ======================================================================== |
| 884 |
cy.log( |
962 |
cy.log( |
| 885 |
"=== TEST 2: Testing lead period prevents selection due to booking conflict ===" |
963 |
"=== TEST 2A: Testing new booking lead period conflicts with existing booking actual dates ===" |
| 886 |
); |
964 |
); |
| 887 |
|
965 |
|
| 888 |
/* |
966 |
/* |
| 889 |
* Lead Period Conflict Test: |
967 |
* Original Conflict Scenario: |
| 890 |
* - Booking A occupies Days 5-7 |
968 |
* Booking A actual dates: Days 20-25 |
| 891 |
* - Hovering Day 8 or 9 as start would require lead period overlapping Booking A |
969 |
* |
| 892 |
* - These dates should get 'leadDisable' class |
970 |
* Test start dates where NEW booking's lead overlaps with Booking A ACTUAL dates: |
| 893 |
* - Clicking should be prevented |
971 |
* - Day 22: Lead Days 20-21 → overlap with Booking A actual Days 20-25 → DISABLED |
|
|
972 |
* - Day 24: Lead Days 22-23 → overlap with Booking A actual Days 20-25 → DISABLED |
| 973 |
* - Day 26: Lead Days 24-25 → overlap with Booking A actual Day 25 → DISABLED |
| 894 |
*/ |
974 |
*/ |
| 895 |
|
975 |
|
| 896 |
const conflictStartDates = [ |
976 |
const actualDateConflicts = [ |
|
|
977 |
{ |
| 978 |
date: today.add(22, "day"), |
| 979 |
leadDays: "20-21", |
| 980 |
reason: "lead Days 20-21 overlap with Booking A actual dates Days 20-25", |
| 981 |
}, |
| 897 |
{ |
982 |
{ |
| 898 |
date: today.add(8, "day"), |
983 |
date: today.add(24, "day"), |
| 899 |
leadDays: "6-7", |
984 |
leadDays: "22-23", |
| 900 |
reason: "lead period Days 6-7 overlap with Booking A", |
985 |
reason: "lead Days 22-23 overlap with Booking A actual dates Days 20-25", |
| 901 |
}, |
986 |
}, |
| 902 |
{ |
987 |
{ |
| 903 |
date: today.add(9, "day"), |
988 |
date: today.add(26, "day"), |
| 904 |
leadDays: "7-8", |
989 |
leadDays: "24-25", |
| 905 |
reason: "lead period Day 7 overlaps with Booking A", |
990 |
reason: "lead Days 24-25 overlap with Booking A actual end Day 25", |
| 906 |
}, |
991 |
}, |
| 907 |
]; |
992 |
]; |
| 908 |
|
993 |
|
| 909 |
conflictStartDates.forEach(test => { |
994 |
actualDateConflicts.forEach(test => { |
| 910 |
if ( |
995 |
if ( |
| 911 |
test.date.month() === today.month() || |
996 |
test.date.month() === today.month() || |
| 912 |
test.date.month() === today.add(1, "month").month() |
997 |
test.date.month() === today.add(1, "month").month() |
|
Lines 924-930
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 924 |
.should("have.class", "leadDisable"); |
1009 |
.should("have.class", "leadDisable"); |
| 925 |
|
1010 |
|
| 926 |
cy.log( |
1011 |
cy.log( |
| 927 |
`✓ ${test.date.format("YYYY-MM-DD")}: Has leadDisable class (click prevented)` |
1012 |
`✓ ${test.date.format("YYYY-MM-DD")}: Has leadDisable (conflicts with actual booking)` |
|
|
1013 |
); |
| 1014 |
} |
| 1015 |
}); |
| 1016 |
|
| 1017 |
// ======================================================================== |
| 1018 |
// TEST 2B: BIDIRECTIONAL - Lead Period Conflict with Existing Booking TRAIL |
| 1019 |
// ======================================================================== |
| 1020 |
cy.log( |
| 1021 |
"=== TEST 2B: Testing new booking lead period conflicts with existing booking TRAIL period ===" |
| 1022 |
); |
| 1023 |
|
| 1024 |
/* |
| 1025 |
* NEW BIDIRECTIONAL Conflict Scenario: |
| 1026 |
* Booking A end: Day 25 |
| 1027 |
* Booking A trail period: Days 26-28 (3 days after end) |
| 1028 |
* |
| 1029 |
* Test start dates where NEW booking's lead overlaps with Booking A TRAIL: |
| 1030 |
* - Day 27: Lead Days 25-26 → Day 26 is in Booking A trail Days 26-28 → DISABLED |
| 1031 |
* - Day 28: Lead Days 26-27 → Days 26-27 are in Booking A trail → DISABLED |
| 1032 |
* - Day 29: Lead Days 27-28 → Days 27-28 are in Booking A trail → DISABLED |
| 1033 |
* - Day 30: Lead Days 28-29 → Day 28 is last day of Booking A trail → DISABLED |
| 1034 |
* |
| 1035 |
* This is the KEY enhancement: respecting existing booking's trail period! |
| 1036 |
*/ |
| 1037 |
|
| 1038 |
const bookingATrailStart = conflictBookings[0].end.add(1, "day"); // Day 26 |
| 1039 |
const bookingATrailEnd = conflictBookings[0].end.add( |
| 1040 |
leadTrailCirculationRules.bookings_trail_period, |
| 1041 |
"day" |
| 1042 |
); // Day 28 |
| 1043 |
|
| 1044 |
cy.log( |
| 1045 |
`Booking A trail period: ${bookingATrailStart.format("YYYY-MM-DD")} to ${bookingATrailEnd.format("YYYY-MM-DD")}` |
| 1046 |
); |
| 1047 |
|
| 1048 |
const trailPeriodConflicts = [ |
| 1049 |
{ |
| 1050 |
date: today.add(27, "day"), |
| 1051 |
leadDays: "25-26", |
| 1052 |
reason: "lead Day 26 is within Booking A trail Days 26-28", |
| 1053 |
}, |
| 1054 |
{ |
| 1055 |
date: today.add(28, "day"), |
| 1056 |
leadDays: "26-27", |
| 1057 |
reason: "lead Days 26-27 overlap with Booking A trail Days 26-28", |
| 1058 |
}, |
| 1059 |
{ |
| 1060 |
date: today.add(29, "day"), |
| 1061 |
leadDays: "27-28", |
| 1062 |
reason: "lead Days 27-28 overlap with Booking A trail Days 26-28", |
| 1063 |
}, |
| 1064 |
{ |
| 1065 |
date: today.add(30, "day"), |
| 1066 |
leadDays: "28-29", |
| 1067 |
reason: "lead Day 28 is the last day of Booking A trail", |
| 1068 |
}, |
| 1069 |
]; |
| 1070 |
|
| 1071 |
trailPeriodConflicts.forEach(test => { |
| 1072 |
if ( |
| 1073 |
test.date.month() === today.month() || |
| 1074 |
test.date.month() === today.add(1, "month").month() || |
| 1075 |
test.date.month() === today.add(2, "month").month() |
| 1076 |
) { |
| 1077 |
cy.log( |
| 1078 |
`Testing ${test.date.format("YYYY-MM-DD")}: ${test.reason}` |
| 1079 |
); |
| 1080 |
|
| 1081 |
cy.get("@leadTrailFlatpickr") |
| 1082 |
.getFlatpickrDate(test.date.toDate()) |
| 1083 |
.trigger("mouseover"); |
| 1084 |
|
| 1085 |
cy.get("@leadTrailFlatpickr") |
| 1086 |
.getFlatpickrDate(test.date.toDate()) |
| 1087 |
.should("have.class", "leadDisable"); |
| 1088 |
|
| 1089 |
cy.log( |
| 1090 |
`✓ ${test.date.format("YYYY-MM-DD")}: Has leadDisable (BIDIRECTIONAL: conflicts with trail)` |
| 928 |
); |
1091 |
); |
| 929 |
} |
1092 |
} |
| 930 |
}); |
1093 |
}); |
|
Lines 938-972
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 938 |
|
1101 |
|
| 939 |
/* |
1102 |
/* |
| 940 |
* Clear Lead Period Test: |
1103 |
* Clear Lead Period Test: |
| 941 |
* - Day 10 as start has lead period Days 8-9 |
1104 |
* - Day 31 as start has lead period Days 29-30 |
| 942 |
* - Days 8-9 are clear (no existing bookings) |
1105 |
* - Booking A trail ends on Day 28 |
| 943 |
* - Day 10 should NOT have leadDisable class |
1106 |
* - Days 29-30 are clear (after Booking A's trail period) |
|
|
1107 |
* - Day 31 should NOT have leadDisable class |
| 944 |
* - Clicking should be allowed |
1108 |
* - Clicking should be allowed |
|
|
1109 |
* |
| 1110 |
* This validates that dates AFTER the full protected period are selectable |
| 945 |
*/ |
1111 |
*/ |
| 946 |
|
1112 |
|
|
|
1113 |
const clearStartAfterBookingA = today.add(31, "day"); |
| 1114 |
|
| 947 |
if ( |
1115 |
if ( |
| 948 |
clearStartDate.month() === today.month() || |
1116 |
clearStartAfterBookingA.month() === today.month() || |
| 949 |
clearStartDate.month() === today.add(1, "month").month() |
1117 |
clearStartAfterBookingA.month() === today.add(2, "month").month() |
| 950 |
) { |
1118 |
) { |
| 951 |
cy.log( |
1119 |
cy.log( |
| 952 |
`Testing ${clearStartDate.format("YYYY-MM-DD")}: lead period Days 8-9 are clear` |
1120 |
`Testing ${clearStartAfterBookingA.format("YYYY-MM-DD")}: lead Days 29-30 clear of Booking A trail (ends Day 28)` |
| 953 |
); |
1121 |
); |
| 954 |
|
1122 |
|
| 955 |
cy.get("@leadTrailFlatpickr") |
1123 |
cy.get("@leadTrailFlatpickr") |
| 956 |
.getFlatpickrDate(clearStartDate.toDate()) |
1124 |
.getFlatpickrDate(clearStartAfterBookingA.toDate()) |
| 957 |
.trigger("mouseover"); |
1125 |
.trigger("mouseover"); |
| 958 |
|
1126 |
|
| 959 |
cy.get("@leadTrailFlatpickr") |
1127 |
cy.get("@leadTrailFlatpickr") |
| 960 |
.getFlatpickrDate(clearStartDate.toDate()) |
1128 |
.getFlatpickrDate(clearStartAfterBookingA.toDate()) |
| 961 |
.should("not.have.class", "leadDisable"); |
1129 |
.should("not.have.class", "leadDisable"); |
| 962 |
|
1130 |
|
| 963 |
// Actually select it to establish start date for trail tests |
1131 |
// Actually select it to establish start date for trail tests |
| 964 |
cy.get("@leadTrailFlatpickr") |
1132 |
cy.get("@leadTrailFlatpickr") |
| 965 |
.getFlatpickrDate(clearStartDate.toDate()) |
1133 |
.getFlatpickrDate(clearStartAfterBookingA.toDate()) |
| 966 |
.click(); |
1134 |
.click(); |
| 967 |
|
1135 |
|
| 968 |
cy.log( |
1136 |
cy.log( |
| 969 |
`✓ ${clearStartDate.format("YYYY-MM-DD")}: No leadDisable, successfully selected as start` |
1137 |
`✓ ${clearStartAfterBookingA.format("YYYY-MM-DD")}: No leadDisable, successfully selected as start` |
| 970 |
); |
1138 |
); |
| 971 |
} |
1139 |
} |
| 972 |
|
1140 |
|
|
Lines 979-1036
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 979 |
|
1147 |
|
| 980 |
/* |
1148 |
/* |
| 981 |
* The max date should be calculated ONLY from circulation rules: |
1149 |
* The max date should be calculated ONLY from circulation rules: |
| 982 |
* - Start: Day 10 |
1150 |
* - Start: Day 31 |
| 983 |
* - Max period: 28 days |
1151 |
* - Issue length: 14 days (using just the issue length, not full max with renewals) |
| 984 |
* - Expected max end: Day 38 (Day 10 + 28) |
1152 |
* - Expected end: Day 45 (Day 31 + 14) |
| 985 |
* |
1153 |
* |
| 986 |
* The trail period (3 days) should NOT reduce this max date. |
1154 |
* The trail period (3 days) should NOT reduce this max date. |
| 987 |
* Trail period Days 39-41 should only matter if they conflict with an existing booking. |
1155 |
* Trail period Days 46-48 should only matter if they conflict with an existing booking. |
| 988 |
* |
1156 |
* |
| 989 |
* Since Days 39-41 are clear (Booking B starts at Day 45), Day 38 MUST be selectable. |
1157 |
* Since Days 46-48 are clear (Booking B starts at Day 60), Day 45 MUST be selectable. |
|
|
1158 |
* This tests that trail period doesn't incorrectly subtract from the booking length. |
| 990 |
*/ |
1159 |
*/ |
| 991 |
|
1160 |
|
| 992 |
const calculatedMaxEnd = clearStartDate.add(maxBookingPeriod, "day"); // Day 38 |
1161 |
// Use issue length for this test (simpler than full max period) |
| 993 |
const trailAfterMax = calculatedMaxEnd.add(1, "day"); // Day 39 (first trail day) |
1162 |
const testEndDate = clearStartAfterBookingA.add( |
| 994 |
const trailEndAfterMax = calculatedMaxEnd.add( |
1163 |
leadTrailCirculationRules.issuelength, |
|
|
1164 |
"day" |
| 1165 |
); // Day 45 |
| 1166 |
const trailAfterEnd = testEndDate.add(1, "day"); // Day 46 (first trail day) |
| 1167 |
const trailEndAfterEnd = testEndDate.add( |
| 995 |
leadTrailCirculationRules.bookings_trail_period, |
1168 |
leadTrailCirculationRules.bookings_trail_period, |
| 996 |
"day" |
1169 |
"day" |
| 997 |
); // Day 41 (last trail day) |
1170 |
); // Day 48 (last trail day) |
| 998 |
|
1171 |
|
| 999 |
cy.log(`Start date: ${clearStartDate.format("YYYY-MM-DD")} (Day 10)`); |
|
|
| 1000 |
cy.log(`Max booking period: ${maxBookingPeriod} days`); |
| 1001 |
cy.log( |
1172 |
cy.log( |
| 1002 |
`Calculated max end date: ${calculatedMaxEnd.format("YYYY-MM-DD")} (Day 38)` |
1173 |
`Start date: ${clearStartAfterBookingA.format("YYYY-MM-DD")} (Day 31)` |
| 1003 |
); |
1174 |
); |
|
|
1175 |
cy.log(`Issue length: ${leadTrailCirculationRules.issuelength} days`); |
| 1176 |
cy.log(`Test end date: ${testEndDate.format("YYYY-MM-DD")} (Day 45)`); |
| 1004 |
cy.log( |
1177 |
cy.log( |
| 1005 |
`Trail period after max: ${trailAfterMax.format("YYYY-MM-DD")} to ${trailEndAfterMax.format("YYYY-MM-DD")} (Days 39-41)` |
1178 |
`Trail period after end: ${trailAfterEnd.format("YYYY-MM-DD")} to ${trailEndAfterEnd.format("YYYY-MM-DD")} (Days 46-48)` |
| 1006 |
); |
1179 |
); |
| 1007 |
cy.log( |
1180 |
cy.log( |
| 1008 |
`Booking B starts: ${conflictBookings[1].start.format("YYYY-MM-DD")} (Day 45) - trail is clear` |
1181 |
`Booking B starts: ${conflictBookings[1].start.format("YYYY-MM-DD")} (Day 60) - trail is clear` |
| 1009 |
); |
1182 |
); |
| 1010 |
|
1183 |
|
| 1011 |
// Verify max end date IS selectable and does NOT have trailDisable |
1184 |
// Verify test end date IS selectable and does NOT have trailDisable |
| 1012 |
if ( |
1185 |
if ( |
| 1013 |
calculatedMaxEnd.month() === clearStartDate.month() || |
1186 |
testEndDate.month() === clearStartAfterBookingA.month() || |
| 1014 |
calculatedMaxEnd.month() === clearStartDate.add(1, "month").month() |
1187 |
testEndDate.month() === |
|
|
1188 |
clearStartAfterBookingA.add(1, "month").month() |
| 1015 |
) { |
1189 |
) { |
| 1016 |
// First check that the date exists and is not disabled by flatpickr |
1190 |
// First check that the date exists and is not disabled by flatpickr |
| 1017 |
cy.get("@leadTrailFlatpickr") |
1191 |
cy.get("@leadTrailFlatpickr") |
| 1018 |
.getFlatpickrDate(calculatedMaxEnd.toDate()) |
1192 |
.getFlatpickrDate(testEndDate.toDate()) |
| 1019 |
.should("not.have.class", "flatpickr-disabled") |
1193 |
.should("not.have.class", "flatpickr-disabled") |
| 1020 |
.and("be.visible"); |
1194 |
.and("be.visible"); |
| 1021 |
|
1195 |
|
| 1022 |
// Hover to trigger trail period logic |
1196 |
// Hover to trigger trail period logic |
| 1023 |
cy.get("@leadTrailFlatpickr") |
1197 |
cy.get("@leadTrailFlatpickr") |
| 1024 |
.getFlatpickrDate(calculatedMaxEnd.toDate()) |
1198 |
.getFlatpickrDate(testEndDate.toDate()) |
| 1025 |
.trigger("mouseover"); |
1199 |
.trigger("mouseover"); |
| 1026 |
|
1200 |
|
| 1027 |
// Should NOT have trailDisable since trail days 38-40 are clear |
1201 |
// Should NOT have trailDisable since trail Days 46-48 are clear |
| 1028 |
cy.get("@leadTrailFlatpickr") |
1202 |
cy.get("@leadTrailFlatpickr") |
| 1029 |
.getFlatpickrDate(calculatedMaxEnd.toDate()) |
1203 |
.getFlatpickrDate(testEndDate.toDate()) |
| 1030 |
.should("not.have.class", "trailDisable"); |
1204 |
.should("not.have.class", "trailDisable"); |
| 1031 |
|
1205 |
|
| 1032 |
cy.log( |
1206 |
cy.log( |
| 1033 |
`✓ CRITICAL: ${calculatedMaxEnd.format("YYYY-MM-DD")} does NOT have trailDisable` |
1207 |
`✓ CRITICAL: ${testEndDate.format("YYYY-MM-DD")} does NOT have trailDisable` |
| 1034 |
); |
1208 |
); |
| 1035 |
cy.log( |
1209 |
cy.log( |
| 1036 |
"✓ BUG FIX VERIFIED: Trail period does NOT incorrectly reduce max date" |
1210 |
"✓ BUG FIX VERIFIED: Trail period does NOT incorrectly reduce max date" |
|
Lines 1046-1079
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1046 |
* Trail Period Visual Hints Test: |
1220 |
* Trail Period Visual Hints Test: |
| 1047 |
* - Hovering over end date shows trail period with CSS classes |
1221 |
* - Hovering over end date shows trail period with CSS classes |
| 1048 |
* - Classes: trailRangeStart, trailRange, trailRangeEnd |
1222 |
* - Classes: trailRangeStart, trailRange, trailRangeEnd |
|
|
1223 |
* - Using testEndDate (Day 45) with trail Days 46-48 |
| 1049 |
*/ |
1224 |
*/ |
| 1050 |
|
1225 |
|
| 1051 |
const trailStart = calculatedMaxEnd; // Day 37 |
1226 |
const trailStart = testEndDate; // Day 45 |
| 1052 |
const trailEnd = calculatedMaxEnd.add( |
1227 |
const trailEnd = testEndDate.add( |
| 1053 |
leadTrailCirculationRules.bookings_trail_period, |
1228 |
leadTrailCirculationRules.bookings_trail_period, |
| 1054 |
"day" |
1229 |
"day" |
| 1055 |
); // Day 40 |
1230 |
); // Day 48 |
| 1056 |
|
1231 |
|
| 1057 |
cy.log( |
1232 |
cy.log( |
| 1058 |
`Hovering ${calculatedMaxEnd.format("YYYY-MM-DD")} to check trail period visual hints` |
1233 |
`Hovering ${testEndDate.format("YYYY-MM-DD")} to check trail period visual hints` |
| 1059 |
); |
1234 |
); |
| 1060 |
cy.log( |
1235 |
cy.log( |
| 1061 |
` Expected trail range: ${trailStart.add(1, "day").format("YYYY-MM-DD")} to ${trailEnd.format("YYYY-MM-DD")}` |
1236 |
` Expected trail range: ${trailStart.add(1, "day").format("YYYY-MM-DD")} to ${trailEnd.format("YYYY-MM-DD")}` |
| 1062 |
); |
1237 |
); |
| 1063 |
|
1238 |
|
| 1064 |
if ( |
1239 |
if ( |
| 1065 |
calculatedMaxEnd.month() === clearStartDate.month() || |
1240 |
testEndDate.month() === clearStartAfterBookingA.month() || |
| 1066 |
calculatedMaxEnd.month() === clearStartDate.add(1, "month").month() |
1241 |
testEndDate.month() === |
|
|
1242 |
clearStartAfterBookingA.add(1, "month").month() |
| 1067 |
) { |
1243 |
) { |
| 1068 |
cy.get("@leadTrailFlatpickr") |
1244 |
cy.get("@leadTrailFlatpickr") |
| 1069 |
.getFlatpickrDate(calculatedMaxEnd.toDate()) |
1245 |
.getFlatpickrDate(testEndDate.toDate()) |
| 1070 |
.trigger("mouseover"); |
1246 |
.trigger("mouseover"); |
| 1071 |
|
1247 |
|
| 1072 |
// Check trail range classes on subsequent days |
1248 |
// Check trail range classes on subsequent days |
| 1073 |
const firstTrailDay = calculatedMaxEnd.add(1, "day"); |
1249 |
const firstTrailDay = testEndDate.add(1, "day"); |
| 1074 |
if ( |
1250 |
if ( |
| 1075 |
firstTrailDay.month() === today.month() || |
1251 |
firstTrailDay.month() === today.month() || |
| 1076 |
firstTrailDay.month() === today.add(1, "month").month() |
1252 |
firstTrailDay.month() === today.add(2, "month").month() |
| 1077 |
) { |
1253 |
) { |
| 1078 |
cy.get("@leadTrailFlatpickr") |
1254 |
cy.get("@leadTrailFlatpickr") |
| 1079 |
.getFlatpickrDate(firstTrailDay.toDate()) |
1255 |
.getFlatpickrDate(firstTrailDay.toDate()) |
|
Lines 1085-1160
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1085 |
} |
1261 |
} |
| 1086 |
|
1262 |
|
| 1087 |
// ======================================================================== |
1263 |
// ======================================================================== |
| 1088 |
// TEST 6: Trail Period Conflict Prevention with Existing Booking |
1264 |
// TEST 6A: Trail Period Conflict with Existing Booking ACTUAL Dates |
| 1089 |
// ======================================================================== |
1265 |
// ======================================================================== |
| 1090 |
cy.log( |
1266 |
cy.log( |
| 1091 |
"=== TEST 6: Testing trail period prevents selection due to booking conflict ===" |
1267 |
"=== TEST 6A: Testing new booking trail period conflicts with existing booking actual dates ===" |
| 1092 |
); |
1268 |
); |
| 1093 |
|
1269 |
|
| 1094 |
/* |
1270 |
/* |
| 1095 |
* Trail Period Conflict Test: |
1271 |
* Original Trail Conflict Scenario: |
| 1096 |
* - Booking B occupies Days 45-50 |
1272 |
* Booking B actual dates: Days 60-65 |
| 1097 |
* - End date Day 42 would have trail period Days 43-45 |
1273 |
* |
| 1098 |
* - Day 45 is in the trail period and conflicts with Booking B |
1274 |
* Test end dates where NEW booking's trail overlaps with Booking B ACTUAL dates: |
| 1099 |
* - Day 42 should get 'trailDisable' class when hovered |
1275 |
* - Day 58: Trail Days 59-61 → Days 60-61 overlap with Booking B actual Days 60-65 → DISABLED |
|
|
1276 |
* - Day 59: Trail Days 60-62 → Days 60-62 overlap with Booking B actual Days 60-65 → DISABLED |
| 1100 |
*/ |
1277 |
*/ |
| 1101 |
|
1278 |
|
| 1102 |
const conflictEndDate = today.add(42, "day"); |
1279 |
const bookingBStart = conflictBookings[1].start; // Day 60 |
| 1103 |
const conflictTrailStart = conflictEndDate.add(1, "day"); // Day 43 |
1280 |
|
| 1104 |
const conflictTrailEnd = conflictEndDate.add( |
1281 |
cy.log( |
| 1105 |
leadTrailCirculationRules.bookings_trail_period, |
1282 |
`Booking B actual dates: ${bookingBStart.format("YYYY-MM-DD")} to ${conflictBookings[1].end.format("YYYY-MM-DD")}` |
|
|
1283 |
); |
| 1284 |
|
| 1285 |
const actualTrailConflicts = [ |
| 1286 |
{ |
| 1287 |
date: today.add(58, "day"), |
| 1288 |
trailDays: "59-61", |
| 1289 |
reason: "trail Days 60-61 overlap with Booking B actual dates Days 60-65", |
| 1290 |
}, |
| 1291 |
{ |
| 1292 |
date: today.add(59, "day"), |
| 1293 |
trailDays: "60-62", |
| 1294 |
reason: "trail Days 60-62 overlap with Booking B actual dates Days 60-65", |
| 1295 |
}, |
| 1296 |
]; |
| 1297 |
|
| 1298 |
actualTrailConflicts.forEach(test => { |
| 1299 |
if ( |
| 1300 |
test.date.month() === clearStartAfterBookingA.month() || |
| 1301 |
test.date.month() === |
| 1302 |
clearStartAfterBookingA.add(2, "month").month() |
| 1303 |
) { |
| 1304 |
cy.log( |
| 1305 |
`Testing ${test.date.format("YYYY-MM-DD")}: ${test.reason}` |
| 1306 |
); |
| 1307 |
|
| 1308 |
cy.get("@leadTrailFlatpickr") |
| 1309 |
.getFlatpickrDate(test.date.toDate()) |
| 1310 |
.trigger("mouseover"); |
| 1311 |
|
| 1312 |
cy.get("@leadTrailFlatpickr") |
| 1313 |
.getFlatpickrDate(test.date.toDate()) |
| 1314 |
.should("have.class", "trailDisable"); |
| 1315 |
|
| 1316 |
cy.log( |
| 1317 |
`✓ ${test.date.format("YYYY-MM-DD")}: Has trailDisable (conflicts with actual booking)` |
| 1318 |
); |
| 1319 |
} |
| 1320 |
}); |
| 1321 |
|
| 1322 |
// ======================================================================== |
| 1323 |
// TEST 6B: BIDIRECTIONAL - Trail Period Conflict with Existing Booking LEAD |
| 1324 |
// ======================================================================== |
| 1325 |
cy.log( |
| 1326 |
"=== TEST 6B: Testing new booking trail period conflicts with existing booking LEAD period ===" |
| 1327 |
); |
| 1328 |
|
| 1329 |
/* |
| 1330 |
* NEW BIDIRECTIONAL Conflict Scenario: |
| 1331 |
* Booking B start: Day 60 |
| 1332 |
* Booking B lead period: Days 58-59 (2 days before start) |
| 1333 |
* |
| 1334 |
* Test end dates where NEW booking's trail overlaps with Booking B LEAD: |
| 1335 |
* - Day 56: Trail Days 57-59 → Days 57-59 overlap with Booking B lead Days 58-59 → DISABLED |
| 1336 |
* - Day 55: Trail Days 56-58 → Day 58 overlaps with Booking B lead Days 58-59 → DISABLED |
| 1337 |
* |
| 1338 |
* This is the KEY enhancement: respecting existing booking's lead period! |
| 1339 |
*/ |
| 1340 |
|
| 1341 |
const bookingBLeadStart = bookingBStart.subtract( |
| 1342 |
leadTrailCirculationRules.bookings_lead_period, |
| 1106 |
"day" |
1343 |
"day" |
| 1107 |
); // Day 45 |
1344 |
); // Day 58 |
|
|
1345 |
const bookingBLeadEnd = bookingBStart.subtract(1, "day"); // Day 59 |
| 1108 |
|
1346 |
|
| 1109 |
if ( |
1347 |
cy.log( |
| 1110 |
conflictEndDate.month() === clearStartDate.month() || |
1348 |
`Booking B lead period: ${bookingBLeadStart.format("YYYY-MM-DD")} to ${bookingBLeadEnd.format("YYYY-MM-DD")}` |
| 1111 |
conflictEndDate.month() === clearStartDate.add(2, "month").month() |
1349 |
); |
| 1112 |
) { |
|
|
| 1113 |
cy.log( |
| 1114 |
`Testing ${conflictEndDate.format("YYYY-MM-DD")}: trail Days ${conflictTrailStart.format("YYYY-MM-DD")}-${conflictTrailEnd.format("YYYY-MM-DD")} conflict with Booking B` |
| 1115 |
); |
| 1116 |
|
1350 |
|
| 1117 |
cy.get("@leadTrailFlatpickr") |
1351 |
const leadPeriodTrailConflicts = [ |
| 1118 |
.getFlatpickrDate(conflictEndDate.toDate()) |
1352 |
{ |
| 1119 |
.trigger("mouseover"); |
1353 |
date: today.add(56, "day"), |
|
|
1354 |
trailDays: "57-59", |
| 1355 |
reason: "trail Days 57-59 overlap with Booking B lead Days 58-59", |
| 1356 |
}, |
| 1357 |
{ |
| 1358 |
date: today.add(55, "day"), |
| 1359 |
trailDays: "56-58", |
| 1360 |
reason: "trail Day 58 overlaps with Booking B lead Days 58-59", |
| 1361 |
}, |
| 1362 |
]; |
| 1120 |
|
1363 |
|
| 1121 |
cy.get("@leadTrailFlatpickr") |
1364 |
leadPeriodTrailConflicts.forEach(test => { |
| 1122 |
.getFlatpickrDate(conflictEndDate.toDate()) |
1365 |
if ( |
| 1123 |
.should("have.class", "trailDisable"); |
1366 |
test.date.month() === clearStartAfterBookingA.month() || |
|
|
1367 |
test.date.month() === |
| 1368 |
clearStartAfterBookingA.add(2, "month").month() |
| 1369 |
) { |
| 1370 |
cy.log( |
| 1371 |
`Testing ${test.date.format("YYYY-MM-DD")}: ${test.reason}` |
| 1372 |
); |
| 1124 |
|
1373 |
|
| 1125 |
cy.log( |
1374 |
cy.get("@leadTrailFlatpickr") |
| 1126 |
`✓ ${conflictEndDate.format("YYYY-MM-DD")}: Has trailDisable class (click prevented)` |
1375 |
.getFlatpickrDate(test.date.toDate()) |
| 1127 |
); |
1376 |
.trigger("mouseover"); |
| 1128 |
} |
1377 |
|
|
|
1378 |
cy.get("@leadTrailFlatpickr") |
| 1379 |
.getFlatpickrDate(test.date.toDate()) |
| 1380 |
.should("have.class", "trailDisable"); |
| 1381 |
|
| 1382 |
cy.log( |
| 1383 |
`✓ ${test.date.format("YYYY-MM-DD")}: Has trailDisable (BIDIRECTIONAL: conflicts with lead)` |
| 1384 |
); |
| 1385 |
} |
| 1386 |
}); |
| 1129 |
|
1387 |
|
| 1130 |
// ======================================================================== |
1388 |
// ======================================================================== |
| 1131 |
// TEST 7: Verify Full Max Range Can Be Selected |
1389 |
// TEST 7: Verify Valid Booking Range Can Be Selected |
| 1132 |
// ======================================================================== |
1390 |
// ======================================================================== |
| 1133 |
cy.log( |
1391 |
cy.log( |
| 1134 |
"=== TEST 7: Testing full max range selection works correctly ===" |
1392 |
"=== TEST 7: Testing valid booking range selection works correctly ===" |
| 1135 |
); |
1393 |
); |
| 1136 |
|
1394 |
|
| 1137 |
/* |
1395 |
/* |
| 1138 |
* Full Range Selection Test: |
1396 |
* Valid Range Selection Test: |
| 1139 |
* - Should be able to select the full range from start to max end |
1397 |
* - Should be able to select a valid range that respects all constraints |
| 1140 |
* - Start: Day 10, End: Day 37 (28-day period) |
1398 |
* - Start: Day 31 (clear of Booking A's trail ending Day 28) |
| 1141 |
* - This verifies the bug fix: trail period doesn't prevent max date selection |
1399 |
* - End: Day 54 (clear of Booking B's lead starting Day 58) |
|
|
1400 |
* - This range: |
| 1401 |
* - Start lead Days 29-30: Clear of Booking A trail (ends Day 28) ✓ |
| 1402 |
* - End trail Days 55-57: Clear of Booking B lead (starts Day 58) ✓ |
| 1403 |
* - This verifies bidirectional lead/trail period checking works correctly |
| 1142 |
*/ |
1404 |
*/ |
| 1143 |
|
1405 |
|
|
|
1406 |
const validClearEnd = today.add(54, "day"); |
| 1407 |
|
| 1144 |
cy.get("#period").clearFlatpickr(); |
1408 |
cy.get("#period").clearFlatpickr(); |
| 1145 |
|
1409 |
|
| 1146 |
if ( |
1410 |
if ( |
| 1147 |
clearStartDate.month() === today.month() || |
1411 |
clearStartAfterBookingA.month() === today.month() || |
| 1148 |
clearStartDate.month() === today.add(1, "month").month() |
1412 |
clearStartAfterBookingA.month() === today.add(2, "month").month() |
| 1149 |
) { |
1413 |
) { |
| 1150 |
if ( |
1414 |
if ( |
| 1151 |
calculatedMaxEnd.month() === clearStartDate.month() || |
1415 |
validClearEnd.month() === clearStartAfterBookingA.month() || |
| 1152 |
calculatedMaxEnd.month() === |
1416 |
validClearEnd.month() === |
| 1153 |
clearStartDate.add(1, "month").month() |
1417 |
clearStartAfterBookingA.add(2, "month").month() |
| 1154 |
) { |
1418 |
) { |
| 1155 |
cy.get("#period").selectFlatpickrDateRange( |
1419 |
cy.get("#period").selectFlatpickrDateRange( |
| 1156 |
clearStartDate, |
1420 |
clearStartAfterBookingA, |
| 1157 |
calculatedMaxEnd |
1421 |
validClearEnd |
| 1158 |
); |
1422 |
); |
| 1159 |
|
1423 |
|
| 1160 |
// Verify the dates were accepted |
1424 |
// Verify the dates were accepted |
|
Lines 1162-1171
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1162 |
cy.get("#booking_end_date").should("not.have.value", ""); |
1426 |
cy.get("#booking_end_date").should("not.have.value", ""); |
| 1163 |
|
1427 |
|
| 1164 |
cy.log( |
1428 |
cy.log( |
| 1165 |
`✓ Successfully selected full max range: ${clearStartDate.format("YYYY-MM-DD")} to ${calculatedMaxEnd.format("YYYY-MM-DD")}` |
1429 |
`✓ Successfully selected valid range: ${clearStartAfterBookingA.format("YYYY-MM-DD")} to ${validClearEnd.format("YYYY-MM-DD")}` |
| 1166 |
); |
1430 |
); |
| 1167 |
cy.log( |
1431 |
cy.log( |
| 1168 |
`✓ Confirmed: ${maxBookingPeriod}-day booking period fully available` |
1432 |
`✓ Confirmed: Booking respects both Booking A's trail and Booking B's lead periods` |
| 1169 |
); |
1433 |
); |
| 1170 |
} |
1434 |
} |
| 1171 |
} |
1435 |
} |
|
Lines 1183-1188
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1183 |
cy.log( |
1447 |
cy.log( |
| 1184 |
"✓ CRITICAL BUG FIX: Trail period does NOT incorrectly limit max date when no conflicts" |
1448 |
"✓ CRITICAL BUG FIX: Trail period does NOT incorrectly limit max date when no conflicts" |
| 1185 |
); |
1449 |
); |
|
|
1450 |
cy.log( |
| 1451 |
"✓ BIDIRECTIONAL ENHANCEMENT: New booking lead respects existing booking trail periods" |
| 1452 |
); |
| 1453 |
cy.log( |
| 1454 |
"✓ BIDIRECTIONAL ENHANCEMENT: New booking trail respects existing booking lead periods" |
| 1455 |
); |
| 1456 |
cy.log( |
| 1457 |
"✓ Full protected period validation: Existing bookings' lead + actual + trail periods all respected" |
| 1458 |
); |
| 1186 |
cy.log( |
1459 |
cy.log( |
| 1187 |
`✓ Validated: ${leadTrailCirculationRules.bookings_lead_period}-day lead + ${maxBookingPeriod}-day max period + ${leadTrailCirculationRules.bookings_trail_period}-day trail` |
1460 |
`✓ Validated: ${leadTrailCirculationRules.bookings_lead_period}-day lead + ${maxBookingPeriod}-day max period + ${leadTrailCirculationRules.bookings_trail_period}-day trail` |
| 1188 |
); |
1461 |
); |
| 1189 |
- |
|
|