Jset
支持断言、异步支持、Mock,代码覆盖率、开箱即用、Fast
test("name",()=>{
expect(2+2).toBe(4)
expect(2+2).not.toBe(5 )
})
const fetchuser = (cb) => {
setTimeout(() => {
cb("user");
}, 100);
};
it("testCB", (done) => {
fetchuser((value) => {
expect(value).toBe("user");
done();
});
});
const userPromise = Promise.resolve("aa");
it("testPromise", () => {
return userPromise.then((value) => {
expect(value).toBe("aa");
});
});
it("testAsync", async () => {
const value = await userPromise;
expect(value).toBe("aa");
});
it("test with expect",()=>{
return expect(userPromise()).resolves.toBe('aa')
})
const axios = require("axios");
jest.mock("axios"); //接管axios模块
axios.get.mockImplementation(() => {
return Promise.resolve({ data: "hello world" });
});
it("test with mock function", () => {
const mockCb = jest.fn(); //模拟一个函数、环境、参数等
mockTest(true, mockCb);
expect(mockCb).toHaveBeenCalled();
expect(mockCb).toHaveBeenCalledTimes(1);
expect(mockCb).toHaveBeenCalledWith("hello world");
});
const loopFetchuser=(cb)=>{
setTimeout(()=>{
cb("aa")
setTimeout(()=>{
cb("hello world")
},100)
},100)
}
jest.useFakeTimers() //接管setTimeout
it("test looptimeout", () => {
const callback=jest.fn()
loopFetchuser(callback)
expect(callback).toHaveBeenCalledTimes()
jest.runAllTimers() //运行所有定时器,待所有定时器执行完成
expect(callback).toHaveBeenCalledTimes(2) //调用次数
})
it("test looptimeout", () => {
const callback=jest.fn()
loopFetchuser(callback)
expect(callback).toHaveBeenCalledTimes()
jest.runOnlyPendingTimes() //运行第一次调用的定时器
expect(callback).toHaveBeenCalledTimes(1) //调用次数
//处理
expect(callback).toHaveBeenCalledTimes() //运行第二次的定时器
expect(callback).toHaveBeenCalledTimes(2) //调用次数
})
//控制时间
it("test looptimeout", () => {
const callback=jest.fn()
loopFetchuser(callback)
jest.advanceTimersByTime(100) //前进100ms
expect(callback).toHaveBeenCalledTimes(1) //调用次数
jest.advanceTimersByTime(50)
expect(callback).toHaveBeenCalledTimes(2) //err未到达第二次执行时间 //调用次数
})
Vue Test Utils
手动配置太过繁琐、我们可以使用插件,注意项目基于vue-cli 、、vue add unit-jest
简单测试
import { shallowMount, mount } from '@vue/test-utils';
import flushPromise from 'flush-promises';
import HelloWorld from '@/components/HelloWorld.vue';
import axios from 'axios';
jest.mock('axios');
const MockAxios = axios as jest.Mocked<typeof axios>;
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message';
const wrapper = shallowMount(HelloWorld, {
props: { msg }
}); //挂载一个组件 shallowMount 浅层挂载也就是只渲染组件本身,子组件不管
console.log(wrapper.html());
console.log(wrapper.get('h1').text()); //获取组件的h1标签的内容
console.log(wrapper.find('h1').text()); //不返回error 找不到返回一个空对象
//fingComponent 找到组件,可以传入一个组件对象查找
console.log(wrapper.findComponent({ name: 'HelloWorld' }).exists()); //判断组件是否存在.props()获取组件的props
it('renders props.msg when passed', async () => {
const msg = 'new message';
const wrapper = mount(HelloWorld, {
props: { msg }
});
await wrapper.get('button').trigger('click');
expect(wrapper.get('button').text()).toBe('2');
//验证表单
await wrapper.get('input').setValue('hello');
expect(wrapper.get('input').element.value).toBe('hello');
await wrapper.get('button').trigger('click');
expect(wrapper.get('.addTodo').text()).toBe('3');
//验证emit是否发送
expect(wrapper.emitted()).toHaveProperty('add');
const events = wrapper.emitted('add');
expect(events[0][0]).toEqual({ text: 'hello', id: 3 });
});
//跳过其他测试,只跑这一个
it.only('mock axios', async () => {
MockAxios.get.mockResolvedValue({ data: { msg: 'hello' } });
wrapper.get('.loading').exists().toBeTruthy();
await flushPromise(); //等待异步操作完成,界面更新完毕
wrapper.get('.loading').exists().toBeFalsy();
expect(wrapper.get('.msg').text()).toBe('hello');
});
});
});
ant-design-vue和复杂单页面
import { mount, VueWrapper } from '@vue/test-utils';
import UserProfile from './UserProfile.vue';
import { message } from 'ant-design-vue';
import store from '@/store';
let wrapper: VueWrapper<any>;
const mockedRoutes: string[] = ['/login'];
jest.mock('vue-router', () => ({
useRouter: () => ({
push: (url: string) => mockedRoutes.push(url)
})
}));
jest.mock('ant-design-vue', () => ({
message: {
success: jest.fn()
}
}));
const mockTemplate = {
template: '<div><slot></slot></div>'
};
const mockTemplate2 = {
template: '<div><slot></slot><slot name="overlay"></slot></div>'
};
const globalComponent = {
'a-button': mockTemplate,
'a-dropdown-button': mockTemplate2
};
describe('UserProfile.vue', () => {
beforeEach(() => {
jest.useFakeTimers();
wrapper = mount(
UserProfile,
{
props: {
user: { isLogin: false }
}
},
{
global: {
components: globalComponent,
provide: {
store
}
}
}
);
});
it('is a Vue instance', async () => {
await wrapper.get('div').trigger('click');
expect(message).toHaveBeenCalled(); // 希望调用message.success
expect(store.state.user.isLogin).toBe(true); // 希望store.state.user.isLogin为true
});
it('is a Vue instance', () => {
expect(wrapper.get('div').text()).toBe('登录'); //希望有包含登录的div
});
it('is a Vue instance', async () => {
await wrapper.setProps({ user: { isLogin: true, username: '用户名' } });
expect(wrapper.get('.userProfileComponent').html()).toContain('用户名'); //希望有包含用户名 的div
expect(wrapper.find('.userProfile-deopdown').exists()).toBeTruthy(); //希望存在登出按钮
});
it('ccc', async () => {
await wrapper.get('.user div').trigger('click');
expect(store.state.user.isLogin).toBe(true);
expect(message.success).toHaveBeenCalled(); // 希望调用message.success
jest.runAllTimers();
expect(mockedRoutes).toEqual('/');
});
afterEach(() => {
(message as jest.Mocked<typeof message>).success.mockReset();
});
});
单测-store
import store from '@/store/index'
import { testData } from '@/store/templates'
// import { testComponents, ComponentData } from '@/store/editor'
import { clone, last } from 'lodash-es'
// import { textDefaultProps } from 'lego-bricks'
const cloneComponents = clone(testComponents)
jest.mock('ant-design-vue')
describe('test vuex store', () => {
it('should have three modules', () => {
expect(store.state).toHaveProperty('user')
expect(store.state).toHaveProperty('templates')
expect(store.state).toHaveProperty('editor')
})
describe('test user module', () => {
it('test login mutation', () => {
store.commit('login')
expect(store.state.user.isLogin).toBeTruthy()
})
it('test logout mutation', () => {
store.commit('logout')
expect(store.state.user.isLogin).toBeFalsy()
})
})
describe('test templates module', () => {
it('should have default templates', () => {
expect(store.state.templates.data).toHaveLength(testData.length)
})
it('should get the correct template by Id', () => {
const selectTemplate = store.getters.getTemplateById(1)
expect(selectTemplate.title).toBe('test title 1')
})
})
})
TDD
测试驱动开发