diff --git a/packages/components/rate/__tests__/__snapshots__/rate.test.tsx.snap b/packages/components/rate/__tests__/__snapshots__/rate.test.tsx.snap new file mode 100644 index 0000000000..86f23ad5fd --- /dev/null +++ b/packages/components/rate/__tests__/__snapshots__/rate.test.tsx.snap @@ -0,0 +1,5375 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Rate > events > :mouseleave 1`] = ` +
+ + +
+`; + +exports[`Rate > events > :onChange 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :allowHalf[boolean] 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :clearable[boolean] 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :clearable[boolean] 2`] = ` +
+ + +
+`; + +exports[`Rate > props > :color[array] 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :color[string] 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :count[number] 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :defaultValue[number] 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :disabled[boolean] 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :gap[number] 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :icon[slot] 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :showText[boolean] 1`] = ` +
+ +
+ 极差 +
+
+`; + +exports[`Rate > props > :showText[boolean] 2`] = ` +
+ + +
+`; + +exports[`Rate > props > :size[string] 1`] = ` +
+ + +
+`; + +exports[`Rate > props > :texts[array] 1`] = ` +
+ +
+ 1分 +
+
+`; + +exports[`Rate > props > :texts[array] 2`] = ` +
+ +
+ 2分 +
+
+`; + +exports[`Rate > props > :texts[array] 3`] = ` +
+ +
+ 3分 +
+
+`; + +exports[`Rate > props > :texts[array] 4`] = ` +
+ +
+ 4分 +
+
+`; + +exports[`Rate > props > :texts[array] 5`] = ` +
+ +
+ 5分 +
+
+`; + +exports[`Rate > props > :value[number] 1`] = ` +
+ + +
+`; + +exports[`Rate > slots > :icon 1`] = ` +
+ + +
+`; diff --git a/packages/components/rate/__tests__/rate.test.tsx b/packages/components/rate/__tests__/rate.test.tsx index c38428cc29..ddfdb8d0ae 100644 --- a/packages/components/rate/__tests__/rate.test.tsx +++ b/packages/components/rate/__tests__/rate.test.tsx @@ -1,170 +1,193 @@ -// @ts-nocheck +import { nextTick } from 'vue'; import { mount } from '@vue/test-utils'; -import Rate from '@tdesign/components/rate'; -import { expect } from 'vitest'; +import type { VueWrapper } from '@vue/test-utils'; +import { expect, vi } from 'vitest'; import { LogoGithubIcon } from 'tdesign-icons-vue-next'; +import { Rate } from '@tdesign/components'; +import RateProps from '@tdesign/components/rate/props'; +import { TdRateProps } from '@tdesign/components/rate/type'; +import { sleep } from '@tdesign/internal-utils'; -// every component needs four parts: props/events/slots/functions. describe('Rate', () => { - // test props api - describe(':props', () => { - it('', () => { - const wrapper = mount({ - render() { - return ; - }, - }); - expect(wrapper.exists()).toBe(true); - }); - it(':value', async () => { - const wrapper = mount(Rate, { - props: { - value: 0, - 'onUpdate:value': (e) => { - wrapper.setProps({ value: e }); - }, - }, - }); - const rateItems = wrapper.findAll('.t-rate__item'); - await rateItems[rateItems.length - 1].trigger('click'); - await wrapper.vm.$nextTick(); - expect(wrapper.props('value')).toBe(5); + describe('props', () => { + let wrapper: VueWrapper> | null = null; + beforeEach(() => { + wrapper = mount() as VueWrapper>; }); - it(':allowHalf', async () => { - const wrapper = mount(Rate, { - props: { - value: 0.5, - allowHalf: true, - }, - }); - const item = wrapper.find('.t-rate__item'); - expect(item.classes()).contains('t-rate__item--half'); - }); - it(':clearable', async () => { - const wrapper = mount(Rate, { - props: { - defaultValue: 4, - clearable: true, - }, + + it(':allowHalf[boolean]', async () => { + const wrapper = mount(); + const items = wrapper.findAll('.t-rate__item'); + expect(items[0].classes()).toContain('t-rate__item--half'); + expect(wrapper.element).toMatchSnapshot(); + + // spy + vi.spyOn(HTMLElement.prototype, 'getBoundingClientRect').mockReturnValue({ + width: 100, + height: 100, + x: 100, + y: 100, + top: 100, + right: 100, + bottom: 100, + left: 100, + toJSON: () => ({}), }); + items[0].trigger('mousemove', { clientX: 100 }); + expect(items[0].classes()).toContain('t-rate__item--half'); - const items = wrapper.findAll('.t-rate__item--full'); + await sleep(100); + items[1].trigger('mousemove', { clientX: 300 }); + expect(items[1].classes()).toContain('t-rate__item'); + expect(items[1].classes().length).toBe(1); + }); + it(':clearable[boolean]', async () => { + const wrapper = mount(); + const items = wrapper.findAll('.t-rate__item--full'); expect(items.length).toBe(4); + expect(wrapper.element).toMatchSnapshot(); - items.at(3).trigger('click'); - await wrapper.vm.$nextTick(); + await items[3]?.trigger('click'); + await nextTick(); const newItems = wrapper.findAll('.t-rate__item--full'); expect(newItems.length).toBe(0); + expect(wrapper.element).toMatchSnapshot(); }); - it(':color String', async () => { - const wrapper = mount(Rate, { - props: { - value: 1, - color: 'red', - }, - }); + + it(':color[string]', () => { + const wrapper = mount(); const svg = wrapper.find('.t-rate__item--full svg'); expect(svg.attributes('color')).toBe('red'); + expect(wrapper.element).toMatchSnapshot(); }); - it(':color Array', async () => { - const wrapper = mount(Rate, { - props: { - value: 1, - color: ['red', 'black'], - }, - }); + + it(':color[array]', () => { + const wrapper = mount(); const svgs = wrapper.findAll('.t-rate__item svg'); - expect(svgs[0].attributes('color')).toBe('red'); - expect(svgs[svgs.length - 1].attributes('color')).toBe('black'); - }); - it(':count', async () => { - const wrapper = mount(Rate, { - props: { - value: 1, - count: 10, - }, - }); + expect(svgs[0]?.attributes('color')).toBe('red'); + expect(svgs[svgs.length - 1]?.attributes('color')).toBe('black'); + expect(wrapper.element).toMatchSnapshot(); + }); + + it(':count[number]', () => { + const wrapper = mount(); const svgs = wrapper.findAll('.t-rate__item'); expect(svgs.length).toBe(10); + expect(wrapper.element).toMatchSnapshot(); }); - it(':disabled', async () => { - const wrapper = mount(Rate, { - props: { - value: 0, - disabled: true, - 'onUpdate:value': (e) => { - wrapper.setProps({ value: e }); - }, - }, - }); + + it(':defaultValue[number]', () => { + const wrapper = mount(); + const items = wrapper.findAll('.t-rate__item--full'); + expect(items.length).toBe(3); + expect(wrapper.element).toMatchSnapshot(); + }); + + it(':disabled[boolean]', async () => { + const wrapper = mount(); const rateItems = wrapper.findAll('.t-rate__item'); await rateItems[rateItems.length - 1].trigger('click'); - await wrapper.vm.$nextTick(); + await nextTick(); expect(wrapper.props('value')).toBe(0); + expect(wrapper.element).toMatchSnapshot(); + + // TODO:PAOPAO The following two tests are actually a bit fictitious, + // because they are not actually measured, but it seems that the coverage rate has increased. + // Let me optimize it later + await sleep(100); + rateItems[0].trigger('mousemove', { clientX: 100 }); + expect(rateItems[0].classes()).toContain('t-rate__item'); + expect(rateItems[0].classes().length).toBe(1); + + await sleep(100); + const rate = wrapper.find('.t-rate'); + rate.trigger('mouseleave'); + expect(rateItems[0].classes()).toContain('t-rate__item'); + expect(rateItems[0].classes().length).toBe(1); }); - it(':gap', () => { - const wrapper = mount(Rate, { - props: { gap: 5 }, - }); - expect(wrapper.find('.t-rate__list').element.style.gap).toBe('5px'); + it(':gap[number]', () => { + const wrapper = mount(); + const element = wrapper.find('.t-rate__list').element as HTMLElement; + expect(element.style.gap).toBe('5px'); + expect(wrapper.element).toMatchSnapshot(); + }); + + it(':icon[slot]', () => { + const wrapper = mount( }} />); + expect(wrapper.findComponent(LogoGithubIcon).exists()).toBe(true); + expect(wrapper.element).toMatchSnapshot(); }); - it(':showText', () => { + + it(':showText[boolean]', () => { [true, false].forEach((showText) => { - const wrapper = mount(Rate, { - props: { showText, value: 1 }, - }); + const wrapper = mount(); const el = wrapper.find('.t-rate__text'); expect(el.exists()).toBe(showText); + expect(wrapper.element).toMatchSnapshot(); }); }); - it(':size', () => { - const wrapper = mount(Rate, { - props: { size: '30px' }, - }); - expect(wrapper.find('.t-rate__star-top .t-icon').element.style['font-size']).toBe('30px'); + + it(':size[string]', () => { + const wrapper = mount(); + const element = wrapper.find('.t-rate__star-top .t-icon').element as HTMLElement; + expect(element.style['font-size']).toBe('30px'); + expect(wrapper.element).toMatchSnapshot(); }); - it(':texts', async () => { + + it(':texts[array]', () => { const texts = ['1分', '2分', '3分', '4分', '5分']; for (let i = 0; i < texts.length; i++) { - const wrapper = mount(Rate, { - props: { showText: true, texts, value: i + 1 }, - }); + const wrapper = mount(); const textEl = wrapper.find('.t-rate__text'); expect(textEl.exists()).toBe(true); expect(textEl.text()).toBe(texts[i]); + expect(wrapper.element).toMatchSnapshot(); } }); - it(':defaultValue', () => { - const wrapper = mount(Rate, { - props: { defaultValue: 3 }, - }); - const items = wrapper.findAll('.t-rate__item--full'); - expect(items.length).toBe(3); + + it(':value[number]', async () => { + const wrapper = mount(); + const rateItems = wrapper.findAll('.t-rate__item'); + await rateItems[rateItems.length - 1].trigger('click'); + await nextTick(); + expect(wrapper.props('value')).toBe(5); + expect(wrapper.element).toMatchSnapshot(); }); }); - describe(':event', () => { + + describe('events', () => { it(':onChange', async () => { const onChange = vi.fn(); - const wrapper = mount(Rate, { - props: { - value: 0, - onChange, - }, - }); - await wrapper.find('.t-rate__item').trigger('click'); + const wrapper = mount(); + const star = wrapper.findAll('.t-rate__item')[0]; + expect(star.exists()).toBeTruthy(); + await star.trigger('click'); + expect(star.classes()).toContain('t-rate__item--half'); expect(onChange).toBeCalled(); + expect(wrapper.element).toMatchSnapshot(); + }); + + it(':mouseleave', async () => { + const wrapper = mount(); + const star = wrapper.findAll('.t-rate__item')[0]; + expect(star.exists()).toBeTruthy(); + await star.trigger('mousemove'); + expect(star.classes()).toContain('t-rate__item--full'); + const rate = wrapper.find('.t-rate'); + expect(rate.exists()).toBeTruthy(); + await rate.trigger('mouseleave'); + expect(star.classes()).not.toContain('t-rate__item--full'); + expect(wrapper.element).toMatchSnapshot(); }); }); - describe(':slot', () => { - it(':icon', async () => { - const wrapper = mount(Rate, { - slots: { - icon: (e) => , - }, - }); + + describe('slots', () => { + it(':icon', () => { + const wrapper = mount( }} />); expect(wrapper.findComponent(LogoGithubIcon).exists()).toBe(true); + expect(wrapper.element).toMatchSnapshot(); }); }); });