【问题标题】:Mocking Vue method external async call to test it模拟 Vue 方法外部异步调用来测试它
【发布时间】:2020-06-14 17:57:36
【问题描述】:

尝试测试具有外部 API 调用的 Vue 组件方法以及返回我试图模拟的 Promise 的响应。这是我在删除其他细节后得到的:

    Component.vue 

    import UserAPI from '../../mixins/UserAPI'

    export default {
       mixins:
          UserAPI
       ,
       methods:

          AddUserInfo(id){     

            if (this.$options.cachedUsers.length === 0 || (!this.$options.cachedUsers.map(u => u.userId.includes(id))
            {        
               this.fetchUserById(id)   <--this is a call I am trying to mock
               .then( user=> {
                   if (user)
                   {
                       this.$options.cahedUsers.push(user);
                   }
               }) 
               .fail( errors => {
                   throw Errors(error)
               });
            }
            return this.$options.cachedUsers.find(el => el.id === id);
         } 
}

Component.spec.js

     it('should add users', () => {
        wrapper.vm.$options.cachedUsers = [];

        const response = { userId: "5ebdae27eb5311e0f7d2f511", userName: "admin", displayName: "Administrator" };
        wrapper.vm.fetchUserById = (id) => {
            return {
                then: () => jest.fn(usr => wrapper.vm.$options.cachedUsers.push(response)),
                fail: () => jest.fn(errors => { })
            };
        };
        status = wrapper.vm.AddUserInfo(user);
        expect(wrapper.vm.$options.cachedUsers.length).toBe(1);
 });

但是,我收到了来自测试运行程序的错误:this.fetchUserById(...).then(...).fail is not a function,这意味着我可能没有正确地模拟它。我需要修改什么才能使这个测试变为绿色?

【问题讨论】:

    标签: vue.js jestjs


    【解决方案1】:

    方法被错误地模拟了,因为它们返回函数。为了可链接,方法应该返回this,这需要在没有箭头的情况下完成:

    {
        then: jest.fn(function (usr) {
          return this;
        }),
        fail: jest.fn(function (errors) { ... })
    }
    

    在模拟方法中执行wrapper.vm.$options.cachedUsers.push(response) 没有意义,因为这已经在原始方法中完成了。

    fetchUserById 似乎返回 jQuery deferred,结果可以用 deferred 来模拟。后者在大多数情况下的行为类似,但需要将 catch 重命名为 failAddUserInfo 的问题在于它不返回一个承诺(延迟),这是一个反模式。应该是:

    AddUserInfo(id){             
      return this.fetchUserById(id) ...
    }
    

    还有:

    const deferred = $.Deferred().resolve(mockUser);
    wrapper.vm.fetchUserById = jest.fn().mockReturnValue(deferred);
    wrapper.vm.AddUserInfo(user);
    await deferred;
    expect(wrapper.vm.$options.cachedUsers.length).toBe(1);
    

    【讨论】:

    • 感谢您的回复!这正是fetchUserById 返回的内容-jQuery deferred,这是一个旧的实现。使调用者 AddUserInfo 异步的问题,即返回 $.Deferred 是它有一些额外的逻辑,我为了简洁而跳过了 - 它检查 user 是否在 wrapper.vm.$options.cachedUsers 中,如果是,它将只返回那个对象.如果没有,或者缓存为空,它会调用用户apifetchUserById,将结果添加到数组中,然后从数组中获取对象并返回
    • 我想你也可以选择const deferred = $.Deferred().resolve(mockUser)。由于可以延迟,因此我希望它与await 以相同的方式工作。
    • 如果你做缓存,尝试引用一个 promise/deferred 作为内部属性,例如this._userRequests[id] = this.fetchUserById(id)...。您至少可以从测试中受益,还可以从组件逻辑中受益,以避免多个请求。无论如何,这可以在不返回延迟更新的情况下解决。
    • 是的,不是 http 缓存,只是一组用户。但是,问题是,此方法是同步和 jQuery $.Deferred 的组合,具体取决于是否找到用户。更新问题
    • 我明白了。使用this._userRequests[id] 将允许不对同一端点执行多个同时请求,因为它们将无用。但在这种情况下对测试并不重要。
    猜你喜欢
    • 1970-01-01
    • 2015-10-09
    • 2014-01-18
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    • 1970-01-01
    • 2018-12-11
    • 1970-01-01
    相关资源
    最近更新 更多