diff --git a/src/image/__test__/__snapshots__/index.test.jsx.snap b/src/image/__test__/__snapshots__/index.test.jsx.snap new file mode 100644 index 000000000..91f2e6185 --- /dev/null +++ b/src/image/__test__/__snapshots__/index.test.jsx.snap @@ -0,0 +1,15 @@ +// Vitest Snapshot v1 + +exports[`Image > props > : lazy 1`] = ` +
+ + +
+`; diff --git a/src/image/__test__/index.test.jsx b/src/image/__test__/index.test.jsx index 47907ee72..08c252e76 100644 --- a/src/image/__test__/index.test.jsx +++ b/src/image/__test__/index.test.jsx @@ -1,86 +1,144 @@ import { mount } from '@vue/test-utils'; -import { describe, it, expect } from 'vitest'; -import Image from '../image.vue'; +import { vi, describe, it, expect } from 'vitest'; import { LoadingIcon } from 'tdesign-icons-vue-next'; import { nextTick } from 'vue'; -import { vi } from 'vitest'; +import Image from '../image.vue'; +import { MockIntersectionObserver } from './utils'; +const prefix = 't' +const name = `${prefix}-image`; const IMAGE = 'https://tdesign.gtimg.com/site/upload1.png'; const FAIL_IMAGE = 'https://123.jpg'; const fitList = ['fill', 'contain', 'cover', 'none', 'scale-down']; const shapeList = ['circle', 'round', 'square']; const positionList = ['top', 'bottom', 'center', 'left', 'right']; -describe('Image.vue', () => { - it('create', async () => { - const wrapper = mount(() => ); - const img = wrapper.find('.t-image__img'); - expect(wrapper.classes()).toContain('t-image'); - expect(img.exists()).toBeTruthy(); - expect(img.attributes('src')).toBe(IMAGE); +describe('Image', () => { + beforeAll(() => { + window.IntersectionObserver = MockIntersectionObserver; }); - it('alt render', async () => { - const wrapper = mount(() => 图片); - const img = wrapper.find('.t-image__img'); - expect(wrapper.classes()).toContain('t-image'); - expect(img.attributes('alt')).toBe('图片'); - }); + describe('props', () => { + it(': lazy', async () => { + const wrapper = mount(() => ); + await nextTick(); + const $image = wrapper.find(`.${name}__img`); + expect(wrapper.find(`.${name}__status`).exists()).toBeTruthy(); + // 触发 IntersectionObserver , 但图片加载完成不会触发 Load 回调, + $image.trigger('resize'); + await nextTick(); + expect($image.attributes('src')).toBe(IMAGE); + // 手动触发 图片加载完成的回调函数 + await $image.trigger('Load'); + expect(wrapper.element).toMatchSnapshot(); + expect(wrapper.find(`.${name}__status`).exists()).toBeFalsy(); + }); - it('fit render', async () => { - fitList.forEach((fit) => { - const wrapper = mount(() => ); - const img = wrapper.find('.t-image__img'); - expect(img.attributes('style')).toContain(`object-fit: ${fit}`); + it(': alt', async () => { + const wrapper = mount(() => 图片); + const $image = wrapper.find(`.${name}__img`); + expect(wrapper.classes()).toContain(`${name}`); + expect($image.attributes('alt')).toBe('图片'); }); - }); - it('shape render', async () => { - shapeList.forEach((shape) => { - const wrapper = mount(() => ); - expect(wrapper.classes()).toContain(`t-image--${shape}`); + it(': fit', async () => { + const wrapper = mount(Image, { + props: { + fit: '', + src: IMAGE, + } + }) + const $image = wrapper.find(`.${name}__img`); + // fit = '' + fitList.forEach(item => { + expect($image.attributes('style').includes(`object-fit: ${item}`)).toBeFalsy(); + }) + + const fit = 'cover'; + await wrapper.setProps({ + fit, + }); + // fit = 'square' + expect($image.attributes('style')).toContain(`object-fit: ${fit}`); }); - }); - it('position render', async () => { - positionList.forEach((position) => { - const wrapper = mount(() => ); - const img = wrapper.find('.t-image__img'); - expect(img.attributes('style')).toContain(`object-position: ${position}`); + it(': shape', async () => { + const wrapper = mount(Image, { + props: { + shape: '', + src: IMAGE, + } + }) + const $image = wrapper.findComponent(Image); + + // shape = '' + shapeList.forEach(item => { + expect($image.classes().includes(`${name}--${item}`)).toBeFalsy(); + }) + + const shape = 'square'; + await wrapper.setProps({ + shape, + }); + // shape = 'square' + expect($image.classes()).toContain(`${name}--${shape}`); }); - }); - it('loading render', async () => { - const slots = { - loading: () => , - }; - const wrapper = mount(() => ); - const status = wrapper.find('.t-image__status'); - expect(status.exists()).toBeTruthy(); - expect(wrapper.findComponent(LoadingIcon).exists()).toBeTruthy(); - }); + it(': position', async () => { + positionList.forEach((position) => { + const wrapper = mount(() => ); + const $image = wrapper.find('.t-image__img'); + expect($image.attributes('style')).toContain(`object-position: ${position}`); + }); + }); - it('error render', async () => { - const onError = vi.fn(); - const slots = { - error: () => '加载失败', - }; - const wrapper = mount(() => ); - const img = wrapper.find('.t-image__img'); - const status = wrapper.find('.t-image__status'); - await nextTick(); - await img.trigger('error'); - expect(status.exists()).toBeTruthy(); - // expect(status.text()).toBe('加载失败'); - // expect(onError).toBeCalled(); - }); + it(': loading', async () => { + const slots = { + loading: () => , + }; + const wrapper = mount(() => ); + const $status = wrapper.find(`.${name}__status`); + expect($status.exists()).toBeTruthy(); + expect(wrapper.findComponent(LoadingIcon).exists()).toBeTruthy(); + }); - it('load render', async () => { - const onLoad = vi.fn(); - const wrapper = mount(() => ); - const img = wrapper.find('.t-image__img'); - await nextTick(); - img.trigger('load'); - // expect(onLoad).toBeCalled(); + it(': src', async () => { + const onError = vi.fn(); + const wrapper = mount(() => ); + await nextTick(); + const $image = wrapper.find(`.${name}__img`); + // 手动触发 图片加载失败的回调函数 + await $image.trigger('Error'); + expect(wrapper.find(`.${name}__status`).exists()).toBeTruthy(); + // src = '',不会触发 error + expect(onError).toBeCalledTimes(0); + }); + + it(': onError', async () => { + const onError = vi.fn(); + const slots = { + error: () => '加载失败', + }; + const wrapper = mount(() => ); + await nextTick(); + const $image = wrapper.find(`.${name}__img`); + // 手动触发 图片加载失败的回调函数 + await $image.trigger('Error'); + const status = wrapper.find(`.${name}__status`); + expect(status.exists()).toBeTruthy(); + expect(status.text()).toBe('加载失败'); + expect(onError).toBeCalledTimes(1); + }); + + it(': onLoad', async () => { + const onLoad = vi.fn(); + const wrapper = mount(() => ); + await nextTick(); + const $image = wrapper.find(`.${name}__img`); + expect($image.attributes('src')).toBe(IMAGE); + // 手动触发 图片加载完成的回调函数 + await $image.trigger('Load'); + expect(onLoad).toBeCalledTimes(1); + }); }); }); diff --git a/src/image/__test__/utils.ts b/src/image/__test__/utils.ts new file mode 100644 index 000000000..c28acdf80 --- /dev/null +++ b/src/image/__test__/utils.ts @@ -0,0 +1,34 @@ +interface IntersectionObserverCallback { + (entries: IntersectionObserverEntry[], observer: IntersectionObserver): void; +} + +export class MockIntersectionObserver { + _callback: Function; + + _element!: HTMLElement; + + constructor(callback: Function) { + this._callback = callback; + } + + observe(element: HTMLElement) { + this._element = element; + this._element.addEventListener('resize', this.trigger); + } + + unobserve() { + this._element.removeEventListener('resize', this.trigger); + } + + disconnect() { + this._element.removeEventListener('resize', this.trigger); + } + + trigger = (event: UIEvent) => { + this._callback([ + { + isIntersecting: true, + }, + ]); + }; +}