Vue Test Utils / Jest - 如何测试是不是在组件方法中调用了类方法

Posted

技术标签:

【中文标题】Vue Test Utils / Jest - 如何测试是不是在组件方法中调用了类方法【英文标题】:Vue Test Utils / Jest - How to test if class method was called within a component methodVue Test Utils / Jest - 如何测试是否在组件方法中调用了类方法 【发布时间】:2019-01-25 00:42:50 【问题描述】:

我的单元测试有一个有趣的问题。我的单元测试是为了单击组件内的按钮而编写的。此按钮调用一个组件方法,该方法包含一个类Service(axios 的包装类)的实例。这个组件方法唯一做的就是调用Service.requestPasswordReset()。我的单元测试需要验证 Service.requestPasswordReset 是否被调用。

我知道我正确地模拟了我的 Service 类,因为这通过了我的单元测试:

await Service.requestPasswordReset()
expect(Service.requestPasswordReset).toHaveBeenCalled()

而且我知道我在点击时正确调用了该方法,因为这通过了我的单元测试:

await wrapper.find('button').trigger('click')
expect(mockMethods.resend).toHaveBeenCalled()

我只是无法让我的测试注册 Service 方法被调用。有什么想法吗?

组件

<template lang="pug">
Layout
    section
        header( class="text-center py-4 pb-12")
            h1( class="text-grey-boulder font-light mb-4") Recovery Email
            p( class="text-orange-yellow") A recovery email has been sent to your email address

        div( class="text-center")
            div( class="mb-6")
                button(
                    type="button"
                    @click.stop="resend()"
                    class="bg-orange-coral font-bold text-white py-3 px-8 rounded-full w-48"
                ) Resend Email
</template>

<script>
import Layout from '@/layouts/MyLayout'
import Service from '@/someDir/Service'
export default 
    name: 'RecoveryEmailSent',
    page: 
        title: 'Recovery Email Sent',
    ,
    components: 
        Layout,
    ,
    data() 
        return 
            errorMessage: null
        
    ,
    computed: 
        userEmail() 
            const reg = this.$store.getters['registration']
            return reg ? reg.email : null
        ,
    ,
    methods: 
        async resend() 
            try 
                await Service.requestPasswordReset(
                    email: this.userEmail,
                )               
             catch (error) 
                this.errorMessage = error
            
        ,
    ,

</script>

Service.js

import client from '@/clientDir/BaseClient'

class Service 
    constructor() 
        this.client = client(baseUrl)
    

    requestPasswordReset(request) 
        return this.client.post('/account_management/request_password_reset', request)
    


export  Service 

export default new Service()

__mock__中的Service.js

export default 
    requestPasswordReset: jest.fn(request => 
        return new Promise((resolve, reject) =>
            resolve(
                data: 
                    statusCode: 'Success',
                ,
            )
        )
    )

单元测试

jest.mock('@/someDir/Service')
import  shallowMount, mount, createLocalVue  from '@vue/test-utils'
import RecoveryEmailSent from './AccountManagement.RecoveryEmailSent'
import Service from '@/someDir/Service'
const localVue = createLocalVue()
// localVue.use(Service) // <-- Tried this, didn't work

describe('Recovery Email Sent', () => 

    it('should resend recovery email', async () => 
        const mockMethods = 
            resend: jest.fn()
        
        const email = 'testemail@test.com'
        const wrapper = mount(RecoveryEmailSent, 
            localVue,
            computed: 
                userEmail() 
                    return email
                ,
            ,
            methods: mockMethods
        )

        // await Service.requestPasswordReset()
        await wrapper.find('button').trigger('click')
        expect(mockMethods.resend).toHaveBeenCalled()
        expect(Service.requestPasswordReset).toHaveBeenCalled()
    )
)

【问题讨论】:

【参考方案1】:

我想通了。显然,如果使用参数调用相关方法,Jest 的 .toHaveBeenCalled() 不会返回 true。你必须使用.toHaveBeenCalledWith()。我在他们的文档中没有看到任何关于此警告的内容,但似乎确实如此。

这是我通过的测试代码

it('should resend email hash', async () => 
    const email = 'testemail@test.com'
    const wrapper = mount(AccountManagementForgottenPasswordSubmitted, 
        localVue,
        computed: 
            userEmail() 
                return email
            ,
        ,
    )

    await wrapper.find('button').trigger('click')
    expect(Service.requestPasswordReset).toHaveBeenCalledWith(
        email: email
    )
)

【讨论】:

【参考方案2】:

您可以使用inject-loader 模拟您的服务

基本思路:

const RecoveryEmailSentInjector = require('!!vue-loader?inject!./AccountManagement.RecoveryEmailSent')
import Service from '@/someDir/Service'

const mockedServices = 
  '@/someDir/Service': Service


describe('Recovery Email Sent', () => 

    it('should resend recovery email', async () => 
      const RecoveryEmailSentWithMocks = RecoveryEmailSentInjector(mockedServices)

      const wrapper = mount(RecoveryEmailSentWithMocks,  
        ...
      )
      await wrapper.find('button').trigger('click')
      expect(mockMethods.resend).toHaveBeenCalled()
      expect(mockedServices.requestPasswordReset).toHaveBeenCalled()
    )
)

【讨论】:

以上是关于Vue Test Utils / Jest - 如何测试是不是在组件方法中调用了类方法的主要内容,如果未能解决你的问题,请参考以下文章

带有 vue-test-utils 和 Jest 的 Vue.js 单元测试用例失败

使用 `vue-test-utils` 和 `jest` 使用 `Created` 钩子进行测试

如何在单元测试期间使用 vue-test-utils 和 jest 模拟 mixin?

如何使用 Vue-test-utils 和 Jest 测试 Vuex 突变

带有 jest 的 vue-test-utils 为 map-spread 运算符抛出了意外的令牌错误

无法在基于 jest 和 vue-test-utils 的测试项目中使用 vue.js 的 ES6 模块