|
Lines 27-39
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 27 |
testData = objects; |
27 |
testData = objects; |
| 28 |
|
28 |
|
| 29 |
// Update items to be bookable with predictable itemtypes |
29 |
// Update items to be bookable with predictable itemtypes |
| 30 |
return cy.task("query", { |
30 |
return cy |
| 31 |
sql: "UPDATE items SET bookable = 1, itype = 'BK', homebranch = 'CPL', enumchron = 'A', dateaccessioned = '2024-12-03' WHERE itemnumber = ?", |
31 |
.task("query", { |
| 32 |
values: [objects.items[0].item_id], |
32 |
sql: "UPDATE items SET bookable = 1, itype = 'BK', homebranch = 'CPL', enumchron = 'A', dateaccessioned = '2024-12-03' WHERE itemnumber = ?", |
| 33 |
}).then(() => cy.task("query", { |
33 |
values: [objects.items[0].item_id], |
| 34 |
sql: "UPDATE items SET bookable = 1, itype = 'CF', homebranch = 'CPL', enumchron = 'B', dateaccessioned = '2024-12-02' WHERE itemnumber = ?", |
34 |
}) |
| 35 |
values: [objects.items[1].item_id], |
35 |
.then(() => |
| 36 |
})); |
36 |
cy.task("query", { |
|
|
37 |
sql: "UPDATE items SET bookable = 1, itype = 'CF', homebranch = 'CPL', enumchron = 'B', dateaccessioned = '2024-12-02' WHERE itemnumber = ?", |
| 38 |
values: [objects.items[1].item_id], |
| 39 |
}) |
| 40 |
); |
| 37 |
}) |
41 |
}) |
| 38 |
.then(() => { |
42 |
.then(() => { |
| 39 |
// Create a test patron using upstream pattern |
43 |
// Create a test patron using upstream pattern |
|
Lines 98-104
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 98 |
|
102 |
|
| 99 |
// Open the modal |
103 |
// Open the modal |
| 100 |
cy.get("booking-modal-island .modal").should("exist"); |
104 |
cy.get("booking-modal-island .modal").should("exist"); |
| 101 |
cy.get("[data-booking-modal]").first().then($btn => $btn[0].click()); |
105 |
cy.get("[data-booking-modal]") |
|
|
106 |
.first() |
| 107 |
.then($btn => $btn[0].click()); |
| 102 |
cy.get("booking-modal-island .modal", { timeout: 10000 }).should( |
108 |
cy.get("booking-modal-island .modal", { timeout: 10000 }).should( |
| 103 |
"be.visible" |
109 |
"be.visible" |
| 104 |
); |
110 |
); |
|
Lines 195-201
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 195 |
|
201 |
|
| 196 |
// Select the specific item that has the existing bookings (by barcode, not index) |
202 |
// Select the specific item that has the existing bookings (by barcode, not index) |
| 197 |
cy.vueSelectShouldBeEnabled("booking_item_id"); |
203 |
cy.vueSelectShouldBeEnabled("booking_item_id"); |
| 198 |
cy.vueSelect("booking_item_id", testData.items[0].external_id, testData.items[0].external_id); |
204 |
cy.vueSelect( |
|
|
205 |
"booking_item_id", |
| 206 |
testData.items[0].external_id, |
| 207 |
testData.items[0].external_id |
| 208 |
); |
| 199 |
cy.wait("@getCirculationRules"); |
209 |
cy.wait("@getCirculationRules"); |
| 200 |
|
210 |
|
| 201 |
// Verify date picker is now enabled |
211 |
// Verify date picker is now enabled |
|
Lines 380-388
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 380 |
|
390 |
|
| 381 |
// Should either succeed (modal closes) or show specific validation error |
391 |
// Should either succeed (modal closes) or show specific validation error |
| 382 |
cy.get("body").then($body => { |
392 |
cy.get("body").then($body => { |
| 383 |
if ( |
393 |
if ($body.find("booking-modal-island .modal:visible").length > 0) { |
| 384 |
$body.find("booking-modal-island .modal:visible").length > 0 |
|
|
| 385 |
) { |
| 386 |
// If modal is still visible, check for validation messages |
394 |
// If modal is still visible, check for validation messages |
| 387 |
cy.log( |
395 |
cy.log( |
| 388 |
"Modal still visible - checking for validation feedback" |
396 |
"Modal still visible - checking for validation feedback" |
|
Lines 458-467
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 458 |
dateTestCirculationRules.issuelength + |
466 |
dateTestCirculationRules.issuelength + |
| 459 |
dateTestCirculationRules.renewalsallowed * |
467 |
dateTestCirculationRules.renewalsallowed * |
| 460 |
dateTestCirculationRules.renewalperiod; // 10 + 3*5 = 25 |
468 |
dateTestCirculationRules.renewalperiod; // 10 + 3*5 = 25 |
| 461 |
const calculatedMaxDate = clearZoneStart.add( |
469 |
const calculatedMaxDate = clearZoneStart.add(maxPeriod - 1, "day"); // Day 50 + 24 = Day 74 |
| 462 |
maxPeriod - 1, |
|
|
| 463 |
"day" |
| 464 |
); // Day 50 + 24 = Day 74 |
| 465 |
|
470 |
|
| 466 |
const beyondMaxDate = calculatedMaxDate.add(1, "day"); // Day 75 |
471 |
const beyondMaxDate = calculatedMaxDate.add(1, "day"); // Day 75 |
| 467 |
|
472 |
|
|
Lines 554-579
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 554 |
}); |
559 |
}); |
| 555 |
}); |
560 |
}); |
| 556 |
|
561 |
|
| 557 |
// For dates in the currently visible month, also verify the DOM class |
562 |
// For dates in the currently visible month, also verify the DOM class. |
| 558 |
expectedBoldDates |
563 |
// Query calendarContainer directly to avoid navigation races (the |
| 559 |
.filter(d => d.month() === clearZoneStart.month()) |
564 |
// booking modal's onMonthChange handler can jump the calendar away). |
| 560 |
.forEach(boldDate => { |
565 |
cy.get("@dateTestFlatpickr").should($el => { |
| 561 |
cy.get("@dateTestFlatpickr") |
566 |
const fp = $el[0]._flatpickr; |
| 562 |
.getFlatpickrDate(boldDate.toDate()) |
567 |
// Ensure calendar shows the start date's month |
| 563 |
.should("have.class", "booking-loan-boundary"); |
568 |
if ( |
| 564 |
cy.log( |
569 |
fp.currentMonth !== clearZoneStart.month() || |
| 565 |
`✓ Day ${boldDate.format("YYYY-MM-DD")}: Has 'booking-loan-boundary' class (bold)` |
570 |
fp.currentYear !== clearZoneStart.year() |
| 566 |
); |
571 |
) { |
| 567 |
}); |
572 |
fp.jumpToDate(clearZoneStart.toDate()); |
|
|
573 |
throw new Error("Jumped to target month, retrying assertion"); |
| 574 |
} |
| 575 |
|
| 576 |
expectedBoldDates |
| 577 |
.filter(d => d.month() === clearZoneStart.month()) |
| 578 |
.forEach(boldDate => { |
| 579 |
const label = `${boldDate.format("MMMM D, YYYY")}`; |
| 580 |
const el = fp.calendarContainer.querySelector( |
| 581 |
`.flatpickr-day[aria-label="${label}"]` |
| 582 |
); |
| 583 |
expect( |
| 584 |
el, |
| 585 |
`Day ${boldDate.format("YYYY-MM-DD")} should exist` |
| 586 |
).to.not.be.null; |
| 587 |
expect( |
| 588 |
el.classList.contains("booking-loan-boundary"), |
| 589 |
`Day ${boldDate.format("YYYY-MM-DD")} should have booking-loan-boundary class` |
| 590 |
).to.be.true; |
| 591 |
}); |
| 568 |
|
592 |
|
| 569 |
// Verify that only expected dates are bold in the current view |
593 |
// Verify no unexpected bold dates in the current view |
| 570 |
cy.get(".flatpickr-day.booking-loan-boundary").each($el => { |
594 |
const boldElements = fp.calendarContainer.querySelectorAll( |
| 571 |
const ariaLabel = $el.attr("aria-label"); |
595 |
".flatpickr-day.booking-loan-boundary" |
| 572 |
const date = dayjs(ariaLabel, "MMMM D, YYYY"); |
|
|
| 573 |
const isExpected = expectedBoldDates.some(expected => |
| 574 |
date.isSame(expected, "day") |
| 575 |
); |
596 |
); |
| 576 |
expect(isExpected, `Unexpected bold date: ${ariaLabel}`).to.be.true; |
597 |
boldElements.forEach(boldEl => { |
|
|
598 |
const ariaLabel = boldEl.getAttribute("aria-label"); |
| 599 |
const date = dayjs(ariaLabel, "MMMM D, YYYY"); |
| 600 |
const isExpected = expectedBoldDates.some(expected => |
| 601 |
date.isSame(expected, "day") |
| 602 |
); |
| 603 |
expect(isExpected, `Unexpected bold date: ${ariaLabel}`).to.be |
| 604 |
.true; |
| 605 |
}); |
| 577 |
}); |
606 |
}); |
| 578 |
|
607 |
|
| 579 |
cy.log( |
608 |
cy.log( |
|
Lines 704-711
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 704 |
cy.get("@fp").openFlatpickr(); |
733 |
cy.get("@fp").openFlatpickr(); |
| 705 |
|
734 |
|
| 706 |
// Helpers that use native events to avoid detached DOM errors from Vue re-renders |
735 |
// Helpers that use native events to avoid detached DOM errors from Vue re-renders |
| 707 |
const monthNames = ["January", "February", "March", "April", "May", "June", |
736 |
const monthNames = [ |
| 708 |
"July", "August", "September", "October", "November", "December"]; |
737 |
"January", |
|
|
738 |
"February", |
| 739 |
"March", |
| 740 |
"April", |
| 741 |
"May", |
| 742 |
"June", |
| 743 |
"July", |
| 744 |
"August", |
| 745 |
"September", |
| 746 |
"October", |
| 747 |
"November", |
| 748 |
"December", |
| 749 |
]; |
| 709 |
const getDateSelector = (isoDate: string) => { |
750 |
const getDateSelector = (isoDate: string) => { |
| 710 |
const d = dayjs(isoDate); |
751 |
const d = dayjs(isoDate); |
| 711 |
return `.flatpickr-day[aria-label="${monthNames[d.month()]} ${d.date()}, ${d.year()}"]`; |
752 |
return `.flatpickr-day[aria-label="${monthNames[d.month()]} ${d.date()}, ${d.year()}"]`; |
|
Lines 714-720
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 714 |
cy.get(getDateSelector(isoDate)) |
755 |
cy.get(getDateSelector(isoDate)) |
| 715 |
.should("be.visible") |
756 |
.should("be.visible") |
| 716 |
.then($el => { |
757 |
.then($el => { |
| 717 |
$el[0].dispatchEvent(new MouseEvent("mouseover", { bubbles: true })); |
758 |
$el[0].dispatchEvent( |
|
|
759 |
new MouseEvent("mouseover", { bubbles: true }) |
| 760 |
); |
| 718 |
}); |
761 |
}); |
| 719 |
}; |
762 |
}; |
| 720 |
const clickDateByISO = (isoDate: string) => { |
763 |
const clickDateByISO = (isoDate: string) => { |
|
Lines 780-789
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 780 |
|
823 |
|
| 781 |
// Hover June 29 - Lead period (June 27-28), June 27 is in blocker booking |
824 |
// Hover June 29 - Lead period (June 27-28), June 27 is in blocker booking |
| 782 |
hoverDateByISO("2026-06-29"); |
825 |
hoverDateByISO("2026-06-29"); |
| 783 |
getDateByISO("2026-06-29").should( |
826 |
getDateByISO("2026-06-29").should("have.class", "flatpickr-disabled"); |
| 784 |
"have.class", |
|
|
| 785 |
"flatpickr-disabled" |
| 786 |
); |
| 787 |
|
827 |
|
| 788 |
// ======================================================================== |
828 |
// ======================================================================== |
| 789 |
// PHASE 3c: BIDIRECTIONAL - Lead Period Conflicts with Existing Booking TRAIL |
829 |
// PHASE 3c: BIDIRECTIONAL - Lead Period Conflicts with Existing Booking TRAIL |
|
Lines 791-807
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 791 |
|
831 |
|
| 792 |
// July 1: Lead June 29-30 → overlaps blocker trail (June 28-30) → DISABLED |
832 |
// July 1: Lead June 29-30 → overlaps blocker trail (June 28-30) → DISABLED |
| 793 |
hoverDateByISO("2026-07-01"); |
833 |
hoverDateByISO("2026-07-01"); |
| 794 |
getDateByISO("2026-07-01").should( |
834 |
getDateByISO("2026-07-01").should("have.class", "flatpickr-disabled"); |
| 795 |
"have.class", |
|
|
| 796 |
"flatpickr-disabled" |
| 797 |
); |
| 798 |
|
835 |
|
| 799 |
// July 2: Lead June 30-July 1 → June 30 in blocker trail → DISABLED |
836 |
// July 2: Lead June 30-July 1 → June 30 in blocker trail → DISABLED |
| 800 |
hoverDateByISO("2026-07-02"); |
837 |
hoverDateByISO("2026-07-02"); |
| 801 |
getDateByISO("2026-07-02").should( |
838 |
getDateByISO("2026-07-02").should("have.class", "flatpickr-disabled"); |
| 802 |
"have.class", |
|
|
| 803 |
"flatpickr-disabled" |
| 804 |
); |
| 805 |
|
839 |
|
| 806 |
// ======================================================================== |
840 |
// ======================================================================== |
| 807 |
// PHASE 3d: First Clear Start Date After Blocker's Protected Period |
841 |
// PHASE 3d: First Clear Start Date After Blocker's Protected Period |
|
Lines 823-832
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 823 |
|
857 |
|
| 824 |
// Hover June 23 - Trail (June 24-26) overlaps blocker ACTUAL (June 25-27) |
858 |
// Hover June 23 - Trail (June 24-26) overlaps blocker ACTUAL (June 25-27) |
| 825 |
hoverDateByISO("2026-06-23"); |
859 |
hoverDateByISO("2026-06-23"); |
| 826 |
getDateByISO("2026-06-23").should( |
860 |
getDateByISO("2026-06-23").should("have.class", "flatpickr-disabled"); |
| 827 |
"have.class", |
|
|
| 828 |
"flatpickr-disabled" |
| 829 |
); |
| 830 |
|
861 |
|
| 831 |
// Clear selection for next phase |
862 |
// Clear selection for next phase |
| 832 |
cy.get("#booking_period").clearFlatpickr(); |
863 |
cy.get("#booking_period").clearFlatpickr(); |
|
Lines 841-857
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 841 |
|
872 |
|
| 842 |
// Hover June 21 - Trail (June 22-24) overlaps blocker LEAD (June 23-24) → DISABLED |
873 |
// Hover June 21 - Trail (June 22-24) overlaps blocker LEAD (June 23-24) → DISABLED |
| 843 |
hoverDateByISO("2026-06-21"); |
874 |
hoverDateByISO("2026-06-21"); |
| 844 |
getDateByISO("2026-06-21").should( |
875 |
getDateByISO("2026-06-21").should("have.class", "flatpickr-disabled"); |
| 845 |
"have.class", |
|
|
| 846 |
"flatpickr-disabled" |
| 847 |
); |
| 848 |
|
876 |
|
| 849 |
// June 20 - Trail (June 21-23), June 23 overlaps blocker lead → DISABLED |
877 |
// June 20 - Trail (June 21-23), June 23 overlaps blocker lead → DISABLED |
| 850 |
hoverDateByISO("2026-06-20"); |
878 |
hoverDateByISO("2026-06-20"); |
| 851 |
getDateByISO("2026-06-20").should( |
879 |
getDateByISO("2026-06-20").should("have.class", "flatpickr-disabled"); |
| 852 |
"have.class", |
|
|
| 853 |
"flatpickr-disabled" |
| 854 |
); |
| 855 |
|
880 |
|
| 856 |
// June 19 - Trail (June 20-22) doesn't reach blocker lead (starts June 23) → NOT disabled |
881 |
// June 19 - Trail (June 20-22) doesn't reach blocker lead (starts June 23) → NOT disabled |
| 857 |
hoverDateByISO("2026-06-19"); |
882 |
hoverDateByISO("2026-06-19"); |
|
Lines 873-882
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 873 |
|
898 |
|
| 874 |
// June 20: trail (June 21-23) overlaps blocker lead (June 23-24) → DISABLED |
899 |
// June 20: trail (June 21-23) overlaps blocker lead (June 23-24) → DISABLED |
| 875 |
hoverDateByISO("2026-06-20"); |
900 |
hoverDateByISO("2026-06-20"); |
| 876 |
getDateByISO("2026-06-20").should( |
901 |
getDateByISO("2026-06-20").should("have.class", "flatpickr-disabled"); |
| 877 |
"have.class", |
|
|
| 878 |
"flatpickr-disabled" |
| 879 |
); |
| 880 |
|
902 |
|
| 881 |
// June 19: trail (June 20-22) clear of blocker lead → NOT disabled |
903 |
// June 19: trail (June 20-22) clear of blocker lead → NOT disabled |
| 882 |
hoverDateByISO("2026-06-19"); |
904 |
hoverDateByISO("2026-06-19"); |
|
Lines 1133-1146
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1133 |
let chain = cy.wrap(null); |
1155 |
let chain = cy.wrap(null); |
| 1134 |
testItems.forEach((item, index) => { |
1156 |
testItems.forEach((item, index) => { |
| 1135 |
const enumchron = String.fromCharCode(65 + index); |
1157 |
const enumchron = String.fromCharCode(65 + index); |
| 1136 |
chain = chain.then(() => cy.task("query", { |
1158 |
chain = chain.then(() => |
| 1137 |
sql: "UPDATE items SET bookable = 1, itype = 'BK', homebranch = 'CPL', enumchron = ?, dateaccessioned = ? WHERE itemnumber = ?", |
1159 |
cy.task("query", { |
| 1138 |
values: [ |
1160 |
sql: "UPDATE items SET bookable = 1, itype = 'BK', homebranch = 'CPL', enumchron = ?, dateaccessioned = ? WHERE itemnumber = ?", |
| 1139 |
enumchron, |
1161 |
values: [ |
| 1140 |
`2024-12-0${4 - index}`, |
1162 |
enumchron, |
| 1141 |
item.item_id, |
1163 |
`2024-12-0${4 - index}`, |
| 1142 |
], |
1164 |
item.item_id, |
| 1143 |
})); |
1165 |
], |
|
|
1166 |
}) |
| 1167 |
); |
| 1144 |
}); |
1168 |
}); |
| 1145 |
return chain; |
1169 |
return chain; |
| 1146 |
}) |
1170 |
}) |
|
Lines 1178-1201
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1178 |
{ item: testItems[0], start: 10, end: 15 }, // ITEM 0 |
1202 |
{ item: testItems[0], start: 10, end: 15 }, // ITEM 0 |
| 1179 |
{ item: testItems[1], start: 13, end: 20 }, // ITEM 1 |
1203 |
{ item: testItems[1], start: 13, end: 20 }, // ITEM 1 |
| 1180 |
{ item: testItems[2], start: 18, end: 25 }, // ITEM 2 |
1204 |
{ item: testItems[2], start: 18, end: 25 }, // ITEM 2 |
| 1181 |
{ item: testItems[3], start: 1, end: 7 }, // ITEM 3 |
1205 |
{ item: testItems[3], start: 1, end: 7 }, // ITEM 3 |
| 1182 |
{ item: testItems[3], start: 23, end: 30 }, // ITEM 3 |
1206 |
{ item: testItems[3], start: 23, end: 30 }, // ITEM 3 |
| 1183 |
]; |
1207 |
]; |
| 1184 |
let chain = cy.wrap(null); |
1208 |
let chain = cy.wrap(null); |
| 1185 |
bookings.forEach(b => { |
1209 |
bookings.forEach(b => { |
| 1186 |
chain = chain.then(() => cy.task("query", { |
1210 |
chain = chain.then(() => |
| 1187 |
sql: `INSERT INTO bookings (biblio_id, patron_id, item_id, pickup_library_id, start_date, end_date, status) |
1211 |
cy.task("query", { |
|
|
1212 |
sql: `INSERT INTO bookings (biblio_id, patron_id, item_id, pickup_library_id, start_date, end_date, status) |
| 1188 |
VALUES (?, ?, ?, ?, ?, ?, ?)`, |
1213 |
VALUES (?, ?, ?, ?, ?, ?, ?)`, |
| 1189 |
values: [ |
1214 |
values: [ |
| 1190 |
testBiblio.biblio_id, |
1215 |
testBiblio.biblio_id, |
| 1191 |
testPatron.patron_id, |
1216 |
testPatron.patron_id, |
| 1192 |
b.item.item_id, |
1217 |
b.item.item_id, |
| 1193 |
"CPL", |
1218 |
"CPL", |
| 1194 |
today.add(b.start, "day").format("YYYY-MM-DD"), |
1219 |
today.add(b.start, "day").format("YYYY-MM-DD"), |
| 1195 |
today.add(b.end, "day").format("YYYY-MM-DD"), |
1220 |
today.add(b.end, "day").format("YYYY-MM-DD"), |
| 1196 |
"new", |
1221 |
"new", |
| 1197 |
], |
1222 |
], |
| 1198 |
})); |
1223 |
}) |
|
|
1224 |
); |
| 1199 |
}); |
1225 |
}); |
| 1200 |
return chain; |
1226 |
return chain; |
| 1201 |
}) |
1227 |
}) |
|
Lines 1213-1219
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1213 |
); |
1239 |
); |
| 1214 |
|
1240 |
|
| 1215 |
cy.get("booking-modal-island .modal").should("exist"); |
1241 |
cy.get("booking-modal-island .modal").should("exist"); |
| 1216 |
cy.get("[data-booking-modal]").first().then($btn => $btn[0].click()); |
1242 |
cy.get("[data-booking-modal]") |
|
|
1243 |
.first() |
| 1244 |
.then($btn => $btn[0].click()); |
| 1217 |
cy.get("booking-modal-island .modal", { |
1245 |
cy.get("booking-modal-island .modal", { |
| 1218 |
timeout: 10000, |
1246 |
timeout: 10000, |
| 1219 |
}).should("be.visible"); |
1247 |
}).should("be.visible"); |
|
Lines 1272-1291
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1272 |
// SCENARIO 1: Start day 5 |
1300 |
// SCENARIO 1: Start day 5 |
| 1273 |
cy.log("=== Scenario 1: Start day 5 ==="); |
1301 |
cy.log("=== Scenario 1: Start day 5 ==="); |
| 1274 |
cy.get("@flatpickrInput").openFlatpickr(); |
1302 |
cy.get("@flatpickrInput").openFlatpickr(); |
| 1275 |
cy.get("@flatpickrInput") |
1303 |
cy.get("@flatpickrInput").selectFlatpickrDate( |
| 1276 |
.selectFlatpickrDate(today.add(5, "day").toDate()); |
1304 |
today.add(5, "day").toDate() |
|
|
1305 |
); |
| 1277 |
|
1306 |
|
| 1278 |
checkDatesAvailable(6, 17); |
1307 |
checkDatesAvailable(6, 17); |
| 1279 |
checkDatesDisabled(18, 20); |
1308 |
checkDatesDisabled(18, 20); |
| 1280 |
|
1309 |
|
| 1281 |
// SCENARIO 2: Start day 8 |
1310 |
// SCENARIO 2: Start day 8 |
| 1282 |
cy.log( |
1311 |
cy.log("=== Scenario 2: Start day 8 (all items available) ==="); |
| 1283 |
"=== Scenario 2: Start day 8 (all items available) ===" |
|
|
| 1284 |
); |
| 1285 |
cy.get("@flatpickrInput").clearFlatpickr(); |
1312 |
cy.get("@flatpickrInput").clearFlatpickr(); |
| 1286 |
cy.get("@flatpickrInput").openFlatpickr(); |
1313 |
cy.get("@flatpickrInput").openFlatpickr(); |
| 1287 |
cy.get("@flatpickrInput") |
1314 |
cy.get("@flatpickrInput").selectFlatpickrDate( |
| 1288 |
.selectFlatpickrDate(today.add(8, "day").toDate()); |
1315 |
today.add(8, "day").toDate() |
|
|
1316 |
); |
| 1289 |
|
1317 |
|
| 1290 |
checkDatesAvailable(9, 22); |
1318 |
checkDatesAvailable(9, 22); |
| 1291 |
checkDatesDisabled(23, 25); |
1319 |
checkDatesDisabled(23, 25); |
|
Lines 1294-1301
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1294 |
cy.log("=== Scenario 3: Start day 19 ==="); |
1322 |
cy.log("=== Scenario 3: Start day 19 ==="); |
| 1295 |
cy.get("@flatpickrInput").clearFlatpickr(); |
1323 |
cy.get("@flatpickrInput").clearFlatpickr(); |
| 1296 |
cy.get("@flatpickrInput").openFlatpickr(); |
1324 |
cy.get("@flatpickrInput").openFlatpickr(); |
| 1297 |
cy.get("@flatpickrInput") |
1325 |
cy.get("@flatpickrInput").selectFlatpickrDate( |
| 1298 |
.selectFlatpickrDate(today.add(19, "day").toDate()); |
1326 |
today.add(19, "day").toDate() |
|
|
1327 |
); |
| 1299 |
|
1328 |
|
| 1300 |
checkDatesAvailable(20, 25); |
1329 |
checkDatesAvailable(20, 25); |
| 1301 |
}); |
1330 |
}); |
|
Lines 1356-1369
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1356 |
let chain = cy.wrap(null); |
1385 |
let chain = cy.wrap(null); |
| 1357 |
testItems.forEach((item, index) => { |
1386 |
testItems.forEach((item, index) => { |
| 1358 |
const enumchron = String.fromCharCode(65 + index); |
1387 |
const enumchron = String.fromCharCode(65 + index); |
| 1359 |
chain = chain.then(() => cy.task("query", { |
1388 |
chain = chain.then(() => |
| 1360 |
sql: "UPDATE items SET bookable = 1, itype = 'BK', homebranch = 'CPL', enumchron = ?, dateaccessioned = ? WHERE itemnumber = ?", |
1389 |
cy.task("query", { |
| 1361 |
values: [ |
1390 |
sql: "UPDATE items SET bookable = 1, itype = 'BK', homebranch = 'CPL', enumchron = ?, dateaccessioned = ? WHERE itemnumber = ?", |
| 1362 |
enumchron, |
1391 |
values: [ |
| 1363 |
`2024-12-0${4 - index}`, |
1392 |
enumchron, |
| 1364 |
item.item_id, |
1393 |
`2024-12-0${4 - index}`, |
| 1365 |
], |
1394 |
item.item_id, |
| 1366 |
})); |
1395 |
], |
|
|
1396 |
}) |
| 1397 |
); |
| 1367 |
}); |
1398 |
}); |
| 1368 |
return chain; |
1399 |
return chain; |
| 1369 |
}) |
1400 |
}) |
|
Lines 1397-1427
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1397 |
}) |
1428 |
}) |
| 1398 |
.then(() => { |
1429 |
.then(() => { |
| 1399 |
// Create bookings on ITEM 0 and ITEM 1 for days 10-12 |
1430 |
// Create bookings on ITEM 0 and ITEM 1 for days 10-12 |
| 1400 |
return cy.task("query", { |
1431 |
return cy |
| 1401 |
sql: `INSERT INTO bookings (biblio_id, patron_id, item_id, pickup_library_id, start_date, end_date, status) |
1432 |
.task("query", { |
|
|
1433 |
sql: `INSERT INTO bookings (biblio_id, patron_id, item_id, pickup_library_id, start_date, end_date, status) |
| 1402 |
VALUES (?, ?, ?, ?, ?, ?, ?)`, |
1434 |
VALUES (?, ?, ?, ?, ?, ?, ?)`, |
| 1403 |
values: [ |
1435 |
values: [ |
| 1404 |
testBiblio.biblio_id, |
1436 |
testBiblio.biblio_id, |
| 1405 |
testPatron.patron_id, |
1437 |
testPatron.patron_id, |
| 1406 |
testItems[0].item_id, |
1438 |
testItems[0].item_id, |
| 1407 |
"CPL", |
1439 |
"CPL", |
| 1408 |
today.add(10, "day").format("YYYY-MM-DD"), |
1440 |
today.add(10, "day").format("YYYY-MM-DD"), |
| 1409 |
today.add(12, "day").format("YYYY-MM-DD"), |
1441 |
today.add(12, "day").format("YYYY-MM-DD"), |
| 1410 |
"new", |
1442 |
"new", |
| 1411 |
], |
1443 |
], |
| 1412 |
}).then(() => cy.task("query", { |
1444 |
}) |
| 1413 |
sql: `INSERT INTO bookings (biblio_id, patron_id, item_id, pickup_library_id, start_date, end_date, status) |
1445 |
.then(() => |
|
|
1446 |
cy.task("query", { |
| 1447 |
sql: `INSERT INTO bookings (biblio_id, patron_id, item_id, pickup_library_id, start_date, end_date, status) |
| 1414 |
VALUES (?, ?, ?, ?, ?, ?, ?)`, |
1448 |
VALUES (?, ?, ?, ?, ?, ?, ?)`, |
| 1415 |
values: [ |
1449 |
values: [ |
| 1416 |
testBiblio.biblio_id, |
1450 |
testBiblio.biblio_id, |
| 1417 |
testPatron.patron_id, |
1451 |
testPatron.patron_id, |
| 1418 |
testItems[1].item_id, |
1452 |
testItems[1].item_id, |
| 1419 |
"CPL", |
1453 |
"CPL", |
| 1420 |
today.add(10, "day").format("YYYY-MM-DD"), |
1454 |
today.add(10, "day").format("YYYY-MM-DD"), |
| 1421 |
today.add(12, "day").format("YYYY-MM-DD"), |
1455 |
today.add(12, "day").format("YYYY-MM-DD"), |
| 1422 |
"new", |
1456 |
"new", |
| 1423 |
], |
1457 |
], |
| 1424 |
})); |
1458 |
}) |
|
|
1459 |
); |
| 1425 |
}) |
1460 |
}) |
| 1426 |
.then(() => { |
1461 |
.then(() => { |
| 1427 |
cy.intercept( |
1462 |
cy.intercept( |
|
Lines 1437-1443
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1437 |
); |
1472 |
); |
| 1438 |
|
1473 |
|
| 1439 |
cy.get("booking-modal-island .modal").should("exist"); |
1474 |
cy.get("booking-modal-island .modal").should("exist"); |
| 1440 |
cy.get("[data-booking-modal]").first().then($btn => $btn[0].click()); |
1475 |
cy.get("[data-booking-modal]") |
|
|
1476 |
.first() |
| 1477 |
.then($btn => $btn[0].click()); |
| 1441 |
cy.get("booking-modal-island .modal", { |
1478 |
cy.get("booking-modal-island .modal", { |
| 1442 |
timeout: 10000, |
1479 |
timeout: 10000, |
| 1443 |
}).should("be.visible"); |
1480 |
}).should("be.visible"); |
|
Lines 1470-1477
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1470 |
); |
1507 |
); |
| 1471 |
|
1508 |
|
| 1472 |
cy.get("@flatpickrInput").openFlatpickr(); |
1509 |
cy.get("@flatpickrInput").openFlatpickr(); |
| 1473 |
cy.get("@flatpickrInput") |
1510 |
cy.get("@flatpickrInput").hoverFlatpickrDate( |
| 1474 |
.hoverFlatpickrDate(today.add(15, "day").toDate()); |
1511 |
today.add(15, "day").toDate() |
|
|
1512 |
); |
| 1475 |
|
1513 |
|
| 1476 |
// Day 15 should NOT be disabled (at least one item is free) |
1514 |
// Day 15 should NOT be disabled (at least one item is free) |
| 1477 |
cy.get("@flatpickrInput") |
1515 |
cy.get("@flatpickrInput") |
|
Lines 1479-1486
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1479 |
.should("not.have.class", "flatpickr-disabled"); |
1517 |
.should("not.have.class", "flatpickr-disabled"); |
| 1480 |
|
1518 |
|
| 1481 |
// Actually click day 15 to verify it's selectable |
1519 |
// Actually click day 15 to verify it's selectable |
| 1482 |
cy.get("@flatpickrInput") |
1520 |
cy.get("@flatpickrInput").selectFlatpickrDate( |
| 1483 |
.selectFlatpickrDate(today.add(15, "day").toDate()); |
1521 |
today.add(15, "day").toDate() |
|
|
1522 |
); |
| 1484 |
|
1523 |
|
| 1485 |
// Reset for next scenario |
1524 |
// Reset for next scenario |
| 1486 |
cy.get("@flatpickrInput").clearFlatpickr(); |
1525 |
cy.get("@flatpickrInput").clearFlatpickr(); |
|
Lines 1512-1518
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1512 |
); |
1551 |
); |
| 1513 |
|
1552 |
|
| 1514 |
cy.get("booking-modal-island .modal").should("exist"); |
1553 |
cy.get("booking-modal-island .modal").should("exist"); |
| 1515 |
cy.get("[data-booking-modal]").first().then($btn => $btn[0].click()); |
1554 |
cy.get("[data-booking-modal]") |
|
|
1555 |
.first() |
| 1556 |
.then($btn => $btn[0].click()); |
| 1516 |
cy.get("booking-modal-island .modal", { |
1557 |
cy.get("booking-modal-island .modal", { |
| 1517 |
timeout: 10000, |
1558 |
timeout: 10000, |
| 1518 |
}).should("be.visible"); |
1559 |
}).should("be.visible"); |
|
Lines 1538-1545
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1538 |
cy.get("#booking_period").as("flatpickrInput2"); |
1579 |
cy.get("#booking_period").as("flatpickrInput2"); |
| 1539 |
|
1580 |
|
| 1540 |
cy.get("@flatpickrInput2").openFlatpickr(); |
1581 |
cy.get("@flatpickrInput2").openFlatpickr(); |
| 1541 |
cy.get("@flatpickrInput2") |
1582 |
cy.get("@flatpickrInput2").hoverFlatpickrDate( |
| 1542 |
.hoverFlatpickrDate(today.add(15, "day").toDate()); |
1583 |
today.add(15, "day").toDate() |
|
|
1584 |
); |
| 1543 |
|
1585 |
|
| 1544 |
// Day 15 should NOW be disabled (all items have conflicts) |
1586 |
// Day 15 should NOW be disabled (all items have conflicts) |
| 1545 |
cy.get("@flatpickrInput2") |
1587 |
cy.get("@flatpickrInput2") |
|
Lines 1555-1562
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1555 |
|
1597 |
|
| 1556 |
// Hover a date whose trail overlaps with bookings |
1598 |
// Hover a date whose trail overlaps with bookings |
| 1557 |
// Day 13 trail should get hover-trail class on hover |
1599 |
// Day 13 trail should get hover-trail class on hover |
| 1558 |
cy.get("@flatpickrInput2") |
1600 |
cy.get("@flatpickrInput2").hoverFlatpickrDate( |
| 1559 |
.hoverFlatpickrDate(today.add(13, "day").toDate()); |
1601 |
today.add(13, "day").toDate() |
|
|
1602 |
); |
| 1560 |
cy.get("@flatpickrInput2") |
1603 |
cy.get("@flatpickrInput2") |
| 1561 |
.getFlatpickrDate(today.add(13, "day").toDate()) |
1604 |
.getFlatpickrDate(today.add(13, "day").toDate()) |
| 1562 |
.should("have.class", "booking-day--hover-trail"); |
1605 |
.should("have.class", "booking-day--hover-trail"); |
|
Lines 1569-1576
describe("Booking Modal Date Picker Tests", () => {
Link Here
|
| 1569 |
); |
1612 |
); |
| 1570 |
|
1613 |
|
| 1571 |
// Hover a date whose lead period overlaps with bookings |
1614 |
// Hover a date whose lead period overlaps with bookings |
| 1572 |
cy.get("@flatpickrInput2") |
1615 |
cy.get("@flatpickrInput2").hoverFlatpickrDate( |
| 1573 |
.hoverFlatpickrDate(today.add(8, "day").toDate()); |
1616 |
today.add(8, "day").toDate() |
|
|
1617 |
); |
| 1574 |
cy.get("@flatpickrInput2") |
1618 |
cy.get("@flatpickrInput2") |
| 1575 |
.getFlatpickrDate(today.add(8, "day").toDate()) |
1619 |
.getFlatpickrDate(today.add(8, "day").toDate()) |
| 1576 |
.should("have.class", "booking-day--hover-lead"); |
1620 |
.should("have.class", "booking-day--hover-lead"); |