|
Lines 674-679
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 674 |
); |
674 |
); |
| 675 |
}); |
675 |
}); |
| 676 |
|
676 |
|
|
|
677 |
it("should handle lead and trail period behavior correctly", () => { |
| 678 |
/** |
| 679 |
* Lead and Trail Period Behavior Tests |
| 680 |
* ==================================== |
| 681 |
* |
| 682 |
* Validates that bookings lead and trail periods work correctly with hover |
| 683 |
* effects and click prevention to avoid conflicts with existing bookings. |
| 684 |
* |
| 685 |
* Test Coverage: |
| 686 |
* 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 |
| 688 |
* 3. Lead period click prevention when it would extend into past dates |
| 689 |
* 4. Trail period visual hints (hover CSS classes) when selecting end dates |
| 690 |
* 5. Trail period click prevention when it would conflict with existing bookings |
| 691 |
* 6. Trail period does NOT incorrectly limit max date when no conflicts exist (BUG FIX) |
| 692 |
* 7. Bookings can reach full max date when trail period is clear |
| 693 |
* |
| 694 |
* LEAD PERIOD EXPLANATION: |
| 695 |
* ======================= |
| 696 |
* 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). |
| 698 |
* 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 |
| 700 |
* clicking is prevented. |
| 701 |
* |
| 702 |
* TRAIL PERIOD EXPLANATION: |
| 703 |
* ======================== |
| 704 |
* 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, |
| 706 |
* 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' |
| 708 |
* class and clicking is prevented. |
| 709 |
* |
| 710 |
* 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. |
| 712 |
* |
| 713 |
* Implementation Details: |
| 714 |
* ====================== |
| 715 |
* - Hover shows lead/trail with CSS classes: leadRange, leadRangeStart, leadRangeEnd, |
| 716 |
* trailRange, trailRangeStart, trailRangeEnd |
| 717 |
* - Conflicts add leadDisable or trailDisable class to the hovered date |
| 718 |
* - Click event listener with disableClick prevents selection |
| 719 |
* |
| 720 |
* Test Scenario Layout: |
| 721 |
* ==================== |
| 722 |
* |
| 723 |
* Circulation Rules: |
| 724 |
* - Lead period: 2 days |
| 725 |
* - Trail period: 3 days |
| 726 |
* - Issue length: 14 days |
| 727 |
* - Renewals: 2 |
| 728 |
* - Renewal period: 7 days each |
| 729 |
* - Max period: 14 + (2 × 7) = 28 days |
| 730 |
* |
| 731 |
* Timeline with Existing Bookings: |
| 732 |
* ================================================================ |
| 733 |
* Day: 5 6 7 8 9 10 11 12 ... 37 38 39 40 41 42 43 44 45 46 |
| 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 |
* |
| 739 |
* Booking A: Days 5-7 (tests lead period conflict) |
| 740 |
* Booking B: Days 45-50 (tests trail period conflict) |
| 741 |
* |
| 742 |
* Clear booking window: Days 10-38 |
| 743 |
* - Start Day 10: Lead period Days 8-9 (clear) |
| 744 |
* - End Day 38: Trail period Days 39-41 (clear, max date test) |
| 745 |
* - End Day 42: Trail period Days 43-45 (conflicts with Booking B at Day 45) |
| 746 |
* |
| 747 |
* Expected Behaviors: |
| 748 |
* - Hovering Day 8 for start: leadRange classes show Days 6-7, leadDisable due to Booking A |
| 749 |
* - Hovering Day 9 for start: leadRange classes show Days 7-8, leadDisable due to Booking A |
| 750 |
* - Hovering Day 10 for start: leadRange classes show Days 8-9, no leadDisable (clear) |
| 751 |
* - With start Day 10, max end should be Day 38 (10 + 28) |
| 752 |
* - Hovering Day 38 for end: trailRange classes show Days 39-41, no trailDisable (clear) |
| 753 |
* - Hovering Day 42 for end: trailRange classes show Days 43-45, trailDisable due to Booking B |
| 754 |
* - Day 38 must be selectable (full max period, trail doesn't reduce it) |
| 755 |
*/ |
| 756 |
|
| 757 |
const today = dayjs().startOf("day"); |
| 758 |
|
| 759 |
// Set up circulation rules with lead and trail periods |
| 760 |
const leadTrailCirculationRules = { |
| 761 |
bookings_lead_period: 2, // 2 days before start |
| 762 |
bookings_trail_period: 3, // 3 days after end |
| 763 |
issuelength: 14, // 14-day issue period |
| 764 |
renewalsallowed: 2, // 2 renewals |
| 765 |
renewalperiod: 7, // 7 days per renewal |
| 766 |
}; |
| 767 |
|
| 768 |
const maxBookingPeriod = |
| 769 |
leadTrailCirculationRules.issuelength + |
| 770 |
leadTrailCirculationRules.renewalsallowed * |
| 771 |
leadTrailCirculationRules.renewalperiod; // 28 days |
| 772 |
|
| 773 |
cy.intercept("GET", "/api/v1/circulation_rules*", { |
| 774 |
body: [leadTrailCirculationRules], |
| 775 |
}).as("getLeadTrailRules"); |
| 776 |
|
| 777 |
// Create existing bookings to test conflict detection |
| 778 |
const conflictBookings = [ |
| 779 |
{ |
| 780 |
name: "Booking A (lead conflict test)", |
| 781 |
start: today.add(5, "day"), |
| 782 |
end: today.add(7, "day"), |
| 783 |
item_id: testData.items[0].item_id, |
| 784 |
}, |
| 785 |
{ |
| 786 |
name: "Booking B (trail conflict test)", |
| 787 |
start: today.add(45, "day"), |
| 788 |
end: today.add(50, "day"), |
| 789 |
item_id: testData.items[0].item_id, |
| 790 |
}, |
| 791 |
]; |
| 792 |
|
| 793 |
// Insert conflict bookings |
| 794 |
conflictBookings.forEach(booking => { |
| 795 |
cy.task("query", { |
| 796 |
sql: `INSERT INTO bookings (biblio_id, item_id, patron_id, start_date, end_date, pickup_library_id, status) |
| 797 |
VALUES (?, ?, ?, ?, ?, ?, '1')`, |
| 798 |
values: [ |
| 799 |
testData.biblio.biblio_id, |
| 800 |
booking.item_id, |
| 801 |
testData.patron.patron_id, |
| 802 |
booking.start.format("YYYY-MM-DD HH:mm:ss"), |
| 803 |
booking.end.format("YYYY-MM-DD HH:mm:ss"), |
| 804 |
testData.libraries[0].library_id, |
| 805 |
], |
| 806 |
}); |
| 807 |
}); |
| 808 |
|
| 809 |
setupModalForDateTesting({ skipItemSelection: true }); |
| 810 |
|
| 811 |
// Select the item with existing bookings |
| 812 |
cy.get("#booking_item_id").should("not.be.disabled"); |
| 813 |
cy.selectFromSelect2ByIndex("#booking_item_id", 1); |
| 814 |
cy.wait("@getLeadTrailRules"); |
| 815 |
|
| 816 |
cy.get("#period").should("not.be.disabled"); |
| 817 |
cy.get("#period").as("leadTrailFlatpickr"); |
| 818 |
cy.get("@leadTrailFlatpickr").openFlatpickr(); |
| 819 |
|
| 820 |
// ======================================================================== |
| 821 |
// TEST 1: Lead Period Visual Hints (Hover Classes) - Clear Zone |
| 822 |
// ======================================================================== |
| 823 |
cy.log("=== TEST 1: Testing lead period visual hints on hover ==="); |
| 824 |
|
| 825 |
/* |
| 826 |
* Lead Period Visual Hints Test: |
| 827 |
* - Hovering over a potential start date should show lead period with CSS classes |
| 828 |
* - Classes: leadRangeStart, leadRange, leadRangeEnd |
| 829 |
* - This provides visual feedback to users about preparation days |
| 830 |
*/ |
| 831 |
|
| 832 |
const clearStartDate = today.add(10, "day"); |
| 833 |
const leadStart = clearStartDate.subtract( |
| 834 |
leadTrailCirculationRules.bookings_lead_period, |
| 835 |
"day" |
| 836 |
); // Day 8 |
| 837 |
const leadEnd = clearStartDate.subtract(1, "day"); // Day 9 |
| 838 |
|
| 839 |
cy.log( |
| 840 |
`Hovering ${clearStartDate.format("YYYY-MM-DD")} to check lead period visual hints` |
| 841 |
); |
| 842 |
cy.log( |
| 843 |
` Expected lead range: ${leadStart.format("YYYY-MM-DD")} to ${leadEnd.format("YYYY-MM-DD")}` |
| 844 |
); |
| 845 |
|
| 846 |
// Trigger hover on the clear start date |
| 847 |
if ( |
| 848 |
clearStartDate.month() === today.month() || |
| 849 |
clearStartDate.month() === today.add(1, "month").month() |
| 850 |
) { |
| 851 |
cy.get("@leadTrailFlatpickr") |
| 852 |
.getFlatpickrDate(clearStartDate.toDate()) |
| 853 |
.trigger("mouseover"); |
| 854 |
|
| 855 |
// Check that lead period days have the appropriate classes |
| 856 |
if ( |
| 857 |
leadStart.month() === today.month() || |
| 858 |
leadStart.month() === today.add(1, "month").month() |
| 859 |
) { |
| 860 |
cy.get("@leadTrailFlatpickr") |
| 861 |
.getFlatpickrDate(leadStart.toDate()) |
| 862 |
.should("have.class", "leadRangeStart"); |
| 863 |
cy.log( |
| 864 |
`✓ ${leadStart.format("YYYY-MM-DD")}: Has leadRangeStart class` |
| 865 |
); |
| 866 |
} |
| 867 |
|
| 868 |
if ( |
| 869 |
leadEnd.month() === today.month() || |
| 870 |
leadEnd.month() === today.add(1, "month").month() |
| 871 |
) { |
| 872 |
cy.get("@leadTrailFlatpickr") |
| 873 |
.getFlatpickrDate(leadEnd.toDate()) |
| 874 |
.should("have.class", "leadRange"); |
| 875 |
cy.log( |
| 876 |
`✓ ${leadEnd.format("YYYY-MM-DD")}: Has leadRange class` |
| 877 |
); |
| 878 |
} |
| 879 |
} |
| 880 |
|
| 881 |
// ======================================================================== |
| 882 |
// TEST 2: Lead Period Conflict Prevention with Existing Booking |
| 883 |
// ======================================================================== |
| 884 |
cy.log( |
| 885 |
"=== TEST 2: Testing lead period prevents selection due to booking conflict ===" |
| 886 |
); |
| 887 |
|
| 888 |
/* |
| 889 |
* Lead Period Conflict Test: |
| 890 |
* - Booking A occupies Days 5-7 |
| 891 |
* - Hovering Day 8 or 9 as start would require lead period overlapping Booking A |
| 892 |
* - These dates should get 'leadDisable' class |
| 893 |
* - Clicking should be prevented |
| 894 |
*/ |
| 895 |
|
| 896 |
const conflictStartDates = [ |
| 897 |
{ |
| 898 |
date: today.add(8, "day"), |
| 899 |
leadDays: "6-7", |
| 900 |
reason: "lead period Days 6-7 overlap with Booking A", |
| 901 |
}, |
| 902 |
{ |
| 903 |
date: today.add(9, "day"), |
| 904 |
leadDays: "7-8", |
| 905 |
reason: "lead period Day 7 overlaps with Booking A", |
| 906 |
}, |
| 907 |
]; |
| 908 |
|
| 909 |
conflictStartDates.forEach(test => { |
| 910 |
if ( |
| 911 |
test.date.month() === today.month() || |
| 912 |
test.date.month() === today.add(1, "month").month() |
| 913 |
) { |
| 914 |
cy.log( |
| 915 |
`Testing ${test.date.format("YYYY-MM-DD")}: ${test.reason}` |
| 916 |
); |
| 917 |
|
| 918 |
cy.get("@leadTrailFlatpickr") |
| 919 |
.getFlatpickrDate(test.date.toDate()) |
| 920 |
.trigger("mouseover"); |
| 921 |
|
| 922 |
cy.get("@leadTrailFlatpickr") |
| 923 |
.getFlatpickrDate(test.date.toDate()) |
| 924 |
.should("have.class", "leadDisable"); |
| 925 |
|
| 926 |
cy.log( |
| 927 |
`✓ ${test.date.format("YYYY-MM-DD")}: Has leadDisable class (click prevented)` |
| 928 |
); |
| 929 |
} |
| 930 |
}); |
| 931 |
|
| 932 |
// ======================================================================== |
| 933 |
// TEST 3: Lead Period Clear - No Conflict |
| 934 |
// ======================================================================== |
| 935 |
cy.log( |
| 936 |
"=== TEST 3: Testing lead period does NOT prevent selection when clear ===" |
| 937 |
); |
| 938 |
|
| 939 |
/* |
| 940 |
* Clear Lead Period Test: |
| 941 |
* - Day 10 as start has lead period Days 8-9 |
| 942 |
* - Days 8-9 are clear (no existing bookings) |
| 943 |
* - Day 10 should NOT have leadDisable class |
| 944 |
* - Clicking should be allowed |
| 945 |
*/ |
| 946 |
|
| 947 |
if ( |
| 948 |
clearStartDate.month() === today.month() || |
| 949 |
clearStartDate.month() === today.add(1, "month").month() |
| 950 |
) { |
| 951 |
cy.log( |
| 952 |
`Testing ${clearStartDate.format("YYYY-MM-DD")}: lead period Days 8-9 are clear` |
| 953 |
); |
| 954 |
|
| 955 |
cy.get("@leadTrailFlatpickr") |
| 956 |
.getFlatpickrDate(clearStartDate.toDate()) |
| 957 |
.trigger("mouseover"); |
| 958 |
|
| 959 |
cy.get("@leadTrailFlatpickr") |
| 960 |
.getFlatpickrDate(clearStartDate.toDate()) |
| 961 |
.should("not.have.class", "leadDisable"); |
| 962 |
|
| 963 |
// Actually select it to establish start date for trail tests |
| 964 |
cy.get("@leadTrailFlatpickr") |
| 965 |
.getFlatpickrDate(clearStartDate.toDate()) |
| 966 |
.click(); |
| 967 |
|
| 968 |
cy.log( |
| 969 |
`✓ ${clearStartDate.format("YYYY-MM-DD")}: No leadDisable, successfully selected as start` |
| 970 |
); |
| 971 |
} |
| 972 |
|
| 973 |
// ======================================================================== |
| 974 |
// TEST 4: Max Date Calculation Does NOT Include Trail Period |
| 975 |
// ======================================================================== |
| 976 |
cy.log( |
| 977 |
"=== TEST 4: Testing max date calculation excludes trail period ===" |
| 978 |
); |
| 979 |
|
| 980 |
/* |
| 981 |
* The max date should be calculated ONLY from circulation rules: |
| 982 |
* - Start: Day 10 |
| 983 |
* - Max period: 28 days |
| 984 |
* - Expected max end: Day 38 (Day 10 + 28) |
| 985 |
* |
| 986 |
* 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. |
| 988 |
* |
| 989 |
* Since Days 39-41 are clear (Booking B starts at Day 45), Day 38 MUST be selectable. |
| 990 |
*/ |
| 991 |
|
| 992 |
const calculatedMaxEnd = clearStartDate.add(maxBookingPeriod, "day"); // Day 38 |
| 993 |
const trailAfterMax = calculatedMaxEnd.add(1, "day"); // Day 39 (first trail day) |
| 994 |
const trailEndAfterMax = calculatedMaxEnd.add( |
| 995 |
leadTrailCirculationRules.bookings_trail_period, |
| 996 |
"day" |
| 997 |
); // Day 41 (last trail day) |
| 998 |
|
| 999 |
cy.log(`Start date: ${clearStartDate.format("YYYY-MM-DD")} (Day 10)`); |
| 1000 |
cy.log(`Max booking period: ${maxBookingPeriod} days`); |
| 1001 |
cy.log( |
| 1002 |
`Calculated max end date: ${calculatedMaxEnd.format("YYYY-MM-DD")} (Day 38)` |
| 1003 |
); |
| 1004 |
cy.log( |
| 1005 |
`Trail period after max: ${trailAfterMax.format("YYYY-MM-DD")} to ${trailEndAfterMax.format("YYYY-MM-DD")} (Days 39-41)` |
| 1006 |
); |
| 1007 |
cy.log( |
| 1008 |
`Booking B starts: ${conflictBookings[1].start.format("YYYY-MM-DD")} (Day 45) - trail is clear` |
| 1009 |
); |
| 1010 |
|
| 1011 |
// Verify max end date IS selectable and does NOT have trailDisable |
| 1012 |
if ( |
| 1013 |
calculatedMaxEnd.month() === clearStartDate.month() || |
| 1014 |
calculatedMaxEnd.month() === clearStartDate.add(1, "month").month() |
| 1015 |
) { |
| 1016 |
// First check that the date exists and is not disabled by flatpickr |
| 1017 |
cy.get("@leadTrailFlatpickr") |
| 1018 |
.getFlatpickrDate(calculatedMaxEnd.toDate()) |
| 1019 |
.should("not.have.class", "flatpickr-disabled") |
| 1020 |
.and("be.visible"); |
| 1021 |
|
| 1022 |
// Hover to trigger trail period logic |
| 1023 |
cy.get("@leadTrailFlatpickr") |
| 1024 |
.getFlatpickrDate(calculatedMaxEnd.toDate()) |
| 1025 |
.trigger("mouseover"); |
| 1026 |
|
| 1027 |
// Should NOT have trailDisable since trail days 38-40 are clear |
| 1028 |
cy.get("@leadTrailFlatpickr") |
| 1029 |
.getFlatpickrDate(calculatedMaxEnd.toDate()) |
| 1030 |
.should("not.have.class", "trailDisable"); |
| 1031 |
|
| 1032 |
cy.log( |
| 1033 |
`✓ CRITICAL: ${calculatedMaxEnd.format("YYYY-MM-DD")} does NOT have trailDisable` |
| 1034 |
); |
| 1035 |
cy.log( |
| 1036 |
"✓ BUG FIX VERIFIED: Trail period does NOT incorrectly reduce max date" |
| 1037 |
); |
| 1038 |
} |
| 1039 |
|
| 1040 |
// ======================================================================== |
| 1041 |
// TEST 5: Trail Period Visual Hints (Hover Classes) |
| 1042 |
// ======================================================================== |
| 1043 |
cy.log("=== TEST 5: Testing trail period visual hints on hover ==="); |
| 1044 |
|
| 1045 |
/* |
| 1046 |
* Trail Period Visual Hints Test: |
| 1047 |
* - Hovering over end date shows trail period with CSS classes |
| 1048 |
* - Classes: trailRangeStart, trailRange, trailRangeEnd |
| 1049 |
*/ |
| 1050 |
|
| 1051 |
const trailStart = calculatedMaxEnd; // Day 37 |
| 1052 |
const trailEnd = calculatedMaxEnd.add( |
| 1053 |
leadTrailCirculationRules.bookings_trail_period, |
| 1054 |
"day" |
| 1055 |
); // Day 40 |
| 1056 |
|
| 1057 |
cy.log( |
| 1058 |
`Hovering ${calculatedMaxEnd.format("YYYY-MM-DD")} to check trail period visual hints` |
| 1059 |
); |
| 1060 |
cy.log( |
| 1061 |
` Expected trail range: ${trailStart.add(1, "day").format("YYYY-MM-DD")} to ${trailEnd.format("YYYY-MM-DD")}` |
| 1062 |
); |
| 1063 |
|
| 1064 |
if ( |
| 1065 |
calculatedMaxEnd.month() === clearStartDate.month() || |
| 1066 |
calculatedMaxEnd.month() === clearStartDate.add(1, "month").month() |
| 1067 |
) { |
| 1068 |
cy.get("@leadTrailFlatpickr") |
| 1069 |
.getFlatpickrDate(calculatedMaxEnd.toDate()) |
| 1070 |
.trigger("mouseover"); |
| 1071 |
|
| 1072 |
// Check trail range classes on subsequent days |
| 1073 |
const firstTrailDay = calculatedMaxEnd.add(1, "day"); |
| 1074 |
if ( |
| 1075 |
firstTrailDay.month() === today.month() || |
| 1076 |
firstTrailDay.month() === today.add(1, "month").month() |
| 1077 |
) { |
| 1078 |
cy.get("@leadTrailFlatpickr") |
| 1079 |
.getFlatpickrDate(firstTrailDay.toDate()) |
| 1080 |
.should("have.class", "trailRange"); |
| 1081 |
cy.log( |
| 1082 |
`✓ ${firstTrailDay.format("YYYY-MM-DD")}: Has trailRange class` |
| 1083 |
); |
| 1084 |
} |
| 1085 |
} |
| 1086 |
|
| 1087 |
// ======================================================================== |
| 1088 |
// TEST 6: Trail Period Conflict Prevention with Existing Booking |
| 1089 |
// ======================================================================== |
| 1090 |
cy.log( |
| 1091 |
"=== TEST 6: Testing trail period prevents selection due to booking conflict ===" |
| 1092 |
); |
| 1093 |
|
| 1094 |
/* |
| 1095 |
* Trail Period Conflict Test: |
| 1096 |
* - Booking B occupies Days 45-50 |
| 1097 |
* - End date Day 42 would have trail period Days 43-45 |
| 1098 |
* - Day 45 is in the trail period and conflicts with Booking B |
| 1099 |
* - Day 42 should get 'trailDisable' class when hovered |
| 1100 |
*/ |
| 1101 |
|
| 1102 |
const conflictEndDate = today.add(42, "day"); |
| 1103 |
const conflictTrailStart = conflictEndDate.add(1, "day"); // Day 43 |
| 1104 |
const conflictTrailEnd = conflictEndDate.add( |
| 1105 |
leadTrailCirculationRules.bookings_trail_period, |
| 1106 |
"day" |
| 1107 |
); // Day 45 |
| 1108 |
|
| 1109 |
if ( |
| 1110 |
conflictEndDate.month() === clearStartDate.month() || |
| 1111 |
conflictEndDate.month() === clearStartDate.add(2, "month").month() |
| 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 |
|
| 1117 |
cy.get("@leadTrailFlatpickr") |
| 1118 |
.getFlatpickrDate(conflictEndDate.toDate()) |
| 1119 |
.trigger("mouseover"); |
| 1120 |
|
| 1121 |
cy.get("@leadTrailFlatpickr") |
| 1122 |
.getFlatpickrDate(conflictEndDate.toDate()) |
| 1123 |
.should("have.class", "trailDisable"); |
| 1124 |
|
| 1125 |
cy.log( |
| 1126 |
`✓ ${conflictEndDate.format("YYYY-MM-DD")}: Has trailDisable class (click prevented)` |
| 1127 |
); |
| 1128 |
} |
| 1129 |
|
| 1130 |
// ======================================================================== |
| 1131 |
// TEST 7: Verify Full Max Range Can Be Selected |
| 1132 |
// ======================================================================== |
| 1133 |
cy.log( |
| 1134 |
"=== TEST 7: Testing full max range selection works correctly ===" |
| 1135 |
); |
| 1136 |
|
| 1137 |
/* |
| 1138 |
* Full Range Selection Test: |
| 1139 |
* - Should be able to select the full range from start to max end |
| 1140 |
* - Start: Day 10, End: Day 37 (28-day period) |
| 1141 |
* - This verifies the bug fix: trail period doesn't prevent max date selection |
| 1142 |
*/ |
| 1143 |
|
| 1144 |
cy.get("#period").clearFlatpickr(); |
| 1145 |
|
| 1146 |
if ( |
| 1147 |
clearStartDate.month() === today.month() || |
| 1148 |
clearStartDate.month() === today.add(1, "month").month() |
| 1149 |
) { |
| 1150 |
if ( |
| 1151 |
calculatedMaxEnd.month() === clearStartDate.month() || |
| 1152 |
calculatedMaxEnd.month() === |
| 1153 |
clearStartDate.add(1, "month").month() |
| 1154 |
) { |
| 1155 |
cy.get("#period").selectFlatpickrDateRange( |
| 1156 |
clearStartDate, |
| 1157 |
calculatedMaxEnd |
| 1158 |
); |
| 1159 |
|
| 1160 |
// Verify the dates were accepted |
| 1161 |
cy.get("#booking_start_date").should("not.have.value", ""); |
| 1162 |
cy.get("#booking_end_date").should("not.have.value", ""); |
| 1163 |
|
| 1164 |
cy.log( |
| 1165 |
`✓ Successfully selected full max range: ${clearStartDate.format("YYYY-MM-DD")} to ${calculatedMaxEnd.format("YYYY-MM-DD")}` |
| 1166 |
); |
| 1167 |
cy.log( |
| 1168 |
`✓ Confirmed: ${maxBookingPeriod}-day booking period fully available` |
| 1169 |
); |
| 1170 |
} |
| 1171 |
} |
| 1172 |
|
| 1173 |
// ======================================================================== |
| 1174 |
// SUMMARY |
| 1175 |
// ======================================================================== |
| 1176 |
cy.log("✓ CONFIRMED: Lead and trail period behavior working correctly"); |
| 1177 |
cy.log( |
| 1178 |
"✓ Lead period: Visual hints on hover, prevents conflicts with bookings and past" |
| 1179 |
); |
| 1180 |
cy.log( |
| 1181 |
"✓ Trail period: Visual hints on hover, prevents conflicts with bookings" |
| 1182 |
); |
| 1183 |
cy.log( |
| 1184 |
"✓ CRITICAL BUG FIX: Trail period does NOT incorrectly limit max date when no conflicts" |
| 1185 |
); |
| 1186 |
cy.log( |
| 1187 |
`✓ Validated: ${leadTrailCirculationRules.bookings_lead_period}-day lead + ${maxBookingPeriod}-day max period + ${leadTrailCirculationRules.bookings_trail_period}-day trail` |
| 1188 |
); |
| 1189 |
}); |
| 1190 |
|
| 677 |
it("should show event dots for dates with existing bookings", () => { |
1191 |
it("should show event dots for dates with existing bookings", () => { |
| 678 |
/** |
1192 |
/** |
| 679 |
* Comprehensive Event Dots Visual Indicator Test |
1193 |
* Comprehensive Event Dots Visual Indicator Test |
| 680 |
- |
|
|