Проверьте вычисленное свойство в Vue.js, используя AVA с Avoriaz

Я пытаюсь проверить вычисляемое свойство компонента Vue.js, используя AVA и Avoriaz. Я могу смонтировать компонент и получить доступ к свойствам данных в порядке.

Когда я пытаюсь получить доступ к вычисляемому свойству, функция, похоже, не имеет области действия для данных этого компонента.

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 Кажется, что вычисленное свойство работает, но не зависит от каких-либо данных в компоненте.

1 ответ

Решение

проблема

Что происходит?

После долгого взгляда и обсуждения это выглядит как 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.

Стек вызовов случая 1. Функция <code> this </ code> функции Getter устанавливается в экземпляр Vue this функции Getter устанавливается в экземпляр Vue">

  • Глядя на стек вызовов неисправных случаев, this контекст вычисляемой функции не устанавливается.

Стек вызовов сбойных случаев. Контекст <code>vm.$options.computed</code> существует, запланированные варианты использования от основной команды Vue, и если ожидаемое поведение ожидается.</p><h1> Что я могу сделать по этому поводу? </h1><p>Вы можете обойти это, выполнив</p><pre><code>wrapper.computed().canAdd.call(wrapper.vm);
</code></pre><p>Также может быть рекомендовано открывать проблемы в <a href=Avoriaz и / или Vue.

Другие вопросы по тегам