如何在组件中测试异步 vue 方法

Posted

技术标签:

【中文标题】如何在组件中测试异步 vue 方法【英文标题】:How to test an async vue method in component 【发布时间】:2020-03-05 02:27:21 【问题描述】:

我正在尝试在我的 vue 组件中测试我的 checkConnection(),但我无法获得正确的解决方案。第一个测试总是失败,第二个测试总是通过......我不明白为什么。有人可以向我解释一下吗?

我的组件:viewTopics

  <div>
    isConnected
  </div>
</template>

<script>
import db from "./firebaseInit";

export default 
  name: "viewTopics",
  data: function() 
    return 
      isConnected: "just a random value"
    ;
  ,
  created() 
    this.checkConnection();
  ,

  methods: 
    checkConnection() 
      var promise1 = new Promise(function(resolve) 
        var connectedRef = db.database().ref(".info/connected");
        connectedRef.on("value", function(snap) 
          if (snap.val() === true) 
            console.log("Connected");
            resolve(snap.val());
           else 
            console.log("It takes some time to connect");
          
        );
      );
      var self = this;
      promise1.then(function(value) 
        console.log(value);
        self.isConnected = true;

        //It sets the variable right but the test is not right
      );
    
  
;
</script>

<style scoped>
</style>

这是我的测试文件:

import  shallowMount  from "@vue/test-utils";
import viewTopics from "@/components/viewTopics";


const wrapper = shallowMount(viewTopics);

test("This test is always failing ", done => 
  wrapper.vm.$nextTick(() => 
    expect(wrapper.vm.isConnected).toEqual(true);
    done();
  );
);

test("This test is always passing", done => 
  wrapper.vm.$nextTick(() => 
    expect(wrapper.vm.isConnected).toEqual(true);
    done();
  );
);

这是我运行 npm run test:unit 时的错误

Microsoft Windows [版本 10.0.18362.418] (c) 2019 年微软公司。 Alle Rechte vorbehalten。

C:\Users\Philipp>cd..

C:\Users>cd..

C:>cd firebaseforum

C:\firebaseforum>npm run test:unit

firebaseforum@0.1.0 测试:单元 C:\firebaseforum vue-cli-service 测试:单元

console.log src/components/viewTopics.vue:31 连接需要一些时间

console.error node_modules/vue/dist/vue.runtime.common.dev.js:621 [Vue 警告]:nextTick 中的错误:“错误:expect(received).toEqual(expected) // 深度相等

Expected: true
Received: "just a random value""

found in

---> <ViewTopics>
       <Root>

console.error node_modules/vue/dist/vue.runtime.common.dev.js:1884 JestAssertionError: expect(received).toEqual(expected) // 深度相等

Expected: true
Received: "just a random value"
    at VueComponent.<anonymous> (C:\firebaseforum\tests\unit\viewTopics.spec.js:8:36)
    at Array.<anonymous> (C:\firebaseforum\node_modules\vue\dist\vue.runtime.common.dev.js:1976:12)
    at flushCallbacks (C:\firebaseforum\node_modules\vue\dist\vue.runtime.common.dev.js:1902:14)
    at processTicksAndRejections (internal/process/task_queues.js:93:5) 
  matcherResult: 
    actual: 'just a random value',
    expected: true,
    message: [Function],
    name: 'toEqual',
    pass: false
  

console.log src/components/viewTopics.vue:28 已连接

console.log src/components/viewTopics.vue:37 真的

失败测试/单元/viewTopics.spec.js (6.694s) × 这个测试总是失败(5008ms) √ 这个测试总是通过(1ms)

● 这个测试总是失败

: Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Error:

  4 | const wrapper = shallowMount(viewTopics);
  5 |
> 6 | test("This test is always failing ", done => 
    | ^
  7 |   wrapper.vm.$nextTick(() => 
  8 |     expect(wrapper.vm.isConnected).toEqual(true);
  9 |     done();

  at new Spec (node_modules/jest-jasmine2/build/jasmine/Spec.js:116:22)
  at Object.<anonymous> (tests/unit/viewTopics.spec.js:6:1)

测试套件:1 个失败,总共 1 个 测试:1 次失败,1 次通过,总共 2 次 快照:共 0 个 时间:7.393s 运行所有测试套件。 Jest 在测试运行完成后一秒钟没有退出。

这通常意味着在您的测试中存在未停止的异步操作。考虑使用 --detectOpenHandles 运行 Jest 来解决此问题。

【问题讨论】:

【参考方案1】:

我认为第二个测试通过了,因为当它运行时,第一个测试已经完成。如果你只在第二次测试中坚持,我认为它会失败。

我认为根本问题是您没有等待创建函数中的 checkConnection。

new Vue(
  el: '#app',
  name: "viewTopics",
  
  data () 
    return 
      isConnected: "just a random value"
    ;
  ,
  
  async created () 
    await this.checkConnection();
  ,

  methods: 
    async checkConnection() 
      const promise1 = new Promise(function(resolve, reject) 
        const connectedRef = db.database().ref(".info/connected");
        
        connectedRef.on("value", function(snap) 
          if (snap.val() === true) 
            console.log("Connected");
            resolve(snap.val());
           else 
            console.log("It takes some time to connect");
            reject('error msg')
          
        );
      );
      
      try 
        const resultFromPromise = await promise1
        this.isConnected = true
        console.log('Connected') 
       catch (error) 
        console.log(`error message: $error`)
      
    
  
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
   isConnected 
</div>

我还将把 shallowMount 移到一个 beforeEach 中,以便为每个测试生成一个新的实例。

就个人而言,我还发现使用 async/await 样式编写测试更容易:

test("This test is always passing", async () => 
  await wrapper.vm.$nextTick()
  expect(wrapper.vm.isConnected).toEqual(true)
)

【讨论】:

如何等待函数?

以上是关于如何在组件中测试异步 vue 方法的主要内容,如果未能解决你的问题,请参考以下文章

Vue with jest - 使用异步调用进行测试

测试 Vue 组件 - 模拟状态和方法

vue异步渲染

异步组件懒加载 获取不到ref

使用 jest 和 avoriaz 时如何在 Vuejs 的组件中测试异步方法

Vue.js如何检测组件/页面是否已完成所有异步调用?