From 6a10d9fce2b0aea71022d8aab9d2ba760c1eeb01 Mon Sep 17 00:00:00 2001 From: KyuWoo Choi Date: Sat, 28 Dec 2019 16:08:29 +0900 Subject: [PATCH] :white_check_mark: write e2e for settings & apis (#34, #57) * :white_check_mark: test for settings adaptiveHeight * :white_check_mark: test for settings arrows * :white_check_mark: test for settings asNavFor * :white_check_mark: test for settings autoplay * :white_check_mark: test for settings centerMode * :white_check_mark: test for settings centerPadding * :white_check_mark: test for settings className * :white_check_mark: test for settings dots * :white_check_mark: change test path as relative path(#53) close: #53 * :white_check_mark: missing focusOnSelect make test fail * :white_check_mark: settings className has been removed (#38) * :white_check_mark: add test for dotsClass * :white_check_mark: add test for draggable * :white_check_mark: add test for edgeFriction * :art: make readable test * :white_check_mark: add test for focusOnSelect * :white_check_mark: add test for infinite * :white_check_mark: add test for initialSlide * :white_check_mark: add test for pauseOnHover * :white_check_mark: add test for pauseOnDotsHover * :white_check_mark: add test for pauseOnFocus * :white_check_mark: add test for responsive * :white_check_mark: add test for rows * :white_check_mark: add test for swipe * :white_check_mark: add test for swipeToSlide * :art: make clear the line is the statement rather than expression * :art: refactor redundant code * :white_check_mark: add test for touchThreshold * :art: to be the same as settings seq * :white_check_mark: add test for api prev * :white_check_mark: add test for api next * :white_check_mark: add test for api goTo close: #34 --- demo/pages/examples/configs.js | 12 ++ demo/pages/examples/index.vue | 3 + tests/e2e/specs/apis.js | 23 +++ tests/e2e/specs/settings.js | 342 ++++++++++++++++++++++++++++++++- tests/e2e/support/commands.js | 59 ++++-- 5 files changed, 420 insertions(+), 19 deletions(-) create mode 100644 tests/e2e/specs/apis.js diff --git a/demo/pages/examples/configs.js b/demo/pages/examples/configs.js index a4a7108..1574f7b 100644 --- a/demo/pages/examples/configs.js +++ b/demo/pages/examples/configs.js @@ -27,6 +27,8 @@ export default { title: 'Simple Slides', settings: { dots: true, + dotsClass: 'slick-dots custom-dot-class', + edgeFriction: 0.35, infinite: false, speed: 500, slidesToShow: 1, @@ -38,10 +40,12 @@ export default { numSlides: 9, settings: { dots: true, + focusOnSelect: true, infinite: true, speed: 500, slidesToShow: 3, slidesToScroll: 3, + touchThreshold: 5, }, }, responsive: { @@ -87,9 +91,11 @@ export default { settings: { dots: true, infinite: true, + initialSlide: 2, speed: 500, slidesToShow: 3, slidesToScroll: 1, + swipeToSlide: true, }, }, 'multiple-rows': { @@ -108,6 +114,7 @@ export default { settings: { centerMode: true, centerPadding: '20px', + focusOnSelect: true, infinite: true, slidesToShow: 3, speed: 500, @@ -168,6 +175,7 @@ export default { 'auto-play': { title: 'Auto Play', settings: { + arrows: false, dots: true, infinite: true, slidesToShow: 3, @@ -187,6 +195,8 @@ export default { slidesToScroll: 1, autoplay: true, autoplaySpeed: 2000, + pauseOnDotsHover: true, + pauseOnFocus: true, pauseOnHover: true, }, }, @@ -225,6 +235,8 @@ export default { title: 'Vertical Swipe To Slide', template: verticalTemplate, settings: { + centerMode: true, + centerPadding: '30px', dots: true, infinite: true, slidesToShow: 3, diff --git a/demo/pages/examples/index.vue b/demo/pages/examples/index.vue index 9d5b5f9..31ae526 100644 --- a/demo/pages/examples/index.vue +++ b/demo/pages/examples/index.vue @@ -160,6 +160,9 @@ export default { enquire.register('(min-width: 0px) and (max-width: 600px)', this.onMobile) enquire.register('(min-width: 601px)', this.onDesktop) }, + mounted() { + window.carousel = this.$refs.c1 + }, methods: { onMobile() { this.screen = 'mobile' diff --git a/tests/e2e/specs/apis.js b/tests/e2e/specs/apis.js new file mode 100644 index 0000000..604c4bd --- /dev/null +++ b/tests/e2e/specs/apis.js @@ -0,0 +1,23 @@ +describe('APIs', () => { + describe('prev', () => { + it('should move the slide right', () => { + cy.visit('/#/example/multiple') + cy.window().then(window => window.carousel.prev()) + cy.get('[data-index="8"]').should('be.visible') + }) + }) + describe('next', () => { + it('should move the slide left', () => { + cy.visit('/#/example/multiple') + cy.window().then(window => window.carousel.next()) + cy.get('[data-index="3"]').should('be.visible') + }) + }) + describe('goTo', () => { + it('should move the given slide to current', () => { + cy.visit('/#/example/multiple') + cy.window().then(window => window.carousel.goTo(3)) + cy.get('[data-index="3"]').should('be.visible') + }) + }) +}) diff --git a/tests/e2e/specs/settings.js b/tests/e2e/specs/settings.js index e3b51e9..13eac1e 100644 --- a/tests/e2e/specs/settings.js +++ b/tests/e2e/specs/settings.js @@ -1,27 +1,363 @@ +import exampleConfig from '../../../demo/pages/examples/configs' + describe('Settings', () => { describe('accessibility', () => { it('enables key navigation', () => { - cy.visit('/example/simple') + cy.visit('/#/example/simple') cy.get('.slick-slider').type('{rightarrow}') cy.get('.slick-track .slick-slide:nth-child(2)').should('be.visible') cy.get('.slick-slider').type('{leftarrow}') cy.get('.slick-track .slick-slide:nth-child(1)').should('be.visible') }) it('disables key navigation', () => { - cy.visit('/example/adaptive-height') + cy.visit('/#/example/adaptive-height') cy.get('.slick-slider').type('{rightarrow}') cy.get('.slick-track .slick-slide:nth-child(1)').should('be.visible') cy.get('.slick-slider').type('{leftarrow}') cy.get('.slick-track .slick-slide:nth-child(1)').should('be.visible') }) }) + describe('adaptiveHeight', () => { + it('adapt slider height to match the height of the current slide', () => { + cy.visit('/#/example/adaptive-height') + let slideHeight + cy.get('.slick-active').then($slide => { + slideHeight = $slide[0].offsetHeight + }) + cy.get('.slick-list').then($list => { + expect($list[0].offsetHeight).to.equal(slideHeight) + }) + cy.get('.slick-slider').type('{rightarrow}') + cy.get('.slick-active').then($slide => { + slideHeight = $slide[0].offsetHeight + }) + cy.get('.slick-list').then($list => { + expect($list[0].offsetHeight).to.equal(slideHeight) + }) + }) + }) + describe('arrows', () => { + it('enables left/right arrows', () => { + cy.visit('/#/example/simple') + cy.get('.slick-prev').should('exist') + cy.get('.slick-next').should('exist') + }) + it('disables left/right arrows', () => { + cy.visit('/#/example/auto-play') + cy.get('.slick-prev').should('not.exist') + cy.get('.slick-next').should('not.exist') + }) + }) + describe('asNavFor', () => { + it('syncs two slides', () => { + cy.visit('/#/example/as-nav-for') + let currentSlide + cy.get('.carousel-wrapper:nth-of-type(1) .slick-prev').click() + cy.get('.carousel-wrapper:nth-of-type(1) .slick-current').then($slide => { + currentSlide = $slide.text() + }) + cy.get('.carousel-wrapper:nth-of-type(2) .slick-current').then($slide => { + expect($slide.text()).to.contains(currentSlide) + }) + }) + }) + describe('autoplay', () => { + it('should change the current slide over time', () => { + cy.visit('/#/example/auto-play') + let currentSlide + cy.get('.slick-current').then($slide => { + currentSlide = $slide.text() + }) + cy.wait(200) + cy.get('.slick-current').then($slide => { + expect($slide.text()).not.to.equal(currentSlide) + }) + }) + }) + describe('centerMode', () => { + it('should center the current slide', () => { + cy.visit('/#/example/center-mode') + let slideCenter + cy.getCenterXY('.slick-current').then(center => { + slideCenter = center + }) + cy.getCenterXY().then(viewportCenter => { + expect(slideCenter.x).to.be.closeTo(viewportCenter.x, 10) + }) + }) + it('should center the clicked slide', () => { + cy.visit('/#/example/center-mode') + cy.get('[data-index="1"]').click() + let slideCenter + cy.getCenterXY('[data-index="1"]').then(center => { + slideCenter = center + }) + cy.getCenterXY().then(viewportCenter => { + expect(slideCenter.x).to.be.closeTo(viewportCenter.x, 10) + }) + }) + }) + describe('centerPadding', () => { + it('should set padding on inner slider', () => { + cy.visit('/#/example/center-mode') + cy.get('.slick-list').then($innerSlider => { + const { centerPadding: settingsCenterPadding } = exampleConfig[ + 'center-mode' + ].settings + const { + paddingTop, + paddingRight, + paddingBottom, + paddingLeft, + } = getComputedStyle($innerSlider[0]) + expect(paddingLeft).to.equal(settingsCenterPadding) + expect(paddingRight).to.equal(settingsCenterPadding) + expect(paddingTop).to.equal('0px') + expect(paddingBottom).to.equal('0px') + }) + + cy.visit('/#/example/vertical-swipe-to-slide') + cy.get('.slick-list').then($innerSlider => { + const { centerPadding: settingsCenterPadding } = exampleConfig[ + 'vertical-swipe-to-slide' + ].settings + const { + paddingTop, + paddingRight, + paddingBottom, + paddingLeft, + } = getComputedStyle($innerSlider[0]) + expect(paddingTop).to.equal(settingsCenterPadding) + expect(paddingBottom).to.equal(settingsCenterPadding) + expect(paddingLeft).to.equal('0px') + expect(paddingRight).to.equal('0px') + }) + }) + }) + describe('dots', () => { + it('should enable dots', () => { + cy.visit('/#/example/simple') + cy.get('.slick-dots').should('exist') + }) + it('should disable dots', () => { + cy.visit('/#/example/multiple-rows') + cy.get('.slick-dots').should('not.exist') + }) + }) + describe('dotClass', () => { + it('should set given class to dots', () => { + cy.visit('/#/example/simple') + cy.get('.slick-dots').should('have.class', 'custom-dot-class') + }) + }) + describe('draggable', () => { + it('should enable drag ability', () => { + cy.visit('/#/example/simple') + let currentSlide + cy.get('.slick-current').then($slide => { + currentSlide = $slide.text() + }) + cy.dragAndDrop('.slick-current', { x: -500 }) + cy.get('.slick-current').then($slide => { + expect($slide.text()).not.to.equal(currentSlide) + }) + }) + }) + describe('edgeFriction', () => { + it('should resist drag', () => { + cy.visit('/#/example/simple') + const { edgeFriction } = exampleConfig['simple'].settings + let originalCenter + cy.getCenterXY('.slick-current').then(center => { + originalCenter = center + }) + cy.drag('.slick-current', { x: 500 }) + cy.getCenterXY('.slick-current').then(center => { + expect(center.x).to.be.closeTo( + originalCenter.x + 500 * edgeFriction, + 10, + ) + }) + }) + }) + describe('focusOnSelect', () => { + it('should move the clicked slide to the first', () => { + cy.visit('/#/example/multiple') + let firstSlideCenter + cy.getCenterXY('.slick-current').then(center => { + firstSlideCenter = center + }) + cy.get('[data-index="1"]').click() + cy.getCenterXY('[data-index="1"]').then(center => { + expect(center.x).to.be.closeTo(firstSlideCenter.x, 10) + }) + }) + it('should not move the clicked slide to the first if disabled', () => { + cy.visit('/#/example/responsive') + let firstSlideCenter + cy.getCenterXY('.slick-current').then(center => { + firstSlideCenter = center + }) + cy.get('[data-index="1"]').click() + cy.getCenterXY('[data-index="1"]').then(center => { + expect(center.x).not.to.be.closeTo(firstSlideCenter.x, 10) + }) + }) + }) + describe('infinite', () => { + it('should navigate around ends', () => { + cy.visit('/#/example/multiple') + let currentSlide + cy.get('.slick-current').then($slide => { + currentSlide = $slide.text().trim() + }) + cy.get('.slick-prev').click() + cy.get('.slick-current').then($slide => { + expect($slide.text().trim()).not.to.equal(currentSlide) + }) + }) + it('should not navigate around ends if disabled', () => { + cy.visit('/#/example/simple') + let currentSlide + cy.get('.slick-current').then($slide => { + currentSlide = $slide.text().trim() + }) + cy.get('.slick-prev').click() + cy.get('.slick-current').then($slide => { + expect($slide.text().trim()).to.equal(currentSlide) + }) + }) + }) + describe('initialSlide', () => { + it('should set first slide', () => { + const { initialSlide } = exampleConfig['resizable'].settings + cy.visit('/#/example/resizable') + cy.get('.slick-current').then($slide => { + expect($slide.text().trim()).to.equal(String(initialSlide + 1)) + }) + }) + }) + describe('pauseOnHover', () => { + it('should pause auto play', () => { + cy.visit('/#/example/pause-on-hover') + cy.get('.slick-current').trigger('mouseover') + let currentSlide + cy.get('.slick-current').then($slide => { + currentSlide = $slide.text().trim() + }) + cy.wait(200) + cy.get('.slick-current').then($slide => { + expect($slide.text().trim()).to.equal(currentSlide) + }) + }) + }) + describe('pauseOnDotsHover', () => { + it('should pause auto play', () => { + cy.visit('/#/example/pause-on-hover') + cy.get('.slick-active > button').trigger('mouseover') + let currentSlide + cy.get('.slick-current').then($slide => { + currentSlide = $slide.text().trim() + }) + cy.wait(200) + cy.get('.slick-current').then($slide => { + expect($slide.text().trim()).to.equal(currentSlide) + }) + }) + }) + describe('pauseOnDotsHover', () => { + it('should pause auto play', () => { + cy.visit('/#/example/pause-on-hover') + cy.get('.slick-current').focus() + let currentSlide + cy.get('.slick-current').then($slide => { + currentSlide = $slide.text().trim() + }) + cy.wait(200) + cy.get('.slick-current').then($slide => { + expect($slide.text().trim()).to.equal(currentSlide) + }) + }) + }) + describe('responsive', () => { + it('should apply settings given to the screen sizes', () => { + cy.visit('/#/example/responsive') + cy.viewport(1025, 660) + cy.get('.slick-list .slick-active').should('have.length', 4) + cy.viewport(1024, 660) + cy.get('.slick-list .slick-active').should('have.length', 3) + cy.viewport(600, 660) + cy.get('.slick-list .slick-active').should('have.length', 2) + cy.viewport(480, 660) + cy.get('.slick-list .slick-active').should('have.length', 1) + }) + }) + describe('rows', () => { + it('enables key navigation', () => { + cy.visit('/#/example/multiple-rows') + const { rows } = exampleConfig['multiple-rows'].settings + cy.get('.slick-current > div').should('have.length', rows) + }) + }) describe('rtl', () => { it('makes key navigation in reverse', () => { - cy.visit('/example/rtl') + cy.visit('/#/example/rtl') cy.get('.slick-slider').type('{rightarrow}') cy.get('.slick-track .slick-slide:nth-child(5)').should('be.visible') cy.get('.slick-slider').type('{leftarrow}') cy.get('.slick-track .slick-slide:nth-child(6)').should('be.visible') }) }) + describe('swipe', () => { + it('should enable swipe ability', () => { + cy.visit('/#/example/simple') + let currentSlide + cy.get('.slick-current').then($slide => { + currentSlide = $slide.text() + }) + cy.swipe('.slick-current', { x: -500 }, true) + cy.get('.slick-current').then($slide => { + expect($slide.text()).not.to.equal(currentSlide) + }) + }) + }) + describe('swipeToSlide', () => { + it('should enable swiping number of slides irrespective of slidesToScroll', () => { + cy.visit('/#/example/resizable') + let firstSlideCenter + cy.getCenterXY('.slick-current').then(center => { + firstSlideCenter = center + }) + let slideDiffX + cy.getCenterXY('[data-index="2"]').then(center => { + slideDiffX = firstSlideCenter.x - center.x + }) + cy.swipe('.slick-current', { x: slideDiffX }, true) + cy.get('.slick-current').then($slide => { + expect($slide.text().trim()).to.equal('3') + }) + }) + }) + describe('touchThreshold', () => { + it('should decide whether move the slide or not', () => { + cy.visit('/#/example/multiple') + const { touchThreshold } = exampleConfig['multiple'].settings + let currentSlide + cy.get('.slick-current').then($slide => { + currentSlide = $slide.text().trim() + }) + cy.getBoundingClientRect('.slick-list').then(({ width: slideWidth }) => { + // swipe less than threshold + cy.swipe('.slick-current', { x: slideWidth / touchThreshold - 10 }) + cy.get('.slick-current').then($slide => { + expect($slide.text().trim()).to.equal(currentSlide) + }) + // swipe more than threshold + cy.swipe('.slick-current', { x: slideWidth / touchThreshold + 10 }) + cy.get('.slick-current').then($slide => { + expect($slide.text().trim()).not.to.equal(currentSlide) + }) + }) + }) + }) }) diff --git a/tests/e2e/support/commands.js b/tests/e2e/support/commands.js index c1f5a77..1cb663d 100644 --- a/tests/e2e/support/commands.js +++ b/tests/e2e/support/commands.js @@ -7,19 +7,46 @@ // commands please read more here: // https://on.cypress.io/custom-commands // *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add("login", (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This is will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) + +Cypress.Commands.add('getBoundingClientRect', el => { + cy.get(el).then($el => $el[0].getBoundingClientRect()) +}) + +Cypress.Commands.add('getCenterXY', el => { + if (el) { + cy.getBoundingClientRect(el).then(rect => ({ + x: (rect.left + rect.right) / 2, + y: (rect.top + rect.bottom) / 2, + })) + } else { + const { viewportWidth, viewportHeight } = Cypress.config() + + return { x: viewportWidth / 2, y: viewportHeight / 2 } + } +}) + +Cypress.Commands.add('drag', (el, diff, touch = false) => { + return cy.getCenterXY(el).then(center => { + const coordination = {} + if (typeof diff.x === 'number') { + coordination.clientX = center.x + diff.x + } + if (typeof diff.y === 'number') { + coordination.clientY = center.y + diff.y + } + return cy + .get(el) + .trigger(touch ? 'touchstart' : 'mousedown', { which: 1 }) // mouse down left button + .trigger(touch ? 'touchmove' : 'mousemove', coordination) + }) +}) + +Cypress.Commands.add('dragAndDrop', (el, diff, touch) => { + return cy.drag(el, diff, touch).then(() => { + return cy.get(el).trigger(touch ? 'touchend' : 'mouseup', { force: true }) + }) +}) + +Cypress.Commands.add('swipe', (el, diff) => { + return cy.dragAndDrop(el, diff, true) +})