【问题标题】:Vue.js unit testing ErrorBoundaryVue.js 单元测试 ErrorBoundary
【发布时间】:2019-04-26 23:51:03
【问题描述】:

我在 Vue.js 中为我的项目构建了简单的 ErrorBoundary 组件,我正在努力为其编写单元测试。组件代码如下:

<template>
  <div class="overvue-error-boundary">
    <slot v-if="!error" />
    <div class="error-message" v-else>Something went horribly wrong here.</div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      error: false
    }
  },
  errorCaptured (error, vm, info) {
    this.error = true;
  }
}
</script>

我创建了一个 ErrorThrowingComponent,它在 created() 生命周期挂钩上引发错误,因此我可以测试 ErrorBoundary:

const ErrorThrowingComponent = Vue.component('error-throwing-component', {
  created() {
    throw new Error(`Generic error`);
  },
  render (h) {
    return h('div', 'lorem ipsum')
  }
});

describe('when component in slot throws an error', () => {
  it('renders div.error-message', () => {
  // this is when error is when 'Generic error' is thrown by ErrorThrowingComponent
  const wrapper = shallowMount(OvervueErrorBoundary, {
    slots: {
      default: ErrorThrowingComponent
    }});
    // below code is not executed
    expect(wrapper.contains(ErrorThrowingComponent)).to.be.false;
    expect(wrapper.contains('div.error-message')).to.be.true;
  });
});

问题是当我尝试实际挂载 ErrorThrowingComponent 时会引发错误(从而导致整个测试失败)。有什么办法可以防止这种情况发生吗?

编辑:我想要实现的是在 ErrorBoundary 组件的默认插槽中实际 mount ErrorThrowing 组件以断言 if ErrorBoundary 将呈现错误消息而不是插槽。这是我首先创建 ErrorThrowingComponent 的方式。但我无法断言 ErrorBoundary 的行为,因为在尝试创建包装器时出现错误。

【问题讨论】:

  • 你是什么意思'当我安装它时它会抛出一个错误'? ...创建时出现错误...(或者我错过了什么??)
  • 我已经在上面的编辑部分澄清了这一点。
  • errorCaptured 被调用了吗?你可以尝试在那里添加一个日志,看看问题是否存在于捕获器中?
  • @Aviad,是的,ErrorBoundary 组件具有可用的 errorCaptured() 挂钩。组件按需要工作,我只是无法使用 vue-test-utils 为其编写单元测试。
  • @Aviad,感谢您的帮助,我已经咨询了 Vue Land 的人员,他们为我提供了一种不同的方法来解决我的问题。你可以在我的回答中找到。

标签: unit-testing vue.js vuejs2 vue-test-utils


【解决方案1】:

对于遇到类似问题的任何人:我已经在 Discord 的 Vue Land 的#vue-testing 频道上提出了这个问题,他们建议将整个错误处理逻辑移到一个将从 errorCaptured() 调用的函数中钩子,然后只是测试这个功能。这种方法对我来说似乎很明智,所以我决定在这里发布。

重构ErrorBoundary组件:

<template>
  <div class="error-boundary">
    <slot v-if="!error" />
    <div class="error-message" v-else>Something went horribly wrong here. Error: {{ error.message }}</div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      error: null
    }
  },
  methods: {
    interceptError(error) {
      this.error = error;
    }
  },
  errorCaptured (error, vm, info) {
    this.interceptError(error);
  }
}
</script>

使用 vue-test-utils 进行单元测试:

describe('when interceptError method is called', () => {
  it('renders div.error-message', () => {
    const wrapper = shallowMount(OvervueErrorBoundary);
    wrapper.vm.interceptError(new Error('Generic error'));
    expect(wrapper.contains('div.error-message')).to.be.true;
  });
});

【讨论】: