基於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
更多功能待完善....