【问题标题】:How do you unit test a Vue.js functional component with a render function that returns any array of elements?如何使用返回任何元素数组的渲染函数对 Vue.js 功能组件进行单元测试?
【发布时间】:2019-06-11 20:30:57
【问题描述】:

在 Vue.js 中,一个函数式组件可以通过使用 render 函数返回多个根节点 returns an array of createdElements

export default {
  functional: true,
  props: ['cellData'],
  render: function (h, context) {
    return [
      h('td', context.props.cellData.category),
      h('td', context.props.cellData.description)
    ]
  }
}

这很好用,但我在尝试为这样的组件创建单元测试时遇到了麻烦。在组件上使用shallowMount 会导致[Vue warn]: Multiple root nodes returned from render function. Render function should return a single root node.

import { shallowMount } from '@vue/test-utils'
import Cell from '@/components/Cell'

wrapper = shallowMount(Cell, {
  context: {
    props: {
      cellData {
        category: 'foo',
        description: 'bar'
      }
    }
  }
});

This github issue 建议需要将组件包装在单个根节点中才能实际渲染它,但尝试这样做会导致[vue-test-utils]: mount.context can only be used when mounting a functional component

import { shallowMount } from '@vue/test-utils'
import Cell from '@/components/Cell'

wrapper = shallowMount('<div><Cell></div>', {
  context: {
    props: {
      cellData {
        category: 'foo',
        description: 'bar'
      }
    }
  }
});

那么如何测试一个返回多个根节点的功能组件呢?

【问题讨论】:

  • 你使用什么构建工具?
  • 只是为了其他人,他们想知道是否可以从渲染函数返回多个VNode[] - 这是不可能的,render 函数的签名只允许一个 VNode,而不是多个。

标签: javascript unit-testing vue.js


【解决方案1】:

您可以使用v-bind="$attrs"[1]v-on="$listeners"[2] 创建一个更高阶的透明包装组件,将所有道具和事件侦听器传递给内部Cell 组件。然后你可以使用propsData 将道具传递给包装器组件..

import { mount } from '@vue/test-utils'
import Cell from '@/components/Cell'

const WrappedCell = {
  components: { Cell },
  template: `
    <div>
      <Cell v-bind="$attrs" v-on="$listeners" />
    </div>
  `
}

const wrapper = mount(WrappedCell, {
  propsData: {
    cellData: {
      category: 'foo',
      description: 'bar'
    }
  }
});

【讨论】:

    【解决方案2】:

    您可以创建一个fragment_wrapper 来用片段(多个根元素)包装您的组件。

    //File: fragment_wrapper.js
    
    exports.fragment_wrapper = function(FragmentComponent){
      const wrapper = {
        components: { FragmentComponent },
        props: FragmentComponent.props,
        template: `<div><FragmentComponent v-bind="$props" v-on="$listeners"/></div>`
      }
      return wrapper;  
    }
    

    然后您可以使用它来测试您的所有碎片组件,如下所示:

    import { mount } from '@vue/test-utils'
    import { fragment_wrapper } from './fragment_wrapper'
    import Cell from './components/Cell'
    
    
    describe('Test Cell', () => {
      let WrappedCell = fragment_wrapper(Cell);
      const wrapper = mount(WrappedCell, {
        propsData: {
          cellData: {
            category: 'foo',
            description: 'bar'
          }
        }
      });
    
      it('renders the correct markup', () => {
        expect(wrapper.html()).toContain('<td>foo</td>')
      });
    });
    

    【讨论】:

      猜你喜欢
      • 2019-06-26
      • 2020-09-28
      • 1970-01-01
      • 2022-01-25
      • 2019-11-29
      • 2020-09-28
      • 1970-01-01
      • 2017-10-09
      • 2019-05-08
      相关资源
      最近更新 更多