diff --git a/devui/carousel/__tests__/carousel.spec.ts b/devui/carousel/__tests__/carousel.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..525d71d7692531a36fe0c585f59b2a3117ccff7d --- /dev/null +++ b/devui/carousel/__tests__/carousel.spec.ts @@ -0,0 +1,237 @@ +import { ref, nextTick } from 'vue' +import { mount } from '@vue/test-utils'; +import Carousel from '../carousel'; +import CarouselItem from '../item'; +import Button from '../../button' + +const wait = (ms = 100) => + new Promise(resolve => setTimeout(() => resolve(), ms)) + +describe('d-carousel', () => { + it('arrowTrigger-never', () => { + const wrapper = mount(Carousel, { + props: { + arrowTrigger: 'never', + height: '200px', + }, + }); + expect(wrapper.find('.devui-carousel-arrow').exists()).toBe(false); + }); + + it('arrowTrigger-hover-out', () => { + const wrapper = mount(Carousel, { + props: { + arrowTrigger: 'hover', + height: '200px', + }, + }); + expect(wrapper.find('.devui-carousel-arrow').exists()).toBe(false); + }); + it('arrowTrigger-hover-in', async () => { + const wrapper = mount(Carousel, { + props: { + arrowTrigger: 'hover', + height: '200px', + }, + }); + wrapper.find('.devui-carousel-container').trigger('mouseenter') + await nextTick() + expect(wrapper.find('.devui-carousel-arrow').exists()).toBe(true); + }); + + it('arrowTrigger-always', () => { + const wrapper = mount(Carousel, { + props: { + arrowTrigger: 'always', + height: '200px', + }, + }); + expect(wrapper.find('.devui-carousel-arrow').exists()).toBe(true); + }); + + it('showDots-false', () => { + const wrapper = mount(Carousel, { + props: { + showDots: false, + height: '200px', + }, + }); + expect(wrapper.find('.devui-carousel-dots').exists()).toBe(false); + }); + + it('showDots-click', async () => { + const wrapper = mount({ + components: { + 'd-carousel': Carousel, + 'd-carousel-item': CarouselItem, + }, + template: ` + + Page 1 + Page 2 + Page 3 + Page 4 + + `, + setup() { + const activeIndex = ref(0) + + const onChange = (index: number) => { + activeIndex.value = index + } + + return { + activeIndex, + + onChange, + } + } + }); + + await nextTick() + wrapper.findAll('.dot-item')[1].trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(1); + }); + + it('showDots-enter', async () => { + const wrapper = mount({ + components: { + 'd-carousel': Carousel, + 'd-carousel-item': CarouselItem, + }, + template: ` + + Page 1 + Page 2 + Page 3 + Page 4 + + `, + setup() { + const activeIndex = ref(0) + + const onChange = (index: number) => { + activeIndex.value = index + } + + return { + activeIndex, + + onChange, + } + } + }); + await nextTick() + wrapper.findAll('.dot-item')[1].trigger('mouseenter') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(1); + }); + + it('operate', async () => { + const wrapper = mount({ + components: { + 'd-carousel': Carousel, + 'd-carousel-item': CarouselItem, + 'd-button': Button, + }, + template: ` + + {{ item }} + + + `, + setup() { + const items = ref(["page 1", 'page 2', 'page 3', 'page 4']) + const activeIndex = ref(0) + + const carousel = ref() + + const onPrev = () => { + carousel.value?.prev?.() + } + const onNext = () => { + carousel.value?.next?.() + } + const onGoFirst = () => { + carousel.value?.goto?.(0) + } + const onChange = (index: number) => { + activeIndex.value = index + } + + return { + activeIndex, + items, + + carousel, + onPrev, + onNext, + onGoFirst, + onChange, + } + } + }); + + await nextTick() + wrapper.find('.arrow-left').trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(3) + wrapper.find('.arrow-right').trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(0) + + wrapper.findAll('.devui-btn')[0].trigger('click') + await nextTick() + wrapper.findAll('.devui-btn')[0].trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(2) + + wrapper.findAll('.devui-btn')[1].trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(3) + + wrapper.findAll('.devui-btn')[2].trigger('click') + await nextTick() + expect(wrapper.vm.activeIndex).toBe(0) + }); + + it('autoplay', async () => { + const wrapper = mount({ + components: { + 'd-carousel': Carousel, + 'd-carousel-item': CarouselItem, + }, + template: ` + + Page 1 + Page 2 + Page 3 + Page 4 + + `, + setup() { + const activeIndex = ref(2) + + const onChange = (index: number) => { + activeIndex.value = index + } + + return { + activeIndex, + + onChange, + } + } + }); + + await wait(4500) + expect(wrapper.vm.activeIndex).toBe(1) + await wait(4600) + expect(wrapper.vm.activeIndex).toBe(3) + }, 10000); +}); diff --git a/devui/carousel/carousel.tsx b/devui/carousel/carousel.tsx index db977d77e97110723fbb146090ef18eb7219311a..db21aaeb04260d6383f1b756a00834cd4a2cc0a1 100644 --- a/devui/carousel/carousel.tsx +++ b/devui/carousel/carousel.tsx @@ -1,5 +1,5 @@ /* eslint-disable */ -import { defineComponent, ref, watch, onMounted, Fragment, Comment } from 'vue'; +import { defineComponent, ref, watch, onMounted, onBeforeUnmount, Fragment, Comment } from 'vue'; import { carouselProps, DotTrigger } from './types'; import Icon from '../icon/src/icon' @@ -26,7 +26,7 @@ export default defineComponent({ const currentIndex = ref(0); const wrapperRef = ref(null); const containerRef = ref(null); - const scheduledId = ref(null); + const scheduledId = ref | null>(null); watch( () => arrowTrigger, @@ -170,6 +170,9 @@ export default defineComponent({ autoScheduleTransition(); }); + onBeforeUnmount(() => { + clearScheduledTransition() + }) return { wrapperRef,