123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696 |
- import { h, nextTick, onMounted, ref } from 'vue'
- import { mount } from '@vue/test-utils'
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
- import { EVENT_CODE } from '@element-plus/constants'
- import { ElFormItem } from '@element-plus/components/form'
- import Slider from '../src/slider.vue'
- import type { SliderProps } from '../src/slider'
- vi.mock('lodash-unified', async () => {
- return {
- ...((await vi.importActual('lodash-unified')) as Record<string, any>),
- debounce: vi.fn((fn) => {
- fn.cancel = vi.fn()
- fn.flush = vi.fn()
- return fn
- }),
- }
- })
- describe('Slider', () => {
- beforeEach(() => {
- vi.useFakeTimers()
- })
- afterEach(() => {
- vi.useRealTimers()
- })
- it('create', () => {
- const wrapper = mount(Slider)
- expect(wrapper.props().modelValue).toBe(0)
- })
- it('should not exceed min and max', async () => {
- const value = ref(60)
- mount(() => <Slider v-model={value.value} min={50} />)
- await nextTick()
- value.value = 40
- await nextTick()
- expect(value.value).toBe(50)
- value.value = 120
- await nextTick()
- expect(value.value).toBe(100)
- })
- it('sizes', () => {
- const value = ref(0)
- const wrapper = mount(() => <Slider v-model={value.value} size="small" />)
- expect(wrapper.find('.el-slider--small').exists()).toBe(true)
- })
- it('show tooltip', () => {
- const value = ref(0)
- const wrapper = mount(() => <Slider v-model={value.value} />)
- const slider = wrapper.findComponent({ name: 'ElSliderButton' })
- slider.vm.handleMouseEnter()
- expect(slider.vm.tooltipVisible).toBeTruthy()
- slider.vm.handleMouseLeave()
- expect(slider.vm.tooltipVisible).toBeFalsy()
- })
- it('hide tooltip', () => {
- const value = ref(0)
- const wrapper = mount({
- setup() {
- return () => (
- <Slider ref="slider" v-model={value.value} show-tooltip={false} />
- )
- },
- })
- const tooltip = wrapper.findComponent({ name: 'ElTooltip' }).vm
- expect(tooltip.disabled).toBe(true)
- })
- it('format tooltip', async () => {
- const value = ref(0)
- const formatTooltip = (val: number) => `$${val}`
- const wrapper = mount(() => (
- <Slider v-model={value.value} format-tooltip={formatTooltip} />
- ))
- const slider = wrapper.findComponent({ name: 'ElSliderButton' })
- await nextTick()
- expect(slider.vm.formatValue).toBe('$0')
- })
- it('placement', async () => {
- const TOOLTIP_CLASS = 'custom_tooltip'
- const PLACEMENT = 'left'
- mount(() => <Slider tooltip-class={TOOLTIP_CLASS} placement={PLACEMENT} />)
- await nextTick()
- await nextTick() // here
- expect(
- (document.querySelector(`.${TOOLTIP_CLASS}`) as HTMLElement).dataset
- .popperPlacement
- ).toBe(PLACEMENT)
- })
- describe('drag', () => {
- it('horizontal', async () => {
- vi.useRealTimers()
- const value = ref(0)
- const wrapper = mount(
- () => (
- <div style="width: 200px;">
- <Slider v-model={value.value} vertical={false} />
- </div>
- ),
- {
- attachTo: document.body,
- }
- )
- const slider = wrapper.findComponent({ name: 'ElSliderButton' })
- vi.spyOn(
- wrapper.find('.el-slider__runway').element,
- 'clientWidth',
- 'get'
- ).mockImplementation(() => 200)
- slider.trigger('mousedown', { clientX: 0 })
- const mousemove = new MouseEvent('mousemove', {
- screenX: 100,
- screenY: 0,
- clientX: 100,
- clientY: 0,
- })
- window.dispatchEvent(mousemove)
- const mouseup = new MouseEvent('mouseup', {
- screenX: 100,
- screenY: 0,
- clientX: 100,
- clientY: 0,
- })
- window.dispatchEvent(mouseup)
- await nextTick()
- expect(value.value === 50).toBeTruthy()
- })
- it('vertical', async () => {
- vi.useRealTimers()
- const value = ref(0)
- const wrapper = mount(
- () => (
- <div style="width: 200px;">
- <Slider v-model={value.value} vertical={true} />
- </div>
- ),
- {
- attachTo: document.body,
- }
- )
- const slider = wrapper.findComponent({ name: 'ElSliderButton' })
- vi.spyOn(
- wrapper.find('.el-slider__runway').element,
- 'clientHeight',
- 'get'
- ).mockImplementation(() => 200)
- slider.trigger('mousedown', { clientY: 0 })
- const mousemove = new MouseEvent('mousemove', {
- screenX: 0,
- screenY: -100,
- clientX: 0,
- clientY: -100,
- })
- window.dispatchEvent(mousemove)
- const mouseup = new MouseEvent('mouseup', {
- screenX: 0,
- screenY: -100,
- clientX: 0,
- clientY: -100,
- })
- window.dispatchEvent(mouseup)
- await nextTick()
- expect(value.value).toBe(50)
- })
- })
- describe('accessibility', () => {
- it('left/right arrows', async () => {
- const value = ref(0)
- const wrapper = mount(() => <Slider v-model={value.value} />)
- const slider = wrapper.findComponent({ name: 'ElSliderButton' })
- slider.vm.onKeyDown(
- new KeyboardEvent('keydown', { key: EVENT_CODE.right })
- )
- await nextTick()
- expect(value.value).toBe(1)
- slider.vm.onKeyDown(
- new KeyboardEvent('keydown', { key: EVENT_CODE.left })
- )
- await nextTick()
- expect(value.value).toBe(0)
- })
- it('up/down arrows', async () => {
- const value = ref(0.1)
- const wrapper = mount(() => <Slider v-model={value.value} />)
- const slider = wrapper.findComponent({ name: 'ElSliderButton' })
- slider.vm.onKeyDown(new KeyboardEvent('keydown', { key: EVENT_CODE.up }))
- await nextTick()
- expect(value.value).toBe(1)
- slider.vm.onKeyDown(
- new KeyboardEvent('keydown', { key: EVENT_CODE.down })
- )
- await nextTick()
- expect(value.value).toBe(0)
- })
- it('page up/down keys', async () => {
- const value = ref(-1)
- const wrapper = mount(() => (
- <Slider v-model={value.value} min={-5} max={10} />
- ))
- const slider = wrapper.findComponent({ name: 'ElSliderButton' })
- slider.vm.onKeyDown(
- new KeyboardEvent('keydown', { key: EVENT_CODE.pageUp })
- )
- await nextTick()
- expect(value.value).toBe(3)
- slider.vm.onKeyDown(
- new KeyboardEvent('keydown', { key: EVENT_CODE.pageDown })
- )
- await nextTick()
- expect(value.value).toBe(-1)
- })
- it('home/end keys', async () => {
- const value = ref(0)
- const wrapper = mount(() => (
- <Slider v-model={value.value} min={-5} max={10} />
- ))
- const slider = wrapper.findComponent({ name: 'ElSliderButton' })
- slider.vm.onKeyDown(
- new KeyboardEvent('keydown', { key: EVENT_CODE.home })
- )
- await nextTick()
- expect(value.value).toBe(-5)
- slider.vm.onKeyDown(new KeyboardEvent('keydown', { key: EVENT_CODE.end }))
- await nextTick()
- expect(value.value).toBe(10)
- })
- })
- it('step', async () => {
- vi.useRealTimers()
- const value = ref(0)
- const wrapper = mount(
- () => (
- <div style="width: 200px;">
- <Slider v-model={value.value} min={0} max={1} step={0.1} />
- </div>
- ),
- {
- attachTo: document.body,
- }
- )
- const mockClientWidth = vi
- .spyOn(wrapper.find('.el-slider__runway').element, 'clientWidth', 'get')
- .mockImplementation(() => 200)
- const slider = wrapper.findComponent({ name: 'ElSliderButton' })
- await nextTick()
- slider.trigger('mousedown', { clientX: 0 })
- const mousemove = new MouseEvent('mousemove', {
- screenX: 100,
- screenY: 0,
- clientX: 100,
- clientY: 0,
- })
- window.dispatchEvent(mousemove)
- const mouseup = new MouseEvent('mouseup', {
- screenX: 100,
- screenY: 0,
- clientX: 100,
- clientY: 0,
- })
- await nextTick()
- window.dispatchEvent(mouseup)
- await nextTick()
- expect(value.value === 0.5).toBeTruthy()
- mockClientWidth.mockRestore()
- })
- it('click', async () => {
- vi.useRealTimers()
- const value = ref(0)
- const wrapper = mount(() => <Slider v-model={value.value} />)
- const mockClientWidth = vi
- .spyOn(wrapper.find('.el-slider__runway').element, 'clientWidth', 'get')
- .mockImplementation(() => 200)
- const slider = wrapper.findComponent({ name: 'ElSlider' })
- slider.vm.onSliderClick(new MouseEvent('mousedown', { clientX: 100 }))
- await nextTick()
- expect(value.value > 0).toBeTruthy()
- mockClientWidth.mockRestore()
- })
- it('change event', async () => {
- vi.useRealTimers()
- const value = ref(0)
- const data = ref<SliderProps['modelValue']>(0)
- const onChange = (val: SliderProps['modelValue']) => (data.value = val)
- const wrapper = mount(() => (
- <div style="width: 200px">
- <Slider v-model={value.value} onChange={onChange} />
- </div>
- ))
- const slider = wrapper.findComponent({ name: 'ElSlider' })
- const mockRectLeft = vi
- .spyOn(
- wrapper.find('.el-slider__runway').element,
- 'getBoundingClientRect'
- )
- .mockImplementation(() => {
- return {
- left: 0,
- } as DOMRect
- })
- const mockClientWidth = vi
- .spyOn(wrapper.find('.el-slider__runway').element, 'clientWidth', 'get')
- .mockImplementation(() => 200)
- expect(data.value).toBe(0)
- slider.vm.onSliderClick(new MouseEvent('mousedown', { clientX: 100 }))
- await nextTick()
- expect(data.value === 50).toBeTruthy()
- mockRectLeft.mockRestore()
- mockClientWidth.mockRestore()
- })
- it('input event', async () => {
- vi.useRealTimers()
- const value = ref(0)
- const data = ref<SliderProps['modelValue']>(0)
- const onInput = (val: SliderProps['modelValue']) => (data.value = val)
- const wrapper = mount(() => (
- <div style="width: 200px">
- <Slider v-model={value.value} onInput={onInput} />
- </div>
- ))
- const slider = wrapper.findComponent({ name: 'ElSlider' })
- const mockRectLeft = vi
- .spyOn(
- wrapper.find('.el-slider__runway').element,
- 'getBoundingClientRect'
- )
- .mockImplementation(() => {
- return {
- left: 0,
- } as DOMRect
- })
- const mockClientWidth = vi
- .spyOn(wrapper.find('.el-slider__runway').element, 'clientWidth', 'get')
- .mockImplementation(() => 200)
- await nextTick()
- expect(data.value).toBe(0)
- slider.vm.onSliderClick(new MouseEvent('mousedown', { clientX: 100 }))
- await nextTick()
- expect(data.value === 50).toBeTruthy()
- mockRectLeft.mockRestore()
- mockClientWidth.mockRestore()
- })
- it('disabled', async () => {
- vi.useRealTimers()
- const value = ref(0)
- const wrapper = mount(() => <Slider v-model={value.value} disabled />)
- const mockClientWidth = vi
- .spyOn(wrapper.find('.el-slider__runway').element, 'clientWidth', 'get')
- .mockImplementation(() => 200)
- const slider = wrapper.findComponent({ name: 'ElSliderButton' })
- slider.vm.onButtonDown({ clientX: 0 })
- const mousemove = new MouseEvent('mousemove', {
- screenX: 50,
- screenY: 0,
- clientX: 50,
- clientY: 0,
- })
- window.dispatchEvent(mousemove)
- const mouseup = new MouseEvent('mouseup', {
- screenX: 50,
- screenY: 0,
- clientX: 50,
- clientY: 0,
- })
- window.dispatchEvent(mouseup)
- await nextTick()
- expect(value.value).toBe(0)
- mockClientWidth.mockRestore()
- })
- it('show input', async () => {
- const value = ref(0)
- const wrapper = mount(() => <Slider v-model={value.value} show-input />)
- const increaseButton = wrapper.find('.el-input-number__increase')
- await increaseButton.trigger('mousedown')
- vi.advanceTimersByTime(200)
- expect(value.value > 0).toBeTruthy()
- })
- it('show stops', () => {
- const wrapper = mount(() => <Slider step={10} show-stops />)
- const stops = wrapper.findAll('.el-slider__stop')
- expect(stops.length).toBe(9)
- })
- it('vertical mode', async () => {
- vi.useRealTimers()
- const value = ref(0)
- const wrapper = mount(
- () => <Slider height="200px" v-model={value.value} vertical />,
- {
- attachTo: document.body,
- }
- )
- const mockRectBottom = vi
- .spyOn(
- wrapper.find('.el-slider__runway').element,
- 'getBoundingClientRect'
- )
- .mockImplementation(() => {
- return {
- bottom: 200,
- } as DOMRect
- })
- const mockClientHeight = vi
- .spyOn(wrapper.find('.el-slider__runway').element, 'clientHeight', 'get')
- .mockImplementation(() => 200)
- const slider = wrapper.getComponent({ name: 'ElSlider' })
- slider.vm.onSliderClick(new MouseEvent('mousedown', { clientX: 100 }))
- await nextTick()
- expect(value.value > 0).toBeTruthy()
- mockRectBottom.mockRestore()
- mockClientHeight.mockRestore()
- })
- it('rerender with min and show-input', async () => {
- const value = ref(30)
- const show = ref(false)
- mount(
- {
- setup() {
- onMounted(() => (show.value = true))
- return () =>
- show.value && <Slider v-model={value.value} min={10} show-input />
- },
- },
- {
- attachTo: document.body,
- }
- )
- await nextTick()
- expect(value.value).toEqual(30)
- })
- describe('range', () => {
- it('basic ranged slider', () => {
- const value = ref([10, 20])
- const wrapper = mount(() => <Slider v-model={value.value} range />)
- const sliders = wrapper.findAllComponents({ name: 'ElSliderButton' })
- expect(sliders.length).toBe(2)
- })
- it('should not exceed min and max', async () => {
- const value = ref([50, 60])
- mount(() => <Slider v-model={value.value} min={50} range />)
- await nextTick()
- value.value = [40, 60]
- await nextTick()
- expect(value.value).toStrictEqual([50, 60])
- value.value = [50, 120]
- await nextTick()
- expect(value.value).toStrictEqual([50, 100])
- })
- it('click', async () => {
- vi.useRealTimers()
- const value = ref([0, 100])
- const wrapper = mount(
- () => (
- <div style="width: 200px;">
- <Slider v-model={value.value} range />
- </div>
- ),
- {
- attachTo: document.body,
- }
- )
- const mockRectLeft = vi
- .spyOn(
- wrapper.find('.el-slider__runway').element,
- 'getBoundingClientRect'
- )
- .mockImplementation(() => {
- return {
- left: 0,
- } as DOMRect
- })
- const mockClientWidth = vi
- .spyOn(wrapper.find('.el-slider__runway').element, 'clientWidth', 'get')
- .mockImplementation(() => 200)
- const slider = wrapper.getComponent({ name: 'ElSlider' })
- slider.vm.onSliderClick(new MouseEvent('mousedown', { clientX: 100 }))
- await nextTick()
- // Because mock the clientWidth, so the targetValue is 50.
- // The behavior of the setPosition method in the useSlider.ts file should be that the value of the second button is 50
- expect(value.value[0] === 0).toBeTruthy()
- expect(value.value[1] === 50).toBeTruthy()
- mockRectLeft.mockRestore()
- mockClientWidth.mockRestore()
- })
- it('responsive to dynamic min and max', async () => {
- const min = ref(0)
- const max = ref(100)
- const value = ref([50, 80])
- mount(() => (
- <Slider v-model={value.value} min={min.value} max={max.value} range />
- ))
- await nextTick()
- min.value = 60
- await nextTick()
- expect(value.value).toStrictEqual([60, 80])
- min.value = 30
- max.value = 40
- await nextTick()
- expect(value.value).toStrictEqual([40, 40])
- })
- it('show stops', async () => {
- const value = ref([30, 60])
- const wrapper = mount(() => (
- <Slider v-model={value.value} step={10} range show-stops />
- ))
- await nextTick()
- const stops = wrapper.findAll('.el-slider__stop')
- expect(stops.length).toBe(5)
- })
- it('marks', async () => {
- const value = ref([30, 60])
- const marksValue = ref({
- 0: '0°C',
- 8: '8°C',
- 37: '37°C',
- 50: {
- style: {
- color: '#f50',
- },
- label: h('strong', '50°C'),
- },
- })
- const wrapper = mount(() => (
- <Slider
- v-model={value.value}
- min={20}
- step={10}
- marks={marksValue.value}
- range
- show-stops
- />
- ))
- await nextTick()
- const stops = wrapper.findAll('.el-slider__marks-stop.el-slider__stop')
- const marks = wrapper.findAll('.el-slider__marks .el-slider__marks-text')
- expect(marks.length).toBe(2)
- expect(stops.length).toBe(2)
- expect(getComputedStyle(marks[marks.length - 1].element).color).toBe(
- 'rgb(255, 85, 0)'
- )
- })
- })
- describe('form item accessibility integration', () => {
- it('automatic id attachment', async () => {
- const wrapper = mount(() => (
- <ElFormItem label="Foobar" data-test-ref="item">
- <Slider />
- </ElFormItem>
- ))
- await nextTick()
- const formItem = wrapper.find('[data-test-ref="item"]')
- const formItemLabel = formItem.find('.el-form-item__label')
- const sliderButton = wrapper.find('.el-slider__button-wrapper')
- expect(formItem.attributes().role).toBeFalsy()
- expect(formItemLabel.attributes().for).toBe(sliderButton.attributes().id)
- })
- it('range with automatic id attachment', async () => {
- const wrapper = mount(() => (
- <ElFormItem label="Foobar" data-test-ref="item">
- <Slider range />
- </ElFormItem>
- ))
- await nextTick()
- const formItem = wrapper.find('[data-test-ref="item"]')
- const formItemLabel = formItem.find('.el-form-item__label')
- const sliderWrapper = wrapper.find('.el-slider')
- expect(formItem.attributes().role).toBeFalsy()
- expect(formItemLabel.attributes().for).toBe(sliderWrapper.attributes().id)
- })
- it('specified id attachment', async () => {
- const wrapper = mount(() => (
- <ElFormItem label="Foobar" data-test-ref="item">
- <Slider id="foobar" />
- </ElFormItem>
- ))
- await nextTick()
- const formItem = wrapper.find('[data-test-ref="item"]')
- const formItemLabel = formItem.find('.el-form-item__label')
- const sliderButton = wrapper.find('.el-slider__button-wrapper')
- expect(formItem.attributes().role).toBeFalsy()
- expect(sliderButton.attributes().id).toBe('foobar')
- expect(formItemLabel.attributes().for).toBe(sliderButton.attributes().id)
- })
- it('range with specified id attachment', async () => {
- const wrapper = mount(() => (
- <ElFormItem label="Foobar" data-test-ref="item">
- <Slider id="foobar" range />
- </ElFormItem>
- ))
- await nextTick()
- const formItem = wrapper.find('[data-test-ref="item"]')
- const formItemLabel = formItem.find('.el-form-item__label')
- const sliderWrapper = wrapper.find('.el-slider')
- expect(formItem.attributes().role).toBeFalsy()
- expect(sliderWrapper.attributes().id).toBe('foobar')
- expect(formItemLabel.attributes().for).toBe(sliderWrapper.attributes().id)
- })
- it('form item role is group when multiple inputs', async () => {
- const wrapper = mount(() => (
- <ElFormItem label="Foobar" data-test-ref="item">
- <Slider />
- <Slider />
- </ElFormItem>
- ))
- await nextTick()
- const formItem = wrapper.find('[data-test-ref="item"]')
- expect(formItem.attributes().role).toBe('group')
- })
- })
- })
|