Bugzilla – Attachment 182772 Details for
Bug 39916
The 'Place booking' modal should have cypress tests
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 39916: Add flatpickr helpers to cypress
Bug-39916-Add-flatpickr-helpers-to-cypress.patch (text/plain), 44.44 KB, created by
Martin Renvoize (ashimema)
on 2025-05-23 15:31:26 UTC
(
hide
)
Description:
Bug 39916: Add flatpickr helpers to cypress
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2025-05-23 15:31:26 UTC
Size:
44.44 KB
patch
obsolete
>From 219525bd6f20b50b2944a1299e83f22327a053ba Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@openfifth.co.uk> >Date: Mon, 19 May 2025 13:29:49 +0100 >Subject: [PATCH] Bug 39916: Add flatpickr helpers to cypress > >--- > t/cypress/support/e2e.js | 1 + > t/cypress/support/flatpickr.js | 1049 ++++++++++++++++++++++++++++++++ > 2 files changed, 1050 insertions(+) > create mode 100644 t/cypress/support/flatpickr.js > >diff --git a/t/cypress/support/e2e.js b/t/cypress/support/e2e.js >index 96250ac2bbc..0777212dd42 100644 >--- a/t/cypress/support/e2e.js >+++ b/t/cypress/support/e2e.js >@@ -26,6 +26,7 @@ > > // Import Select2 helpers > import "./select2"; >+import "./flatpickr.js"; > > function get_fallback_login_value(param) { > var env_var = param == "username" ? "KOHA_USER" : "KOHA_PASS"; >diff --git a/t/cypress/support/flatpickr.js b/t/cypress/support/flatpickr.js >new file mode 100644 >index 00000000000..2347360d674 >--- /dev/null >+++ b/t/cypress/support/flatpickr.js >@@ -0,0 +1,1049 @@ >+// flatpickrHelpers.js - Reusable Cypress functions for Flatpickr date pickers >+ >+/** >+ * Helper functions for interacting with Flatpickr date picker components in Cypress tests >+ * Uses click-driven interactions instead of Flatpickr's JavaScript API >+ * Supports all standard Flatpickr operations including date selection, range selection, >+ * navigation, and direct input with full chainability >+ * >+ * CHAINABILITY: >+ * All Flatpickr helper commands are fully chainable. You can: >+ * - Chain multiple Flatpickr operations (open, navigate, select) >+ * - Chain Flatpickr commands with standard Cypress commands >+ * - Split complex interactions into multiple steps for better reliability >+ * >+ * Examples: >+ * cy.getFlatpickr('#myDatepicker') >+ * .flatpickr({ open: true }) >+ * .flatpickr({ selectDate: '2023-05-15' }); >+ * >+ * cy.getFlatpickr('#rangePicker') >+ * .flatpickr({ open: true }) >+ * .flatpickr({ selectRange: ['2023-06-01', '2023-06-15'] }) >+ * .should('have.value', '2023-06-01 to 2023-06-15'); >+ */ >+ >+/** >+ * Main Flatpickr interaction command to perform operations on Flatpickr date pickers >+ * @param {string|JQuery} [subject] - Optional jQuery element (when used with .flatpickr()) >+ * @param {Object} options - Configuration options for the Flatpickr operation >+ * @param {boolean} [options.open=false] - Whether to open the Flatpickr calendar >+ * @param {boolean} [options.close=false] - Whether to close the Flatpickr calendar >+ * @param {boolean} [options.clear=false] - Whether to clear the current selection >+ * @param {string|Date} [options.selectDate] - Date to select (YYYY-MM-DD string or Date object) >+ * @param {Array} [options.selectRange] - Array with start and end dates for range selection >+ * @param {string} [options.typeDate] - Date string to type directly into the input >+ * @param {string|Date} [options.navigateToMonth] - Navigate to specified month/year >+ * @param {number} [options.selectDay] - Day of month to select from current month view >+ * @param {boolean} [options.nextMonth=false] - Whether to navigate to next month >+ * @param {boolean} [options.prevMonth=false] - Whether to navigate to previous month >+ * @param {number} [options.setYear] - Year to set in the calendar >+ * @param {boolean} [options.selectToday=false] - Whether to select today's date >+ * @param {string} [options.selector] - CSS selector to find the element (when not using subject) >+ * @param {number} [options.timeout=10000] - Timeout for operations in milliseconds >+ * @returns {Cypress.Chainable} - Returns a chainable Cypress object for further commands >+ * >+ * @example >+ * // Basic usage >+ * cy.get('#myDatepicker').flatpickr({ selectDate: '2023-05-15' }); >+ * >+ * @example >+ * // Chained operations (more reliable for complex interactions) >+ * cy.getFlatpickr('#myDatepicker') >+ * .flatpickr({ open: true }) >+ * .flatpickr({ navigateToMonth: '2023-06-01' }) >+ * .flatpickr({ selectDay: 15 }); >+ * >+ * @example >+ * // Date range selection >+ * cy.getFlatpickr('#rangePicker').flatpickr({ >+ * selectRange: ['2023-06-01', '2023-06-15'] >+ * }); >+ */ >+Cypress.Commands.add( >+ "flatpickr", >+ { >+ prevSubject: "optional", >+ }, >+ (subject, options) => { >+ // Default configuration >+ const defaults = { >+ open: false, // Whether to open the Flatpickr calendar >+ close: false, // Whether to close the Flatpickr calendar >+ clear: false, // Whether to clear the current selection >+ selectDate: null, // Date to select (YYYY-MM-DD string or Date object) >+ selectRange: null, // Array with start and end dates for range selection >+ typeDate: null, // Date string to type directly into the input >+ navigateToMonth: null, // Navigate to specified month/year >+ selectDay: null, // Day of month to select from current month view >+ nextMonth: false, // Whether to navigate to next month >+ prevMonth: false, // Whether to navigate to previous month >+ setYear: null, // Year to set in the calendar >+ selectToday: false, // Whether to select today's date >+ selector: null, // CSS selector to find the element (when not using subject) >+ timeout: 10000, // Timeout for operations in milliseconds >+ }; >+ >+ // Merge passed options with defaults >+ const config = { ...defaults, ...options }; >+ >+ // Handle selecting the target Flatpickr element >+ let $originalInput; >+ if (subject) { >+ $originalInput = subject; >+ // Store the element ID as a data attribute for chaining >+ cy.wrap(subject).then($el => { >+ const inputId = $el.attr("id"); >+ if (inputId) { >+ Cypress.$($el).attr("data-flatpickr-helper-id", inputId); >+ } >+ }); >+ } else if (config.selector) { >+ $originalInput = cy.get(config.selector); >+ } else { >+ throw new Error( >+ "Either provide a subject or a selector to identify the Flatpickr element" >+ ); >+ } >+ >+ return cy.wrap($originalInput).then($el => { >+ // Try to get the ID either from the element or from the stored data attribute >+ const inputId = $el.attr("id") || $el.data("flatpickr-helper-id"); >+ const originalInputSelector = inputId ? `#${inputId}` : null; >+ >+ // Get the visible flatpickr input element >+ const getVisibleInput = () => { >+ if (originalInputSelector) { >+ return cy >+ .get(originalInputSelector) >+ .parents() >+ .find(".flatpickr_wrapper input.flatpickr-input"); >+ } else { >+ return cy >+ .wrap($el) >+ .parents() >+ .find(".flatpickr_wrapper input.flatpickr-input"); >+ } >+ }; >+ >+ // Open the Flatpickr calendar if requested >+ if (config.open) { >+ cy.get(".flatpickr-calendar").then($calendar => { >+ const isVisible = >+ $calendar.hasClass("open") && $calendar.is(":visible"); >+ >+ if (!isVisible) { >+ getVisibleInput().click(); >+ } >+ >+ // Always wait for the calendar to be visible â retry if necessary >+ cy.get(".flatpickr-calendar.open", { >+ timeout: config.timeout, >+ }).should("be.visible"); >+ }); >+ } >+ >+ // Close the Flatpickr calendar if requested >+ if (config.close) { >+ cy.get("body").click(0, 0); >+ cy.get(".flatpickr-calendar.open").should("not.exist", { >+ timeout: config.timeout, >+ }); >+ } >+ >+ // Clear the Flatpickr input if requested >+ if (config.clear) { >+ cy.wrap($el).parents().find(".clear_date").click(); >+ cy.wrap($el).should("have.value", ""); >+ getVisibleInput().should("have.value", ""); >+ } >+ >+ // Navigate to a specific month/year if requested >+ if (config.navigateToMonth !== null) { >+ // Ensure calendar is open >+ if (!config.open) { >+ cy.get(".flatpickr-calendar").then($calendar => { >+ const isVisible = >+ $calendar.hasClass("open") && >+ $calendar.is(":visible"); >+ >+ if (!isVisible) { >+ getVisibleInput().click(); >+ } >+ >+ // Always wait for the calendar to be visible â retry if necessary >+ cy.get(".flatpickr-calendar.open", { >+ timeout: config.timeout, >+ }).should("be.visible"); >+ }); >+ } >+ >+ // Convert to Date object if string was provided >+ const dateObj = >+ typeof config.navigateToMonth === "string" >+ ? new Date(config.navigateToMonth) >+ : config.navigateToMonth; >+ >+ const targetYear = dateObj.getFullYear(); >+ const targetMonth = dateObj.getMonth(); // 0-based index >+ >+ // Click-based navigation to the correct month and year >+ cy.get(".flatpickr-current-month").then($currentMonth => { >+ cy.log("Inside currentMonth"); >+ cy.get(".flatpickr-current-month .numInput.cur-year").then( >+ $currentYear => { >+ // Parse the current month and year from the calendar display >+ const currentMonthName = $currentMonth >+ .text() >+ .trim(); >+ const monthNames = [ >+ "January", >+ "February", >+ "March", >+ "April", >+ "May", >+ "June", >+ "July", >+ "August", >+ "September", >+ "October", >+ "November", >+ "December", >+ ]; >+ const currentMonth = monthNames.findIndex(name => >+ currentMonthName.includes(name) >+ ); >+ const currentYear = parseInt($currentYear.val()); >+ >+ // Calculate the number of months to move forward or backward >+ const monthDiff = >+ (targetYear - currentYear) * 12 + >+ (targetMonth - currentMonth); >+ >+ if (monthDiff > 0) { >+ // Click next month button the appropriate number of times >+ for (let i = 0; i < monthDiff; i++) { >+ cy.get(".flatpickr-next-month").click(); >+ cy.wait(100); // Give time for the calendar to update >+ } >+ } else if (monthDiff < 0) { >+ // Click previous month button the appropriate number of times >+ for (let i = 0; i < Math.abs(monthDiff); i++) { >+ cy.get(".flatpickr-prev-month").click(); >+ cy.wait(100); // Give time for the calendar to update >+ } >+ } >+ } >+ ); >+ }); >+ } >+ >+ // Move to next month if requested >+ if (config.nextMonth) { >+ // Ensure calendar is open >+ if (!config.open && !config.navigateToMonth) { >+ cy.get(".flatpickr-calendar").then($calendar => { >+ const isVisible = >+ $calendar.hasClass("open") && >+ $calendar.is(":visible"); >+ >+ if (!isVisible) { >+ getVisibleInput().click(); >+ } >+ >+ // Always wait for the calendar to be visible â retry if necessary >+ cy.get(".flatpickr-calendar.open", { >+ timeout: config.timeout, >+ }).should("be.visible"); >+ }); >+ } >+ >+ cy.get(".flatpickr-next-month").click(); >+ cy.wait(100); // Give time for the calendar to update >+ } >+ >+ // Move to previous month if requested >+ if (config.prevMonth) { >+ // Ensure calendar is open >+ if ( >+ !config.open && >+ !config.navigateToMonth && >+ !config.nextMonth >+ ) { >+ cy.get(".flatpickr-calendar").then($calendar => { >+ const isVisible = >+ $calendar.hasClass("open") && >+ $calendar.is(":visible"); >+ >+ if (!isVisible) { >+ getVisibleInput().click(); >+ } >+ >+ // Always wait for the calendar to be visible â retry if necessary >+ cy.get(".flatpickr-calendar.open", { >+ timeout: config.timeout, >+ }).should("be.visible"); >+ }); >+ } >+ >+ cy.get(".flatpickr-prev-month").click(); >+ cy.wait(100); // Give time for the calendar to update >+ } >+ >+ // Set year if requested - using click interactions on year input >+ if (config.setYear !== null) { >+ // Ensure calendar is open >+ if ( >+ !config.open && >+ !config.navigateToMonth && >+ !config.nextMonth && >+ !config.prevMonth >+ ) { >+ cy.get(".flatpickr-calendar").then($calendar => { >+ const isVisible = >+ $calendar.hasClass("open") && >+ $calendar.is(":visible"); >+ >+ if (!isVisible) { >+ getVisibleInput().click(); >+ } >+ >+ // Always wait for the calendar to be visible â retry if necessary >+ cy.get(".flatpickr-calendar.open", { >+ timeout: config.timeout, >+ }).should("be.visible"); >+ }); >+ } >+ >+ const yearNum = parseInt(config.setYear, 10); >+ >+ // Click on the year input to focus it >+ cy.get(".flatpickr-current-month .numInput.cur-year").click(); >+ >+ // Clear the current year and type the new year >+ cy.get(".flatpickr-current-month .numInput.cur-year") >+ .clear() >+ .type(yearNum.toString(), { force: true }) >+ .type("{enter}"); >+ >+ cy.wait(100); // Give time for the calendar to update >+ } >+ >+ // Select a specific day from the current month view if requested >+ if (config.selectDay !== null) { >+ // Ensure calendar is open >+ if ( >+ !config.open && >+ !config.navigateToMonth && >+ !config.nextMonth && >+ !config.prevMonth && >+ !config.setYear >+ ) { >+ cy.get(".flatpickr-calendar").then($calendar => { >+ const isVisible = >+ $calendar.hasClass("open") && >+ $calendar.is(":visible"); >+ >+ if (!isVisible) { >+ getVisibleInput().click(); >+ } >+ >+ // Always wait for the calendar to be visible â retry if necessary >+ cy.get(".flatpickr-calendar.open", { >+ timeout: config.timeout, >+ }).should("be.visible"); >+ }); >+ } >+ >+ const dayNum = parseInt(config.selectDay, 10); >+ >+ // Get current month and year from the calendar display >+ cy.get(".flatpickr-current-month").then($currentMonth => { >+ cy.get(".flatpickr-current-month .numInput.cur-year").then( >+ $currentYear => { >+ const currentMonthName = $currentMonth >+ .text() >+ .trim(); >+ const monthNames = [ >+ "January", >+ "February", >+ "March", >+ "April", >+ "May", >+ "June", >+ "July", >+ "August", >+ "September", >+ "October", >+ "November", >+ "December", >+ ]; >+ const currentMonth = monthNames.findIndex(name => >+ currentMonthName.includes(name) >+ ); >+ const currentYear = parseInt($currentYear.val()); >+ >+ // Format the aria-label for the target day >+ const formattedDayLabel = `${monthNames[currentMonth]} ${dayNum}, ${currentYear}`; >+ >+ // Select the day using aria-label >+ cy.get( >+ `.flatpickr-day[aria-label="${formattedDayLabel}"]` >+ ).click(); >+ } >+ ); >+ }); >+ >+ // Verify the selection was made >+ cy.wrap($el).should("not.have.value", ""); >+ } >+ >+ // Select today's date if requested >+ if (config.selectToday) { >+ // Ensure calendar is open >+ if ( >+ !config.open && >+ !config.navigateToMonth && >+ !config.nextMonth && >+ !config.prevMonth && >+ !config.setYear && >+ !config.selectDay >+ ) { >+ cy.get(".flatpickr-calendar").then($calendar => { >+ const isVisible = >+ $calendar.hasClass("open") && >+ $calendar.is(":visible"); >+ >+ if (!isVisible) { >+ getVisibleInput().click(); >+ } >+ >+ // Always wait for the calendar to be visible â retry if necessary >+ cy.get(".flatpickr-calendar.open", { >+ timeout: config.timeout, >+ }).should("be.visible"); >+ }); >+ } >+ >+ cy.get(".flatpickr-day.today").click(); >+ >+ // Verify the selection was made >+ cy.wrap($el).should("not.have.value", ""); >+ } >+ >+ // Select a specific date if requested >+ if (config.selectDate !== null) { >+ // Ensure calendar is open >+ if ( >+ !config.open && >+ !config.navigateToMonth && >+ !config.nextMonth && >+ !config.prevMonth && >+ !config.setYear && >+ !config.selectDay && >+ !config.selectToday >+ ) { >+ cy.get(".flatpickr-calendar").then($calendar => { >+ const isVisible = >+ $calendar.hasClass("open") && >+ $calendar.is(":visible"); >+ >+ if (!isVisible) { >+ getVisibleInput().click(); >+ } >+ >+ // Always wait for the calendar to be visible â retry if necessary >+ cy.get(".flatpickr-calendar.open", { >+ timeout: config.timeout, >+ }).should("be.visible"); >+ }); >+ } >+ >+ // Convert to Date object if string was provided >+ const dateObj = >+ typeof config.selectDate === "string" >+ ? new Date(config.selectDate) >+ : config.selectDate; >+ >+ const targetYear = dateObj.getFullYear(); >+ const targetMonth = dateObj.getMonth(); // 0-based index >+ const targetDay = dateObj.getDate(); >+ >+ // Click-based navigation to the correct month and year >+ cy.get(".flatpickr-current-month").then($currentMonth => { >+ cy.get(".flatpickr-current-month .numInput.cur-year").then( >+ $currentYear => { >+ // Parse the current month and year from the calendar display >+ const currentMonthName = $currentMonth >+ .text() >+ .trim(); >+ const monthNames = [ >+ "January", >+ "February", >+ "March", >+ "April", >+ "May", >+ "June", >+ "July", >+ "August", >+ "September", >+ "October", >+ "November", >+ "December", >+ ]; >+ const currentMonth = monthNames.findIndex(name => >+ currentMonthName.includes(name) >+ ); >+ const currentYear = parseInt($currentYear.val()); >+ >+ // Calculate the number of months to move forward or backward >+ const monthDiff = >+ (targetYear - currentYear) * 12 + >+ (targetMonth - currentMonth); >+ >+ if (monthDiff > 0) { >+ // Click next month button the appropriate number of times >+ for (let i = 0; i < monthDiff; i++) { >+ cy.get(".flatpickr-next-month").click(); >+ cy.wait(100); // Give time for the calendar to update >+ } >+ } else if (monthDiff < 0) { >+ // Click previous month button the appropriate number of times >+ for (let i = 0; i < Math.abs(monthDiff); i++) { >+ cy.get(".flatpickr-prev-month").click(); >+ cy.wait(100); // Give time for the calendar to update >+ } >+ } >+ >+ // Format the aria-label for the target date >+ const formattedDateLabel = `${monthNames[targetMonth]} ${targetDay}, ${targetYear}`; >+ >+ // Select the day using aria-label >+ cy.get( >+ `.flatpickr-day[aria-label="${formattedDateLabel}"]` >+ ).click(); >+ } >+ ); >+ }); >+ >+ // Verify the selection was made >+ cy.wait(200); >+ const formattedDate = `${targetYear}-${(targetMonth + 1).toString().padStart(2, "0")}-${targetDay.toString().padStart(2, "0")}`; >+ cy.wrap($el).should("have.value", formattedDate); >+ } >+ >+ // Select a date range if requested >+ if (config.selectRange !== null) { >+ // Ensure calendar is open >+ if ( >+ !config.open && >+ !config.navigateToMonth && >+ !config.nextMonth && >+ !config.prevMonth && >+ !config.setYear && >+ !config.selectDay && >+ !config.selectToday && >+ !config.selectDate >+ ) { >+ cy.get(".flatpickr-calendar").then($calendar => { >+ const isVisible = >+ $calendar.hasClass("open") && >+ $calendar.is(":visible"); >+ >+ if (!isVisible) { >+ getVisibleInput().click(); >+ } >+ >+ // Always wait for the calendar to be visible â retry if necessary >+ cy.get(".flatpickr-calendar.open", { >+ timeout: config.timeout, >+ }).should("be.visible"); >+ }); >+ } >+ >+ if ( >+ !Array.isArray(config.selectRange) || >+ config.selectRange.length !== 2 >+ ) { >+ throw new Error( >+ "selectRange must be an array with exactly two dates" >+ ); >+ } >+ >+ // Convert to Date objects if strings were provided >+ const startDateObj = >+ typeof config.selectRange[0] === "string" >+ ? new Date(config.selectRange[0]) >+ : config.selectRange[0]; >+ >+ const endDateObj = >+ typeof config.selectRange[1] === "string" >+ ? new Date(config.selectRange[1]) >+ : config.selectRange[1]; >+ >+ // Navigate to start date using click-based interactions >+ const startYear = startDateObj.getFullYear(); >+ const startMonth = startDateObj.getMonth(); >+ const startDay = startDateObj.getDate(); >+ >+ // Check if the flatpickr instance is in range mode >+ // Get the flatpickr instance from the DOM element >+ cy.window().then(win => { >+ // First ensure we have a valid element before proceeding >+ if (!$el || !$el.length) { >+ throw new Error("Cannot find flatpickr element"); >+ } >+ >+ // Try to get the flatpickr instance from the element >+ const fpInstance = $el[0]._flatpickr; >+ >+ if (!fpInstance) { >+ throw new Error( >+ "Cannot find flatpickr instance on this element. Make sure it's initialized with flatpickr." >+ ); >+ } >+ >+ // Check if it's in range mode >+ if ( >+ fpInstance.config && >+ fpInstance.config.mode !== "range" >+ ) { >+ throw new Error( >+ "This flatpickr instance is not in range mode. Current mode: " + >+ fpInstance.config.mode >+ ); >+ } >+ >+ cy.log("Confirmed flatpickr is in range mode"); >+ }); >+ >+ cy.get( >+ ".flatpickr-current-month .flatpickr-monthDropdown-months" >+ ).then($dropdown => { >+ cy.get(".flatpickr-current-month .numInput.cur-year").then( >+ $currentYear => { >+ // Get the selected month value from the dropdown >+ const selectedOption = $dropdown >+ .find("option:selected") >+ .first(); >+ const currentMonthName = selectedOption >+ .text() >+ .trim(); >+ >+ const monthNames = [ >+ "January", >+ "February", >+ "March", >+ "April", >+ "May", >+ "June", >+ "July", >+ "August", >+ "September", >+ "October", >+ "November", >+ "December", >+ ]; >+ const currentMonth = monthNames.findIndex(name => >+ currentMonthName.includes(name) >+ ); >+ const currentYear = parseInt($currentYear.val()); >+ >+ // Calculate the number of months to move forward or backward >+ const monthDiff = >+ (startYear - currentYear) * 12 + >+ (startMonth - currentMonth); >+ >+ if (monthDiff > 0) { >+ // Click next month button the appropriate number of times >+ for (let i = 0; i < monthDiff; i++) { >+ cy.get(".flatpickr-next-month").click(); >+ cy.wait(100); // Give time for the calendar to update >+ } >+ } else if (monthDiff < 0) { >+ // Click previous month button the appropriate number of times >+ for (let i = 0; i < Math.abs(monthDiff); i++) { >+ cy.get(".flatpickr-prev-month").click(); >+ cy.wait(100); // Give time for the calendar to update >+ } >+ } >+ >+ // Format the aria-label for the start date >+ const formattedStartDateLabel = `${monthNames[startMonth]} ${startDay}, ${startYear}`; >+ >+ // Select start date using aria-label - don't wait here >+ cy.get( >+ `.flatpickr-day[aria-label="${formattedStartDateLabel}"]` >+ ).click(); >+ cy.wait(300); >+ >+ // Verify calendar stays open for range selection >+ cy.get(".flatpickr-calendar.open").should( >+ "be.visible", >+ { >+ timeout: config.timeout, >+ } >+ ); >+ } >+ ); >+ }); >+ >+ // Navigate to end date if in different month >+ const endYear = endDateObj.getFullYear(); >+ const endMonth = endDateObj.getMonth(); >+ const endDay = endDateObj.getDate(); >+ >+ cy.get(".flatpickr-calendar.open").should("be.visible"); >+ >+ if (startMonth !== endMonth || startYear !== endYear) { >+ cy.get( >+ ".flatpickr-current-month .flatpickr-monthDropdown-months" >+ ).then($dropdown => { >+ cy.get( >+ ".flatpickr-current-month .numInput.cur-year" >+ ).then($currentYear => { >+ // Get the selected month value from the dropdown >+ const selectedOption = $dropdown >+ .find("option:selected") >+ .first(); >+ const currentMonthName = selectedOption >+ .text() >+ .trim(); >+ >+ const monthNames = [ >+ "January", >+ "February", >+ "March", >+ "April", >+ "May", >+ "June", >+ "July", >+ "August", >+ "September", >+ "October", >+ "November", >+ "December", >+ ]; >+ const currentMonth = monthNames.findIndex(name => >+ currentMonthName.includes(name) >+ ); >+ const currentYear = parseInt($currentYear.val()); >+ >+ // Calculate months to navigate >+ const monthDiff = >+ (endYear - currentYear) * 12 + >+ (endMonth - currentMonth); >+ >+ if (monthDiff > 0) { >+ // Click next month button >+ for (let i = 0; i < monthDiff; i++) { >+ cy.get(".flatpickr-next-month").click(); >+ cy.wait(100); // Give time for the calendar to update >+ } >+ } else if (monthDiff < 0) { >+ // Click previous month button >+ for (let i = 0; i < Math.abs(monthDiff); i++) { >+ cy.get(".flatpickr-prev-month").click(); >+ cy.wait(100); // Give time for the calendar to update >+ } >+ } >+ }); >+ }); >+ } >+ >+ // Select end date using aria-label >+ const monthNames = [ >+ "January", >+ "February", >+ "March", >+ "April", >+ "May", >+ "June", >+ "July", >+ "August", >+ "September", >+ "October", >+ "November", >+ "December", >+ ]; >+ const formattedEndDateLabel = `${monthNames[endMonth]} ${endDay}, ${endYear}`; >+ >+ // Ensure the calendar is still open before selecting the end date >+ cy.get(".flatpickr-calendar.open").should("be.visible"); >+ >+ cy.get( >+ `.flatpickr-day[aria-label="${formattedEndDateLabel}"]` >+ ).click(); >+ >+ // Add a small delay to ensure proper state before proceeding >+ cy.wait(300); >+ >+ // Verify the selection was made >+ cy.wrap($el).should("not.have.value", ""); >+ } >+ >+ // Type a date directly into the input if requested >+ if (config.typeDate !== null) { >+ getVisibleInput().clear().type(config.typeDate); >+ >+ // Click away to apply the date >+ cy.get("body").click(0, 0); >+ >+ // Verify the input has been updated >+ cy.wrap($el).should("not.have.value", ""); >+ } >+ }); >+ } >+); >+ >+/** >+ * Helper to get a Flatpickr input by any jQuery-like selector >+ * This is the recommended starting point for chainable Flatpickr operations >+ * >+ * @param {string} selector - jQuery-like selector for the original input element >+ * @returns {Cypress.Chainable} - Returns a chainable Cypress object for further commands >+ * >+ * @example >+ * // Chain multiple Flatpickr operations >+ * cy.getFlatpickr('#dateInput') >+ * .flatpickr({ open: true }) >+ * .flatpickr({ navigateToMonth: '2023-06-01' }) >+ * .flatpickr({ selectDay: 15 }); >+ * >+ * @example >+ * // Chain with standard Cypress assertions >+ * cy.getFlatpickr('#startDate') >+ * .flatpickr({ selectDate: '2023-05-15' }) >+ * .should('have.value', '2023-05-15'); >+ */ >+Cypress.Commands.add("getFlatpickr", selector => { >+ return cy.get(selector); >+}); >+ >+/** >+ * Helper to clear a Flatpickr selection >+ * Can be used as a standalone command or as part of a chain >+ * >+ * @param {string} selector - jQuery-like selector for the original input element >+ * @returns {Cypress.Chainable} - Returns a chainable Cypress object for further commands >+ * >+ * @example >+ * // Standalone usage >+ * cy.clearFlatpickr('#dateInput'); >+ * >+ * @example >+ * // As part of a chain >+ * cy.getFlatpickr('#dateInput') >+ * .flatpickr({ selectDate: '2023-05-15' }) >+ * .clearFlatpickr('#dateInput') >+ * .flatpickr({ selectDate: '2023-06-01' }); >+ */ >+Cypress.Commands.add("clearFlatpickr", selector => { >+ return cy.getFlatpickr(selector).flatpickr({ clear: true }); >+}); >+ >+/** >+ * Helper to open a Flatpickr calendar >+ * Can be used as a standalone command or as part of a chain >+ * >+ * @param {string} selector - jQuery-like selector for the original input element >+ * @returns {Cypress.Chainable} - Returns a chainable Cypress object for further commands >+ * >+ * @example >+ * // Standalone usage >+ * cy.openFlatpickr('#dateInput'); >+ * >+ * @example >+ * // As part of a chain >+ * cy.getFlatpickr('#dateInput') >+ * .openFlatpickr('#dateInput') >+ * .flatpickr({ selectDay: 15 }); >+ */ >+Cypress.Commands.add("openFlatpickr", selector => { >+ return cy.getFlatpickr(selector).flatpickr({ open: true }); >+}); >+ >+/** >+ * Helper to close an open Flatpickr calendar >+ * Can be used as a standalone command or as part of a chain >+ * >+ * @param {string} [selector] - Optional jQuery-like selector for the original input element >+ * @returns {Cypress.Chainable} - Returns a chainable Cypress object for further commands >+ * >+ * @example >+ * // Standalone usage >+ * cy.closeFlatpickr(); >+ * >+ * @example >+ * // As part of a chain >+ * cy.getFlatpickr('#dateInput') >+ * .flatpickr({ open: true }) >+ * .flatpickr({ close: true }); >+ */ >+Cypress.Commands.add("closeFlatpickr", selector => { >+ if (selector) { >+ return cy.getFlatpickr(selector).flatpickr({ close: true }); >+ } else { >+ return cy.flatpickr({ close: true }); >+ } >+}); >+ >+/** >+ * Helper to select a date in a Flatpickr >+ * Can be used as a standalone command or as part of a chain >+ * >+ * @param {string} selector - jQuery-like selector for the original input element >+ * @param {Date|string} date - The date to select (Date object or YYYY-MM-DD string) >+ * @returns {Cypress.Chainable} - Returns a chainable Cypress object for further commands >+ * >+ * @example >+ * // Standalone usage >+ * cy.selectFlatpickrDate('#dateInput', '2023-05-15'); >+ * >+ * @example >+ * // As part of a chain >+ * cy.getFlatpickr('#dateInput') >+ * .selectFlatpickrDate('#dateInput', '2023-05-15') >+ * .should('have.value', '2023-05-15'); >+ */ >+Cypress.Commands.add("selectFlatpickrDate", (selector, date) => { >+ return cy.getFlatpickr(selector).flatpickr({ selectDate: date }); >+}); >+ >+/** >+ * Helper to type a date directly into a Flatpickr input >+ * Can be used as a standalone command or as part of a chain >+ * >+ * @param {string} selector - jQuery-like selector for the original input element >+ * @param {string} dateString - The date string to type in the format expected by Flatpickr >+ * @returns {Cypress.Chainable} - Returns a chainable Cypress object for further commands >+ * >+ * @example >+ * // Standalone usage >+ * cy.typeFlatpickrDate('#dateInput', '2023-05-15'); >+ * >+ * @example >+ * // As part of a chain >+ * cy.getFlatpickr('#dateInput') >+ * .typeFlatpickrDate('#dateInput', '2023-05-15') >+ * .should('have.value', '2023-05-15'); >+ */ >+Cypress.Commands.add("typeFlatpickrDate", (selector, dateString) => { >+ return cy.getFlatpickr(selector).flatpickr({ typeDate: dateString }); >+}); >+ >+/** >+ * Helper to select a date range in a Flatpickr range picker >+ * Can be used as a standalone command or as part of a chain >+ * >+ * @param {string} selector - jQuery-like selector for the original input element >+ * @param {Date|string} startDate - The start date to select >+ * @param {Date|string} endDate - The end date to select >+ * @returns {Cypress.Chainable} - Returns a chainable Cypress object for further commands >+ * >+ * @example >+ * // Standalone usage >+ * cy.selectFlatpickrDateRange('#rangePicker', '2023-06-01', '2023-06-15'); >+ * >+ * @example >+ * // As part of a chain >+ * cy.getFlatpickr('#rangePicker') >+ * .selectFlatpickrDateRange('#rangePicker', '2023-06-01', '2023-06-15') >+ * .should('have.value', '2023-06-01 to 2023-06-15'); >+ */ >+Cypress.Commands.add( >+ "selectFlatpickrDateRange", >+ (selector, startDate, endDate) => { >+ return cy.getFlatpickr(selector).flatpickr({ >+ selectRange: [startDate, endDate], >+ }); >+ } >+); >+ >+// Helper function to navigate to a specific date in the flatpickr calendar >+Cypress.Commands.add("navigateToFlatpickrDate", targetDate => { >+ cy.get(".flatpickr-current-month .numInput.cur-year").then($year => { >+ cy.get(".flatpickr-current-month").then($month => { >+ const currentYear = parseInt($year.val()); >+ >+ // Extract month name from the displayed text >+ const currentMonthText = $month.text().trim(); >+ const monthNames = [ >+ "January", >+ "February", >+ "March", >+ "April", >+ "May", >+ "June", >+ "July", >+ "August", >+ "September", >+ "October", >+ "November", >+ "December", >+ ]; >+ >+ // Find current month index >+ const currentMonth = monthNames.findIndex(name => >+ currentMonthText.includes(name) >+ ); >+ >+ // Calculate how many months to move >+ const targetYear = targetDate.getFullYear(); >+ const targetMonth = targetDate.getMonth(); >+ >+ const monthDiff = >+ (targetYear - currentYear) * 12 + (targetMonth - currentMonth); >+ >+ if (monthDiff > 0) { >+ // Move forward >+ for (let i = 0; i < monthDiff; i++) { >+ cy.get(".flatpickr-next-month").click(); >+ cy.wait(100); >+ } >+ } else if (monthDiff < 0) { >+ // Move backward >+ for (let i = 0; i < Math.abs(monthDiff); i++) { >+ cy.get(".flatpickr-prev-month").click(); >+ cy.wait(100); >+ } >+ } >+ }); >+ }); >+}); >+ >+/** >+ * Helper to get the current value from a Flatpickr input >+ * >+ * @param {string} selector - jQuery-like selector for the original input element >+ * @returns {string} The date value in the input >+ * >+ * @example >+ * // Standalone usage >+ * cy.getFlatpickrValue('#dateInput').then(value => { >+ * expect(value).to.equal('2023-05-15'); >+ * }); >+ */ >+Cypress.Commands.add("getFlatpickrValue", selector => { >+ return cy.get(selector).invoke("val"); >+}); >+ >+/** >+ * Helper to assert that a Flatpickr input has a specific date value >+ * >+ * @param {string} selector - jQuery-like selector for the original input element >+ * @param {string} expectedDate - The expected date value in the input >+ * >+ * @example >+ * // Standalone usage >+ * cy.flatpickrShouldHaveValue('#dateInput', '2023-05-15'); >+ * >+ * @example >+ * // As part of a chain >+ * cy.getFlatpickr('#dateInput') >+ * .flatpickr({ selectDate: '2023-05-15' }) >+ * .flatpickrShouldHaveValue('#dateInput', '2023-05-15'); >+ */ >+Cypress.Commands.add("flatpickrShouldHaveValue", (selector, expectedDate) => { >+ return cy.get(selector).should("have.value", expectedDate); >+}); >-- >2.49.0
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 39916
:
182515
|
182516
|
182545
|
182546
|
182635
|
182636
|
182637
|
182771
|
182772
|
182773
|
183206
|
183207
|
183208
|
183209
|
183210