Skip to content

Commit

Permalink
test(Image): improve unit test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
anlyyao committed Oct 12, 2022
1 parent 1bf78b8 commit f428d89
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 63 deletions.
15 changes: 15 additions & 0 deletions src/image/__test__/__snapshots__/index.test.jsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Vitest Snapshot v1

exports[`Image > props > : lazy 1`] = `
<div
class="t-image t-image--round"
>
<!--v-if-->
<img
alt=""
class="t-image__img"
src="https://tdesign.gtimg.com/site/upload1.png"
style="object-fit: fill; object-position: center;"
/>
</div>
`;
184 changes: 121 additions & 63 deletions src/image/__test__/index.test.jsx
Original file line number Diff line number Diff line change
@@ -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(() => <Image src={IMAGE} />);
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(() => <Image src={IMAGE} alt="图片" />);
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(() => <Image src={IMAGE} lazy />);
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(() => <Image src={IMAGE} fit={fit} />);
const img = wrapper.find('.t-image__img');
expect(img.attributes('style')).toContain(`object-fit: ${fit}`);
it(': alt', async () => {
const wrapper = mount(() => <Image src={IMAGE} alt="图片" />);
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(() => <Image src={IMAGE} shape={shape} />);
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(() => <Image src={IMAGE} position={position} />);
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: () => <LoadingIcon />,
};
const wrapper = mount(() => <Image src={IMAGE} v-slots={slots} />);
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(() => <Image src={IMAGE} position={position} />);
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(() => <Image src={FAIL_IMAGE} v-slots={slots} onError={onError} />);
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: () => <LoadingIcon />,
};
const wrapper = mount(() => <Image src={IMAGE} v-slots={slots} />);
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(() => <Image src={IMAGE} onLoad={onLoad} />);
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(() => <Image src='' onError={onError} />);
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(() => <Image src={FAIL_IMAGE} v-slots={slots} onError={onError} />);
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(() => <Image src={IMAGE} onLoad={onLoad} />);
await nextTick();
const $image = wrapper.find(`.${name}__img`);
expect($image.attributes('src')).toBe(IMAGE);
// 手动触发 图片加载完成的回调函数
await $image.trigger('Load');
expect(onLoad).toBeCalledTimes(1);
});
});
});
34 changes: 34 additions & 0 deletions src/image/__test__/utils.ts
Original file line number Diff line number Diff line change
@@ -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,
},
]);
};
}

0 comments on commit f428d89

Please sign in to comment.