使用 AVA 和 Avoriaz 在 Vue.js 中测试计算 属性
Test computed property in Vue.js using AVA with Avoriaz
我正在尝试使用 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
计算 属性 似乎有效,但不依赖于组件中的任何数据。
问题
发生了什么事?
经过长时间的查看和讨论,计算的 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);
我正在尝试使用 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
计算 属性 似乎有效,但不依赖于组件中的任何数据。
问题
发生了什么事?
经过长时间的查看和讨论,计算的 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);