我想使用document.createElement('img')创建img标签。给它一个src并用笑话测试onload或onerror事件。
我正在为我的sdk写一些组件,我不能使用任何框架,并且必须确保它可以在IE7中使用。所以我正在使用document.createElement创建我需要的所有类型的组件。然后编写单元测试以确保其正常运行。 但是我不喜欢测试img标签,因为它需要获取src数据,并且似乎不支持它。
interface ComponentProps {
className?: string
onClick?: (e?: Event, el?: HTMLElement) => void
style?: {}
}
type HTMLComponent = Element | string | HTMLElement | DocumentFragment
type FunctionComponent = () => HTMLComponent
type Children = HTMLComponent[] | HTMLComponent | FunctionComponent | FunctionComponent[] | (HTMLComponent | FunctionComponent)[]
function createComponent(type: string, props: ComponentProps, children?: Children) {
const current = document.createElement(type)
props.className && (current.className = props.className)
props.style && $.style(current, props.style)
props.onClick && $.addEventListener(current, 'click', (e) => props.onClick(e, current))
function wrapperText(str: string) {
return document.createTextNode(str)
}
function render(node: Children) {
if (Object.prototype.toString.call(node) !== '[object Array]') {
node = [node as any]
}
foreach(node as Children[], node => {
if (typeof node === 'string') {
current.appendChild(wrapperText(node))
} else if (typeof node === 'function') {
render(node())
} else {
current.appendChild(node as HTMLElement)
}
})
}
if (children) {
render(children)
}
return current
}
type ImgProps = ComponentProps & {
src: string,
onLoad?: (e?: Event, el?: HTMLElement) => void
onError?: (e: Event) => void
}
const img = (props: ImgProps): HTMLElement => {
const img = createComponent('img', props) as HTMLImageElement
img.src = props.src;
props.onLoad && $.addEventListener(img, 'load', (e) => props.onLoad(e, img))
props.onError && $.addEventListener(img, 'error', (e) => props.onError(e))
return img as HTMLElement
}
const div = (props: ComponentProps, children: Children) => createComponent('div', props, children)
export default function Img(style: AnyObject, config: ImgConfig, handlers?: MessageEventHandlers): Deferred<Option<HTMLElement>> {
if (!config.src) {
return Deferred.resolve(None);
}
return new Deferred<Option<HTMLElement>>((resolve, reject) => {
img({
src: config.src,
className: '_gio_c_img',
style: style,
onLoad: (_, current) => {
// IE自动给图片加上width和height属性的修复
current.removeAttribute('width')
current.removeAttribute('height')
resolve(Option.build(current))
},
onError: (e) => {
reject(e)
},
onClick: Option.build(config.target).flatMap(_ => Option.build(_.href)).map(href => {
return redirectOnClick(href, () => {
handlers && handlers.onClickTargetAndDisappearPermanently();
})
}).getOrElse(undefined)
})
})
}
我的单元测试代码如下。
it('Render With Wrong Src', async () => {
return Img({}, {
src: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2854956166,1658664264&fm=26&gp=0.jpg',
target: {}
}).then(img => {
expect(img.isEmpty()).toBe(true)
})
})
然后开玩笑会发生如下错误。
超时-在指定的5000ms超时内未调用异步回调 jest.setTimeout.Error: