import selectors from '../selectors' import pickerProperties from '../pickerProperties' const { singleDatepickerInput, daterangeInputStart, daterangeInputEnd, } = selectors const { singleDatepickerProperties, getDaterangeProperties } = pickerProperties function checkPickerProperties(picker, isDaterange, id) { return function({ property, defaultValue, domElement, selector, deepEqual, isFunction, notOwnProperty }) { const value = picker[property] if (!notOwnProperty) { // The property should exist on the picker. expect(picker, `(checkPickerProperties) isDaterange<${isDaterange}>`).to.haveOwnProperty(property) } // Special case for id. if (isDaterange && property === 'id') { expect(value, 'id').to.equal(id) // First get the dom element, then ensure it has the correct default value. } else if (domElement) { cy.get(selector).then(elements => { expect(value, `(checkPickerProperties) ${property}`).to.equal(defaultValue(elements)) expect(elements, `(checkPickerProperties) ${selector}`).to.have.lengthOf(1) }) // Ensure the value is a function. } else if (isFunction) { expect(value, `(checkPickerProperties) method<${property}>`).to.be.a('function') // The property should have the correct default value. } else if (deepEqual) { expect(value, `(checkPickerProperties) ${property}`).to.deep.equal(defaultValue) } else { expect(value, `(checkPickerProperties) ${property}`).to.equal(defaultValue) } } } function testDomStructure(pickerType, selectorObj) { const date = new Date() const multiplier = pickerType === 'single' ? 1 : 2 cy.get(selectorObj.calendarContainer).as('calendarContainer') cy.get(selectorObj.calendar).as('calendar') cy.get(selectorObj.controls).as('controls') cy.get(`${selectorObj.controls} .qs-arrow`).as('arrows') cy.get(`${selectorObj.controls} .qs-month-year`).as('monthYear') cy.get(`${selectorObj.controls} .qs-month`).as('month') cy.get(`${selectorObj.controls} .qs-year`).as('year') cy.get(selectorObj.squaresContainer).as('squaresContainer') cy.get(`${selectorObj.squaresContainer} ${selectors.common.everySquare}`).as('squares') cy.get(selectorObj.overlay).as('overlay') cy.get(selectorObj.overlayInputContainer).as('overlayInputContainer') cy.get(`${selectorObj.overlayInputContainer} .qs-overlay-year`).as('overlayYearInput') cy.get(`${selectorObj.overlayInputContainer} .qs-close`).as('overlayClose') cy.get(selectorObj.overlayMonthContainer).as('overlayMonthContainer') // calendarContainer cy.get(selectors.common.container).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@calendarContainer').should('have.length', 1) // Searching within the specified section of the document. cy.get('@calendarContainer').children().should('have.length', 1) cy.get('@calendarContainer').should('have.attr', 'class', 'qs-datepicker-container qs-hidden') // calendar cy.get(selectors.common.calendar).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@calendar').should('have.length', 1) // Searching within the specified section of the document. cy.get('@calendar').children().should('have.length', 3) cy.get('@calendar').should('have.attr', 'class', 'qs-datepicker') // calendar => controls cy.get(selectors.common.controls).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@controls').should('have.length', 1) // Searching within the specified section of the document. cy.get('@controls').children().should('have.length', 3) cy.get('@controls').should('have.attr', 'class', 'qs-controls') // calendar => controls => arrows cy.get(`${selectors.common.controls} .qs-arrow`).should('have.length', 2 * multiplier) // Searching the whole document. cy.get('@arrows').should('have.length', 2) // Searching within the specified section of the document. cy.get('@arrows').then($arrows => { cy.get($arrows[0]).children().should('have.length', 0) cy.get($arrows[1]).children().should('have.length', 0) expect($arrows[0], '@arrows - left').to.have.attr('class', 'qs-arrow qs-left') expect($arrows[1], '@arrows - right').to.have.attr('class', 'qs-arrow qs-right') }) // calendar => controls => month/year cy.get(`${selectors.common.controls} .qs-month-year`).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@monthYear').should('have.length', 1) // Searching within the specified section of the document. cy.get('@monthYear').children().should('have.length', 2) cy.get('@monthYear').should('have.attr', 'class', 'qs-month-year') // calendar => controls => month/year => month cy.get(`${selectors.common.controls} .qs-month`).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@month').should('have.length', 1) // Searching within the specified section of the document. cy.get('@month').children().should('have.length', 0) cy.get('@month').should('have.text', pickerProperties.months[date.getMonth()]) cy.get('@month').should('have.attr', 'class', 'qs-month') // calendar => controls => month/year => year cy.get(`${selectors.common.controls} .qs-year`).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@year').should('have.length', 1) // Searching within the specified section of the document. cy.get('@year').children().should('have.length', 0) cy.get('@year').should('have.text', date.getFullYear()) cy.get('@year').should('have.attr', 'class', 'qs-year') // calendar => squares cy.get(selectors.common.squaresContainer).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@squaresContainer').should('have.length', 1) // Searching within the specified section of the document. cy.get('@squaresContainer').should('have.attr', 'class', 'qs-squares') // calendar => squares => various types of squares cy.get('@squaresContainer').children().then($allSquares => { cy.get(selectors.common.everySquare).should('have.length', $allSquares.length * multiplier) /* It's a little hard to test the correct number of total squares since there's a lot of logic involved. I don't want to simply repeat the logic in the library, defeating the purpose of testing. https://github.com/qodesmith/datepicker/issues/86 One thing we can do to guage if we have extra days is to test the 1st 7 and last 7 calendar days. If any one of those sets are completely empty, we've got an extra row that shouldn't be there. */ const arrayOfSquares = Array.from($allSquares) // 1st 7 days - NOT the days of the week header. const firstWeekHasContent = arrayOfSquares.slice(7, 14).some(square => square.textContent === '1') // Last 7 days. const lastWeekHasContent = arrayOfSquares.slice(-7).some(square => { // The last day of any month will be on of these numbers. One of them should be found in the last week. return ['28', '29', '30', '31'].some(num => square.textContent === num) }) expect(firstWeekHasContent, '@squaresContainer - First week has content').to.equal(true) expect(lastWeekHasContent, '@squaresContainer - Last week has content').to.equal(true) }) cy.get('@squares').filter('.qs-day') .should('have.length', 7) .should('have.attr', 'class', 'qs-square qs-day') .then($qsDays => { const message = '@squaresContainer/.qs-day' $qsDays.each((i, qsDay) => { pickerProperties.days.forEach(day => { expect(qsDay.classList.contains(day), `${message} (day of week class: ${day})`).to.equal(false) }) expect(qsDay.textContent, message).to.be.oneOf(pickerProperties.days) expect(qsDay, message).to.not.have.attr('data-direction') }) }) cy.get('@squares').filter('.qs-outside-current-month').then($outsides => { $outsides.each((_, outside) => { const message = '@squaresContainer/.qs-outside-current-month' const hasDayClass = pickerProperties.days.reduce((found, day) => { return found || outside.classList.contains(day) }, false) expect(hasDayClass, `${message} (has day of week class)`).to.equal(true) expect(outside, message).to.have.text('') expect(outside, message).to.have.class('qs-empty') expect(outside, message).to.have.attr('data-direction') expect(outside.dataset.direction, message).to.be.oneOf(['-1', '1']) }) }) cy.get('@squares').filter('.qs-num').then($qsNums => { const numOfDays = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate() const message = '@squaresContainer/.qs-num' expect($qsNums.length, message).to.equal(numOfDays) $qsNums.each((i, qsNum) => { const hasDayClass = pickerProperties.days.reduce((found, day) => { return found || qsNum.classList.contains(day) }, false) expect(hasDayClass, `${message} (has day of week class)`).to.equal(true) expect(qsNum.dataset.direction, message).to.equal('0') expect(qsNum.textContent, message).to.equal(`${i + 1}`) }) }) cy.get('@squares').filter('.qs-current').then($qsCurrent => { const message = '@squaresContainer/.qs-num/.qs-current' const hasDayClass = pickerProperties.days.reduce((found, day) => { return found || $qsCurrent[0].classList.contains(day) }, false) expect(hasDayClass, `${message} (has day of week class)`).to.equal(true) expect($qsCurrent, message).to.have.length(1) expect($qsCurrent.text(), message).to.equal(`${date.getDate()}`) }) // calendar => overlay cy.get(selectors.common.overlay).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@overlay').should('have.length', 1) // Searching within the specified section of the document. cy.get('@overlay').should('have.attr', 'class', 'qs-overlay qs-hidden') cy.get('@overlay').children().should('have.length', 3) // calendar => overlay => overlayInputContainer cy.get(selectors.common.overlayInputContainer).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@overlayInputContainer').should('have.length', 1) // Searching within the specified section of the document. cy.get('@overlayInputContainer').children().should('have.length', 2) cy.get('@overlayInputContainer').should('not.have.attr', 'class') cy.get('@overlayInputContainer').then($overlayInputContainer => { expect($overlayInputContainer[0].getAttributeNames(), '@overlayInputContainer - getAttributeNames()').to.deep.equal([]) }) // calendar => overlay => overlayInputContainer => year input cy.get(selectors.common.overlayYearInput).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@overlayYearInput').should('have.length', 1) // Searching within the specified section of the document. cy.get('@overlayYearInput').should('have.prop', 'tagName').should('eq', 'INPUT') cy.get('@overlayYearInput').should('have.attr', 'class', 'qs-overlay-year') cy.get('@overlayYearInput').should('have.attr', 'placeholder', '4-digit year') cy.get('@overlayYearInput').should('have.prop', 'value', '') cy.get('@overlayYearInput').should('have.attr', 'inputmode', 'numeric') // calendar => overlay => overlayInputContainer => close cy.get(selectors.common.overlayClose).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@overlayClose').should('have.length', 1) // Searching within the specified section of the document. cy.get('@overlayClose').should('have.attr', 'class', 'qs-close') cy.get('@overlayClose').should('have.text', '✕') // calendar => overlay => overlayMonthContainer cy.get(selectors.common.overlayMonthContainer).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@overlayMonthContainer').should('have.length', 1) // Searching within the specified section of the document. cy.get('@overlayMonthContainer').children().should('have.length', 12) cy.get('@overlayMonthContainer').should('have.attr', 'class', 'qs-overlay-month-container') // calendar => overlay => overlayMonthContainer => overlayMonth cy.get(selectors.common.overlayMonth).should('have.length', 12 * multiplier) // Searching the whole document. cy.get('@overlayMonthContainer').children().then($qsOverlayMonths => { $qsOverlayMonths.each((i, overlayMonth) => { const message = `.qs-overlay-month [${i}]` expect(overlayMonth.textContent, message).to.have.length(3) expect(overlayMonth.textContent, message).to.equal(pickerProperties.months[i].slice(0, 3)) expect(overlayMonth, message).to.have.attr('class', 'qs-overlay-month') expect(overlayMonth, message).to.have.attr('data-month-num', `${i}`) }) }) // calendar => overlay => overlaySubmit cy.get(selectors.common.overlaySubmit).should('have.length', 1 * multiplier) // Searching the whole document. cy.get('@overlay').find(selectors.common.overlaySubmit) // Searching within the specified section of the document. .should('have.length', 1) .should('have.text', 'Submit') .should('have.attr', 'class', 'qs-submit qs-disabled') .should('have.prop', 'tagName').should('eq', 'DIV') // This element is not a