首页 > 解决方案 > 使用 Jest 测试 img 标签 onload 事件

问题描述

我想使用 document.createElement('img') 创建 img 标签。给它一个 src 并用 jest 测试 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)
    })
  })

然后 Jest 出现如下错误。

超时 - 在 jest.setTimeout.Error 指定的 5000 毫秒超时内未调用异步回调:

标签: javascripttypescriptjestjs

解决方案


推荐阅读