javascript - 使用 AVA 和 Avoriaz 在 Vue.js 中测试计算属性

标签 javascript vue.js computed-properties ava 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 实例。

Call stack of case 1. Getter function's <code>this</code> is being set to Vue instance

  • 查看失败案例的调用堆栈,未设置计算函数的 this 上下文。

Call stack of failing cases. The <code>this</code> context of the computed function is not being set

至于为什么会这样——我不知道。要理解这一点,我认为我们需要知道 vm.$options.computed 存在的原因、核心 Vue 团队计划的用例以及我们正在经历的行为是否符合预期。

我该怎么办?

你可以通过做来解决这个问题

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

也可能建议您在 Avoriaz 中打开问题和/或 Vue .

关于javascript - 使用 AVA 和 Avoriaz 在 Vue.js 中测试计算属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42768924/

相关文章:

javascript - 获取变量函数表达式的名称?

php - 使用 VueJS AJAX 和 Laravel 5.3 上传多个文件

javascript - Vue V-绑定(bind)到以编程方式创建的实例

javascript - $store 属性在使用计算属性(Vuex)时不是 react 性的

unit-testing - 使用 Jest 测试 Vue3 组件时如何模拟计算属性

javascript - CSS 优先级,当使用 JS 设置样式时

javascript - 这种 WebSockets 方法正确吗?

javascript - 异步加载下划线模板的最佳方式

vue.js - 使用 vuetify 的响应式布局

ios - 对计算属性的 Realm 结果集合进行排序?