Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@tarojs/mobx相关的控件,用jest测试时存在问题 #1850

Closed
neoscript99 opened this issue Jan 8, 2019 · 13 comments
Closed

@tarojs/mobx相关的控件,用jest测试时存在问题 #1850

neoscript99 opened this issue Jan 8, 2019 · 13 comments

Comments

@neoscript99
Copy link

问题描述

  • 我的工程通过mobx做状态管理
  • 用jest单元测试,配置参考taro-ui
  • mobx的Provider时出现以下错误

复现步骤

  it('with mobx', () => {
    const component = renderToString(
      <Provider store={stores}>
        <BaseInfo baseInfoStore={baseInfoStore} paramStore={paramStore} />
      </Provider>
    )
    expect(component)
      .toMatchSnapshot()
  })

报错信息

    TypeError: Cannot call a class as a function

      20 | 
      21 |   it('with mobx', () => {
    > 22 |     const component = renderToString(
         |                       ^
      23 |       <Provider store={stores}>
      24 |         <BaseInfo baseInfoStore={baseInfoStore} paramStore={paramStore} />
      25 |       </Provider>

      at _classCallCheck (node_modules/@tarojs/mobx/dist/index.js:9:11)
      at Provider (node_modules/@tarojs/mobx/dist/index.js:319:3)
      at renderVNodeToString (node_modules/nerv-server/src/index.ts:155:22)
      at Object.renderToString (node_modules/nerv-server/src/index.ts:161:10)
      at Object.it (src/pages/__tests__/ui.test.tsx:22:23)

系统信息

  • Taro 版本 [1.2.4]
@taro-bot
Copy link

taro-bot bot commented Jan 8, 2019

欢迎提交 Issue~

如果你提交的是 bug 报告,请务必遵循 Issue 模板的规范,尽量用简洁的语言描述你的问题,最好能提供一个稳定简单的复现。🙏🙏🙏

如果你的信息提供过于模糊或不足,或者已经其他 issue 已经存在相关内容,你的 issue 有可能会被关闭。

Good luck and happy coding~

@luckyadam
Copy link
Member

看上去是没有配置好,提供一下你的工程的相关内容吧

@nanjingboy
Copy link
Member

@neoscript99 来个完整的 demo,[email protected]

@neoscript99
Copy link
Author

  • no mobx这个案例是正常的
  • with mobx出现上述错误
  • 所以jest配置应该是没问题的,@luckyadam
import Nerv from 'nervjs'
import { renderToString } from 'nerv-server'
import { Provider } from '@tarojs/mobx'
import stores from '../../stores'
import BaseInfoTest from '../../../.temp/components/BaseInfoTest'
import BaseInfo from '../../../.temp/components/BaseInfo'

jest.mock('../../utils/database')
const { baseInfoStore, paramStore } = stores

describe('ui test', () => {
  it('no mobx', () => {
    const component = renderToString(
      <BaseInfoTest baseInfoStore={baseInfoStore} paramStore={paramStore} />
    )
    expect(component)
      .toMatchSnapshot()
  })

  it('with mobx', () => {
    const component = renderToString(
      <Provider store={stores}>
        <BaseInfo baseInfoStore={baseInfoStore} paramStore={paramStore} />
      </Provider>
    )
    expect(component)
      .toMatchSnapshot()
  })
})

@nanjingboy
Copy link
Member

@neoscript99 所以来一个完整的 demo 嘛 ^ _ ^

@neoscript99
Copy link
Author

@nanjingboy 这个jest测试环境有点麻烦,需要点时间,我整理看看

@neoscript99
Copy link
Author

neoscript99 commented Jan 8, 2019

  • 这是nerv-server的代码,是不是不支持mobx、redux这种,需要注入props的框架的server-render?@yuche
  • nerv-server
function renderVNodeToString (vnode, parent, context, firstChild) {
  const { tagName, props, children } = vnode
  if (isVText(vnode)) {
    return encodeEntities(vnode.text)
  } else if (isVNode(vnode)) {
    let renderedString = `<${tagName}`
    let html
    if (!isNullOrUndef(props)) {
      for (const prop in props) {
        const value = props[prop]
        if (skipAttributes[prop]) {
          continue
        }
        if (prop === 'dangerouslySetInnerHTML') {
          html = value.__html
        } else if (prop === 'style') {
          renderedString += ` style="${renderStylesToString(value)}"`
        } else if (prop === 'class' || prop === 'className') {
          renderedString += ` class="${isString(value) ? value : hashToClassName(value)}"`
        } else if (prop === 'defaultValue') {
          if (!props.value) {
            renderedString += ` value="${escapeText(value)}"`
          }
        } else if (prop === 'defaultChecked') {
          if (!props.checked) {
            renderedString += ` checked="${value}"`
          }
        } else {
          if (isString(value)) {
            renderedString += ` ${prop}="${escapeText(value)}"`
          } else if (isNumber(value)) {
            renderedString += ` ${prop}="${value}"`
          } else if (value === true) {
            renderedString += ` ${prop}`
          }
        }
      }
    }
    if (isVoidElements[tagName]) {
      renderedString += `/>`
    } else {
      renderedString += `>`
      if (!isInvalid(children)) {
        if (isString(children)) {
          renderedString += children === '' ? ' ' : escapeText(children)
        } else if (isNumber(children)) {
          renderedString += children + ''
        } else if (isArray(children)) {
          for (let i = 0, len = children.length; i < len; i++) {
            const child = children[i]
            if (isString(child)) {
              renderedString += child === '' ? ' ' : escapeText(child)
            } else if (isNumber(child)) {
              renderedString += child
            } else if (!isInvalid(child)) {
              renderedString += renderVNodeToString(
                child,
                vnode,
                context,
                i === 0
              )
            }
          }
        } else {
          renderedString += renderVNodeToString(children, vnode, context, true)
        }
      } else if (html) {
        renderedString += html
      }
      if (!isVoidElements[tagName]) {
        renderedString += `</${tagName}>`
      }
    }
    return renderedString
  } else if (isWidget(vnode)) {
    const { ComponentType: type } = vnode
    const instance = new type(props, context)
    instance._disable = true
    if (isFunction(instance.getChildContext)) {
      context = assign(assign({}, context), instance.getChildContext())
    }
    instance.context = context
    if (isFunction(instance.componentWillMount)) {
      instance.componentWillMount()
    }
    const nextVnode = instance.render(props, instance.state, context)

    if (isInvalid(nextVnode)) {
      return '<!--!-->'
    }
    return renderVNodeToString(nextVnode, vnode, context, true)
  } else if (isStateLess(vnode)) {
    const nextVnode = tagName(props, context)

    if (isInvalid(nextVnode)) {
      return '<!--!-->'
    }
    return renderVNodeToString(nextVnode, vnode, context, true)
  }
}

@neoscript99
Copy link
Author

问题我找到了

  • mobx.Provider被nerv-server识别为Stateless控件
  • nerv-server通过函数调用的方式type(props, context)进行初始化
  • 但Provider要求一定要通过new Provider(props)进行初始化

如何解决,@nanjingboy

if (isStateless(vnode)) {
    const rendered = type(props, context)
    return renderVNodeToString(rendered, vnode, context, isSvg)
  }

@nanjingboy
Copy link
Member

@neoscript99 知道了,稍后我提一个 PR

@nanjingboy
Copy link
Member

@neoscript99 #1852

@neoscript99
Copy link
Author

@luckyadam
Copy link
Member

@neoscript99 Tom 兄已提交 PR,可以下个版本试试

@yuche
Copy link
Contributor

yuche commented Apr 8, 2019

close via 2aaf6d7

@yuche yuche closed this as completed Apr 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants