Compute computed property in Vue.js using AVA with Avoriaz

I am trying to check the computed property of a Vue.js component using AVA and Avoriaz. I can mount the component and access the data properties.

When I try to access the computed property, the function does not seem to have a data region for this component.

computed: { canAdd() { return this.crew.firstName !== '' && this.crew.lastName !== ''; } 

The error I get is Error: Cannot read property 'firstName' of undefined

Test file:

 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()); }); 

component:

 <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> 

The computed isTrue property seems to work, but does not rely on any data in the component.

+7
javascript computed-properties ava
source share
1 answer

Problem

What's happening?

After a long look and discussion, it seems that this context of the computed getter is set to something unexpected. As a result of the unexpected context, this this no longer refers to the Vue instance, which results in the component properties being unavailable.

You are observing this with a runtime error

Error: Cannot read property 'firstName' of undefined

Why is this happening?

Without deep immersion in the work of Avoriaz and Vue, we cannot know. I did a deeper study with the following minimal, complete, and verifiable example. You or other people will want to study it more deeply.

 '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 method of accessing a Vue component computed properties. * Avoriaz returns the Vue instance `$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 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()); 

Some observations:

  • Looking at the call case stack (case 1), you can see that the internal components of Vue set the this context to the Vue instance.

Selects stack stack 1. Installs the <code> of this> this </code> function for the Vue instance

  • Considering the call stack in case of failures, the context of this computed function is not established.

Stack calls failures. Context <code> this </code> function not set

How does this happen? I have no idea. To understand this, I think we need to know why vm.$options.computed exists, the planned use cases for the main Vue command, and if the behavior we are experiencing is expected.

What can I do about this?

You can get around this by doing

 wrapper.computed().canAdd.call(wrapper.vm); 

You can also recommend opening problems in Avoriaz and / or Vue .

+5
source share

All Articles