前端测试(Vue)

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

测试驱动开发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值