Add test for component "ClosetItem"

This commit is contained in:
Pig Fang 2018-07-27 16:17:22 +08:00
parent 83c40cfd40
commit 69e9641bf4
2 changed files with 258 additions and 0 deletions

View File

@ -0,0 +1,141 @@
<template>
<div class="item" :class="{ 'item-selected': selected }">
<div class="item-body" @click="$emit('select')">
<img :src="previewLink">
</div>
<div class="item-footer">
<p class="texture-name">
<span :title="name">{{ textureName }} <small>({{ type }})</small></span>
</p>
<a :href="linkToSkinlib" :title="$t('user.viewInSkinlib')" class="more" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-share"></i></a>
<span :title="$t('general.more')" class="more" data-toggle="dropdown" aria-haspopup="true" id="more-button"><i class="fa fa-cog"></i></span>
<ul class="dropup dropdown-menu" aria-labelledby="more-button">
<li><a @click="rename" v-t="'user.renameItem'"></a></li>
<li><a @click="remove" v-t="'user.removeItem'"></a></li>
<li><a @click="setAsAvatar" v-t="'user.setAsAvatar'"></a></li>
</ul>
</div>
</div>
</template>
<script>
import swal from 'sweetalert2';
import toastr from 'toastr';
import axios from 'axios';
export default {
name: 'ClosetItem',
props: {
tid: {
type: Number,
required: true,
},
type: {
type: String,
validator: value => ['steve', 'alex', 'cape'].includes(value)
},
name: {
type: String,
required: true
},
selected: Boolean
},
computed: {
previewLink() {
return `${blessing.base_url}/preview/${this.tid}.png`;
},
linkToSkinlib() {
return `${blessing.base_url}/skinlib/show/${this.tid}`;
}
},
data() {
return {
textureName: this.name
};
},
methods: {
async rename() {
let newTextureName = '';
try {
newTextureName = await swal({
title: this.$t('user.renameClosetItem'),
input: 'text',
inputValue: this.textureName,
showCancelButton: true,
inputValidator: value => (new Promise((resolve, reject) => {
value ? resolve() : reject(this.$t('skinlib.emptyNewTextureName'));
}))
});
} catch (error) {
return;
}
const { data: { errno, msg } } = await axios.post(
'/user/closet/rename',
{ tid: this.tid, new_name: newTextureName }
);
if (errno === 0) {
this.textureName = newTextureName;
toastr.success(msg);
} else {
toastr.warning(msg);
}
},
async remove() {
try {
await swal({
text: this.$t('user.removeFromClosetNotice'),
type: 'warning',
showCancelButton: true
});
} catch (error) {
return;
}
const { data: { errno, msg } } = await axios.post(
'/user/closet/remove',
{ tid: this.tid }
);
if (errno === 0) {
this.$emit('item-removed', this.tid);
swal({ type: 'success', html: msg });
} else {
toastr.warning(msg);
}
},
async setAsAvatar() {
try {
await swal({
title: this.$t('user.setAvatar'),
text: this.$t('user.setAvatarNotice'),
type: 'question',
showCancelButton: true
});
} catch (error) {
return;
}
const { data: { errno, msg } } = await axios.post(
'/user/profile/avatar',
{ tid: this.tid }
);
if (errno === 0) {
toastr.success(msg);
// Refresh avatars
$('[alt="User Image"]').each(function () {
$(this).prop('src', $(this).attr('src') + '?' + new Date().getTime());
});
} else {
toastr.warning(msg);
}
}
}
};
</script>

View File

@ -0,0 +1,117 @@
import { mount } from '@vue/test-utils';
import ClosetItem from '@/user/ClosetItem';
import axios from 'axios';
import swal from 'sweetalert2';
jest.mock('axios');
jest.mock('sweetalert2');
window.blessing = {
base_url: ''
};
function factory(opt = {}) {
return {
tid: 1,
name: 'texture',
type: 'steve',
...opt
};
}
beforeEach(() => {
axios.post.mockReset();
swal.mockReset();
});
test('computed values', () => {
const wrapper = mount(ClosetItem, { propsData: factory() });
expect(wrapper.find('img').attributes().src).toBe('/preview/1.png');
expect(wrapper.find('a.more').attributes().href).toBe('/skinlib/show/1');
});
test('selected item', () => {
const wrapper = mount(ClosetItem, { propsData: factory({ selected: true }) });
expect(wrapper.find('.item').classes()).toContain('item-selected');
});
test('click item body', () => {
const wrapper = mount(ClosetItem, { propsData: factory() });
wrapper.find('.item').trigger('click');
expect(wrapper.emitted().select).toBeUndefined();
wrapper.find('.item-body').trigger('click');
expect(wrapper.emitted().select).toBeTruthy();
});
test('rename texture', async () => {
axios.post
.mockResolvedValueOnce({ data: { errno: 0 } })
.mockResolvedValueOnce({ data: { errno: 1 } });
swal.mockImplementation(async options => {
options.inputValidator('name');
options.inputValidator().catch(() => {});
return 'new-name';
});
const wrapper = mount(ClosetItem, { propsData: factory() });
const button = wrapper.findAll('.dropdown-menu > li').at(0).find('a');
button.trigger('click');
await wrapper.vm.$nextTick();
button.trigger('click');
await wrapper.vm.$nextTick();
expect(wrapper.find('.texture-name > span').text()).toBe('new-name (steve)');
expect(axios.post).toBeCalledWith(
'/user/closet/rename',
{ tid: 1, new_name: 'new-name' }
);
});
test('remove texture', async () => {
axios.post
.mockResolvedValueOnce({ data: { errno: 0 } })
.mockResolvedValueOnce({ data: { errno: 1 } });
swal.mockResolvedValue();
const wrapper = mount(ClosetItem, { propsData: factory() });
const button = wrapper.findAll('.dropdown-menu > li').at(1).find('a');
button.trigger('click');
await wrapper.vm.$nextTick();
button.trigger('click');
await wrapper.vm.$nextTick();
await wrapper.vm.$nextTick();
expect(wrapper.emitted()['item-removed'][0][0]).toBe(1);
expect(axios.post).toBeCalledWith('/user/closet/remove', { tid: 1 });
});
test('set as avatar', async () => {
axios.post
.mockResolvedValueOnce({ data: { errno: 0 } })
.mockResolvedValueOnce({ data: { errno: 1 } });
swal.mockResolvedValue();
window.$ = jest.fn(() => ({
each(fn) { fn(); },
prop() {},
attr() { return ''; }
}));
const wrapper = mount(ClosetItem, { propsData: factory() });
const button = wrapper.findAll('.dropdown-menu > li').at(2).find('a');
button.trigger('click');
await wrapper.vm.$nextTick();
button.trigger('click');
await wrapper.vm.$nextTick();
await wrapper.vm.$nextTick();
expect(axios.post).toBeCalledWith('/user/profile/avatar', { tid: 1 });
expect(window.$).toBeCalledWith('[alt="User Image"]');
});