基于React+Ant Design(如下用Antd表示)的项目,在对于本身封装的,或者基于Antd封装的公共组件的自动化测试技术的选型和实践。前端
随着前端项目愈来愈大,业务逻辑日益繁杂,协同开发的同事也愈来愈多,迭代频繁,许多页面有一些类似的功能,会复用一些组件,这些组件被剥离出来,通常放在component文件夹下,你们共同维护,这时会出现一些常见问题:react
铭记:测试不是最终目的,尽量在开发阶段有意识地提升代码质量、规避问题。后端
jest针对为实现某些业务逻辑而封装的函数,设定多种可能的输入,判断是否准确地返回了指望值框架
侧边菜单栏组件(./src/componets/SiderMenu.js)中使用到的数据和逻辑处理函数输入输出表现ide
业务角度分析:这是一个按权限展现的多级侧边主菜单栏。(权限方面须要测试及后端人员进行)
组件实现分析:根据后端提供的数据作菜单展现,若是存在多级数据就多级展现,同时可基于菜单实现路由映射。(jest单元测试)函数
如下两个文件中包含并导出了咱们的测试对象组件SiderMenu使用到的函数
**js文件1:./src/componets/_utils/pathTools.js**单元测试
// /userinfo/2144/id => ['/userinfo','/useinfo/2144,'/userindo/2144/id'] export function urlToList(url) { const urllist = url.split('/').filter(i => i); return urllist.map((urlItem, index) => { return `/${urllist.slice(0, index + 1).join('/')}`; }); }
js文件2:./src/componets/SiderMenu.js测试
...... ...... /** * 递归扁平化数据 * [{path:string},{path:string}] => [path,path2] * @param menu */ export const getFlatMenuKeys = menu => menu.reduce((keys, item) => { keys.push(item.path); if (item.children) { return keys.concat(getFlatMenuKeys(item.children)); } return keys; }, []); /** * 根据paths查找全部匹配的菜单的keys * @param flatMenuKeys: [/abc, /abc/:id, /abc/:id/info] * @param paths: [/abc, /abc/11, /abc/11/info] */ export const getMenuMatchKeys = (flatMenuKeys, paths) => paths.reduce( (matchKeys, path) => matchKeys.concat(flatMenuKeys.filter(item => pathToRegexp(item).test(path))), [] ); ...... ......
在测试组件目录下添加.test.js文件,运行jest将会自动识别并执行.test.js结尾的文件进行测试。ui
测试用例:SlideMenu.test.jsurl
// 导入待测试的三个函数 import { urlToList } from '../_utils/pathTools'; import { getFlatMenuKeys, getMenuMatchKeys } from './SiderMenu'; // 先mock一个测试的菜单栏数据做为参数 const menu = [ { path: '/dashboard', children: [ { path: '/dashboard/name', }, ], }, { path: '/userinfo', children: [ { path: '/userinfo/:id', children: [ { path: '/userinfo/:id/info', }, ], }, ], }, ]; // 传入mock的数据给getFlatMenuKeys获得的输出为flatMenuKeys const flatMenuKeys = getFlatMenuKeys(menu); // 测试getFlatMenuKeys返回的结果是否符合咱们的预期 describe('test convert nested menu to flat menu', () => { it('simple menu', () => { expect(flatMenuKeys).toEqual([ '/dashboard', '/dashboard/name', '/userinfo', '/userinfo/:id', '/userinfo/:id/info', ]); }); }); // 测试菜单匹配 模拟多种可能的输入是否符合指望(多种输入对应的输出是否符合预期) describe('test menu match', () => { // 简单的一级菜单应该返回对应的一个一级菜单结果 it('simple path', () => { expect(getMenuMatchKeys(flatMenuKeys, urlToList('/dashboard'))).toEqual(['/dashboard']); }); // 错误或不存在的路径应该返回[] it('error path', () => { expect(getMenuMatchKeys(flatMenuKeys, urlToList('/dashboardname'))).toEqual([]); }); // 二级菜单应该返回对应的全部菜单keys it('Secondary path', () => { expect(getMenuMatchKeys(flatMenuKeys, urlToList('/dashboard/name'))).toEqual([ '/dashboard', '/dashboard/name', ]); }); // 存在参数的路径应该返回对应的预期 it('Parameter path', () => { expect(getMenuMatchKeys(flatMenuKeys, urlToList('/userinfo/2144'))).toEqual([ '/userinfo', '/userinfo/:id', ]); }); // 三级带参数路径 it('three parameter path', () => { expect(getMenuMatchKeys(flatMenuKeys, urlToList('/userinfo/2144/info'))).toEqual([ '/userinfo', '/userinfo/:id', '/userinfo/:id/info', ]); }); });
// 由于当前项目是基于roadhog、roadhog将Jest已经隐藏 yarn roadhog test ./src/componets/SiderMenu // 若是是普通react项目使用jest须要安装 yarn jest test ./src/componets/SiderMenu
更多功能待完善....