使用带有 Avoriaz 的 AVA 在 Vue.js 中测试计算属性
Posted
技术标签:
【中文标题】使用带有 Avoriaz 的 AVA 在 Vue.js 中测试计算属性【英文标题】:Test computed property in Vue.js using AVA with Avoriaz 【发布时间】:2017-08-03 18:45:20 【问题描述】:我正在尝试使用 AVA 和 Avoriaz 测试 Vue.js 组件的计算属性。我可以挂载组件并正常访问数据属性。
当我尝试访问计算属性时,该函数似乎没有该组件上数据的范围。
computed:
canAdd()
return this.crew.firstName !== '' && this.crew.lastName !== '';
我得到的错误是Error: Cannot read property 'firstName' of undefined
测试文件:
import Vue from 'vue';
import mount
from 'avoriaz';
import test from 'ava';
import nextTick from 'p-immediate';
import ComputedPropTest from '../../../js/vue-components/computed_prop_test.vue';
Vue.config.productionTip = false;
test.only('Should handle computed properties', async(t) =>
const MOCK_PROPS_DATA =
propsData:
forwardTo: '/crew',
crew:
,
wrapper = mount(ComputedPropTest, MOCK_PROPS_DATA),
DATA =
crew:
firstName: 'Ryan',
lastName: 'Gill'
;
wrapper.setData(DATA);
await nextTick();
console.log('firstName: ', wrapper.data().crew.firstName); // Ryan
console.log('isTrue: ', wrapper.computed().isTrue()); // true
console.log('canAdd: ', wrapper.computed().canAdd()); // Errors
t.true(wrapper.computed().isTrue());
);
组件:
<template>
<div>
<label for="firstName" class="usa-color-text-primary">First Name
<i class="tooltipTextIcon fa fa-info-circle usa-color-text-gray" title="First name of crew."></i>
<span class="required usa-additional_text usa-color-text-secondary-dark">Required</span>
</label>
<input id="firstName" type="text" class="requiredInput" name="firstName" v-model="crew.firstName" autofocus>
<label for="lastName" class="usa-color-text-primary">Last Name
<i class="tooltipTextIcon fa fa-info-circle usa-color-text-gray" title="Last name of crew."></i>
<span class="required usa-additional_text usa-color-text-secondary-dark">Required</span>
</label>
<input id="lastName" type="text" class="requiredInput" name="lastName" v-model="crew.lastName" autofocus>
</div>
</template>
<script>
export default
name: 'crew-inputs',
data()
return
crew:
firstName: '',
lastName: ''
,
computed:
canAdd()
return this.crew.firstName !== '' && this.crew.lastName !== '';
,
isTrue()
return true;
</script>
isTrue
计算属性似乎有效,但不依赖组件中的任何数据。
【问题讨论】:
我看到您添加了控制台日志,以访问您正在测试的组件的数据和计算属性。他们是否按照您的期望报告?建议您在描述实际结果和预期结果的日志上方/旁边添加 cmets,而不是不加注释。 @wing 是的,日志符合预期。我刚刚用日志的值作为 cmets 更新了问题。谢谢。 好像不用Avoriaz
let comp = new Vue(ComputedPropTest, MOCK_PROPS_DATA).$mount(); comp.crew = DATA; console.log(comp.canAdd);
也能工作
我不相信箭头函数会阻止this
被正确绑定。您可以尝试更改一些箭头功能,但我怀疑它会起作用。您的测试代码是否在浏览器中运行?您正在使用 Ava,所以我假设它不是。我怀疑不在浏览器中运行 Avoriaz 会导致问题:我在浏览器和非浏览器环境中运行了简化的测试用例。浏览器通过,而非浏览器环境失败——尽管我仍在调查到底发生了什么以及为什么。
环境理论更新:我认为我正在排除它。我认为 Avoriaz 正在影响 this
与您不想要的东西的绑定。
【参考方案1】:
问题
发生了什么?
经过长时间的查看和讨论,看起来计算 getter 的 this
上下文被设置为意想不到的东西。由于意外的 this
上下文,this
不再引用 Vue 实例,导致组件属性无法访问。
您正在见证运行时错误
Error: Cannot read property 'firstName' of undefined
为什么会这样?
如果不深入了解 Avoriaz 和 Vue 的工作原理,我们就无法知道。我确实尝试使用以下最小、完整且可验证的示例进行更深入的调查。您或其他人可能想要更深入地了解它。
'use-strict';
import Vue from 'vue';
import mount from 'avoriaz';
const FooBar =
template: `
<div> foobar </div>
`,
data()
return
foo: 'foo',
bar: 'bar',
;
,
computed:
foobar()
debugger;
return `$this.foo $this.bar`;
,
,
;
const vueMountedCt = new Vue(FooBar).$mount();
const vueMountedVm = vueMountedCt;
const avoriazMountedCt = mount(FooBar);
const avoriazMountedVm = avoriazMountedCt.vm;
/**
* Control case, accessing component computed property in the usual way as documented by Vue.
*
* @see @link https://vuejs.org/v2/guide/computed.html
*
* Expectation from log: 'foobar' (the result of the computed property)
* Actual result from log: 'foobar'
*/
console.log(vueMountedVm.foobar);
/**
* Reproduce Avoriaz's method of accessing a Vue component's computed properties.
* Avoriaz returns the Vue instance's `$option.computed` when calling `wrapper.computed()`.
*
* @see @link https://github.com/eddyerburgh/avoriaz/blob/9882f286e7476cd51fe069946fee23dcb2c4a3e3/src/Wrapper.js#L50
*
* Expectation from log: 'foobar' (the result of the computed property)
* Actual result from log: 'undefined undefined'
*/
console.log(vueMountedVm.$options.computed.foobar());
/**
* Access Vue component computed property via Avoriaz's documented method.
*
* @see @link https://eddyerburgh.gitbooks.io/avoriaz/content/api/mount/computed.html
*
* Expectation from log: 'foobar' (the result of the computed property)
* Actual result from log: 'undefined undefined'
*/
console.log(avoriazMountedCt.computed().foobar());
一些观察:
查看控制案例的调用堆栈(案例 1),您可以看到 Vue 内部将this
上下文设置为 Vue 实例。
查看失败案例的调用堆栈,未设置计算函数的 this
上下文。
至于为什么会这样——我不知道。为了理解这一点,我认为我们需要知道为什么 vm.$options.computed
存在,核心 Vue 团队的计划用例以及我们遇到的行为是否符合预期。
对此我能做些什么?
您可以通过以下方式解决此问题
wrapper.computed().canAdd.call(wrapper.vm);
也可能建议您在Avoriaz 和/或Vue 中打开问题。
【讨论】:
您好,感谢您的详细回答。我是 avoriaz 的作者,我很想在下一个版本中修复这个错误 @Edd:不用担心。我不熟悉 Avoriaz 或 Vue 的内部结构,所以这份报告只是我对我认为正在发生的事情的观察和评论。希望它能帮助您解决这个问题。向下看的一个潜在途径是查看vm.$options.computed
的用途——我怀疑它可能不是可靠地为您提供计算属性的地方,但我无法确认核心团队对此的立场。
很好的解释。计算属性不容易测试。以上是关于使用带有 Avoriaz 的 AVA 在 Vue.js 中测试计算属性的主要内容,如果未能解决你的问题,请参考以下文章
带有 appcompat 库 v7 的 ActionBar(ava.lang.IllegalStateException:您需要使用 Theme.AppCompat 主题)
无法使用 Jest 中的提交按钮触发 Vuetify 表单提交