记录在进行单元测试中所遇到的特殊场景,使用的依赖版本为 "jest": "26.6.0"
。不断补充,积少成多(但愿吧···)
模拟 DOM 事件
这里以模拟touch
事件为例。测试中需要模拟左滑和右滑,需要触发 touchstart
和 touchmove
等事件。
使用 dispatchEvent(event: Event)
|
describe('TouchLREvent', () => { |
|
// 目标元素 |
|
let demoDom: HTMLElement | null = null; |
|
|
|
beforeAll(() => { |
|
// 创建并添加目标元素到body下 |
|
demoDom = document.createElement('div') |
|
demoDom.style.height = '500px' |
|
demoDom.style.width = '300px' |
|
document.body.appendChild(demoDom) |
|
}) |
|
afterAll( () => { |
|
// 清除元素 |
|
document.body.removeChild(demoDom!) |
|
demoDom = null |
|
}) |
|
|
|
test('left' , () => { |
|
// 模拟回调函数 |
|
let leftCallBack = jest.fn() |
|
let rightCallBack = jest.fn() |
|
|
|
TouchLREvent(demoDom!,leftCallBack,rightCallBack) |
|
|
|
// 模拟 touchstart |
|
demoDom?.dispatchEvent(new TouchEvent('touchstart',{ |
|
touches: [ |
|
// @ts-ignore |
|
{clientX: 100,clientY:100} |
|
] |
|
})) |
|
|
|
// 模拟 touchmove |
|
demoDom?.dispatchEvent(new TouchEvent('touchmove',{ |
|
touches: [ |
|
// @ts-ignore |
|
{clientX: 60,clientY:100} |
|
] |
|
})) |
|
|
|
// 模拟 touchend |
|
demoDom?.dispatchEvent(new TouchEvent('touchend',{ |
|
touches: [ |
|
// @ts-ignore |
|
{clientX: 50,clientY:100} |
|
] |
|
})) |
|
|
|
expect(leftCallBack).toBeCalled() |
|
expect(rightCallBack).toBeCalledTimes(0) |
|
|
|
// 还原函数 |
|
leftCallBack.mockRestore() |
|
rightCallBack.mockRestore() |
|
}) |
|
}) |
模拟 localStorage
在window
下自己定义一个localStorage
对象。
模拟的localStorage
对象实现如下:
|
|
|
// localStorage功能的简易实现 |
|
|
|
export default class LocalStorageMock { |
|
private store: Record<string, string> = {}; |
|
|
|
public setItem(key: string, value: string) { |
|
this.store[key] = String(value); |
|
} |
|
|
|
public getItem(key: string): string | null { |
|
return this.store[key] || null; |
|
} |
|
|
|
public removeItem(key: string) { |
|
delete this.store[key]; |
|
} |
|
|
|
public clear() { |
|
this.store = {}; |
|
} |
|
|
|
public key(index: number): string | null { |
|
return Object.keys(this.store)[index] || null; |
|
} |
|
|
|
public get length(): number { |
|
return Object.keys(this.store).length; |
|
} |
|
} |
测试文件:
|
import LocalStorageMock from './__mock__/localStorage' |
|
|
|
describe('test LocalStorage', () => { |
|
const localStorageMock = new LocalStorageMock() |
|
const _data = {test:123,test1:'456',test2:true,test3:{}} |
|
|
|
beforeAll(() => { |
|
// 自定义 localStorage 对象 |
|
Object.defineProperty(window, 'localStorage', { |
|
value: localStorageMock |
|
}); |
|
}) |
|
|
|
afterAll( () => { |
|
// 环境还原 |
|
// @ts-ignore |
|
delete window.localStorage |
|
}) |
|
|
|
test('set same data',() => { |
|
LocalStorage.setItem('test',_data) |
|
expect(LocalStorage.getItem('test')).toEqual(_data) |
|
}) |
|
}) |
当然,如果多个测试文件都需要localStorage
,可以在全局模拟此对象,在setupFiles
中实现即可。
模拟 location
delete window.location
, 然后重新赋值
|
describe('test getSearchs', () => { |
|
// 备份 location对象 |
|
const { location } = window |
|
|
|
beforeAll( () => { |
|
// 删除 location |
|
// @ts-ignore |
|
delete window.location; |
|
}) |
|
|
|
afterAll( () => { |
|
// 还原 location |
|
window.location = location |
|
}) |
|
|
|
test('one search params, no hash', () => { |
|
// 测试时 模拟location |
|
// @ts-ignore |
|
window.location = new URL('https://www.baidu.com/?test=123') |
|
expect(getSearchs()).toEqual({test:"123"}) |
|
}) |
|
}) |
模拟 userAgent
思路和 模拟 location
一样,先删除再赋值
|
describe('test getStatuBarHeight', () => { |
|
// 备份 |
|
const { navigator } = window |
|
|
|
beforeAll( () => { |
|
// 模拟 |
|
//@ts-ignore |
|
delete window.navigator |
|
}) |
|
|
|
afterAll( () => { |
|
// 还原 |
|
window.navigator = navigator |
|
}) |
|
|
|
test('no xx in userAgent', () => { |
|
// 模拟 userAgent |
|
window.navigator = { |
|
...navigator, |
|
userAgent:'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1' |
|
} |
|
|
|
expect(xx).toBe(xx) |
|
}) |
|
}) |